Skip to content

Commit b5eaf37

Browse files
authored
Merge pull request #26 from jacwu/main
Add PR Copilot Review workflow and normalize review result script
2 parents 4a0d3c2 + d760a36 commit b5eaf37

3 files changed

Lines changed: 144 additions & 17 deletions

File tree

.github/workflows/pr-codex-review.yml

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on:
44
pull_request:
55
types: [opened, reopened, ready_for_review, synchronize]
66

7+
78
permissions:
89
contents: read
910
pull-requests: write
@@ -19,6 +20,7 @@ jobs:
1920
| All files | No actionable feedback generated | None | info |
2021
AZURE_OPENAI_BASE_URL: ${{ secrets.AZURE_OPENAI_BASE_URL }}
2122
AZURE_OPENAI_MODEL: ${{ secrets.AZURE_OPENAI_MODEL || 'gpt-5-codex' }}
23+
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
2224
steps:
2325
- name: Checkout code
2426
uses: actions/checkout@v4
@@ -43,13 +45,11 @@ jobs:
4345
- name: Prepare fallback review
4446
if: steps.diff.outputs.no_changes == 'true'
4547
run: |
46-
printf '%s' "$REVIEW_TABLE_FALLBACK" > codex_review.md
47-
cp codex_review.md review_result.md
48+
printf '%s' "$REVIEW_TABLE_FALLBACK" > raw_review.md
49+
cp raw_review.md review_result.md
4850
4951
- name: Install Codex CLI
5052
if: steps.diff.outputs.no_changes == 'false'
51-
env:
52-
AZURE_OPENAI_BASE_URL: ${{ secrets.AZURE_OPENAI_BASE_URL }}
5353
run: |
5454
sudo apt-get update
5555
sudo apt-get install -y --no-install-recommends curl ca-certificates git
@@ -75,8 +75,6 @@ jobs:
7575
7676
- name: Run Codex code review
7777
if: steps.diff.outputs.no_changes == 'false'
78-
env:
79-
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
8078
run: |
8179
if [ -z "$AZURE_OPENAI_API_KEY" ]; then
8280
echo "AZURE_OPENAI_API_KEY secret is not configured." >&2
@@ -97,16 +95,14 @@ jobs:
9795
9896
printf '\n\nRaw Codex Output:\n%s\n' "$(cat codex_raw.txt)"
9997
100-
sed -E 's/\x1B\[[0-9;]*[A-Za-z]//g' codex_raw.txt | tr -d '\r' > codex_review.md
98+
sed -E 's/\x1B\[[0-9;]*[A-Za-z]//g' codex_raw.txt | tr -d '\r' > raw_review.md
10199
102-
if ! grep -q '|' codex_review.md; then
103-
printf '%s\n' "$REVIEW_TABLE_FALLBACK" > codex_review.md
100+
if ! grep -q '|' raw_review.md; then
101+
printf '%s\n' "$REVIEW_TABLE_FALLBACK" > raw_review.md
104102
fi
105103
106104
- name: Normalize review table with Azure OpenAI
107-
if: steps.diff.outputs.no_changes == 'false'
108-
env:
109-
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
105+
if: steps.diff.outputs.no_changes == 'false'
110106
run: |
111107
python3 -m pip install --quiet --upgrade pip 'openai>=1.45.0'
112108
python3 scripts/normalize_review_result.py
@@ -117,13 +113,16 @@ jobs:
117113
run: |
118114
if [ -f review_result.md ]; then
119115
BODY_FILE=review_result.md
120-
elif [ -f codex_review.md ]; then
121-
BODY_FILE=codex_review.md
116+
elif [ -f raw_review.md ]; then
117+
BODY_FILE=raw_review.md
122118
else
123119
printf '%s' "$REVIEW_TABLE_FALLBACK" > review_result.md
124120
BODY_FILE=review_result.md
125121
fi
126122
123+
# Append attribution footer to the comment body
124+
printf '\n\nReviewed by Codex\n' >> "$BODY_FILE"
125+
127126
gh pr comment ${{ github.event.pull_request.number }} --body-file "$BODY_FILE"
128127
129128
- name: Upload Codex raw output
@@ -133,7 +132,7 @@ jobs:
133132
name: codex-review-logs
134133
path: |
135134
codex_raw.txt
136-
codex_review.md
135+
raw_review.md
137136
review_result.md
138137
diff.patch
139138
changed_files.txt
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
name: PR Copilot Review
2+
3+
on:
4+
pull_request:
5+
types: [opened, reopened, ready_for_review, synchronize]
6+
7+
8+
permissions:
9+
contents: read
10+
pull-requests: write
11+
12+
jobs:
13+
copilot_pr_review:
14+
name: Copilot PR Review
15+
runs-on: ubuntu-latest
16+
env:
17+
REVIEW_TABLE_FALLBACK: |
18+
| File | Concern | Recommendation | Severity |
19+
| --- | --- | --- | --- |
20+
| All files | No actionable feedback generated | None | info |
21+
AZURE_OPENAI_BASE_URL: ${{ secrets.AZURE_OPENAI_BASE_URL }}
22+
AZURE_OPENAI_MODEL: ${{ secrets.AZURE_OPENAI_MODEL || 'gpt-5-codex' }}
23+
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
24+
steps:
25+
- name: Checkout code
26+
uses: actions/checkout@v4
27+
with:
28+
fetch-depth: 0
29+
30+
- name: Set up Node.js
31+
uses: actions/setup-node@v4
32+
with:
33+
node-version: '22'
34+
35+
- name: Compute diff and changed files
36+
id: diff
37+
run: |
38+
BASE_SHA="${{ github.event.pull_request.base.sha }}"
39+
HEAD_SHA="${{ github.event.pull_request.head.sha }}"
40+
41+
git diff --name-only "$BASE_SHA" "$HEAD_SHA" > changed_files.txt
42+
git diff --unified=3 "$BASE_SHA" "$HEAD_SHA" > diff.patch
43+
44+
if [ ! -s changed_files.txt ]; then
45+
echo "no_changes=true" >> "$GITHUB_OUTPUT"
46+
else
47+
echo "no_changes=false" >> "$GITHUB_OUTPUT"
48+
fi
49+
50+
- name: Prepare fallback review
51+
if: steps.diff.outputs.no_changes == 'true'
52+
run: |
53+
printf '%s' "$REVIEW_TABLE_FALLBACK" > raw_review.md
54+
cp raw_review.md review_result.md
55+
56+
- name: Install Copilot CLI
57+
env:
58+
GITHUB_TOKEN: ${{ secrets.COPILOT_CLI_PAT }}
59+
if: steps.diff.outputs.no_changes == 'false'
60+
run: |
61+
npm install -g @github/copilot
62+
copilot --version
63+
64+
- name: Run Copilot code review
65+
env:
66+
GITHUB_TOKEN: ${{ secrets.COPILOT_CLI_PAT }}
67+
if: steps.diff.outputs.no_changes == 'false'
68+
run: |
69+
if [ -z "$AZURE_OPENAI_API_KEY" ]; then
70+
echo "AZURE_OPENAI_API_KEY secret is not configured." >&2
71+
exit 1
72+
fi
73+
74+
HEADER="You are an expert software engineer performing a strict code review for the provided pull request diff."
75+
RULES="Rules:\n- Output ONLY a GitHub-flavored Markdown table with exactly these columns: File | Concern | Recommendation | Severity.\n- Every row must reference a real file path from the Changed files list.\n- Severity must be one of: info, minor, major, critical.\n- If no issues are found, return a single table row with 'All files' in the File column and 'No issues found' in the Concern column.\n- Cite line numbers from the diff using the format L<line>.\n- Do not wrap the table in backticks or add any prose before or after the table.\n- Focus on actionable feedback specific to the diff."
76+
77+
CHANGED_FILES_SECTION="Changed files:\n$(cat changed_files.txt)"
78+
DIFF_SECTION="Unified diff:\n$(cat diff.patch)"
79+
80+
export COPILOT_PROMPT="$HEADER\n\n$RULES\n\n$CHANGED_FILES_SECTION\n\n$DIFF_SECTION"
81+
82+
printf '%s\n' "$COPILOT_PROMPT"
83+
84+
copilot -p "$COPILOT_PROMPT" | tee copilot_raw.txt >/dev/null
85+
86+
printf '\n\nRaw Copilot Output:\n%s\n' "$(cat copilot_raw.txt)"
87+
88+
sed -E 's/\x1B\[[0-9;]*[A-Za-z]//g' copilot_raw.txt | tr -d '\r' > raw_review.md
89+
90+
if ! grep -q '|' raw_review.md; then
91+
printf '%s\n' "$REVIEW_TABLE_FALLBACK" > raw_review.md
92+
fi
93+
94+
- name: Normalize review table with Azure OpenAI
95+
if: steps.diff.outputs.no_changes == 'false'
96+
run: |
97+
python3 -m pip install --quiet --upgrade pip 'openai>=1.45.0'
98+
python3 scripts/normalize_review_result.py
99+
100+
- name: Post review as PR comment
101+
env:
102+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
103+
run: |
104+
if [ -f review_result.md ]; then
105+
BODY_FILE=review_result.md
106+
elif [ -f raw_review.md ]; then
107+
BODY_FILE=raw_review.md
108+
else
109+
printf '%s' "$REVIEW_TABLE_FALLBACK" > review_result.md
110+
BODY_FILE=review_result.md
111+
fi
112+
113+
# Append attribution footer to the comment body
114+
printf '\n\nReviewed by GitHub Copilot CLI\n' >> "$BODY_FILE"
115+
116+
gh pr comment ${{ github.event.pull_request.number }} --body-file "$BODY_FILE"
117+
118+
- name: Upload Copilot raw output
119+
if: steps.diff.outputs.no_changes == 'false'
120+
uses: actions/upload-artifact@v4
121+
with:
122+
name: copilot-review-logs
123+
path: |
124+
copilot_raw.txt
125+
raw_review.md
126+
review_result.md
127+
diff.patch
128+
changed_files.txt

scripts/normalize_review_result.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ def require_env(name: str) -> str:
3939

4040

4141
def main() -> None:
42-
source_path = Path("codex_review.md")
42+
source_path = Path("raw_review.md")
4343
if not source_path.exists():
44-
print("codex_review.md not found; cannot repair review output.", file=sys.stderr)
44+
print("raw_review.md not found; cannot repair review output.", file=sys.stderr)
4545
raise SystemExit(1)
4646

4747
source_text = source_path.read_text(encoding="utf-8")

0 commit comments

Comments
 (0)