@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/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
- > - 如果路由的是 **CodeX** 供应商:设置 `llm.url` 为 `http://127.0.0.1:15721/v1`
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, synchronized, or reopened, the workflow triggers
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 origin/<head> --format json` to analyze the diff
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.pull_request.types` array in the workflow file:
49
+ Modify the `on.pull_request_target.types` array in the workflow file:
50
50
 
51
51
  ```yaml
52
52
  on:
53
- pull_request:
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 == 'pull_request' ||
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 == 'pull_request' ||
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, synchronized, or reopened
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 == 'pull_request' ||
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 != 'pull_request'
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.event_name != 'pull_request' && steps.pr-context.outputs.head_sha || '' }}
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 refs from PR context (different for comment triggers)
83
- if [ "${{ github.event_name }}" = "pull_request" ]; then
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
- HEAD_REF="${{ github.event.pull_request.head.ref }}"
97
+ HEAD_SHA="${{ github.event.pull_request.head.sha }}"
86
98
  else
87
99
  BASE_REF="${{ steps.pr-context.outputs.base_ref }}"
88
- HEAD_REF="${{ steps.pr-context.outputs.head_ref }}"
100
+ HEAD_SHA="${{ steps.pr-context.outputs.head_sha }}"
89
101
  fi
90
102
 
91
- echo "Reviewing PR: ${HEAD_REF} against ${BASE_REF}"
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 "origin/${HEAD_REF}" \
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 === 'pull_request') {
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 setting variables with value length less than 8, so you can't set use_anthropic as a CI variable
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 "origin/${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" \
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
- API_TOKEN = os.environ["GITLAB_API_TOKEN"]
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
- "PRIVATE-TOKEN": API_TOKEN,
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=None, start_sha=None, head_sha=None):
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 or TARGET_BRANCH,
96
- "start_sha": start_sha or TARGET_BRANCH,
97
- "head_sha": head_sha or COMMIT_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={"PRIVATE-TOKEN": API_TOKEN})
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
- kwargs = {}
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
- summary = f"🔍 **OpenCodeReview** found **{len(comments)}** issue(s) in this MR."
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 origin/<source> --format json` to analyze the diff
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` | Yes | Yes | GitLab access token with `api` scope |
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` does NOT have sufficient permissions to create MR discussions, which is why a separate token is needed.
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 origin/$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
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 origin/$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
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 origin/$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
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", f"origin/{SOURCE_BRANCH}",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alibaba-group/open-code-review",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
4
4
  "description": "OpenCodeReview CLI — AI-powered code review tool",
5
5
  "bin": {
6
6
  "ocr": "bin/ocr.js"
@@ -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 생성은 사용자가 명시적으로 요청한 경우에만 수행합니다.