name: PR Failure Codex Dispatch on: workflow_run: workflows: ["PR-tests"] types: [completed] jobs: codex_on_failure: if: > ${{ github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.pull_requests && github.event.workflow_run.pull_requests[0] && !startsWith(github.event.workflow_run.head_commit.message, 'Fix CI failures for PR #') }} runs-on: ubuntu-latest permissions: contents: write pull-requests: write issues: write actions: read steps: - name: Resolve PR context id: pr_context env: PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }} GH_TOKEN: ${{ github.token }} run: | pr_author=$(gh api -H "Accept: application/vnd.github+json" \ /repos/${{ github.repository }}/pulls/${PR_NUMBER} \ --jq '.user.login') pr_head_repo=$(gh api -H "Accept: application/vnd.github+json" \ /repos/${{ github.repository }}/pulls/${PR_NUMBER} \ --jq '.head.repo.full_name') pr_head_branch=$(gh api -H "Accept: application/vnd.github+json" \ /repos/${{ github.repository }}/pulls/${PR_NUMBER} \ --jq '.head.ref') { echo "number=${PR_NUMBER}" echo "author=${pr_author}" echo "head_repo=${pr_head_repo}" echo "head_branch=${pr_head_branch}" } >> "$GITHUB_OUTPUT" - name: Comment on PR with failure info if: ${{ steps.pr_context.outputs.author == 'carlospolop' }} uses: actions/github-script@v7 env: PR_NUMBER: ${{ steps.pr_context.outputs.number }} RUN_URL: ${{ github.event.workflow_run.html_url }} WORKFLOW_NAME: ${{ github.event.workflow_run.name }} with: github-token: ${{ github.token }} script: | const prNumber = Number(process.env.PR_NUMBER); const body = `PR #${prNumber} had a failing workflow "${process.env.WORKFLOW_NAME}".\n\nRun: ${process.env.RUN_URL}\n\nLaunching Codex to attempt a fix.`; await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: prNumber, body, }); - name: Checkout PR head if: ${{ steps.pr_context.outputs.author == 'carlospolop' }} uses: actions/checkout@v5 with: repository: ${{ steps.pr_context.outputs.head_repo }} ref: ${{ github.event.workflow_run.head_sha }} fetch-depth: 0 persist-credentials: true - name: Configure git author if: ${{ steps.pr_context.outputs.author == 'carlospolop' }} run: | git config user.name "codex-action" git config user.email "codex-action@users.noreply.github.com" - name: Fetch failure summary if: ${{ steps.pr_context.outputs.author == 'carlospolop' }} env: GH_TOKEN: ${{ github.token }} RUN_ID: ${{ github.event.workflow_run.id }} run: | gh api -H "Accept: application/vnd.github+json" \ /repos/${{ github.repository }}/actions/runs/$RUN_ID/jobs \ --paginate > /tmp/jobs.json python3 - <<'PY' import json data = json.load(open('/tmp/jobs.json')) lines = [] for job in data.get('jobs', []): if job.get('conclusion') == 'failure': lines.append(f"Job: {job.get('name')} (id {job.get('id')})") lines.append(f"URL: {job.get('html_url')}") for step in job.get('steps', []): if step.get('conclusion') == 'failure': lines.append(f" Step: {step.get('name')}") lines.append("") summary = "\n".join(lines).strip() or "No failing job details found." with open('codex_failure_summary.txt', 'w') as handle: handle.write(summary) PY - name: Create Codex prompt if: ${{ steps.pr_context.outputs.author == 'carlospolop' }} env: PR_NUMBER: ${{ steps.pr_context.outputs.number }} RUN_URL: ${{ github.event.workflow_run.html_url }} HEAD_BRANCH: ${{ steps.pr_context.outputs.head_branch }} run: | { echo "You are fixing CI failures for PR #${PR_NUMBER} in ${{ github.repository }}." echo "The failing workflow run is: ${RUN_URL}" echo "The PR branch is: ${HEAD_BRANCH}" echo "" echo "Failure summary:" cat codex_failure_summary.txt echo "" echo "Please identify the cause, apply a easy, simple and minimal fix, and update files accordingly." echo "Run any fast checks you can locally (no network)." echo "Leave the repo in a state ready to commit as when you finish, it'll be automatically committed and pushed." } > codex_prompt.txt - name: Run Codex if: ${{ steps.pr_context.outputs.author == 'carlospolop' }} id: run_codex uses: openai/codex-action@v1 with: openai-api-key: ${{ secrets.OPENAI_API_KEY }} prompt-file: codex_prompt.txt sandbox: workspace-write model: gpt-5.2-codex - name: Commit and push if changed if: ${{ steps.pr_context.outputs.author == 'carlospolop' }} env: TARGET_BRANCH: ${{ steps.pr_context.outputs.head_branch }} PR_NUMBER: ${{ steps.pr_context.outputs.number }} run: | if git diff --quiet; then echo "No changes to commit." exit 0 fi rm -f codex_failure_summary.txt codex_prompt.txt git add -A git reset -- codex_failure_summary.txt codex_prompt.txt git commit -m "Fix CI failures for PR #${PR_NUMBER}" git push origin HEAD:${TARGET_BRANCH} - name: Comment with Codex result if: ${{ steps.pr_context.outputs.author == 'carlospolop' && steps.run_codex.outputs.final-message != '' }} uses: actions/github-script@v7 env: PR_NUMBER: ${{ steps.pr_context.outputs.number }} CODEX_MESSAGE: ${{ steps.run_codex.outputs.final-message }} with: github-token: ${{ github.token }} script: | await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: Number(process.env.PR_NUMBER), body: process.env.CODEX_MESSAGE, });