Skip to content

Commit 55aed79

Browse files
Dev (#15)
* 合并 (#8) * chore: add comprehensive contributing guide (#10) * chore: add comprehensive contributing guide * Update CONTRIBUTING.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update CONTRIBUTING.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * ci: restore pr-check.yml workflow for dev branch - Restore backend and frontend PR checks - Enable Python syntax check and import test for backend - Enable pnpm build check for frontend - Fix 'Expected — Waiting for status to be reported' issue * feat(ci): upgrade PR review + add CI auto-fix & review responder - Upgrade codex-pr-review.md to 6-perspective review with confidence scoring - Rewrite claude-pr-review.yml with Codex-first fallback pattern - Add claude-ci-autofix.yml for auto-fixing CI failures + dev sync - Add claude-review-responder.yml for auto-responding to PR reviews - Update CI_CD_SETUP.md with new workflow documentation * fix(ci): address Codex review security findings - [Critical] auto-fix: restrict to same-repo PRs only (fork protection) - [High] review-responder: require explicit @claude mention, restrict to same-repo - [Medium] auto-fix: use `gh run view --log-failed` instead of broken API call - [Medium] pr-review: fix Codex matching to use head_sha + pull_requests - [Low] auto-fix: correct workflow name "Tests" → "Test Suite" * fix(ci): restore workflow name to match branch protection rules Rename "Claude PR Review (Fallback)" back to "Claude PR Review" so the check name matches what branch protection expects. * revert: restore workflow name to "Claude PR Review (Fallback)" * ci: fix invalid workflow syntax * ci: fix pnpm cache setup * ci: fix test workflow step order * ci: harden Claude workflows * ci: pin review responder checkout to SHA --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
1 parent 7f1958e commit 55aed79

File tree

7 files changed

+111
-29
lines changed

7 files changed

+111
-29
lines changed

.github/workflows/claude-ci-autofix.yml

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,15 +204,57 @@ jobs:
204204
- name: Checkout code
205205
uses: actions/checkout@v5
206206
with:
207-
ref: ${{ github.event.workflow_run.head_branch }}
207+
ref: ${{ github.event.workflow_run.head_sha }}
208208
fetch-depth: 0
209209

210210
- name: Fetch failed logs
211211
id: failed_logs
212212
env:
213213
GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
214+
GH_REPO: ${{ github.repository }}
214215
run: |
215-
gh run view ${{ github.event.workflow_run.id }} --log-failed > failed.log 2>/dev/null || echo "Failed to fetch logs" > failed.log
216+
set -euo pipefail
217+
218+
run_id="${{ github.event.workflow_run.id }}"
219+
run_url="${{ github.event.workflow_run.html_url }}"
220+
221+
if [ -z "$run_id" ]; then
222+
echo "::error::Missing workflow_run.id; this job only supports workflow_run triggers."
223+
exit 1
224+
fi
225+
226+
echo "Fetching failed logs for run $run_id ($run_url)"
227+
228+
tmp_err="$(mktemp)"
229+
if gh run view "$run_id" --repo "$GH_REPO" --log-failed > failed.log 2>"$tmp_err"; then
230+
if [ ! -s failed.log ]; then
231+
echo "::error::Fetched logs are empty (run $run_id)."
232+
{
233+
echo "ERROR: fetched logs are empty."
234+
echo "Run URL: $run_url"
235+
} > failed.log
236+
exit 1
237+
fi
238+
else
239+
echo "::error::Failed to fetch logs for run $run_id."
240+
{
241+
echo "ERROR: failed to fetch logs for run $run_id."
242+
echo "Run URL: $run_url"
243+
echo ""
244+
echo "--- gh stderr ---"
245+
cat "$tmp_err"
246+
} > failed.log
247+
{
248+
echo "### Claude CI Auto-Fix"
249+
echo ""
250+
echo "Failed to fetch logs for run $run_id."
251+
echo ""
252+
echo "- Run: $run_url"
253+
echo "- Details captured in \`failed.log\` (runner workspace)"
254+
} >> "$GITHUB_STEP_SUMMARY"
255+
exit 1
256+
fi
257+
216258
echo "log_path=failed.log" >> "$GITHUB_OUTPUT"
217259

218260
- name: Get CI failure details
@@ -243,7 +285,8 @@ jobs:
243285
failedJobs: failedJobs.map(j => j.name),
244286
hasPR: hasPR,
245287
prNumber: hasPR ? pullRequests[0].number : null,
246-
headBranch: '${{ github.event.workflow_run.head_branch }}'
288+
headBranch: '${{ github.event.workflow_run.head_branch }}',
289+
headSha: '${{ github.event.workflow_run.head_sha }}'
247290
};
248291
249292
- name: Run Claude Code for Auto-Fix
@@ -266,6 +309,7 @@ jobs:
266309
- **Workflow**: ${{ fromJSON(steps.failure_details.outputs.result).workflowName }}
267310
- **Failed Run**: ${{ fromJSON(steps.failure_details.outputs.result).runUrl }}
268311
- **Branch**: ${{ fromJSON(steps.failure_details.outputs.result).headBranch }}
312+
- **SHA (pinned)**: ${{ fromJSON(steps.failure_details.outputs.result).headSha }}
269313
- **Has PR**: ${{ fromJSON(steps.failure_details.outputs.result).hasPR }}
270314
- **PR Number**: ${{ fromJSON(steps.failure_details.outputs.result).prNumber }}
271315
- **Failed Jobs**: ${{ join(fromJSON(steps.failure_details.outputs.result).failedJobs, ', ') }}

.github/workflows/claude-issue-duplicate-check.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ on:
77
jobs:
88
check-duplicate:
99
if: |
10-
!endsWith(github.actor, '[bot]') &&
11-
secrets.ANTHROPIC_API_KEY != ''
10+
!endsWith(github.actor, '[bot]')
1211
runs-on: ubuntu-latest
1312
timeout-minutes: 10
1413
concurrency:
@@ -19,12 +18,18 @@ jobs:
1918
issues: write
2019

2120
steps:
21+
- name: Skip (missing ANTHROPIC_API_KEY)
22+
if: ${{ secrets.ANTHROPIC_API_KEY == '' }}
23+
run: echo "ANTHROPIC_API_KEY is not configured; skipping duplicate check."
24+
2225
- name: Checkout repository
26+
if: ${{ secrets.ANTHROPIC_API_KEY != '' }}
2327
uses: actions/checkout@v5
2428
with:
2529
fetch-depth: 1
2630

2731
- name: Ensure duplicate label exists
32+
if: ${{ secrets.ANTHROPIC_API_KEY != '' }}
2833
uses: actions/github-script@v7
2934
with:
3035
github-token: ${{ github.token }}
@@ -50,6 +55,7 @@ jobs:
5055
}
5156
5257
- name: Load prompt
58+
if: ${{ secrets.ANTHROPIC_API_KEY != '' }}
5359
id: prompt
5460
shell: bash
5561
run: |
@@ -60,6 +66,7 @@ jobs:
6066
} >> "$GITHUB_OUTPUT"
6167
6268
- name: Run Claude duplicate check
69+
if: ${{ secrets.ANTHROPIC_API_KEY != '' }}
6370
uses: anthropics/claude-code-action@v1
6471
env:
6572
ISSUE_NUMBER: ${{ github.event.issue.number }}

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,15 @@ jobs:
5252
});
5353
5454
const prNumber = context.payload.pull_request.number;
55-
const matchingRun = runs.data.workflow_runs.find(run =>
56-
run.head_sha === context.payload.pull_request.head.sha &&
57-
run.pull_requests?.some(pr => pr.number === prNumber)
58-
);
55+
const prSha = context.payload.pull_request.head.sha;
56+
const prBranch = context.payload.pull_request.head.ref;
57+
58+
const matchingRun = runs.data.workflow_runs.find(run => {
59+
if (run.head_sha !== prSha) return false;
60+
if (run.head_branch && run.head_branch !== prBranch) return false;
61+
if (!Array.isArray(run.pull_requests) || run.pull_requests.length === 0) return true;
62+
return run.pull_requests.some(pr => pr.number === prNumber);
63+
});
5964
6065
if (matchingRun) {
6166
if (matchingRun.status === 'completed') {

.github/workflows/claude-review-responder.yml

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,21 @@ jobs:
2323
uses: actions/checkout@v5
2424
with:
2525
fetch-depth: 0
26-
ref: ${{ github.event.pull_request.head.ref }}
26+
ref: ${{ github.event.pull_request.head.sha }}
27+
28+
- name: Verify PR branch matches reviewed SHA
29+
run: |
30+
set -euo pipefail
31+
expected="${{ github.event.pull_request.head.sha }}"
32+
branch="${{ github.event.pull_request.head.ref }}"
33+
34+
git fetch origin "$branch"
35+
actual="$(git rev-parse FETCH_HEAD)"
36+
37+
if [ "$actual" != "$expected" ]; then
38+
echo "::error::PR branch '$branch' moved since this review was submitted. Expected $expected but remote is $actual."
39+
exit 1
40+
fi
2741
2842
- name: Run Claude Code for Review Response
2943
uses: anthropics/claude-code-action@v1
@@ -47,6 +61,7 @@ jobs:
4761
- **Review State**: ${{ github.event.review.state }}
4862
- **Review Body**: ${{ github.event.review.body }}
4963
- **PR Branch**: ${{ github.event.pull_request.head.ref }}
64+
- **PR SHA (pinned)**: ${{ github.event.pull_request.head.sha }}
5065
5166
---
5267
@@ -101,8 +116,10 @@ jobs:
101116
### Phase 4: Implementation
102117
103118
```bash
104-
git checkout ${{ github.event.pull_request.head.ref }}
105-
git pull origin ${{ github.event.pull_request.head.ref }}
119+
# IMPORTANT: The workspace is already checked out at the reviewed PR head SHA (pinned).
120+
# DO NOT `git pull` or `git checkout` the branch by name.
121+
git rev-parse HEAD
122+
git switch -c claude-review-responder-${{ github.event.pull_request.number }}-${{ github.run_id }}
106123
```
107124
108125
For each change:
@@ -148,7 +165,8 @@ jobs:
148165
149166
Addresses review comments on PR #${{ github.event.pull_request.number }}"
150167
151-
git push origin ${{ github.event.pull_request.head.ref }}
168+
# Push commits back onto the PR branch ref (will fail if the branch advanced).
169+
git push origin HEAD:${{ github.event.pull_request.head.ref }}
152170
```
153171
154172
### Phase 7: Response

.github/workflows/codex-issue-triage.yml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ on:
77
jobs:
88
triage:
99
if: |
10-
!endsWith(github.actor, '[bot]') &&
11-
secrets.OPENAI_API_KEY != ''
10+
!endsWith(github.actor, '[bot]')
1211
runs-on: ubuntu-latest
1312
concurrency:
1413
group: ${{ github.workflow }}-${{ github.event.issue.number }}
@@ -18,12 +17,18 @@ jobs:
1817
issues: write
1918

2019
steps:
20+
- name: Skip (missing OPENAI_API_KEY)
21+
if: ${{ secrets.OPENAI_API_KEY == '' }}
22+
run: echo "OPENAI_API_KEY is not configured; skipping issue triage."
23+
2124
- name: Checkout repository (for docs context)
25+
if: ${{ secrets.OPENAI_API_KEY != '' }}
2226
uses: actions/checkout@v5
2327
with:
2428
fetch-depth: 1
2529

2630
- name: Compute Responses API endpoint override (optional)
31+
if: ${{ secrets.OPENAI_API_KEY != '' }}
2732
id: responses_endpoint
2833
shell: bash
2934
run: |
@@ -38,6 +43,7 @@ jobs:
3843
fi
3944
4045
- name: Run Codex triage
46+
if: ${{ secrets.OPENAI_API_KEY != '' }}
4147
id: run_codex
4248
uses: openai/codex-action@v1
4349
env:
@@ -56,7 +62,7 @@ jobs:
5662
prompt-file: .github/prompts/codex-issue-triage.md
5763

5864
- name: Apply labels and upsert comment
59-
if: steps.run_codex.outputs.final-message != ''
65+
if: ${{ secrets.OPENAI_API_KEY != '' && steps.run_codex.outputs.final-message != '' }}
6066
uses: actions/github-script@v7
6167
env:
6268
TRIAGE_JSON: ${{ steps.run_codex.outputs.final-message }}

.github/workflows/pr-check.yml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ jobs:
2828
- name: Backend syntax check (compileall)
2929
run: python -m compileall -q backend/app
3030
- name: Backend import smoke test
31-
run: python -c "from app.main import app; print('backend app import: ok')"
31+
run: |
32+
python -c "from app.main import app; print('backend app import: ok')"
3233
3334
frontend:
3435
if: github.event.pull_request.draft == false
@@ -38,17 +39,17 @@ jobs:
3839
working-directory: frontend
3940
steps:
4041
- uses: actions/checkout@v5
42+
- name: Setup pnpm
43+
uses: pnpm/action-setup@v4
44+
with:
45+
version: "9.12.2"
46+
run_install: false
4147
- name: Setup Node.js
4248
uses: actions/setup-node@v4
4349
with:
4450
node-version: "20"
4551
cache: "pnpm"
4652
cache-dependency-path: frontend/pnpm-lock.yaml
47-
- name: Setup pnpm
48-
uses: pnpm/action-setup@v4
49-
with:
50-
version: "9.12.2"
51-
run_install: false
5253
- name: Install dependencies
5354
run: pnpm install --frozen-lockfile
5455
- name: Build web app

.github/workflows/test.yml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ jobs:
4545
run: python -m compileall -q backend/app
4646
- name: Backend import smoke test
4747
if: steps.detect.outputs.exists == 'true'
48-
run: python -c "from app.main import app; print('backend app import: ok')"
48+
run: |
49+
python -c "from app.main import app; print('backend app import: ok')"
4950
5051
frontend:
5152
runs-on: ubuntu-latest
@@ -65,19 +66,19 @@ jobs:
6566
if: steps.detect.outputs.exists != 'true'
6667
run: echo "No frontend/ found; skipping frontend checks."
6768

69+
- name: Setup pnpm
70+
if: steps.detect.outputs.exists == 'true'
71+
uses: pnpm/action-setup@v4
72+
with:
73+
version: "9.12.2"
74+
run_install: false
6875
- name: Setup Node.js
6976
if: steps.detect.outputs.exists == 'true'
7077
uses: actions/setup-node@v4
7178
with:
7279
node-version: "20"
7380
cache: "pnpm"
7481
cache-dependency-path: frontend/pnpm-lock.yaml
75-
- name: Setup pnpm
76-
if: steps.detect.outputs.exists == 'true'
77-
uses: pnpm/action-setup@v4
78-
with:
79-
version: "9.12.2"
80-
run_install: false
8182
- name: Install dependencies
8283
if: steps.detect.outputs.exists == 'true'
8384
working-directory: frontend

0 commit comments

Comments
 (0)