name: Codex pull request review
on:
pull_request_target:
types:
- opened
- synchronize
- reopened
- ready_for_review
permissions:
contents: read
issues: write
pull-requests: write
concurrency:
group: codex-review-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
codex-review:
name: Codex review
if: github.event.pull_request.head.repo.full_name == github.repository && github.event.pull_request.draft == false
runs-on: self-hosted
timeout-minutes: 45
env:
BASE_REF: ${{ github.event.pull_request.base.ref }}
CODEX_REVIEW_DIR: ${{ github.workspace }}/.codex-review
CODEX_REVIEW_OUTPUT: ${{ github.workspace }}/.codex-review/codex-review.md
GH_CONFIG_DIR: ${{ github.workspace }}/.codex-review/gh-config
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REVIEW_WORKSPACE: ${{ github.workspace }}/review
steps:
- name: Checkout trusted review tools
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.base.sha }}
path: trusted
fetch-depth: 0
persist-credentials: false
- name: Checkout pull request
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}
path: review
fetch-depth: 0
persist-credentials: false
- name: Verify runner tools and auth
shell: bash
run: |
set -euo pipefail
if [[ -z "${CODEX_REVIEW_DIR}" || "${CODEX_REVIEW_DIR}" != "${GITHUB_WORKSPACE}/.codex-review" ]]; then
echo "Unexpected CODEX_REVIEW_DIR: ${CODEX_REVIEW_DIR}" >&2
exit 2
fi
rm -rf "${CODEX_REVIEW_DIR}"
mkdir -p "${GH_CONFIG_DIR}"
command -v gh
command -v codex
gh auth status --active --hostname github.com
codex --version
- name: Run Codex oneshot review
id: codex
continue-on-error: true
shell: bash
run: |
"${GITHUB_WORKSPACE}/trusted/.github/scripts/codex-pr-review.sh"
- name: Submit Codex pull request review
if: always()
uses: actions/github-script@v9
with:
github-token: ${{ github.token }}
script: |
const fs = require('fs');
const { buildReviewPayload } = require(`${process.env.GITHUB_WORKSPACE}/trusted/.github/scripts/codex-review-comments.js`);
const outputPath = process.env.CODEX_REVIEW_OUTPUT;
let body = '';
if (outputPath && fs.existsSync(outputPath)) {
body = fs.readFileSync(outputPath, 'utf8').trim();
}
const pull_number = Number(process.env.PR_NUMBER);
const files = await github.paginate(github.rest.pulls.listFiles, {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number,
per_page: 100,
});
await github.rest.pulls.createReview({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number,
event: 'COMMENT',
...buildReviewPayload(body, files),
});
- name: Fail on Codex review error
if: steps.codex.outcome == 'failure'
shell: bash
run: exit 1