-
Notifications
You must be signed in to change notification settings - Fork 732
Expand file tree
/
Copy pathaction.yml
More file actions
305 lines (290 loc) · 11.3 KB
/
Copy pathaction.yml
File metadata and controls
305 lines (290 loc) · 11.3 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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
name: OpenCodeReview PR Review
description: >-
AI-powered GitHub PR review with inline comments, sticky summary, and
incremental non-destructive posting.
author: alibaba
branding:
icon: eye
color: green
inputs:
llm_url:
description: LLM API endpoint URL (mapped to env OCR_LLM_URL).
required: true
llm_auth_token:
description: LLM auth token (mapped to env OCR_LLM_TOKEN).
required: true
llm_model:
description: Model name (mapped to env OCR_LLM_MODEL).
required: true
llm_use_anthropic:
description: "'true' for Anthropic Claude, 'false' for OpenAI-compatible APIs
(mapped to env OCR_USE_ANTHROPIC). Required to force an explicit choice."
required: true
llm_auth_header:
description: Custom auth header name (mapped to env OCR_LLM_AUTH_HEADER).
required: false
llm_extra_headers:
description: Extra headers "K=V,K=V" (mapped to env OCR_LLM_EXTRA_HEADERS).
required: false
llm_extra_body:
description: >-
extra_body JSON for LLM requests. No env var exists for this, so it is
written via `ocr config set llm.extra_body`.
required: false
default: '{"thinking": {"type": "disabled"}}'
language:
description: >-
Review output language, written via `ocr config set language`
(e.g. English, 中文). No env var exists for this.
required: false
default: 'English'
llm_timeout:
description: LLM request timeout in seconds (mapped to env OCR_LLM_TIMEOUT).
required: false
github_token:
description: GitHub token used to post review comments.
required: false
default: ${{ github.token }}
ocr_version:
description: npm version spec for @alibaba-group/open-code-review.
required: false
default: latest
review_concurrency:
description: Value passed to `ocr review --concurrency`.
required: false
background:
description: Value passed to `ocr review --background`.
required: false
rule:
description: Path to a custom rules JSON file passed to `ocr review --rule`.
required: false
upload_artifacts:
description: >-
Upload raw JSON result and stderr as workflow artifacts. Must be the
literal string 'true' or 'false' (quoted); the step gates on a string
comparison, so an unquoted YAML boolean will not match.
required: false
default: 'true'
sticky_summary:
description: >-
Summary dimension. true = update an existing summary comment in place
(sticky) instead of posting a new one each run.
required: false
default: 'true'
incremental:
description: >-
Incremental dimension. true = only append inline comments whose (path,
line range) does not overlap an existing bot review comment. History is
never deleted (non-destructive).
required: false
default: 'false'
incremental_overlap_threshold:
description: >-
IoU (intersection-over-union) threshold used by incremental mode to decide
whether a new multi-line comment overlaps an existing one. Two single-line
comments match when on the same line; single- vs multi-line never match.
Value in (0, 1]; ignored unless incremental is true.
required: false
default: '0.6'
base_ref:
description: >-
Override the base ref. Provide this (and head_sha) when invoking from a
non-PR event such as issue_comment.
required: false
head_sha:
description: Override the head commit SHA (use with base_ref for comment triggers).
required: false
node_version:
description: Node.js version for actions/setup-node.
required: false
default: '24'
outputs:
comments_total:
description: Total number of review comments generated by OCR.
value: ${{ steps.post.outputs.comments_total }}
comments_inline:
description: Number of inline comments successfully posted.
value: ${{ steps.post.outputs.comments_inline }}
comments_skipped:
description: Number of inline comments skipped by incremental mode (overlap with history).
value: ${{ steps.post.outputs.comments_skipped }}
comments_failed:
description: Number of inline comments that failed to post.
value: ${{ steps.post.outputs.comments_failed }}
summary_comment_url:
description: URL of the posted/updated summary comment, if any.
value: ${{ steps.post.outputs.summary_comment_url }}
runs:
using: composite
steps:
- name: Check git and Node.js
id: check_deps
shell: bash
run: |
if command -v git >/dev/null 2>&1; then
echo "git_installed=true" >> "$GITHUB_OUTPUT"
echo "git is already installed: $(git --version)"
else
echo "git_installed=false" >> "$GITHUB_OUTPUT"
echo "git is not installed"
fi
if command -v node >/dev/null 2>&1; then
echo "node_installed=true" >> "$GITHUB_OUTPUT"
echo "node is already installed: $(node --version)"
else
echo "node_installed=false" >> "$GITHUB_OUTPUT"
echo "node is not installed"
fi
- name: Install git
if: steps.check_deps.outputs.git_installed != 'true'
shell: bash
run: |
if command -v apt-get >/dev/null 2>&1; then
sudo apt-get update
sudo apt-get install -y git
elif command -v brew >/dev/null 2>&1; then
brew install git
elif command -v yum >/dev/null 2>&1; then
sudo yum install -y git
elif command -v apk >/dev/null 2>&1; then
sudo apk add --no-cache git
else
echo "::error::Unable to install git: no supported package manager found"
exit 1
fi
git --version
- name: Setup Node.js
if: steps.check_deps.outputs.node_installed != 'true'
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node_version }}
- name: Resolve PR refs
shell: bash
env:
INPUT_BASE_REF: ${{ inputs.base_ref }}
INPUT_HEAD_SHA: ${{ inputs.head_sha }}
EVENT_BASE_REF: ${{ github.event.pull_request.base.ref }}
EVENT_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
BASE_REF="${INPUT_BASE_REF:-$EVENT_BASE_REF}"
HEAD_SHA="${INPUT_HEAD_SHA:-$EVENT_HEAD_SHA}"
echo "BASE_REF=$BASE_REF" >> "$GITHUB_ENV"
echo "HEAD_SHA=$HEAD_SHA" >> "$GITHUB_ENV"
echo "PR base ref: $BASE_REF"
echo "PR head sha: $HEAD_SHA"
- name: Checkout base
uses: actions/checkout@v4
with:
# Checkout the trusted base, not the PR head. OCR reviews the
# base-to-head diff from git objects; the head commit's blobs are
# fetched separately so they are resolvable without materializing
# untrusted PR files into the working tree.
fetch-depth: 0
- name: Fetch PR head (fork-safe)
if: env.HEAD_SHA != ''
shell: bash
env:
PR_NUM: ${{ github.event.pull_request.number || github.event.issue.number }}
run: |
if [ -n "$PR_NUM" ]; then
git fetch origin "pull/${PR_NUM}/head"
fi
- name: Compute merge-base
shell: bash
run: |
git fetch origin "${BASE_REF}" 2>/dev/null || true
MERGE_BASE=$(git merge-base "origin/${BASE_REF}" "${HEAD_SHA}" 2>/dev/null || echo "${HEAD_SHA}")
echo "MERGE_BASE=$MERGE_BASE" >> "$GITHUB_ENV"
echo "Reviewing ${HEAD_SHA} from merge-base ${MERGE_BASE} (base origin/${BASE_REF})"
- name: Install OpenCodeReview
shell: bash
env:
OCR_VERSION: ${{ inputs.ocr_version }}
run: |
npm install -g "@alibaba-group/open-code-review@${OCR_VERSION}"
echo "OpenCodeReview installed:"
ocr version || true
- name: Configure OCR
env:
OCR_EXTRA_BODY: ${{ inputs.llm_extra_body }}
OCR_LANGUAGE: ${{ inputs.language }}
shell: bash
run: |
ocr config set llm.extra_body "$OCR_EXTRA_BODY"
ocr config set language "$OCR_LANGUAGE"
- name: Run OpenCodeReview
env:
OCR_LLM_URL: ${{ inputs.llm_url }}
OCR_LLM_TOKEN: ${{ inputs.llm_auth_token }}
OCR_LLM_MODEL: ${{ inputs.llm_model }}
OCR_USE_ANTHROPIC: ${{ inputs.llm_use_anthropic }}
OCR_LLM_AUTH_HEADER: ${{ inputs.llm_auth_header }}
OCR_LLM_EXTRA_HEADERS: ${{ inputs.llm_extra_headers }}
OCR_LLM_TIMEOUT: ${{ inputs.llm_timeout }}
OCR_REVIEW_CONCURRENCY: ${{ inputs.review_concurrency }}
OCR_BACKGROUND: ${{ inputs.background }}
OCR_RULE: ${{ inputs.rule }}
shell: bash
run: |
ARGS=(--from "${MERGE_BASE}" --to "${HEAD_SHA}" --format json)
[ -n "$OCR_REVIEW_CONCURRENCY" ] && ARGS+=(--concurrency "$OCR_REVIEW_CONCURRENCY")
[ -n "$OCR_BACKGROUND" ] && ARGS+=(--background "$OCR_BACKGROUND")
[ -n "$OCR_RULE" ] && ARGS+=(--rule "$OCR_RULE")
set +e
ocr review "${ARGS[@]}" > /tmp/ocr-result.json 2>/tmp/ocr-stderr.log
OCR_EXIT_CODE=$?
set -e
echo "OCR_EXIT_CODE=$OCR_EXIT_CODE" >> "$GITHUB_ENV"
echo "=== OCR result ==="
cat /tmp/ocr-result.json
echo "=== OCR stderr ==="
cat /tmp/ocr-stderr.log
- name: Upload review artifacts
if: ${{ always() && inputs.upload_artifacts == 'true' }}
uses: actions/upload-artifact@v4
with:
name: ocr-review-result-${{ github.run_id }}-${{ github.run_attempt }}
path: |
/tmp/ocr-result.json
/tmp/ocr-stderr.log
if-no-files-found: warn
- name: Fail job on OCR error
if: env.OCR_EXIT_CODE != '0'
shell: bash
run: |
echo "ocr review exited with code ${OCR_EXIT_CODE}; see uploaded artifacts for details."
exit "${OCR_EXIT_CODE}"
- name: Post review comments
if: env.OCR_EXIT_CODE == '0'
id: post
uses: actions/github-script@v7
env:
OCR_INCREMENTAL_OVERLAP_THRESHOLD: ${{ inputs.incremental_overlap_threshold }}
with:
github-token: ${{ inputs.github_token }}
script: |
// Locate the helper shipped alongside action.yml at runtime.
// GITHUB_ACTION_PATH: correct for published (remote) actions and for
// local actions when not running in a container.
// GITHUB_WORKSPACE: correct for local `uses: ./` actions — under
// self-hosted + container setups, GITHUB_ACTION_PATH points to the
// host path (invisible inside the container), whereas GITHUB_WORKSPACE
// is correctly mapped to /__w.
const fs = require('fs');
const path = require('path');
const REL = 'scripts/github-actions/post-review-comments.js';
const roots = [process.env.GITHUB_ACTION_PATH, process.env.GITHUB_WORKSPACE].filter(Boolean);
const helper = roots.map(r => path.resolve(r, REL)).find(p => fs.existsSync(p));
if (!helper) throw new Error(`Could not locate ${REL}; searched roots: ${roots.join(', ')}`);
const { runPostReviewComments } = require(helper);
await runPostReviewComments({
github,
context,
core,
fs,
resultPath: '/tmp/ocr-result.json',
stderrPath: '/tmp/ocr-stderr.log',
stickySummary: ${{ inputs.sticky_summary == 'true' }},
incremental: ${{ inputs.incremental == 'true' }},
incrementalOverlapThreshold: parseFloat(process.env.OCR_INCREMENTAL_OVERLAP_THRESHOLD),
});