Skip to content

update

update #48

name: Codex PR Review
on:
pull_request_target:
types: [opened, synchronize, reopened, ready_for_review]
jobs:
pr-review:
if: |
github.event.pull_request.draft == false
runs-on: ubuntu-latest
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: write
issues: write
steps:
- name: Validate OpenAI configuration
run: |
if [ -z "${{ secrets.OPENAI_API_KEY }}" ]; then
echo "::error::Missing required secret OPENAI_API_KEY (Settings → Secrets and variables → Actions)."
exit 1
fi
- name: Compute Responses API endpoint override (optional)
id: responses_endpoint
shell: bash
run: |
base="${{ secrets.OPENAI_BASE_URL }}"
base="${base%/}"
if [ -z "$base" ]; then
echo "endpoint=" >> "$GITHUB_OUTPUT"
elif [[ "$base" == */responses ]]; then
echo "endpoint=$base" >> "$GITHUB_OUTPUT"
else
echo "endpoint=$base/responses" >> "$GITHUB_OUTPUT"
fi
- name: Checkout base branch (safe)
uses: actions/checkout@v5
with:
ref: ${{ github.event.pull_request.base.sha }}
fetch-depth: 0
- name: Run Codex review
id: run_codex
uses: openai/codex-action@v1
env:
GH_TOKEN: ${{ github.token }}
GITHUB_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_REPO: ${{ github.repository }}
with:
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
# NOTE: openai/codex-action expects a full Responses endpoint (…/v1/responses).
responses-api-endpoint: ${{ steps.responses_endpoint.outputs.endpoint }}
model: ${{ vars.OPENAI_MODEL || 'gpt-5.2' }}
effort: ${{ vars.OPENAI_EFFORT || 'high' }}
sandbox: read-only
safety-strategy: drop-sudo
prompt-file: .github/prompts/codex-pr-review.md
allow-users: "*"
- name: Validate Codex output
shell: bash
env:
FINAL_MESSAGE: ${{ steps.run_codex.outputs.final-message }}
run: |
if [[ -z "${FINAL_MESSAGE//[[:space:]]/}" ]]; then
echo "::error::Codex returned empty output; failing to avoid passing a required check without a review."
exit 1
fi
- name: Upsert PR comment
if: steps.run_codex.outputs.final-message != ''
uses: actions/github-script@v7
env:
REVIEW_BODY: ${{ steps.run_codex.outputs.final-message }}
MARKER: "<!-- codex-pr-review -->"
with:
github-token: ${{ github.token }}
script: |
const marker = process.env.MARKER;
const reviewBody = process.env.REVIEW_BODY || "";
let body = `${marker}\n${reviewBody}`.trim() + "\n";
const maxLen = 65000;
if (body.length > maxLen) {
body =
body.slice(0, maxLen - 500) +
"\n\n---\n(Truncated: review output exceeded GitHub comment limit.)\n";
}
const { owner, repo } = context.repo;
const issue_number = context.payload.pull_request.number;
const comments = await github.paginate(
github.rest.issues.listComments,
{ owner, repo, issue_number, per_page: 100 }
);
const existing = comments.find((c) => {
const isBot = c.user?.type === "Bot";
return isBot && typeof c.body === "string" && c.body.includes(marker);
});
if (existing) {
await github.rest.issues.updateComment({
owner,
repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner,
repo,
issue_number,
body,
});
}