Auto-Merge: auto/histogram-basic/matplotlib #343
Workflow file for this run
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: "Bot: Auto-Merge" | |
| run-name: "Auto-Merge: ${{ github.event.inputs.pr_number || github.event.pull_request.head.ref || 'push' }}" | |
| on: | |
| pull_request: | |
| types: [labeled, closed] | |
| workflow_dispatch: | |
| inputs: | |
| pr_number: | |
| description: 'PR number to auto-merge' | |
| required: true | |
| type: number | |
| push: | |
| branches: [main] | |
| paths: | |
| - 'plots/**' | |
| jobs: | |
| # ============================================================================ | |
| # Job 1: Enable auto-merge when ai-approved label is added or dispatched | |
| # ============================================================================ | |
| auto-merge: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| issues: write | |
| steps: | |
| - name: Check conditions | |
| id: check | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| # Handle workflow_dispatch trigger | |
| if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | |
| PR_NUM="${{ github.event.inputs.pr_number }}" | |
| PR_DATA=$(gh pr view "$PR_NUM" --repo ${{ github.repository }} --json headRefName,labels) | |
| BRANCH=$(echo "$PR_DATA" | jq -r '.headRefName') | |
| HAS_APPROVED=$(echo "$PR_DATA" | jq -r '.labels[].name' | grep -c "ai-approved" || echo "0") | |
| if [[ ! "$BRANCH" =~ ^auto/ ]]; then | |
| echo "::notice::Skipping: Branch '$BRANCH' is not auto/*" | |
| echo "should_run=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| if [[ "$HAS_APPROVED" == "0" ]]; then | |
| echo "::notice::Skipping: PR does not have ai-approved label" | |
| echo "should_run=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| echo "pr_number=$PR_NUM" >> $GITHUB_OUTPUT | |
| echo "branch=$BRANCH" >> $GITHUB_OUTPUT | |
| echo "should_run=true" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| # Handle pull_request labeled trigger | |
| ACTION="${{ github.event.action }}" | |
| LABEL="${{ github.event.label.name }}" | |
| BRANCH="${{ github.event.pull_request.head.ref }}" | |
| if [[ "$ACTION" != "labeled" ]]; then | |
| echo "::notice::Skipping: Action is '$ACTION', not 'labeled'" | |
| echo "should_run=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| if [[ "$LABEL" != "ai-approved" ]]; then | |
| echo "::notice::Skipping: Label is '$LABEL', not 'ai-approved'" | |
| echo "should_run=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| if [[ ! "$BRANCH" =~ ^auto/ ]]; then | |
| echo "::notice::Skipping: Branch '$BRANCH' is not auto/*" | |
| echo "should_run=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| echo "pr_number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT | |
| echo "branch=$BRANCH" >> $GITHUB_OUTPUT | |
| echo "should_run=true" >> $GITHUB_OUTPUT | |
| - name: Checkout repository | |
| if: steps.check.outputs.should_run == 'true' | |
| uses: actions/checkout@v6 | |
| - name: Extract info from branch | |
| if: steps.check.outputs.should_run == 'true' | |
| id: extract | |
| run: | | |
| BRANCH="${{ steps.check.outputs.branch }}" | |
| # Format: auto/{spec-id}/{library} | |
| SPEC_ID=$(echo "$BRANCH" | cut -d'/' -f2) | |
| LIBRARY=$(echo "$BRANCH" | cut -d'/' -f3) | |
| echo "spec_id=$SPEC_ID" >> $GITHUB_OUTPUT | |
| echo "library=$LIBRARY" >> $GITHUB_OUTPUT | |
| - name: Get sub-issue from PR body | |
| if: steps.check.outputs.should_run == 'true' | |
| id: sub_issue | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| PR_NUM="${{ steps.check.outputs.pr_number }}" | |
| PR_BODY=$(gh pr view "$PR_NUM" --json body -q '.body' 2>/dev/null || echo "") | |
| SUB_ISSUE=$(echo "$PR_BODY" | grep -oP '\*\*Sub-Issue:\*\* #\K\d+' | head -1 || echo "") | |
| echo "number=$SUB_ISSUE" >> $GITHUB_OUTPUT | |
| - name: React with rocket emoji | |
| if: steps.check.outputs.should_run == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| gh api repos/${{ github.repository }}/issues/${{ steps.check.outputs.pr_number }}/reactions \ | |
| -f content=rocket | |
| - name: Update sub-issue label | |
| if: steps.check.outputs.should_run == 'true' && steps.sub_issue.outputs.number != '' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| gh issue edit ${{ steps.sub_issue.outputs.number }} \ | |
| --remove-label "reviewing" \ | |
| --remove-label "ai-rejected" \ | |
| --add-label "ai-approved" | |
| - name: Merge PR directly | |
| if: steps.check.outputs.should_run == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| gh pr merge ${{ steps.check.outputs.pr_number }} \ | |
| --repo ${{ github.repository }} \ | |
| --squash \ | |
| --delete-branch | |
| - name: Close sub-issue after merge | |
| if: steps.check.outputs.should_run == 'true' && steps.sub_issue.outputs.number != '' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| SUB_ISSUE="${{ steps.sub_issue.outputs.number }}" | |
| LIBRARY="${{ steps.extract.outputs.library }}" | |
| SPEC_ID="${{ steps.extract.outputs.spec_id }}" | |
| PR_NUM="${{ steps.check.outputs.pr_number }}" | |
| echo "Closing sub-issue #$SUB_ISSUE after merge" | |
| # Update labels | |
| gh issue edit $SUB_ISSUE \ | |
| --remove-label "ai-approved" \ | |
| --remove-label "reviewing" \ | |
| --remove-label "generating" \ | |
| --remove-label "testing" \ | |
| --add-label "merged" 2>/dev/null || true | |
| # Post completion comment (only if not already posted) | |
| EXISTING_MERGED=$(gh issue view $SUB_ISSUE --json comments -q '[.comments[].body | select(startswith("## Merged"))] | length' 2>/dev/null || echo "0") | |
| if [ "$EXISTING_MERGED" = "0" ]; then | |
| gh issue comment $SUB_ISSUE --body "## Merged | |
| **$LIBRARY** implementation for \`$SPEC_ID\` has been merged! | |
| - **PR:** #$PR_NUM | |
| --- | |
| :rocket: *Auto-merged by pyplots CI*" | |
| fi | |
| # Close sub-issue (ignore if already closed) | |
| gh issue close $SUB_ISSUE --reason completed 2>/dev/null || true | |
| echo "Sub-issue #$SUB_ISSUE closed" | |
| - name: Get main issue number | |
| if: steps.check.outputs.should_run == 'true' | |
| id: main_issue | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| PR_NUM="${{ steps.check.outputs.pr_number }}" | |
| SPEC_ID="${{ steps.extract.outputs.spec_id }}" | |
| PR_BODY=$(gh pr view "$PR_NUM" --json body -q '.body' 2>/dev/null || echo "") | |
| # Extract main issue from PR body | |
| MAIN_ISSUE=$(echo "$PR_BODY" | grep -oP '\*\*Parent Issue:\*\* #\K\d+' | head -1 || echo "") | |
| # Fallback: search for main issue | |
| if [ -z "$MAIN_ISSUE" ]; then | |
| MAIN_ISSUE=$(gh issue list --label plot-request --search "$SPEC_ID in:title" --json number -q '.[0].number' 2>/dev/null || echo "") | |
| fi | |
| echo "number=$MAIN_ISSUE" >> $GITHUB_OUTPUT | |
| echo "Main issue: #$MAIN_ISSUE" | |
| - name: Check if all libraries are done | |
| if: steps.check.outputs.should_run == 'true' && steps.main_issue.outputs.number != '' | |
| id: check_complete | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| MAIN_ISSUE="${{ steps.main_issue.outputs.number }}" | |
| # Get all sub-issues for this main issue | |
| SUB_ISSUES=$(gh issue list --label "plot-request:impl" --search "Parent Issue.*#$MAIN_ISSUE" --state all --json number,labels -q '.' 2>/dev/null || echo "[]") | |
| # Count statuses (use 'any' to avoid double-counting issues with multiple labels) | |
| TOTAL=$(echo "$SUB_ISSUES" | jq 'length') | |
| MERGED=$(echo "$SUB_ISSUES" | jq '[.[] | select(any(.labels[]; .name == "merged"))] | length') | |
| NOT_FEASIBLE=$(echo "$SUB_ISSUES" | jq '[.[] | select(any(.labels[]; .name == "not-feasible"))] | length') | |
| DONE=$((MERGED + NOT_FEASIBLE)) | |
| echo "total=$TOTAL" >> $GITHUB_OUTPUT | |
| echo "merged=$MERGED" >> $GITHUB_OUTPUT | |
| echo "not_feasible=$NOT_FEASIBLE" >> $GITHUB_OUTPUT | |
| if [ "$DONE" -eq "$TOTAL" ] && [ "$TOTAL" -gt 0 ]; then | |
| echo "all_done=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "all_done=false" >> $GITHUB_OUTPUT | |
| fi | |
| echo "Progress: $DONE/$TOTAL complete ($MERGED merged, $NOT_FEASIBLE not feasible)" | |
| - name: Create and merge feature-to-main PR | |
| if: steps.check.outputs.should_run == 'true' && steps.check_complete.outputs.all_done == 'true' && steps.main_issue.outputs.number != '' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| SPEC_ID="${{ steps.extract.outputs.spec_id }}" | |
| MAIN_ISSUE="${{ steps.main_issue.outputs.number }}" | |
| MERGED="${{ steps.check_complete.outputs.merged }}" | |
| NOT_FEASIBLE="${{ steps.check_complete.outputs.not_feasible }}" | |
| # Check if main issue already completed | |
| LABELS=$(gh issue view "$MAIN_ISSUE" --json labels -q '.labels[].name' 2>/dev/null || echo "") | |
| if echo "$LABELS" | grep -q "completed"; then | |
| echo "Main issue #$MAIN_ISSUE already completed" | |
| exit 0 | |
| fi | |
| # Check if feature branch exists | |
| if ! gh api repos/${{ github.repository }}/branches/plot/$SPEC_ID &>/dev/null; then | |
| echo "Feature branch plot/$SPEC_ID does not exist, skipping" | |
| exit 0 | |
| fi | |
| # Check if PR already exists | |
| EXISTING_PR=$(gh pr list --base main --head "plot/$SPEC_ID" --json number -q '.[0].number' 2>/dev/null || echo "") | |
| if [ -n "$EXISTING_PR" ]; then | |
| echo "PR #$EXISTING_PR already exists for plot/$SPEC_ID -> main" | |
| gh pr merge "$EXISTING_PR" --squash --delete-branch --auto 2>/dev/null || true | |
| FEATURE_PR="$EXISTING_PR" | |
| else | |
| # Create PR from feature branch to main | |
| FEATURE_PR=$(gh pr create \ | |
| --base main \ | |
| --head "plot/$SPEC_ID" \ | |
| --title "feat: add $SPEC_ID implementation ($MERGED libraries)" \ | |
| --body "## Summary | |
| Adds \`$SPEC_ID\` plot implementation. | |
| ### Libraries | |
| - **Merged:** $MERGED | |
| - **Not Feasible:** $NOT_FEASIBLE | |
| ### Links | |
| - **Spec:** \`specs/$SPEC_ID.md\` | |
| - **Parent Issue:** #$MAIN_ISSUE (closes on merge) | |
| --- | |
| :robot: *Auto-generated by pyplots CI*" | sed 's|.*/||') | |
| echo "Created PR #$FEATURE_PR" | |
| # Enable auto-merge | |
| gh pr merge "$FEATURE_PR" --squash --delete-branch --auto 2>/dev/null || true | |
| fi | |
| # Post completion to main issue | |
| if [ "$NOT_FEASIBLE" -gt 0 ]; then | |
| STATUS_MSG="$MERGED libraries ready, $NOT_FEASIBLE not feasible" | |
| else | |
| STATUS_MSG="All $MERGED libraries ready" | |
| fi | |
| gh issue comment "$MAIN_ISSUE" --body "## :tada: All Libraries Complete! | |
| **Status:** $STATUS_MSG | |
| **Feature PR:** #$FEATURE_PR (auto-merge enabled) | |
| --- | |
| :rocket: *pyplots CI*" | |
| # Add completed label | |
| gh issue edit "$MAIN_ISSUE" --add-label "completed" 2>/dev/null || true | |
| # ============================================================================ | |
| # Job 2: Post-merge summary (per library) - only for PR close events | |
| # ============================================================================ | |
| post-merge-summary: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| issues: write | |
| pull-requests: read | |
| steps: | |
| - name: Check conditions | |
| id: check | |
| run: | | |
| ACTION="${{ github.event.action }}" | |
| MERGED="${{ github.event.pull_request.merged }}" | |
| BRANCH="${{ github.event.pull_request.head.ref }}" | |
| if [[ "$ACTION" != "closed" ]]; then | |
| echo "::notice::Skipping: Action is '$ACTION', not 'closed'" | |
| echo "should_run=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| if [[ "$MERGED" != "true" ]]; then | |
| echo "::notice::Skipping: PR was closed but not merged" | |
| echo "should_run=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| if [[ ! "$BRANCH" =~ ^auto/ ]]; then | |
| echo "::notice::Skipping: Branch '$BRANCH' is not auto/*" | |
| echo "should_run=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| echo "should_run=true" >> $GITHUB_OUTPUT | |
| - name: Checkout code | |
| if: steps.check.outputs.should_run == 'true' | |
| uses: actions/checkout@v6 | |
| - name: Extract spec ID, library, and issues | |
| if: steps.check.outputs.should_run == 'true' | |
| id: extract | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| BRANCH="${{ github.event.pull_request.head.ref }}" | |
| PR_NUM="${{ github.event.pull_request.number }}" | |
| PR_BODY=$(gh pr view "$PR_NUM" --json body -q '.body' 2>/dev/null || echo "") | |
| # Format: auto/{spec-id}/{library} | |
| SPEC_ID=$(echo "$BRANCH" | cut -d'/' -f2) | |
| LIBRARY=$(echo "$BRANCH" | cut -d'/' -f3) | |
| # Extract issues from PR body | |
| SUB_ISSUE=$(echo "$PR_BODY" | grep -oP '\*\*Sub-Issue:\*\* #\K\d+' | head -1 || echo "") | |
| MAIN_ISSUE=$(echo "$PR_BODY" | grep -oP '\*\*Parent Issue:\*\* #\K\d+' | head -1 || echo "") | |
| # Fallback: search for main issue | |
| if [ -z "$MAIN_ISSUE" ]; then | |
| MAIN_ISSUE=$(gh issue list --label plot-request --search "$SPEC_ID in:title" --json number -q '.[0].number' || echo "") | |
| fi | |
| echo "spec_id=$SPEC_ID" >> $GITHUB_OUTPUT | |
| echo "library=$LIBRARY" >> $GITHUB_OUTPUT | |
| echo "sub_issue=$SUB_ISSUE" >> $GITHUB_OUTPUT | |
| echo "main_issue=$MAIN_ISSUE" >> $GITHUB_OUTPUT | |
| echo "Spec: $SPEC_ID, Library: $LIBRARY, Sub: #$SUB_ISSUE, Main: #$MAIN_ISSUE" | |
| - name: Find implementation file | |
| if: steps.check.outputs.should_run == 'true' | |
| id: files | |
| run: | | |
| SPEC_ID="${{ steps.extract.outputs.spec_id }}" | |
| LIBRARY="${{ steps.extract.outputs.library }}" | |
| # Find implementation file for this library | |
| IMPL_FILE=$(find plots/$LIBRARY -name "default.py" -path "*/$SPEC_ID/*" 2>/dev/null | head -1 || echo "") | |
| echo "impl_file=$IMPL_FILE" >> $GITHUB_OUTPUT | |
| - name: Update sub-issue to merged | |
| if: steps.check.outputs.should_run == 'true' && steps.extract.outputs.sub_issue != '' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| SUB_ISSUE="${{ steps.extract.outputs.sub_issue }}" | |
| LIBRARY="${{ steps.extract.outputs.library }}" | |
| SPEC_ID="${{ steps.extract.outputs.spec_id }}" | |
| PR_NUM="${{ github.event.pull_request.number }}" | |
| # Check if already merged (skip if so) | |
| LABELS=$(gh issue view "$SUB_ISSUE" --json labels -q '.labels[].name' 2>/dev/null || echo "") | |
| if echo "$LABELS" | grep -q "merged"; then | |
| echo "Sub-issue #$SUB_ISSUE already merged, skipping" | |
| exit 0 | |
| fi | |
| # Update labels | |
| gh issue edit $SUB_ISSUE \ | |
| --remove-label "ai-approved" \ | |
| --remove-label "reviewing" \ | |
| --remove-label "generating" \ | |
| --remove-label "testing" \ | |
| --add-label "merged" 2>/dev/null || true | |
| # Post completion comment (only if not already posted) | |
| EXISTING_MERGED=$(gh issue view $SUB_ISSUE --json comments -q '[.comments[].body | select(startswith("## Merged"))] | length' 2>/dev/null || echo "0") | |
| if [ "$EXISTING_MERGED" = "0" ]; then | |
| gh issue comment $SUB_ISSUE --body "## Merged | |
| **$LIBRARY** implementation for \`$SPEC_ID\` has been merged! | |
| - **PR:** #$PR_NUM | |
| --- | |
| :rocket: *Auto-merged by pyplots CI*" | |
| fi | |
| # Close sub-issue | |
| gh issue close $SUB_ISSUE --reason completed 2>/dev/null || true | |
| - name: Check if all libraries are done | |
| if: steps.check.outputs.should_run == 'true' | |
| id: check_complete | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| MAIN_ISSUE="${{ steps.extract.outputs.main_issue }}" | |
| if [ -z "$MAIN_ISSUE" ]; then | |
| echo "all_done=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| # Get all sub-issues for this main issue | |
| SUB_ISSUES=$(gh issue list --search "**Parent Issue:** #$MAIN_ISSUE in:body" --json number,labels -q '.') | |
| # Count statuses (use 'any' to avoid double-counting issues with multiple labels) | |
| TOTAL=$(echo "$SUB_ISSUES" | jq 'length') | |
| MERGED=$(echo "$SUB_ISSUES" | jq '[.[] | select(any(.labels[]; .name == "merged"))] | length') | |
| NOT_FEASIBLE=$(echo "$SUB_ISSUES" | jq '[.[] | select(any(.labels[]; .name == "not-feasible"))] | length') | |
| DONE=$((MERGED + NOT_FEASIBLE)) | |
| echo "total=$TOTAL" >> $GITHUB_OUTPUT | |
| echo "merged=$MERGED" >> $GITHUB_OUTPUT | |
| echo "not_feasible=$NOT_FEASIBLE" >> $GITHUB_OUTPUT | |
| if [ "$DONE" -eq "$TOTAL" ] && [ "$TOTAL" -gt 0 ]; then | |
| echo "all_done=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "all_done=false" >> $GITHUB_OUTPUT | |
| fi | |
| echo "Progress: $DONE/$TOTAL complete ($MERGED merged, $NOT_FEASIBLE not feasible)" | |
| - name: Post progress to main issue | |
| if: steps.check.outputs.should_run == 'true' && steps.extract.outputs.main_issue != '' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| MAIN_ISSUE="${{ steps.extract.outputs.main_issue }}" | |
| LIBRARY="${{ steps.extract.outputs.library }}" | |
| SPEC_ID="${{ steps.extract.outputs.spec_id }}" | |
| PR_NUM="${{ github.event.pull_request.number }}" | |
| MERGED="${{ steps.check_complete.outputs.merged }}" | |
| NOT_FEASIBLE="${{ steps.check_complete.outputs.not_feasible }}" | |
| TOTAL="${{ steps.check_complete.outputs.total }}" | |
| gh issue comment $MAIN_ISSUE --body "## :white_check_mark: $LIBRARY Merged | |
| **$LIBRARY** implementation for \`$SPEC_ID\` has been merged! | |
| **Progress:** $MERGED merged, $NOT_FEASIBLE not feasible, $((TOTAL - MERGED - NOT_FEASIBLE)) pending | |
| --- | |
| :robot: *PR #$PR_NUM*" | |
| - name: Create and merge feature-to-main PR | |
| if: steps.check.outputs.should_run == 'true' && steps.check_complete.outputs.all_done == 'true' && steps.extract.outputs.main_issue != '' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| SPEC_ID="${{ steps.extract.outputs.spec_id }}" | |
| MAIN_ISSUE="${{ steps.extract.outputs.main_issue }}" | |
| MERGED="${{ steps.check_complete.outputs.merged }}" | |
| NOT_FEASIBLE="${{ steps.check_complete.outputs.not_feasible }}" | |
| # Check if feature branch exists | |
| if ! gh api repos/${{ github.repository }}/branches/plot/$SPEC_ID &>/dev/null; then | |
| echo "Feature branch plot/$SPEC_ID does not exist, skipping" | |
| exit 0 | |
| fi | |
| # Check if PR already exists | |
| EXISTING_PR=$(gh pr list --base main --head "plot/$SPEC_ID" --json number -q '.[0].number' 2>/dev/null || echo "") | |
| if [ -n "$EXISTING_PR" ]; then | |
| echo "PR #$EXISTING_PR already exists for plot/$SPEC_ID -> main" | |
| if gh pr merge "$EXISTING_PR" --squash --delete-branch; then | |
| FEATURE_PR="$EXISTING_PR" | |
| else | |
| echo "::error::Failed to merge existing PR #$EXISTING_PR" | |
| exit 1 | |
| fi | |
| else | |
| # Create and merge feature PR using reusable script | |
| .github/scripts/create-feature-pr.sh "$SPEC_ID" "$MAIN_ISSUE" "$MERGED" "$NOT_FEASIBLE" | |
| fi | |
| # Post completion to main issue | |
| gh issue comment "$MAIN_ISSUE" --body "## :tada: All Complete! | |
| All library implementations for \`$SPEC_ID\` have been merged to main! | |
| ### Final Status | |
| - **Merged:** $MERGED libraries | |
| - **Not Feasible:** $NOT_FEASIBLE libraries | |
| - **Feature PR:** #$FEATURE_PR | |
| --- | |
| :rocket: *pyplots CI*" | |
| # Add completed label and close | |
| gh issue edit "$MAIN_ISSUE" --add-label "completed" | |
| gh issue close "$MAIN_ISSUE" --reason completed | |
| # ============================================================================ | |
| # Job 3: Handle push-triggered post-merge summary | |
| # ============================================================================ | |
| push-post-merge: | |
| if: github.event_name == 'push' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| issues: write | |
| pull-requests: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 2 | |
| - name: Extract info from commit | |
| id: extract | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| # Get the commit message | |
| COMMIT_MSG=$(git log -1 --format='%s') | |
| COMMIT_SHA="${{ github.sha }}" | |
| SHORT_SHA=$(echo "$COMMIT_SHA" | cut -c1-7) | |
| echo "commit_msg=$COMMIT_MSG" >> $GITHUB_OUTPUT | |
| echo "commit_sha=$COMMIT_SHA" >> $GITHUB_OUTPUT | |
| echo "short_sha=$SHORT_SHA" >> $GITHUB_OUTPUT | |
| # Try to extract library and spec from commit message | |
| # Format: feat(library): implement spec-id (#PR) | |
| if [[ "$COMMIT_MSG" =~ feat\(([a-z]+)\):.*implement[[:space:]]+([a-z0-9-]+) ]]; then | |
| LIBRARY="${BASH_REMATCH[1]}" | |
| SPEC_ID="${BASH_REMATCH[2]}" | |
| echo "library=$LIBRARY" >> $GITHUB_OUTPUT | |
| echo "spec_id=$SPEC_ID" >> $GITHUB_OUTPUT | |
| echo "found=true" >> $GITHUB_OUTPUT | |
| echo "Found: Library=$LIBRARY, Spec=$SPEC_ID" | |
| else | |
| echo "found=false" >> $GITHUB_OUTPUT | |
| echo "Could not extract library/spec from commit: $COMMIT_MSG" | |
| fi | |
| - name: Find and update sub-issue | |
| if: steps.extract.outputs.found == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| LIBRARY="${{ steps.extract.outputs.library }}" | |
| SPEC_ID="${{ steps.extract.outputs.spec_id }}" | |
| COMMIT_SHA="${{ steps.extract.outputs.commit_sha }}" | |
| SHORT_SHA="${{ steps.extract.outputs.short_sha }}" | |
| # Find sub-issue for this library/spec | |
| SUB_ISSUE=$(gh issue list --label "library:$LIBRARY" --search "[$SPEC_ID] in:title" --json number,labels -q '.[0].number' 2>/dev/null || echo "") | |
| if [ -z "$SUB_ISSUE" ]; then | |
| echo "No sub-issue found for $LIBRARY/$SPEC_ID" | |
| exit 0 | |
| fi | |
| # Check if already merged | |
| LABELS=$(gh issue view "$SUB_ISSUE" --json labels -q '.labels[].name' 2>/dev/null || echo "") | |
| if echo "$LABELS" | grep -q "merged"; then | |
| echo "Sub-issue #$SUB_ISSUE already has merged label" | |
| exit 0 | |
| fi | |
| # Find implementation file | |
| IMPL_FILE=$(find plots/$LIBRARY -name "default.py" -path "*/${SPEC_ID}/*" 2>/dev/null | head -1 || echo "") | |
| # Update labels | |
| gh issue edit "$SUB_ISSUE" \ | |
| --remove-label "ai-approved" \ | |
| --remove-label "reviewing" \ | |
| --remove-label "generating" \ | |
| --remove-label "testing" \ | |
| --add-label "merged" 2>/dev/null || true | |
| # Post completion comment | |
| gh issue comment "$SUB_ISSUE" --body "## Merged | |
| **$LIBRARY** implementation for \`$SPEC_ID\` has been merged to main! | |
| ### Details | |
| - **Commit:** [$SHORT_SHA](https://github.com/${{ github.repository }}/commit/$COMMIT_SHA) | |
| - **File:** \`$IMPL_FILE\` | |
| --- | |
| :rocket: *Auto-merged by pyplots CI (push trigger)*" | |
| # Close sub-issue | |
| gh issue close "$SUB_ISSUE" --reason completed | |
| echo "Updated sub-issue #$SUB_ISSUE" | |
| - name: Check if all libraries are done | |
| if: steps.extract.outputs.found == 'true' | |
| id: check_complete | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| SPEC_ID="${{ steps.extract.outputs.spec_id }}" | |
| # Find main issue | |
| MAIN_ISSUE=$(gh issue list --label plot-request --search "$SPEC_ID in:title" --json number -q '.[0].number' 2>/dev/null || echo "") | |
| if [ -z "$MAIN_ISSUE" ]; then | |
| echo "all_done=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| echo "main_issue=$MAIN_ISSUE" >> $GITHUB_OUTPUT | |
| # Get all sub-issues for this main issue | |
| SUB_ISSUES=$(gh issue list --search "**Parent Issue:** #$MAIN_ISSUE in:body" --json number,labels -q '.' 2>/dev/null || echo "[]") | |
| # Count statuses (use 'any' to avoid double-counting issues with multiple labels) | |
| TOTAL=$(echo "$SUB_ISSUES" | jq 'length') | |
| MERGED=$(echo "$SUB_ISSUES" | jq '[.[] | select(any(.labels[]; .name == "merged"))] | length') | |
| NOT_FEASIBLE=$(echo "$SUB_ISSUES" | jq '[.[] | select(any(.labels[]; .name == "not-feasible"))] | length') | |
| DONE=$((MERGED + NOT_FEASIBLE)) | |
| echo "total=$TOTAL" >> $GITHUB_OUTPUT | |
| echo "merged=$MERGED" >> $GITHUB_OUTPUT | |
| echo "not_feasible=$NOT_FEASIBLE" >> $GITHUB_OUTPUT | |
| if [ "$DONE" -eq "$TOTAL" ] && [ "$TOTAL" -gt 0 ]; then | |
| echo "all_done=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "all_done=false" >> $GITHUB_OUTPUT | |
| fi | |
| echo "Progress: $DONE/$TOTAL complete ($MERGED merged, $NOT_FEASIBLE not feasible)" | |
| - name: Create and merge feature-to-main PR | |
| if: steps.extract.outputs.found == 'true' && steps.check_complete.outputs.all_done == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| MAIN_ISSUE="${{ steps.check_complete.outputs.main_issue }}" | |
| SPEC_ID="${{ steps.extract.outputs.spec_id }}" | |
| MERGED="${{ steps.check_complete.outputs.merged }}" | |
| NOT_FEASIBLE="${{ steps.check_complete.outputs.not_feasible }}" | |
| # Check if already completed | |
| LABELS=$(gh issue view "$MAIN_ISSUE" --json labels -q '.labels[].name' 2>/dev/null || echo "") | |
| if echo "$LABELS" | grep -q "completed"; then | |
| echo "Main issue #$MAIN_ISSUE already completed" | |
| exit 0 | |
| fi | |
| # Check if feature branch exists | |
| if ! gh api repos/${{ github.repository }}/branches/plot/$SPEC_ID &>/dev/null; then | |
| echo "Feature branch plot/$SPEC_ID does not exist, skipping" | |
| exit 0 | |
| fi | |
| # Check if PR already exists | |
| EXISTING_PR=$(gh pr list --base main --head "plot/$SPEC_ID" --json number -q '.[0].number' 2>/dev/null || echo "") | |
| if [ -n "$EXISTING_PR" ]; then | |
| echo "PR #$EXISTING_PR already exists for plot/$SPEC_ID -> main" | |
| if gh pr merge "$EXISTING_PR" --squash --delete-branch; then | |
| FEATURE_PR="$EXISTING_PR" | |
| else | |
| echo "::error::Failed to merge existing PR #$EXISTING_PR" | |
| exit 1 | |
| fi | |
| else | |
| # Create PR from feature branch to main | |
| PR_URL=$(gh pr create \ | |
| --base main \ | |
| --head "plot/$SPEC_ID" \ | |
| --title "feat: add $SPEC_ID implementation ($MERGED libraries)" \ | |
| --body "## Summary | |
| Adds \`$SPEC_ID\` plot implementation. | |
| ### Libraries | |
| - **Merged:** $MERGED | |
| - **Not Feasible:** $NOT_FEASIBLE | |
| ### Links | |
| - **Spec:** \`specs/$SPEC_ID.md\` | |
| - **Parent Issue:** #$MAIN_ISSUE | |
| --- | |
| :robot: *Auto-generated by pyplots CI*") | |
| FEATURE_PR=$(echo "$PR_URL" | sed 's|.*/||') | |
| echo "Created PR #$FEATURE_PR" | |
| # Merge the PR immediately | |
| if ! gh pr merge "$FEATURE_PR" --squash --delete-branch; then | |
| echo "::error::Failed to merge PR #$FEATURE_PR" | |
| gh issue comment "$MAIN_ISSUE" --body "## :warning: Merge Failed | |
| Failed to automatically merge PR #$FEATURE_PR. Please merge manually." | |
| exit 1 | |
| fi | |
| fi | |
| # Post completion to main issue | |
| gh issue comment "$MAIN_ISSUE" --body "## :tada: All Complete! | |
| All library implementations for \`$SPEC_ID\` have been merged to main! | |
| ### Final Status | |
| - **Merged:** $MERGED libraries | |
| - **Not Feasible:** $NOT_FEASIBLE libraries | |
| - **Feature PR:** #$FEATURE_PR | |
| --- | |
| :rocket: *pyplots CI (push trigger)*" | |
| # Add completed label and close | |
| gh issue edit "$MAIN_ISSUE" --add-label "completed" | |
| gh issue close "$MAIN_ISSUE" --reason completed |