Skip to content

[explorer] Improve testing for new features implemented #3383

[explorer] Improve testing for new features implemented

[explorer] Improve testing for new features implemented #3383

name: "Issue Work Started"
description: "Update issue work started date when Status field changes to In Progress"
on:
# Manual trigger for testing and specific issue updates
workflow_dispatch:
inputs:
issue_number:
description: 'Issue number to update'
required: false
type: string
default: ''
bulk_update:
description: 'Bulk update all issues'
required: false
type: boolean
default: false
# Automatic trigger for any issue activity
issues:
types: [opened, edited, closed, reopened, assigned, unassigned, labeled, unlabeled]
# Daily schedule to check all issues and update Work Started field
schedule:
# Run at 11 PM Central Time (5 AM UTC the next day)
- cron: '0 5 * * *'
permissions:
repository-projects: write
issues: read
contents: read
jobs:
update_work_started:
# Skip if the actor is a bot to avoid infinite loops
if: github.actor != 'github-actions[bot]' && github.actor != 'dependabot[bot]' && ( github.event.inputs.issue_number || inputs.issue_number != '')
runs-on: ubuntu-latest
steps:
- name: Determine Issue Number
id: get_issue_number
run: |
# Extract issue number based on trigger type
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
# Manual trigger
issue_number="${{ github.event.inputs.issue_number }}"
echo "Manual trigger for issue #$issue_number"
elif [[ "${{ github.event_name }}" == "issues" ]]; then
# Issue events
issue_number="${{ github.event.issue.number }}"
echo "Issue event triggered for issue #$issue_number"
else
echo "Unknown trigger type: ${{ github.event_name }}, skipping"
exit 0
fi
if [[ -z "$issue_number" || "$issue_number" == "null" ]]; then
echo "Could not determine issue number, skipping"
exit 0
fi
echo "issue_number=$issue_number" >> $GITHUB_OUTPUT
echo "Processing issue #$issue_number"
- name: Set Environment Variables
run: |
echo "project_id=PVT_kwDOA9MHEM4AjeTl" >> $GITHUB_ENV
echo "work_started_field_id=PVTF_lADOA9MHEM4AjeTlzgzZQtk" >> $GITHUB_ENV
echo "status_field_id=PVTSSF_lADOA9MHEM4AjeTlzgb1Hjo" >> $GITHUB_ENV
- name: Get Issue ID
id: get_issue_id
run: |
issue_number="${{ steps.get_issue_number.outputs.issue_number }}"
echo "Getting issue ID for issue #$issue_number"
issue_details=$(curl -H "Authorization: Bearer ${{ secrets.TT_FORGE_PROJECT }}" -s "https://api.github.com/repos/${{ github.repository }}/issues/$issue_number")
issue_id=$(echo "$issue_details" | jq -r '.node_id')
echo "issue_id=$issue_id" >> $GITHUB_ENV
- name: Get Project Item ID
id: get_item_id
run: |
source $GITHUB_ENV
found_item_id=""
cursor=""
page_count=0
echo "Searching for issue ID: $issue_id in project: $project_id"
# Search through all pages to find the issue
while true; do
page_count=$((page_count + 1))
echo "Searching page $page_count..."
# Build the query with or without cursor
if [[ -z "$cursor" ]]; then
QUERY='query($projectId: ID!) {
node(id: $projectId) {
... on ProjectV2 {
items(first: 100) {
pageInfo {
hasNextPage
endCursor
}
nodes {
id
content {
... on Issue {
id
}
}
}
}
}
}
}'
JSON_PAYLOAD=$(jq -n \
--arg query "$QUERY" \
--arg projectId "$project_id" \
'{ query: $query, variables: { projectId: $projectId }}')
else
QUERY='query($projectId: ID!, $cursor: String!) {
node(id: $projectId) {
... on ProjectV2 {
items(first: 100, after: $cursor) {
pageInfo {
hasNextPage
endCursor
}
nodes {
id
content {
... on Issue {
id
}
}
}
}
}
}
}'
JSON_PAYLOAD=$(jq -n \
--arg query "$QUERY" \
--arg projectId "$project_id" \
--arg cursor "$cursor" \
'{ query: $query, variables: { projectId: $projectId, cursor: $cursor }}')
fi
# Make the GraphQL request
RESPONSE=$(curl -s -X POST -H "Authorization: Bearer ${{ secrets.TT_FORGE_PROJECT }}" \
-H "Content-Type: application/json" \
-d "$JSON_PAYLOAD" \
https://api.github.com/graphql)
# Check for errors
ERRORS=$(echo "$RESPONSE" | jq -r '.errors // empty')
if [[ -n "$ERRORS" && "$ERRORS" != "null" ]]; then
echo "GraphQL Error: $ERRORS"
exit 0
fi
# Look for the issue in current batch
ITEM_ID=$(echo "$RESPONSE" | jq -r --arg issue_id "$issue_id" \
'.data.node.items.nodes[]? | select(.content.id==$issue_id) | .id')
if [[ -n "$ITEM_ID" && "$ITEM_ID" != "null" ]]; then
found_item_id="$ITEM_ID"
echo "Found issue in project"
break
fi
# Check if there are more pages
has_next_page=$(echo "$RESPONSE" | jq -r '.data.node.items.pageInfo.hasNextPage // false')
if [[ "$has_next_page" != "true" ]]; then
echo "Searched all $page_count pages. No more pages available."
break
fi
# Get cursor for next page
cursor=$(echo "$RESPONSE" | jq -r '.data.node.items.pageInfo.endCursor')
if [[ $page_count -gt 100 ]]; then
echo "Searched 100 pages (10,000+ items). Stopping to prevent infinite loop."
break
fi
done
# If issue not found in project, exit with error
if [[ -z "$found_item_id" ]]; then
echo "Issue not found in project after searching all pages."
echo "The issue may not be added to this project yet."
echo "Please manually add the issue to the project first."
exit 0
fi
echo "item_id=$found_item_id" >> $GITHUB_OUTPUT
- name: Check Status Field
if: steps.get_item_id.outputs.item_id != ''
id: check_status
run: |
source $GITHUB_ENV
# Query to get the current Status field value with timestamp
QUERY='query($itemId: ID!) {
node(id: $itemId) {
... on ProjectV2Item {
fieldValues(first: 20) {
nodes {
... on ProjectV2ItemFieldSingleSelectValue {
field {
... on ProjectV2Field {
id
name
}
}
name
optionId
updatedAt
}
... on ProjectV2ItemFieldDateValue {
field {
... on ProjectV2Field {
id
name
}
}
date
updatedAt
}
}
}
}
}
}'
JSON_PAYLOAD=$(jq -n \
--arg query "$QUERY" \
--arg itemId "${{ steps.get_item_id.outputs.item_id }}" \
'{ query: $query, variables: { itemId: $itemId }}')
RESPONSE=$(curl -s -X POST \
-H "Authorization: Bearer ${{ secrets.TT_FORGE_PROJECT }}" \
-H "Content-Type: application/json" \
-d "$JSON_PAYLOAD" \
https://api.github.com/graphql)
ERRORS=$(echo "$RESPONSE" | jq -r '.errors // empty')
if [[ -n "$ERRORS" && "$ERRORS" != "null" ]]; then
echo "GraphQL Error checking status: $ERRORS"
exit 0
fi
# Extract Status field value and its update timestamp
# For single select fields, we need to find by matching known Status values
STATUS_VALUE=$(echo "$RESPONSE" | jq -r \
'.data.node.fieldValues.nodes[] |
select(.name and (.name=="In Progress" or .name=="Assigned" or .name=="Screen" or .name=="Blocked" or .name=="Done" or .name=="In Review")) | .name')
STATUS_UPDATED_AT=$(echo "$RESPONSE" | jq -r \
'.data.node.fieldValues.nodes[] |
select(.name and (.name=="In Progress" or .name=="Assigned" or .name=="Screen" or .name=="Blocked" or .name=="Done" or .name=="In Review")) | .updatedAt')
# Extract Work Started field value to check if it's already set
WORK_STARTED_VALUE=$(echo "$RESPONSE" | jq -r --arg work_started_field_id "$work_started_field_id" \
'.data.node.fieldValues.nodes[] |
select(.field.id==$work_started_field_id or .field.name=="Work Started") | .date')
if [[ "$STATUS_VALUE" == "In Progress" ]]; then
if [[ -z "$WORK_STARTED_VALUE" || "$WORK_STARTED_VALUE" == "null" ]]; then
# Convert timestamp to date format (YYYY-MM-DD)
if [[ -n "$STATUS_UPDATED_AT" && "$STATUS_UPDATED_AT" != "null" ]]; then
status_date=$(echo "$STATUS_UPDATED_AT" | cut -d'T' -f1)
echo "Status changed to 'In Progress' on: $status_date (from timestamp: $STATUS_UPDATED_AT)"
echo "should_update=true" >> $GITHUB_OUTPUT
echo "work_started_date=$status_date" >> $GITHUB_OUTPUT
else
echo "Could not determine when status changed - using current date as fallback"
current_date=$(date +%Y-%m-%d)
echo "should_update=true" >> $GITHUB_OUTPUT
echo "work_started_date=$current_date" >> $GITHUB_OUTPUT
fi
else
echo "Status is 'In Progress' but Work Started already set to '$WORK_STARTED_VALUE' - skipping to avoid overwriting"
echo "should_update=false" >> $GITHUB_OUTPUT
fi
elif [[ -z "$STATUS_VALUE" || "$STATUS_VALUE" == "null" ]]; then
echo "Status field not found or empty - skipping update"
echo "should_update=false" >> $GITHUB_OUTPUT
else
echo "Status is '$STATUS_VALUE' - not 'In Progress', skipping update"
echo "should_update=false" >> $GITHUB_OUTPUT
fi
- name: Update Work Started Field
if: steps.check_status.outputs.should_update == 'true'
run: |
source $GITHUB_ENV
work_started_date="${{ steps.check_status.outputs.work_started_date }}"
echo "Setting Work Started date to: $work_started_date (date when status changed to 'In Progress')"
RESPONSE=$(curl -s -X POST \
-H "Authorization: Bearer ${{ secrets.TT_FORGE_PROJECT }}" \
-H "Content-Type: application/json" \
-d "{ \"query\": \"mutation { updateProjectV2ItemFieldValue(input: { projectId: \\\"$project_id\\\", itemId: \\\"${{ steps.get_item_id.outputs.item_id }}\\\", fieldId: \\\"$work_started_field_id\\\", value: { date: \\\"$work_started_date\\\" } }) { clientMutationId } }\" }" \
https://api.github.com/graphql)
ERRORS=$(echo "$RESPONSE" | jq -r '.errors // empty')
if [[ -n "$ERRORS" && "$ERRORS" != "null" ]]; then
echo "GraphQL Error: $ERRORS"
exit 0
fi
- name: Verify Work Started Field Update
if: steps.check_status.outputs.should_update == 'true'
run: |
source $GITHUB_ENV
echo "Verifying Work Started field was updated..."
# Query to get the current Work Started field value
VERIFY_QUERY='query($itemId: ID!) {
node(id: $itemId) {
... on ProjectV2Item {
fieldValues(first: 20) {
nodes {
... on ProjectV2ItemFieldDateValue {
field {
... on ProjectV2Field {
id
name
}
}
date
}
}
}
}
}
}'
JSON_PAYLOAD=$(jq -n \
--arg query "$VERIFY_QUERY" \
--arg itemId "${{ steps.get_item_id.outputs.item_id }}" \
'{ query: $query, variables: { itemId: $itemId }}')
VERIFY_RESPONSE=$(curl -s -X POST \
-H "Authorization: Bearer ${{ secrets.TT_FORGE_PROJECT }}" \
-H "Content-Type: application/json" \
-d "$JSON_PAYLOAD" \
https://api.github.com/graphql)
WORK_STARTED_VALUE=$(echo "$VERIFY_RESPONSE" | jq -r --arg work_started_field_id "$work_started_field_id" \
'.data.node.fieldValues.nodes[] |
select(.field.id==$work_started_field_id or .field.name=="Work Started") | .date')
echo "Work Started field set to: $WORK_STARTED_VALUE (date when status changed to 'In Progress')"
# Bulk processing job for scheduled runs
bulk_update_work_started:
# Only run on scheduled triggers (cron)
if: github.event_name == 'schedule' || inputs.bulk_update
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set Environment Variables
run: |
echo "project_id=PVT_kwDOA9MHEM4AjeTl" >> $GITHUB_ENV
echo "work_started_field_id=PVTF_lADOA9MHEM4AjeTlzgzZQtk" >> $GITHUB_ENV
- name: python install
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Run bulk update
env:
GITHUB_TOKEN: ${{ secrets.TT_FORGE_PROJECT }}
run: |
pip install -r ./.github/scripts/python/bulk_update_issues/requirements-bulk-update.txt
python ./.github/scripts/python/bulk_update_issues/bulk_update_issues.py