One-time baseline — move closed issues to their terminal column #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: One-time baseline — move closed issues to their terminal column | |
| # Run this ONCE (dry_run first) before enabling board-reopen-reconcile's | |
| # schedule. It moves any already-closed issue that is sitting in a | |
| # non-terminal column into its terminal column (Org Kanban -> Done, | |
| # Open Roles -> Filled). That establishes a clean baseline so the reopen | |
| # reconciler never resurrects issues that were closed before this automation | |
| # existed. Safe to delete after a successful run, or keep as a manual repair | |
| # tool. See docs/active-spikes/board-sync-redesign.md. | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| dry_run: | |
| description: 'Dry run (log without changing status)' | |
| required: false | |
| default: 'true' | |
| type: boolean | |
| env: | |
| GH_TOKEN: ${{ secrets.ACTIONS_TOKEN }} | |
| jobs: | |
| baseline-cleanup: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Move closed issues in non-terminal columns to their terminal column | |
| run: | | |
| DRY_RUN="${{ github.event.inputs.dry_run || 'true' }}" | |
| echo "Dry run: $DRY_RUN" | |
| echo "---" | |
| cleanup_board() { | |
| PROJECT_ID="$1" | |
| STATUS_FIELD_ID="$2" | |
| TERMINAL_OPTION="$3" | |
| BOARD_NAME="$4" | |
| CURSOR="" | |
| while true; do | |
| if [ -n "$CURSOR" ]; then | |
| RESULT=$(gh api graphql -f query=' | |
| query($project: ID!, $cursor: String!) { | |
| node(id: $project) { | |
| ... on ProjectV2 { | |
| items(first: 100, after: $cursor) { | |
| nodes { | |
| id | |
| fieldValueByName(name: "Status") { | |
| ... on ProjectV2ItemFieldSingleSelectValue { optionId } | |
| } | |
| content { ... on Issue { number state } } | |
| } | |
| pageInfo { hasNextPage endCursor } | |
| } | |
| } | |
| } | |
| }' -f project="$PROJECT_ID" -f cursor="$CURSOR") | |
| else | |
| RESULT=$(gh api graphql -f query=' | |
| query($project: ID!) { | |
| node(id: $project) { | |
| ... on ProjectV2 { | |
| items(first: 100) { | |
| nodes { | |
| id | |
| fieldValueByName(name: "Status") { | |
| ... on ProjectV2ItemFieldSingleSelectValue { optionId } | |
| } | |
| content { ... on Issue { number state } } | |
| } | |
| pageInfo { hasNextPage endCursor } | |
| } | |
| } | |
| } | |
| }' -f project="$PROJECT_ID") | |
| fi | |
| HAS_NEXT=$(echo "$RESULT" | jq -r '.data.node.items.pageInfo.hasNextPage') | |
| CURSOR=$(echo "$RESULT" | jq -r '.data.node.items.pageInfo.endCursor') | |
| while IFS= read -r item; do | |
| ITEM_ID=$(echo "$item" | jq -r '.id') | |
| OPTION_ID=$(echo "$item" | jq -r '.fieldValueByName.optionId // ""') | |
| NUMBER=$(echo "$item" | jq -r '.content.number // ""') | |
| STATE=$(echo "$item" | jq -r '.content.state // ""') | |
| # Only closed issues, with a status set, not already terminal | |
| [ "$STATE" != "CLOSED" ] && continue | |
| [ -z "$OPTION_ID" ] && continue | |
| [ "$OPTION_ID" == "$TERMINAL_OPTION" ] && continue | |
| echo "Would move #$NUMBER ($BOARD_NAME) to its terminal column." | |
| if [ "$DRY_RUN" != "true" ]; then | |
| gh api graphql -f query=' | |
| mutation($project: ID!, $item: ID!, $field: ID!, $option: String!) { | |
| updateProjectV2ItemFieldValue(input: { | |
| projectId: $project, | |
| itemId: $item, | |
| fieldId: $field, | |
| value: { singleSelectOptionId: $option } | |
| }) { | |
| projectV2Item { id } | |
| } | |
| }' -f project="$PROJECT_ID" -f item="$ITEM_ID" \ | |
| -f field="$STATUS_FIELD_ID" -f option="$TERMINAL_OPTION" > /dev/null | |
| echo " → Moved." | |
| fi | |
| done < <(echo "$RESULT" | jq -c '.data.node.items.nodes[]') | |
| [ "$HAS_NEXT" != "true" ] && break | |
| done | |
| } | |
| # Org Kanban -> Done, Open Roles -> Filled | |
| cleanup_board "PVT_kwDOAA7NZM4AqQF8" "PVTSSF_lADOAA7NZM4AqQF8zghh1hc" "98236657" "Org Kanban" | |
| cleanup_board "PVT_kwDOAA7NZM4AmdbW" "PVTSSF_lADOAA7NZM4AmdbWzgeWrcw" "47fc9ee4" "Open Roles" | |
| echo "---" | |
| if [ "$DRY_RUN" == "true" ]; then | |
| echo "Dry run complete. Run with dry_run=false to apply." | |
| fi |