CI Assistant #96
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
| # CI Assistant — automated bot | |
| # | |
| # Triggers after the "Tests" workflow completes: | |
| # | |
| # 1. Push to main + Tests FAIL → sends "ci_failure" to the CI assistant | |
| # Claude attempts a fix and pushes, or creates a GitHub issue | |
| # explaining the root cause with options/pros/cons. | |
| # | |
| # 2. PR + Tests PASS → sends "pr_review" to the CI assistant | |
| # Claude posts a PR comment with a structured review: | |
| # a) Purpose check — does the PR state what problem it solves | |
| # and how users benefit? (can be implicit) | |
| # b) If purpose unclear or PR not useful → explain why, recommend closing | |
| # c) If useful → review implementation and quality | |
| # d) Quality OK → recommend merging (may suggest optional improvements) | |
| # e) Quality not OK → request specific changes | |
| # | |
| # 3. PR + Tests FAIL → sends "pr_ci_failure" to the CI assistant | |
| # Claude posts a review comment noting the test failure + reviews the PR. | |
| # | |
| # 4. Comment "@@fix" on any issue → sends "issue_fix" to the CI assistant | |
| # Claude reads the issue, fixes it, and pushes (or opens a PR). | |
| # | |
| # Secrets required: CI_ASSISTANT_URL, CI_ASSISTANT_SECRET | |
| name: CI Assistant | |
| on: | |
| workflow_run: | |
| workflows: ["Tests"] | |
| types: [completed] | |
| issue_comment: | |
| types: [created] | |
| jobs: | |
| fix-on-comment: | |
| if: >- | |
| github.event_name == 'issue_comment' | |
| && contains(github.event.comment.body, '@@fix') | |
| && (github.event.comment.author_association == 'OWNER' | |
| || github.event.comment.author_association == 'MEMBER' | |
| || github.event.comment.author_association == 'COLLABORATOR') | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Notify CI Assistant | |
| run: | | |
| # Determine if this is a PR comment or issue comment | |
| if [ -n "${{ github.event.issue.pull_request.url }}" ]; then | |
| EVENT="pr_ci_failure" | |
| PR_NUMBER=${{ github.event.issue.number }} | |
| ISSUE_NUMBER=null | |
| REF=$(gh pr view $PR_NUMBER --repo ${{ github.repository }} --json headRefName --jq '.headRefName') | |
| else | |
| EVENT="issue_fix" | |
| PR_NUMBER=null | |
| ISSUE_NUMBER=${{ github.event.issue.number }} | |
| REF=$(gh repo view ${{ github.repository }} --json defaultBranchRef --jq '.defaultBranchRef.name') | |
| fi | |
| jq -n \ | |
| --arg repo "${{ github.repository }}" \ | |
| --arg ref "$REF" \ | |
| --arg event "$EVENT" \ | |
| --argjson pr_number "$PR_NUMBER" \ | |
| --argjson issue_number "$ISSUE_NUMBER" \ | |
| --arg details "${{ github.event.issue.title }}" \ | |
| '{repo: $repo, ref: $ref, event: $event, pr_number: $pr_number, issue_number: $issue_number, details: $details}' \ | |
| > /tmp/payload.json | |
| curl -s -X POST "${{ secrets.CI_ASSISTANT_URL }}/webhook" \ | |
| -H "Content-Type: application/json" \ | |
| -H "Authorization: Bearer ${{ secrets.CI_ASSISTANT_SECRET }}" \ | |
| -d @/tmp/payload.json | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| on-failure: | |
| if: >- | |
| github.event.workflow_run.conclusion == 'failure' | |
| && github.event.workflow_run.event == 'push' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Fetch failure logs | |
| id: logs | |
| run: | | |
| gh run view ${{ github.event.workflow_run.id }} --repo ${{ github.repository }} --log-failed 2>/dev/null | tail -50 > /tmp/logs.txt || echo "Could not fetch logs" > /tmp/logs.txt | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Notify CI Assistant | |
| run: | | |
| jq -n \ | |
| --arg repo "${{ github.repository }}" \ | |
| --arg ref "${{ github.event.workflow_run.head_branch }}" \ | |
| --arg event "ci_failure" \ | |
| --argjson run_id ${{ github.event.workflow_run.id }} \ | |
| --arg details "$(cat /tmp/logs.txt)" \ | |
| '{repo: $repo, ref: $ref, event: $event, run_id: $run_id, details: $details}' \ | |
| > /tmp/payload.json | |
| curl -s -X POST "${{ secrets.CI_ASSISTANT_URL }}/webhook" \ | |
| -H "Content-Type: application/json" \ | |
| -H "Authorization: Bearer ${{ secrets.CI_ASSISTANT_SECRET }}" \ | |
| -d @/tmp/payload.json | |
| on-pr-tests-passed: | |
| if: >- | |
| github.event.workflow_run.conclusion == 'success' | |
| && github.event.workflow_run.event == 'pull_request' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Get PR number | |
| id: pr | |
| run: | | |
| PR_NUMBER=$(echo '${{ toJSON(github.event.workflow_run.pull_requests) }}' | jq '.[0].number // empty') | |
| if [ -z "$PR_NUMBER" ]; then | |
| PR_NUMBER=$(gh pr list --repo ${{ github.repository }} --head ${{ github.event.workflow_run.head_branch }} --json number --jq '.[0].number') | |
| fi | |
| echo "number=$PR_NUMBER" >> $GITHUB_OUTPUT | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Notify CI Assistant | |
| if: steps.pr.outputs.number | |
| run: | | |
| jq -n \ | |
| --arg repo "${{ github.repository }}" \ | |
| --arg ref "${{ github.event.workflow_run.head_branch }}" \ | |
| --arg event "pr_review" \ | |
| --argjson pr_number ${{ steps.pr.outputs.number }} \ | |
| '{repo: $repo, ref: $ref, event: $event, pr_number: $pr_number}' \ | |
| > /tmp/payload.json | |
| curl -s -X POST "${{ secrets.CI_ASSISTANT_URL }}/webhook" \ | |
| -H "Content-Type: application/json" \ | |
| -H "Authorization: Bearer ${{ secrets.CI_ASSISTANT_SECRET }}" \ | |
| -d @/tmp/payload.json | |
| on-pr-tests-failed: | |
| if: >- | |
| github.event.workflow_run.conclusion == 'failure' | |
| && github.event.workflow_run.event == 'pull_request' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Get PR number | |
| id: pr | |
| run: | | |
| PR_NUMBER=$(echo '${{ toJSON(github.event.workflow_run.pull_requests) }}' | jq '.[0].number // empty') | |
| if [ -z "$PR_NUMBER" ]; then | |
| PR_NUMBER=$(gh pr list --repo ${{ github.repository }} --head ${{ github.event.workflow_run.head_branch }} --json number --jq '.[0].number') | |
| fi | |
| echo "number=$PR_NUMBER" >> $GITHUB_OUTPUT | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Fetch failure logs | |
| run: | | |
| gh run view ${{ github.event.workflow_run.id }} --repo ${{ github.repository }} --log-failed 2>/dev/null | tail -50 > /tmp/logs.txt || echo "Could not fetch logs" > /tmp/logs.txt | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Notify CI Assistant | |
| if: steps.pr.outputs.number | |
| run: | | |
| jq -n \ | |
| --arg repo "${{ github.repository }}" \ | |
| --arg ref "${{ github.event.workflow_run.head_branch }}" \ | |
| --arg event "pr_ci_failure" \ | |
| --argjson pr_number ${{ steps.pr.outputs.number }} \ | |
| --argjson run_id ${{ github.event.workflow_run.id }} \ | |
| --arg details "$(cat /tmp/logs.txt)" \ | |
| '{repo: $repo, ref: $ref, event: $event, pr_number: $pr_number, run_id: $run_id, details: $details}' \ | |
| > /tmp/payload.json | |
| curl -s -X POST "${{ secrets.CI_ASSISTANT_URL }}/webhook" \ | |
| -H "Content-Type: application/json" \ | |
| -H "Authorization: Bearer ${{ secrets.CI_ASSISTANT_SECRET }}" \ | |
| -d @/tmp/payload.json |