@alibaba-group/open-code-review 1.2.4 → 1.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.ko-KR.md +223 -0
- package/CONTRIBUTING.md +6 -2
- package/README.ja-JP.md +94 -3
- package/README.ko-KR.md +427 -0
- package/README.md +97 -4
- package/README.zh-CN.md +94 -3
- package/examples/github_actions/README.md +6 -6
- package/examples/github_actions/ocr-review.yml +24 -12
- package/examples/gitlab_ci/.gitlab-ci.yml +41 -20
- package/examples/gitlab_ci/README.md +10 -8
- package/package.json +1 -1
- package/plugins/open-code-review/.codex-plugin/plugin.json +34 -0
- package/plugins/open-code-review/CODEX.ko-KR.md +108 -0
- package/plugins/open-code-review/skills/open-code-review/SKILL.md +236 -0
package/README.zh-CN.md
CHANGED
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
<p align="center">
|
|
8
8
|
<a href="https://www.npmjs.com/package/@alibaba-group/open-code-review"><img alt="npm" src="https://img.shields.io/npm/v/@alibaba-group/open-code-review?style=flat-square" /></a>
|
|
9
9
|
<a href="https://github.com/alibaba/open-code-review/actions/workflows/release.yml"><img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/alibaba/open-code-review/release.yml?style=flat-square" /></a>
|
|
10
|
+
<a href="https://goreportcard.com/report/github.com/alibaba/open-code-review"><img alt="Go Report Card" src="https://goreportcard.com/badge/github.com/alibaba/open-code-review?style=flat-square" /></a>
|
|
10
11
|
<a href="https://github.com/alibaba/open-code-review/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/github/license/alibaba/open-code-review?style=flat-square" /></a>
|
|
11
12
|
</p>
|
|
12
13
|
<p align="center">
|
|
13
|
-
<a href="README.md">English</a> | 简体中文 | <a href="README.ja-JP.md">日本語</a>
|
|
14
|
+
<a href="README.md">English</a> | 简体中文 | <a href="README.ja-JP.md">日本語</a> | <a href="README.ko-KR.md">한국어</a>
|
|
14
15
|
</p>
|
|
15
16
|
|
|
16
17
|
---
|
|
@@ -128,11 +129,21 @@ export OCR_USE_ANTHROPIC=true
|
|
|
128
129
|
|
|
129
130
|
配置存储于 `~/.opencodereview/config.json`。
|
|
130
131
|
|
|
132
|
+
**`auth_header`(可选):** 控制使用 Anthropic 时通过哪个 HTTP header 传递 API key。省略时默认为 `authorization`(Bearer token)。如果你使用标准 `sk-ant-*` API key,需要将其设为 `x-api-key`:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
ocr config set llm.auth_header x-api-key
|
|
136
|
+
# 或
|
|
137
|
+
export OCR_LLM_AUTH_HEADER=x-api-key
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
支持的值:`x-api-key`、`authorization`(别名:`bearer`)。其他值会直接报错。
|
|
141
|
+
|
|
131
142
|
同时兼容了 Claude Code 环境变量(`ANTHROPIC_BASE_URL`、`ANTHROPIC_AUTH_TOKEN`、`ANTHROPIC_MODEL`),并解析 `~/.zshrc` / `~/.bashrc` 中的相关导出。
|
|
132
143
|
|
|
133
144
|
> **CC-Switch 用户特别提醒**:如果你使用 [CC-Switch](https://github.com/farion1231/cc-switch) 并开启了[路由服务](https://www.ccswitch.io/zh/docs?section=proxy&item=service),可以将 `llm.url` 配置成 CC-Switch 启动的代理地址,无需额外配置:
|
|
134
145
|
> - 如果路由的是 **Claude** 供应商:设置 `llm.url` 为 `http://127.0.0.1:15721`
|
|
135
|
-
> - 如果路由的是 **
|
|
146
|
+
> - 如果路由的是 **Codex** 供应商:设置 `llm.url` 为 `http://127.0.0.1:15721/v1`
|
|
136
147
|
> - `llm.model` 根据你的供应商设置进行配置
|
|
137
148
|
> - `llm.auth_token` 可以设置成任意值
|
|
138
149
|
> - `extra_body` 设置依然生效
|
|
@@ -183,7 +194,43 @@ npx skills add alibaba/open-code-review --skill open-code-review
|
|
|
183
194
|
|
|
184
195
|
此命令注册 `/open-code-review:review` 斜杠命令,运行 OCR 并自动过滤和修复问题。
|
|
185
196
|
|
|
186
|
-
####
|
|
197
|
+
#### 方式三:作为 Codex Plugin 安装
|
|
198
|
+
|
|
199
|
+
对于本地 Codex,可以从此仓库安装 Open Code Review plugin:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
codex plugin marketplace add alibaba/open-code-review
|
|
203
|
+
codex
|
|
204
|
+
/plugins
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
对于本地 checkout 或 fork:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
codex plugin marketplace add .
|
|
211
|
+
codex
|
|
212
|
+
/plugins
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
安装并启用 `Open Code Review` 后,启动新的 Codex thread 并显式调用:
|
|
216
|
+
|
|
217
|
+
```text
|
|
218
|
+
@Open Code Review review my current changes
|
|
219
|
+
@Open Code Review review this branch against main
|
|
220
|
+
@Open Code Review review and fix high-confidence issues
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
这会注册一个 Codex skill,用于运行本地 OCR CLI:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
ocr review --audience agent
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
此集成不会改变 OCR 的内部 LLM backend,也不需要为 Codex 配置 OpenAI Responses API endpoint。OCR 本身仍需要按照 CLI setup 部分安装并配置 `ocr` CLI。
|
|
230
|
+
|
|
231
|
+
韩文指南:[`plugins/open-code-review/CODEX.ko-KR.md`](plugins/open-code-review/CODEX.ko-KR.md)
|
|
232
|
+
|
|
233
|
+
#### 方式四:直接复制命令文件
|
|
187
234
|
|
|
188
235
|
如果不想使用任何包管理器,可以直接复制命令文件,在 Claude Code 中使用 `/open-code-review` 斜杠命令。
|
|
189
236
|
|
|
@@ -316,6 +363,48 @@ OCR 通过四层优先级链解析评审规则。每层采用首次匹配原则
|
|
|
316
363
|
- 在每一层内,规则按声明顺序评估 —— 首次匹配生效。
|
|
317
364
|
- 如果规则文件不存在,将被静默跳过。
|
|
318
365
|
|
|
366
|
+
### 路径过滤
|
|
367
|
+
|
|
368
|
+
规则文件同时支持 `include` 和 `exclude` 字段,用于控制哪些文件进入审查范围:
|
|
369
|
+
|
|
370
|
+
```json
|
|
371
|
+
{
|
|
372
|
+
"rules": [
|
|
373
|
+
{"path": "**/*.java", "rule": "检查空值安全"}
|
|
374
|
+
],
|
|
375
|
+
"include": ["src/main/**/*.java", "lib/**/*.kt"],
|
|
376
|
+
"exclude": ["**/generated/**", "vendor/**"]
|
|
377
|
+
}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
**过滤决策优先级(从高到低):**
|
|
381
|
+
|
|
382
|
+
| 步骤 | 条件 | 结果 |
|
|
383
|
+
|------|------|------|
|
|
384
|
+
| 1 | 文件为二进制文件 | 排除 |
|
|
385
|
+
| 2 | 路径匹配用户 `exclude` 模式 | 排除 |
|
|
386
|
+
| 3 | 文件扩展名不在支持列表中 | 排除 |
|
|
387
|
+
| 4 | 配置了 `include` 且路径匹配 | **纳入审查**(跳过步骤 5) |
|
|
388
|
+
| 5 | 路径匹配内置默认排除模式(测试文件等) | 排除 |
|
|
389
|
+
| 6 | 以上均不满足 | 纳入审查 |
|
|
390
|
+
|
|
391
|
+
**生效逻辑:**
|
|
392
|
+
|
|
393
|
+
- `include` 和 `exclude` 遵循与评审规则相同的优先级链(`--rule` > 项目配置 > 全局配置),取**最高优先级中配置了 include/exclude 的那一层**整体生效,不会跨层合并。
|
|
394
|
+
- `exclude` 始终优先于 `include` —— 同时匹配两者的文件会被排除。
|
|
395
|
+
- `include` 的作用是**绕过内置默认排除模式**(如测试文件),而非限制审查范围 —— 未匹配 `include` 的文件仍会正常进入后续的默认过滤判断。
|
|
396
|
+
- 模式语法:支持 `**` 递归匹配、`*` 单级匹配和 `{a,b}` 大括号展开,匹配时不区分大小写。
|
|
397
|
+
|
|
398
|
+
**内置默认排除模式**(用于过滤测试文件等,可通过 `include` 覆盖):
|
|
399
|
+
|
|
400
|
+
```
|
|
401
|
+
**/*_test.go, **/*Test.java, **/*Tests.java, **/*_test.rs,
|
|
402
|
+
**/*.test.{js,jsx,ts,tsx}, **/*.spec.{js,jsx,ts,tsx}, **/__tests__/**,
|
|
403
|
+
**/src/test/java/**/*.java, **/src/test/**/*.kt,
|
|
404
|
+
**/test/**/*_test.py, **/tests/**/*_test.py, **/*_test.py,
|
|
405
|
+
**/*_spec.rb, **/spec/**/*_spec.rb, **/oh_modules/**
|
|
406
|
+
```
|
|
407
|
+
|
|
319
408
|
## 配置参考
|
|
320
409
|
|
|
321
410
|
配置文件:`~/.opencodereview/config.json`
|
|
@@ -324,6 +413,7 @@ OCR 通过四层优先级链解析评审规则。每层采用首次匹配原则
|
|
|
324
413
|
|----|------|------|
|
|
325
414
|
| `llm.url` | string | `https://api.openai.com/v1/chat/completions` |
|
|
326
415
|
| `llm.auth_token` | string | `sk-xxxxxxx` |
|
|
416
|
+
| `llm.auth_header` | string | 仅 Anthropic:`x-api-key` \| `authorization` |
|
|
327
417
|
| `llm.model` | string | `claude-opus-4-6` |
|
|
328
418
|
| `llm.use_anthropic` | boolean | `true` \| `false` |
|
|
329
419
|
| `language` | string | `English` \| `Chinese`(默认:Chinese) |
|
|
@@ -340,6 +430,7 @@ OCR 通过四层优先级链解析评审规则。每层采用首次匹配原则
|
|
|
340
430
|
|------|------|
|
|
341
431
|
| `OCR_LLM_URL` | LLM API 端点 URL |
|
|
342
432
|
| `OCR_LLM_TOKEN` | API 密钥 / 认证令牌 |
|
|
433
|
+
| `OCR_LLM_AUTH_HEADER` | Anthropic 认证头(`x-api-key` 或 `authorization`) |
|
|
343
434
|
| `OCR_LLM_MODEL` | 模型名称 |
|
|
344
435
|
| `OCR_USE_ANTHROPIC` | `true` = Anthropic,`false` = OpenAI |
|
|
345
436
|
|
|
@@ -10,10 +10,10 @@ PR Created/Updated → GitHub Actions Triggered → OCR Reviews Diff → Comment
|
|
|
10
10
|
Comment with trigger keyword ↗
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
1. When a PR is opened,
|
|
13
|
+
1. When a PR is opened, the workflow triggers (uses `pull_request_target` for fork secret access)
|
|
14
14
|
2. Alternatively, when a comment containing `/open-code-review` or `@open-code-review` is posted on a PR, the workflow triggers
|
|
15
15
|
3. It installs OCR via `npm install -g @alibaba-group/open-code-review`
|
|
16
|
-
4. Runs `ocr review --from origin/<base> --to
|
|
16
|
+
4. Runs `ocr review --from origin/<base> --to <head_sha> --format json` to analyze the diff (uses commit SHA to support fork PRs)
|
|
17
17
|
5. Parses the JSON output and posts inline review comments on the PR using GitHub's Pull Request Review API
|
|
18
18
|
|
|
19
19
|
## Setup
|
|
@@ -46,11 +46,11 @@ Go to your repository's **Settings → Secrets and variables → Actions** and a
|
|
|
46
46
|
|
|
47
47
|
### Change the trigger events
|
|
48
48
|
|
|
49
|
-
Modify the `on.
|
|
49
|
+
Modify the `on.pull_request_target.types` array in the workflow file:
|
|
50
50
|
|
|
51
51
|
```yaml
|
|
52
52
|
on:
|
|
53
|
-
|
|
53
|
+
pull_request_target:
|
|
54
54
|
types: [opened, synchronize, reopened, ready_for_review]
|
|
55
55
|
```
|
|
56
56
|
|
|
@@ -60,7 +60,7 @@ By default, the workflow triggers when a PR comment starts with `/open-code-revi
|
|
|
60
60
|
|
|
61
61
|
```yaml
|
|
62
62
|
if: |
|
|
63
|
-
github.event_name == '
|
|
63
|
+
github.event_name == 'pull_request_target' ||
|
|
64
64
|
(github.event_name == 'issue_comment' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/review')) ||
|
|
65
65
|
(github.event_name == 'issue_comment' && github.event.issue.pull_request && startsWith(github.event.comment.body, '@mybot'))
|
|
66
66
|
```
|
|
@@ -69,7 +69,7 @@ Or use a more flexible pattern with `contains` to trigger on any comment contain
|
|
|
69
69
|
|
|
70
70
|
```yaml
|
|
71
71
|
if: |
|
|
72
|
-
github.event_name == '
|
|
72
|
+
github.event_name == 'pull_request_target' ||
|
|
73
73
|
(github.event_name == 'issue_comment' && github.event.issue.pull_request && contains(github.event.comment.body, '/review'))
|
|
74
74
|
```
|
|
75
75
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# and posts review comments directly on the PR.
|
|
5
5
|
#
|
|
6
6
|
# Triggers:
|
|
7
|
-
# - PR opened
|
|
7
|
+
# - PR opened (uses pull_request_target for fork secret access)
|
|
8
8
|
# - Comment on PR containing '/open-code-review' or '@open-code-review'
|
|
9
9
|
#
|
|
10
10
|
# Required secrets:
|
|
@@ -18,8 +18,15 @@
|
|
|
18
18
|
|
|
19
19
|
name: OpenCodeReview PR Review
|
|
20
20
|
|
|
21
|
+
concurrency:
|
|
22
|
+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
23
|
+
cancel-in-progress: true
|
|
24
|
+
|
|
21
25
|
on:
|
|
22
|
-
pull_request
|
|
26
|
+
# Use pull_request_target instead of pull_request so that secrets are
|
|
27
|
+
# available even for PRs from forks. This is safe because OCR only reads
|
|
28
|
+
# the diff and does not execute any code from the PR.
|
|
29
|
+
pull_request_target:
|
|
23
30
|
types: [opened]
|
|
24
31
|
issue_comment:
|
|
25
32
|
types: [created]
|
|
@@ -33,13 +40,13 @@ jobs:
|
|
|
33
40
|
runs-on: ubuntu-latest
|
|
34
41
|
# Run on PR events, or on comments starting with trigger keywords
|
|
35
42
|
if: |
|
|
36
|
-
github.event_name == '
|
|
43
|
+
github.event_name == 'pull_request_target' ||
|
|
37
44
|
(github.event_name == 'issue_comment' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/open-code-review')) ||
|
|
38
45
|
(github.event_name == 'issue_comment' && github.event.issue.pull_request && startsWith(github.event.comment.body, '@open-code-review'))
|
|
39
46
|
steps:
|
|
40
47
|
- name: Get PR context
|
|
41
48
|
id: pr-context
|
|
42
|
-
if: github.event_name != '
|
|
49
|
+
if: github.event_name != 'pull_request_target'
|
|
43
50
|
uses: actions/github-script@v7
|
|
44
51
|
with:
|
|
45
52
|
script: |
|
|
@@ -58,7 +65,10 @@ jobs:
|
|
|
58
65
|
uses: actions/checkout@v4
|
|
59
66
|
with:
|
|
60
67
|
fetch-depth: 0 # Full history needed for merge-base diff
|
|
61
|
-
ref: ${{ github.
|
|
68
|
+
ref: ${{ github.event.pull_request.head.sha || steps.pr-context.outputs.head_sha }}
|
|
69
|
+
|
|
70
|
+
- name: Fetch PR head ref (ensures fork commits are available)
|
|
71
|
+
run: git fetch origin pull/${{ github.event.pull_request.number || github.event.issue.number }}/head
|
|
62
72
|
|
|
63
73
|
- name: Setup Node.js
|
|
64
74
|
uses: actions/setup-node@v4
|
|
@@ -79,21 +89,23 @@ jobs:
|
|
|
79
89
|
- name: Run OpenCodeReview
|
|
80
90
|
id: review
|
|
81
91
|
run: |
|
|
82
|
-
# Get base and head
|
|
83
|
-
|
|
92
|
+
# Get base ref and head SHA from PR context (different for comment triggers)
|
|
93
|
+
# Note: We use HEAD_SHA instead of origin/${HEAD_REF} to support fork PRs,
|
|
94
|
+
# because fork branches don't exist on the origin remote.
|
|
95
|
+
if [ "${{ github.event_name }}" = "pull_request_target" ]; then
|
|
84
96
|
BASE_REF="${{ github.event.pull_request.base.ref }}"
|
|
85
|
-
|
|
97
|
+
HEAD_SHA="${{ github.event.pull_request.head.sha }}"
|
|
86
98
|
else
|
|
87
99
|
BASE_REF="${{ steps.pr-context.outputs.base_ref }}"
|
|
88
|
-
|
|
100
|
+
HEAD_SHA="${{ steps.pr-context.outputs.head_sha }}"
|
|
89
101
|
fi
|
|
90
102
|
|
|
91
|
-
echo "Reviewing PR: ${
|
|
103
|
+
echo "Reviewing PR: ${HEAD_SHA} against origin/${BASE_REF}"
|
|
92
104
|
|
|
93
105
|
# Run OCR in range mode with JSON output
|
|
94
106
|
ocr review \
|
|
95
107
|
--from "origin/${BASE_REF}" \
|
|
96
|
-
--to "
|
|
108
|
+
--to "${HEAD_SHA}" \
|
|
97
109
|
--format json \
|
|
98
110
|
> /tmp/ocr-result.json 2>/tmp/ocr-stderr.log || true
|
|
99
111
|
|
|
@@ -150,7 +162,7 @@ jobs:
|
|
|
150
162
|
let commitSha;
|
|
151
163
|
|
|
152
164
|
// Get commit SHA from event context
|
|
153
|
-
if (context.eventName === '
|
|
165
|
+
if (context.eventName === 'pull_request_target') {
|
|
154
166
|
commitSha = context.payload.pull_request.head.sha;
|
|
155
167
|
} else {
|
|
156
168
|
// For comment events, we need to fetch the PR
|
|
@@ -2,20 +2,30 @@
|
|
|
2
2
|
#
|
|
3
3
|
# This pipeline automatically reviews Merge Requests using OpenCodeReview
|
|
4
4
|
# and posts review comments (discussions) directly on the MR diff.
|
|
5
|
+
# Supports both same-repo and forked MR scenarios.
|
|
5
6
|
#
|
|
6
7
|
# Required CI/CD Variables (Settings → CI/CD → Variables):
|
|
7
8
|
# OCR_LLM_URL - LLM API endpoint (e.g., https://api.openai.com/v1/chat/completions)
|
|
8
9
|
# OCR_LLM_AUTH_TOKEN - Authentication token for the LLM API (mark as "Masked")
|
|
9
|
-
# GITLAB_API_TOKEN - GitLab Personal/Project Access Token with "api" scope
|
|
10
10
|
#
|
|
11
11
|
# Optional CI/CD Variables:
|
|
12
12
|
# OCR_LLM_MODEL - Model name (default: gpt-4o)
|
|
13
|
+
# GITLAB_API_TOKEN - GitLab Personal/Project Access Token with "api" scope
|
|
14
|
+
# (falls back to CI_JOB_TOKEN if not set)
|
|
15
|
+
#
|
|
16
|
+
# Fork MR Support:
|
|
17
|
+
# The script uses CI_COMMIT_SHA as the diff target to correctly resolve the
|
|
18
|
+
# source commit from forked repos. For some GitLab versions, you may need to enable:
|
|
19
|
+
# Project Settings → CI/CD → General pipelines →
|
|
20
|
+
# "Run pipelines in the parent project for merge requests from forked projects"
|
|
13
21
|
|
|
14
22
|
stages:
|
|
15
23
|
- review
|
|
16
24
|
|
|
17
25
|
code-review:
|
|
18
26
|
stage: review
|
|
27
|
+
interruptible: true
|
|
28
|
+
resource_group: mr-review-$CI_MERGE_REQUEST_IID
|
|
19
29
|
image: node:20
|
|
20
30
|
only:
|
|
21
31
|
- merge_requests
|
|
@@ -27,7 +37,7 @@ code-review:
|
|
|
27
37
|
|
|
28
38
|
# Configure OCR
|
|
29
39
|
- mkdir -p ~/.open-code-review
|
|
30
|
-
# Gitlab CI/CD does not support
|
|
40
|
+
# Gitlab CI/CD does not support configuring variables with value length less than 8, so you can't set use_anthropic as a CI variable
|
|
31
41
|
- |
|
|
32
42
|
ocr config set llm.url $OCR_LLM_URL
|
|
33
43
|
ocr config set llm.auth_token $OCR_LLM_AUTH_TOKEN
|
|
@@ -35,13 +45,14 @@ code-review:
|
|
|
35
45
|
ocr config set llm.use_anthropic false
|
|
36
46
|
ocr config set llm.extra_body '{"thinking": {"type": "disabled"}}'
|
|
37
47
|
|
|
38
|
-
# Run OCR review
|
|
48
|
+
# Run OCR review (use CI_COMMIT_SHA for --to to support both same-repo and forked MRs)
|
|
39
49
|
- |
|
|
40
50
|
echo "Reviewing MR: ${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME} against ${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}"
|
|
41
51
|
ocr review \
|
|
42
52
|
--from "origin/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}" \
|
|
43
|
-
--to "
|
|
53
|
+
--to "${CI_COMMIT_SHA}" \
|
|
44
54
|
--format json \
|
|
55
|
+
--audience agent \
|
|
45
56
|
> /tmp/ocr-result.json 2>/tmp/ocr-stderr.log || true
|
|
46
57
|
echo "OCR review completed."
|
|
47
58
|
cat /tmp/ocr-result.json
|
|
@@ -58,18 +69,27 @@ code-review:
|
|
|
58
69
|
GITLAB_URL = os.environ.get("CI_SERVER_URL", "https://gitlab.com")
|
|
59
70
|
PROJECT_ID = os.environ["CI_PROJECT_ID"]
|
|
60
71
|
MR_IID = os.environ["CI_MERGE_REQUEST_IID"]
|
|
61
|
-
|
|
72
|
+
# Fall back to CI_JOB_TOKEN for fork MR pipelines where GITLAB_API_TOKEN is unavailable
|
|
73
|
+
API_TOKEN = os.environ.get("GITLAB_API_TOKEN") or os.environ.get("CI_JOB_TOKEN", "")
|
|
62
74
|
SOURCE_BRANCH = os.environ["CI_MERGE_REQUEST_SOURCE_BRANCH_NAME"]
|
|
63
75
|
TARGET_BRANCH = os.environ["CI_MERGE_REQUEST_TARGET_BRANCH_NAME"]
|
|
64
76
|
COMMIT_SHA = os.environ["CI_COMMIT_SHA"]
|
|
65
77
|
|
|
78
|
+
if not API_TOKEN:
|
|
79
|
+
print("ERROR: No API token available (GITLAB_API_TOKEN or CI_JOB_TOKEN). Cannot post comments.", file=sys.stderr)
|
|
80
|
+
sys.exit(1)
|
|
81
|
+
|
|
66
82
|
API_BASE = f"{GITLAB_URL}/api/v4/projects/{PROJECT_ID}/merge_requests/{MR_IID}"
|
|
67
83
|
|
|
84
|
+
# Determine auth header: PRIVATE-TOKEN for personal/project tokens, JOB-TOKEN for CI_JOB_TOKEN
|
|
85
|
+
USE_JOB_TOKEN = not os.environ.get("GITLAB_API_TOKEN")
|
|
86
|
+
AUTH_HEADER = "JOB-TOKEN" if USE_JOB_TOKEN else "PRIVATE-TOKEN"
|
|
87
|
+
|
|
68
88
|
def api_request(endpoint, data=None, method="POST"):
|
|
69
89
|
"""Make a GitLab API request."""
|
|
70
90
|
url = f"{API_BASE}{endpoint}"
|
|
71
91
|
headers = {
|
|
72
|
-
|
|
92
|
+
AUTH_HEADER: API_TOKEN,
|
|
73
93
|
"Content-Type": "application/json"
|
|
74
94
|
}
|
|
75
95
|
body = json.dumps(data).encode("utf-8") if data else None
|
|
@@ -85,16 +105,16 @@ code-review:
|
|
|
85
105
|
"""Post a general note/comment on the MR."""
|
|
86
106
|
return api_request("/notes", {"body": body})
|
|
87
107
|
|
|
88
|
-
def post_discussion(path, line, body, base_sha
|
|
108
|
+
def post_discussion(path, line, body, base_sha, start_sha, head_sha):
|
|
89
109
|
"""Post an inline discussion on a specific file/line in the MR diff."""
|
|
90
110
|
position = {
|
|
91
111
|
"position_type": "text",
|
|
92
112
|
"new_path": path,
|
|
93
113
|
"old_path": path,
|
|
94
114
|
"new_line": line,
|
|
95
|
-
"base_sha": base_sha
|
|
96
|
-
"start_sha": start_sha
|
|
97
|
-
"head_sha": head_sha
|
|
115
|
+
"base_sha": base_sha,
|
|
116
|
+
"start_sha": start_sha,
|
|
117
|
+
"head_sha": head_sha,
|
|
98
118
|
}
|
|
99
119
|
data = {
|
|
100
120
|
"body": body,
|
|
@@ -138,7 +158,7 @@ code-review:
|
|
|
138
158
|
|
|
139
159
|
# --- Main ---
|
|
140
160
|
|
|
141
|
-
# Read OCR result
|
|
161
|
+
# Read OCR result (skip first line which is summary, not JSON)
|
|
142
162
|
try:
|
|
143
163
|
with open("/tmp/ocr-result.json", "r") as f:
|
|
144
164
|
result = json.load(f)
|
|
@@ -168,7 +188,7 @@ code-review:
|
|
|
168
188
|
diff_refs = None
|
|
169
189
|
try:
|
|
170
190
|
versions_url = f"{API_BASE}/versions"
|
|
171
|
-
req = urllib.request.Request(versions_url, headers={
|
|
191
|
+
req = urllib.request.Request(versions_url, headers={AUTH_HEADER: API_TOKEN})
|
|
172
192
|
with urllib.request.urlopen(req) as resp:
|
|
173
193
|
versions = json.loads(resp.read().decode("utf-8"))
|
|
174
194
|
if versions:
|
|
@@ -191,15 +211,11 @@ code-review:
|
|
|
191
211
|
start_line = comment.get("start_line", end_line)
|
|
192
212
|
body = format_comment(comment)
|
|
193
213
|
|
|
194
|
-
if not path or not end_line:
|
|
214
|
+
if not path or not end_line or not diff_refs:
|
|
195
215
|
failed_comments.append(comment)
|
|
196
216
|
continue
|
|
197
217
|
|
|
198
|
-
|
|
199
|
-
if diff_refs:
|
|
200
|
-
kwargs = diff_refs
|
|
201
|
-
|
|
202
|
-
result_resp = post_discussion(path, end_line, body, **kwargs)
|
|
218
|
+
result_resp = post_discussion(path, end_line, body, **diff_refs)
|
|
203
219
|
if result_resp:
|
|
204
220
|
success_count += 1
|
|
205
221
|
else:
|
|
@@ -214,8 +230,13 @@ code-review:
|
|
|
214
230
|
fallback_body += format_comment_fallback(comment) + "\n\n---\n\n"
|
|
215
231
|
post_note(fallback_body)
|
|
216
232
|
|
|
217
|
-
# Post summary
|
|
218
|
-
|
|
233
|
+
# Post summary last
|
|
234
|
+
total_count = len(comments)
|
|
235
|
+
failed_count = len(failed_comments)
|
|
236
|
+
summary = f"🔍 **OpenCodeReview** found **{total_count}** issue(s) in this MR."
|
|
237
|
+
if total_count > 0:
|
|
238
|
+
summary += f"\n- ✅ {success_count} posted as inline comment(s)"
|
|
239
|
+
summary += f"\n- 📝 {failed_count} posted as summary (missing line info)"
|
|
219
240
|
if warnings:
|
|
220
241
|
summary += f"\n\n⚠️ {len(warnings)} warning(s) occurred during review."
|
|
221
242
|
post_note(summary)
|
|
@@ -10,7 +10,7 @@ MR Created/Updated → GitLab Pipeline Triggered → OCR Reviews Diff → Discus
|
|
|
10
10
|
|
|
11
11
|
1. When a Merge Request is opened or updated, the pipeline triggers
|
|
12
12
|
2. It installs OCR via npm in a `node:20` Docker image
|
|
13
|
-
3. Runs `ocr review --from origin/<target> --to
|
|
13
|
+
3. Runs `ocr review --from origin/<target> --to <commit_sha> --format json --audience agent` to analyze the diff (uses commit SHA to support fork MRs)
|
|
14
14
|
4. Parses the JSON output and posts inline discussions on the MR using GitLab's Discussions API
|
|
15
15
|
|
|
16
16
|
## Setup
|
|
@@ -39,7 +39,7 @@ Go to your project's **Settings → CI/CD → Variables** and add:
|
|
|
39
39
|
| `OCR_LLM_URL` | Yes | No | LLM API endpoint URL (e.g., `https://api.openai.com/v1/chat/completions`) |
|
|
40
40
|
| `OCR_LLM_AUTH_TOKEN` | Yes | Yes | API authentication token |
|
|
41
41
|
| `OCR_LLM_MODEL` | No | No | Model name (defaults to `gpt-4o`) |
|
|
42
|
-
| `GITLAB_API_TOKEN` |
|
|
42
|
+
| `GITLAB_API_TOKEN` | No | Yes | GitLab access token with `api` scope (falls back to `CI_JOB_TOKEN` if not set) |
|
|
43
43
|
|
|
44
44
|
> **Note:** GitLab CI/CD does not support variables with values shorter than 8 characters, so `use_anthropic` cannot be set as a CI variable. The pipeline sets it to `false` by default. If you need to use Anthropic Claude models, you'll need to modify the `.gitlab-ci.yml` script directly.
|
|
45
45
|
>
|
|
@@ -53,7 +53,7 @@ You need a token with `api` scope to post discussions on MRs. Options:
|
|
|
53
53
|
- **Personal Access Token**: User Settings → Access Tokens → Create with `api` scope
|
|
54
54
|
- **Group Access Token**: For organization-wide usage
|
|
55
55
|
|
|
56
|
-
> **Note:** The built-in `CI_JOB_TOKEN`
|
|
56
|
+
> **Note:** The built-in `CI_JOB_TOKEN` has limited API scope and may not support all discussion features (e.g., creating new threads on older GitLab versions). If `GITLAB_API_TOKEN` is not set, the pipeline falls back to `CI_JOB_TOKEN` automatically — but for best results, a dedicated token with `api` scope is recommended.
|
|
57
57
|
>
|
|
58
58
|
> **Tip:** For Project Access Tokens and Group Access Tokens, the token name determines the bot name shown in MR discussions. For example, naming your token `OpenCodeReview Bot` will make review comments appear as posted by `OpenCodeReview Bot`.
|
|
59
59
|
|
|
@@ -95,7 +95,7 @@ Use the `--rule` flag to pass a custom rules JSON file:
|
|
|
95
95
|
|
|
96
96
|
```yaml
|
|
97
97
|
script:
|
|
98
|
-
- ocr review --rule ./my-rules.json --from origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME --to
|
|
98
|
+
- ocr review --rule ./my-rules.json --from origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME --to $CI_COMMIT_SHA
|
|
99
99
|
```
|
|
100
100
|
|
|
101
101
|
### Limit concurrency
|
|
@@ -104,7 +104,7 @@ Adjust the `--concurrency` flag for large MRs to control the number of concurren
|
|
|
104
104
|
|
|
105
105
|
```yaml
|
|
106
106
|
script:
|
|
107
|
-
- ocr review --concurrency 5 --from origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME --to
|
|
107
|
+
- ocr review --concurrency 5 --from origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME --to $CI_COMMIT_SHA
|
|
108
108
|
```
|
|
109
109
|
|
|
110
110
|
### Provide background context
|
|
@@ -113,7 +113,7 @@ Use the `--background` flag to pass additional context that helps OCR better und
|
|
|
113
113
|
|
|
114
114
|
```yaml
|
|
115
115
|
script:
|
|
116
|
-
- ocr review --background "$CI_MERGE_REQUEST_TITLE" --from origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME --to
|
|
116
|
+
- ocr review --background "$CI_MERGE_REQUEST_TITLE" --from origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME --to $CI_COMMIT_SHA
|
|
117
117
|
```
|
|
118
118
|
|
|
119
119
|
This is particularly useful when your MR titles follow semantic conventions (e.g., `feat(auth): add OAuth2 support`) that clearly summarize what the MR implements. The background information helps OCR provide more relevant and context-aware review comments.
|
|
@@ -168,11 +168,13 @@ script:
|
|
|
168
168
|
|
|
169
169
|
# No existing review found - run OCR
|
|
170
170
|
print("🔍 No existing OCR review found. Running review...")
|
|
171
|
+
COMMIT_SHA = os.environ["CI_COMMIT_SHA"]
|
|
171
172
|
result = subprocess.run([
|
|
172
173
|
"ocr", "review",
|
|
173
174
|
"--from", f"origin/{TARGET_BRANCH}",
|
|
174
|
-
"--to",
|
|
175
|
-
"--format", "json"
|
|
175
|
+
"--to", COMMIT_SHA,
|
|
176
|
+
"--format", "json",
|
|
177
|
+
"--audience", "agent"
|
|
176
178
|
], capture_output=True, text=True)
|
|
177
179
|
|
|
178
180
|
# Save output for the posting script
|
package/package.json
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "open-code-review",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Use Alibaba Open Code Review from local Codex.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Alibaba"
|
|
7
|
+
},
|
|
8
|
+
"homepage": "https://github.com/alibaba/open-code-review",
|
|
9
|
+
"repository": "https://github.com/alibaba/open-code-review",
|
|
10
|
+
"license": "Apache-2.0",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"code-review",
|
|
13
|
+
"codex",
|
|
14
|
+
"ocr",
|
|
15
|
+
"open-code-review"
|
|
16
|
+
],
|
|
17
|
+
"skills": "./skills/",
|
|
18
|
+
"interface": {
|
|
19
|
+
"displayName": "Open Code Review",
|
|
20
|
+
"shortDescription": "Run structured code reviews from local Codex.",
|
|
21
|
+
"longDescription": "Adds a Codex skill that invokes the local Open Code Review CLI to review Git workspace changes, commits, and branch comparisons.",
|
|
22
|
+
"developerName": "Alibaba",
|
|
23
|
+
"category": "Developer Tools",
|
|
24
|
+
"capabilities": [
|
|
25
|
+
"Read"
|
|
26
|
+
],
|
|
27
|
+
"websiteURL": "https://github.com/alibaba/open-code-review",
|
|
28
|
+
"defaultPrompt": [
|
|
29
|
+
"Use Open Code Review to review my current changes.",
|
|
30
|
+
"Use Open Code Review to review this branch against main.",
|
|
31
|
+
"Use Open Code Review to review and fix high-confidence issues."
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Open Code Review Codex 플러그인 사용법
|
|
2
|
+
|
|
3
|
+
이 문서는 로컬 Codex에서 Alibaba Open Code Review를 사용하는 방법을 설명합니다.
|
|
4
|
+
|
|
5
|
+
## 개요
|
|
6
|
+
|
|
7
|
+
이 플러그인은 Open Code Review를 Codex 내부 LLM backend로 바꾸지 않습니다. Codex에서 로컬 `ocr` CLI를 호출할 수 있도록 skill을 제공하는 통합입니다.
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
Codex
|
|
11
|
+
└─ Open Code Review plugin
|
|
12
|
+
└─ ocr review --audience agent
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## 사전 준비
|
|
16
|
+
|
|
17
|
+
`ocr` CLI가 설치되어 있어야 합니다.
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g @alibaba-group/open-code-review
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
설치 확인:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
command -v ocr
|
|
27
|
+
ocr version
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
OCR 자체의 LLM 설정도 필요합니다.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
ocr llm test
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
이 명령이 실패하면 Codex 플러그인 설치와 별개로 OCR의 LLM 설정을 먼저 완료해야 합니다.
|
|
37
|
+
|
|
38
|
+
## Codex에서 설치
|
|
39
|
+
|
|
40
|
+
Codex에서 이 repo를 marketplace로 추가합니다.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
codex plugin marketplace add alibaba/open-code-review
|
|
44
|
+
codex
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Codex 안에서 `/plugins`를 열고 `Open Code Review`를 설치 및 활성화합니다.
|
|
48
|
+
|
|
49
|
+
로컬 checkout 또는 fork에서 테스트할 때는 다음을 사용할 수 있습니다.
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
codex plugin marketplace add .
|
|
53
|
+
codex
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 사용 예시
|
|
57
|
+
|
|
58
|
+
새 Codex thread에서 다음처럼 요청합니다.
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
@Open Code Review review my current changes
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
브랜치 비교:
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
@Open Code Review review this branch against main
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
검토 후 안전한 항목만 수정:
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
@Open Code Review review and fix high-confidence issues
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 내부적으로 실행되는 명령
|
|
77
|
+
|
|
78
|
+
현재 workspace 변경사항 검토:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
ocr review --audience agent
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
특정 commit 검토:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
ocr review --audience agent --commit <sha>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
브랜치 비교:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
ocr review --audience agent --from <base-ref> --to <head-ref>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
미리보기:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
ocr review --preview
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## 주의사항
|
|
103
|
+
|
|
104
|
+
- 이 플러그인은 OpenAI Responses API endpoint를 설정하지 않습니다.
|
|
105
|
+
- 이 플러그인은 `OPENAI_API_KEY`나 `gpt-5.1-codex-max` 설정을 요구하지 않습니다.
|
|
106
|
+
- OCR 자체는 별도의 LLM 설정이 필요합니다.
|
|
107
|
+
- 파일 수정은 사용자가 명시적으로 요청한 경우에만 수행합니다.
|
|
108
|
+
- commit 생성은 사용자가 명시적으로 요청한 경우에만 수행합니다.
|