-
Notifications
You must be signed in to change notification settings - Fork 33
223 lines (210 loc) Β· 10.8 KB
/
Copy pathocr.yml
File metadata and controls
223 lines (210 loc) Β· 10.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
name: π Code Review
# from: github.com/alibaba/open-code-review/tree/5829539379e/examples/github_actions/ocr-review.yml
# Conditional concurrency group.
#
# GitHub Actions evaluates concurrency BEFORE job-level if-conditions. With a
# flat group (ocr-<pr_number>), every comment on the PR β even an unrelated
# conversation reply that will be skipped β enters the same group and, because
# cancel-in-progress is true, cancels any in-progress review. The result: a
# single normal comment kills a running review, and you see "two runs, one
# cancelled" in the Actions tab.
#
# Fix: matching events (PR events + /open-code-review comments) share a per-PR
# group so a new review cancels any stale one for the same PR. Non-matching
# comments land in a unique noop-<run_id> group that can never collide with a
# real review, so they are skipped instantly without disrupting anything.
concurrency:
group: >-
${{
(
github.event_name == 'pull_request_target'
|| (
github.event_name == 'issue_comment'
&& github.event.issue.pull_request
&& github.event.comment.user.type != 'Bot'
&& (
github.event.comment.author_association == 'MEMBER'
|| github.event.comment.author_association == 'OWNER'
|| github.event.comment.author_association == 'COLLABORATOR'
)
&& (
startsWith(github.event.comment.body, '/open-code-review')
|| startsWith(github.event.comment.body, '@open-code-review')
|| startsWith(github.event.comment.body, '@ocr')
|| startsWith(github.event.comment.body, '/ocr')
)
)
)
&& format('ocr-{0}', github.event.pull_request.number || github.event.issue.number)
|| format('noop-{0}', github.run_id)
}}
cancel-in-progress: true
on:
# Use pull_request_target instead of pull_request so that secrets are
# available even for PRs from forks. This is safe because the reusable
# action only reads the diff and does not execute any code from the PR.
pull_request_target:
types: [opened, synchronize, reopened]
issue_comment:
types: [created]
permissions:
contents: read
pull-requests: write
jobs:
code-review:
name: π§ OCR
runs-on: ubuntu-latest
timeout-minutes: 100
# Run on PR events, or on human-authored comments starting with trigger
# keywords. Bot comments are excluded as a safety net: GITHUB_TOKEN already
# suppresses events from bot-posted comments, but a PAT/App token would not.
# issue_comment triggers are further gated on author_association so only
# MEMBER/OWNER/COLLABORATOR users can spend LLM quota via re-review.
if: |
github.event_name == 'pull_request_target'
|| (
github.event_name == 'issue_comment'
&& github.event.issue.pull_request
&& github.event.comment.user.type != 'Bot'
&& (
github.event.comment.author_association == 'MEMBER'
|| github.event.comment.author_association == 'OWNER'
|| github.event.comment.author_association == 'COLLABORATOR'
)
&& (
startsWith(github.event.comment.body, '/open-code-review')
|| startsWith(github.event.comment.body, '@open-code-review')
|| startsWith(github.event.comment.body, '@ocr')
|| startsWith(github.event.comment.body, '/ocr')
)
)
steps:
- name: π¦ Context
id: pr-context
if: github.event_name == 'issue_comment'
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with:
script: |
// For issue_comment events, resolve PR base/head so the action
// can review the right diff (issue_comment has no top-level
// pull_request payload fields).
const prNumber = context.issue.number;
const { data: pullRequest } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
const isClosed = pullRequest.state === 'closed';
core.setOutput('is_closed', isClosed ? 'true' : 'false');
// Always use the branch name β the action's internal
// actions/checkout fetches all branches, so origin/<branch>
// resolves naturally via refs/remotes/origin/<branch>. The old
// bare-SHA approach caused empty diffs because git can't resolve
// origin/<sha> without a named ref (FETCH_HEAD is not one).
core.setOutput('base_ref', pullRequest.base.ref);
// Also expose the SHA for the rare deleted-branch fallback in
// the prepare step.
core.setOutput('base_sha', pullRequest.base.sha);
core.setOutput('head_sha', pullRequest.head.sha);
# Supply-chain hardening: this job holds secrets, so every action here
# is pinned by full commit SHA (github-script, checkout, and the OCR
# action itself). First-party actions are pinned too; a mutable tag
# in a secrets-bearing pull_request_target job is an injection vector.
#
# Strategy for closed PRs: always pass base.ref (the branch name) to
# the OCR action β its internal actions/checkout fetches all branches,
# so `origin/<branch>` resolves naturally via refs/remotes/origin/<branch>.
# The old approach (base.sha for closed PRs) failed because git can't
# resolve `origin/<sha>` without a named ref; FETCH_HEAD is not one.
#
# Edge case: if the base branch was deleted after merge (rare), the
# action's fetch fails and merge-base falls back to HEAD_SHA (empty
# diff). The prepare step detects this via ls-remote, falls back to
# the base SHA, and creates refs/origin/<sha> so git DWIM (rule 2:
# refs/<refname>) resolves it. This namespace survives the action's
# checkout: refs/heads/* are deleted (prepareExistingDirectory),
# refs/remotes/origin/* and refs/tags/* are pruned (--prune fetch),
# but refs/origin/* is untouched.
- name: β¬οΈ Checkout (shallow β prepare step needs a git remote)
if: github.event_name == 'issue_comment' && steps.pr-context.outputs.is_closed == 'true'
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
fetch-depth: 1
persist-credentials: false
- name: π Prepare closed-PR reviews
id: prepare
if: github.event_name == 'issue_comment' && steps.pr-context.outputs.is_closed == 'true'
shell: bash
env:
BASE_REF: ${{ steps.pr-context.outputs.base_ref }}
BASE_SHA: ${{ steps.pr-context.outputs.base_sha }}
HEAD_SHA: ${{ steps.pr-context.outputs.head_sha }}
PR_NUM: ${{ github.event.pull_request.number || github.event.issue.number }}
run: |
set -eux
# share.google/aimode/lmbJxZFxHJb5l7Bfd
# Fork PRs: the head may live in a deleted fork. Fetch the PR's
# pull/<n>/head ref (advertised on the base repo, persistent after
# close) so the head objects are present for the action's merge-base
# and diff.
if [ -n "${PR_NUM}" ]; then
git fetch origin "pull/${PR_NUM}/head" 2>/dev/null || true
fi
git fetch origin "${HEAD_SHA}" 2>/dev/null || true
# Base branch deleted after merge β rare. Fall back to the base
# SHA. The action's `git fetch origin <sha>` only writes
# FETCH_HEAD (not a named ref), so `git merge-base origin/<sha>`
# can't resolve it. We create refs/origin/<sha> instead: git
# DWIM rule 2 (refs/<refname>) resolves origin/<sha>.
#
# This must NOT be refs/heads/origin/<sha>: the action's internal
# checkout deletes ALL local branches (prepareExistingDirectory).
# refs/remotes/origin/<sha> would be pruned by its --prune fetch.
# refs/origin/<sha> is outside every namespace checkout mutates.
echo "::warning::base branch '${BASE_REF}' deleted on origin; falling back to SHA ${BASE_SHA}"
git fetch origin "${BASE_SHA}" 2>/dev/null || true
if git cat-file -e "${BASE_SHA}^{commit}" 2>/dev/null; then
git update-ref "refs/origin/${BASE_SHA}" "${BASE_SHA}"
echo "Created refs/origin/${BASE_SHA} as DWIM fallback"
echo "base_ref=${BASE_SHA}" >> "$GITHUB_OUTPUT"
else
echo "::error::base SHA ${BASE_SHA} not fetchable; review may produce an empty diff"
# Check whether the base branch still exists on origin. For the
# common case (main, develop, release/*) it does, and the action's
# own checkout creates refs/remotes/origin/<branch> which makes
# `git merge-base origin/<branch> <head>` work naturally.
if git ls-remote --exit-code --heads origin "${BASE_REF}" >/dev/null 2>&1; then
echo "Base branch '${BASE_REF}' exists on origin"
echo "base_ref=${BASE_REF}" >> "$GITHUB_OUTPUT"
fi
fi
if git cat-file -e "${HEAD_SHA}^{commit}" 2>/dev/null; then
echo "Head ${HEAD_SHA} resolved"
else
echo "::warning::head SHA ${HEAD_SHA} not yet resolved; the action's fork-safe fetch will retry"
fi
- name: π¦βπ₯ Review
uses: alibaba/open-code-review@e78474478f168a8009bd3b12334a87a2c985819d # v1.8.4
with:
llm_url: ${{ secrets.OCR_LLM_URL }}
llm_auth_token: ${{ secrets.OCR_LLM_AUTH_TOKEN }}
llm_model: ${{ vars.OCR_LLM_MODEL }}
llm_use_anthropic: ${{ vars.OCR_LLM_USE_ANTHROPIC }}
# turn on thinking mode as expected by anthropic api
llm_extra_body: '${{ vars.OCR_LLM_EXTRA_BODY }}'
# For issue_comment triggers, pass the resolved refs; for
# pull_request_target the action resolves them from the
# event automatically:
# github.com/alibaba/open-code-review/blob/5829539379e/action.yml#L208-L216
#
# prepare.outputs.base_ref is set only for closed PRs: branch name
# if the branch exists on origin, base SHA otherwise (with DWIM
# fallback). For open PRs or pull_request_target, fall back to the
# pr-context output (branch name).
base_ref: ${{ steps.prepare.outputs.base_ref || steps.pr-context.outputs.base_ref }}
head_sha: ${{ steps.pr-context.outputs.head_sha }}
# Pin the npm CLI to the same release as the pinned action commit.
# The action's own default is `latest` (action.yml install step:
# npm install -g "@alibaba-group/open-code-review@${OCR_VERSION}"),
# which could drift away from the action code at e7847447.
ocr_version: 1.8.4