CI failure repair #145
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 failure repair — uses .agents/ci-failure-repair.yaml to diagnose logs and | |
| # optionally auto-apply Ruff fixes + push to the same branch (agent as code). | |
| # | |
| # Requires OPENAI_API_KEY. Auto-push only when the agent returns high confidence | |
| # and failure_category is ruff_format or ruff_check (safe, deterministic fixes). | |
| # | |
| # IMPORTANT: This workflow must NEVER commit generated logs or diagnostic JSON | |
| # to the branch. Those files are uploaded as GitHub Actions artifacts instead. | |
| # This avoids polluting PRs with noise that confuses contributors and reviewers. | |
| name: CI failure repair | |
| on: | |
| workflow_run: | |
| workflows: | |
| - CI | |
| types: | |
| - completed | |
| concurrency: | |
| group: ci-repair-${{ github.event.workflow_run.head_branch }} | |
| cancel-in-progress: true | |
| jobs: | |
| diagnose: | |
| if: ${{ github.event.workflow_run.conclusion == 'failure' }} | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| actions: read | |
| pull-requests: read | |
| steps: | |
| - name: Checkout failed head | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.workflow_run.head_sha }} | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install OA CLI + deps for applying fixes | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install . | |
| pip install ".[dev]" | |
| - name: Fetch failed job log | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| mkdir -p /tmp/repair-artifacts | |
| gh run view "${{ github.event.workflow_run.id }}" --log-failed > /tmp/repair-artifacts/failed-log.txt 2>/dev/null || \ | |
| gh run view "${{ github.event.workflow_run.id }}" --log > /tmp/repair-artifacts/failed-log.txt | |
| head -c 120000 /tmp/repair-artifacts/failed-log.txt > /tmp/repair-artifacts/failed-log.trimmed.txt | |
| mv /tmp/repair-artifacts/failed-log.trimmed.txt /tmp/repair-artifacts/failed-log.txt | |
| wc -c /tmp/repair-artifacts/failed-log.txt | |
| - name: Run OA repair agent | |
| id: oa | |
| env: | |
| OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} | |
| run: | | |
| if [ -z "$OPENAI_API_KEY" ]; then | |
| echo "OPENAI_API_KEY not set — skipping agent run" | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| LOG_CONTENT=$(jq -Rs . < /tmp/repair-artifacts/failed-log.txt) | |
| jq -n \ | |
| --arg w "${{ github.event.workflow_run.name }}" \ | |
| --arg b "${{ github.event.workflow_run.head_branch }}" \ | |
| --arg c "Python package; CI runs ruff check, ruff format --check, mypy, pytest" \ | |
| --argjson log "$LOG_CONTENT" \ | |
| '{workflow_name:$w, branch:$b, repo_context:$c, job_log:$log}' > /tmp/repair-artifacts/repair-input.json | |
| oa run --spec .agents/ci-failure-repair.yaml \ | |
| --task diagnose_and_remediate \ | |
| --input "$(cat /tmp/repair-artifacts/repair-input.json)" \ | |
| --quiet > /tmp/repair-artifacts/repair-output.json | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| cat /tmp/repair-artifacts/repair-output.json | head -c 4000 | |
| - name: Apply Ruff remediation and push | |
| if: steps.oa.outputs.skip != 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| if ! jq -e . /tmp/repair-artifacts/repair-output.json >/dev/null 2>&1; then | |
| echo "No valid repair-output.json" | |
| exit 0 | |
| fi | |
| if jq -e '.output' /tmp/repair-artifacts/repair-output.json >/dev/null 2>&1; then | |
| jq '.output' /tmp/repair-artifacts/repair-output.json > /tmp/repair-artifacts/repair-plan.json | |
| else | |
| cp /tmp/repair-artifacts/repair-output.json /tmp/repair-artifacts/repair-plan.json | |
| fi | |
| CATEGORY=$(jq -r '.failure_category // empty' /tmp/repair-artifacts/repair-plan.json) | |
| CONF=$(jq -r '.confidence // empty' /tmp/repair-artifacts/repair-plan.json) | |
| PUSH=$(jq -r '.push_to_branch // false' /tmp/repair-artifacts/repair-plan.json) | |
| echo "category=$CATEGORY confidence=$CONF push_to_branch=$PUSH" | |
| if [ "$PUSH" != "true" ] || [ "$CONF" != "high" ]; then | |
| echo "Agent did not authorize auto-push; upload artifact only." | |
| exit 0 | |
| fi | |
| case "$CATEGORY" in | |
| ruff_format|ruff_check) | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git config user.name "github-actions[bot]" | |
| ruff format . --exclude test_output/ || true | |
| ruff check --fix . --exclude test_output/ || true | |
| if git diff --quiet; then | |
| echo "No changes after ruff — nothing to push" | |
| exit 0 | |
| fi | |
| MSG=$(jq -r '.commit_message // "chore: ci auto-fix (ruff)"' /tmp/repair-artifacts/repair-plan.json) | |
| # Stage only tracked source files that ruff modified; logs live | |
| # outside the workspace in /tmp so they can never be staged. | |
| git add -u | |
| git commit -m "$MSG" | |
| git push origin "HEAD:${{ github.event.workflow_run.head_branch }}" | |
| echo "Pushed remediation to ${{ github.event.workflow_run.head_branch }}" | |
| ;; | |
| *) | |
| echo "Category $CATEGORY not auto-applied; see ci-repair-plan artifact" | |
| ;; | |
| esac | |
| - name: Upload repair plan artifact | |
| if: always() && steps.oa.outputs.skip != 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ci-repair-plan | |
| path: /tmp/repair-artifacts/ | |
| retention-days: 14 |