Skip to content

docs(examples): add GitFlic CI auto-review example#201

Open
revenant20 wants to merge 3 commits into
alibaba:mainfrom
revenant20:feat/gitflic-ci-example
Open

docs(examples): add GitFlic CI auto-review example#201
revenant20 wants to merge 3 commits into
alibaba:mainfrom
revenant20:feat/gitflic-ci-example

Conversation

@revenant20

Copy link
Copy Markdown
Contributor

This adds a GitFlic CI integration example under examples/gitflic_ci/, reworking #138 in line with the feedback there: the platform-specific publishing glue lives in the CI layer rather than in the ocr binary, consistent with the GitHub and GitLab examples. Implements #102; supersedes #138.

The posting glue is a small, dependency-free post_review.py (standard library only): it reads ocr review --format json and posts the findings onto the merge request as inline discussions, a fallback note, and a summary. GitFlic's Discussions API requires an old-side line even for a comment on the new side of the diff — which the new-side-only review output doesn't carry — so the script recomputes it from the same merge-base diff the review ran on (git diff merge-base(from, to)..to), anchoring added lines to the closest preceding old line.

It ships with post_review_test.py, a standard-library unittest suite (no network, git, or Go toolchain) whose line-mapping cases are ported from the original Go tests, so the example stays verifiable. I've also run it end-to-end against a live GitFlic CE instance to confirm the inline positions render correctly via the API.

cc @lizhengfeng101 — thanks again for the thoughtful review on #138; happy to keep iterating here or in #102.

Add examples/gitflic_ci/, a CI-layer integration that reviews GitFlic
merge requests with OpenCodeReview and posts the findings as MR
discussions. Like the GitHub and GitLab examples, the posting glue lives
outside the core binary.

post_review.py (standard library only) reads `ocr review --format json`
and posts inline discussions plus a fallback note and a summary. GitFlic's
Discussions API requires an old-side line for inline comments, which the
new-side-only review output lacks, so the script recomputes it from the
same merge-base diff the review ran on. Ships with a stdlib unittest suite
whose line-mapping cases are ported from the review's diff logic.
@github-actions

Copy link
Copy Markdown
Contributor

OpenCodeReview: No comments generated. Looks good to me.

@lizhengfeng101 lizhengfeng101 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感谢 @revenant20 的高质量贡献!这个 PR 完全遵循了 #138 评审中的架构方向,将平台特定的发布逻辑放在 CI 层而非核心二进制中。代码结构清晰、测试覆盖充分、文档详尽,--dry-run 调试支持也很实用。

以下是一些小的改进建议,整体上这是一个很棒的贡献。

Comment thread examples/gitflic_ci/gitflic-ci.yaml Outdated
- |
ocr config set llm.url $OCR_LLM_URL
ocr config set llm.auth_token $OCR_LLM_AUTH_TOKEN
ocr config set llm.model $OCR_LLM_MODEL

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: OCR_LLM_MODEL 在 README 中标注为 Optional,但这里无条件执行。当该变量未设置时,$OCR_LLM_MODEL 展开为空字符串,ocr config set llm.model "" 会写入空模型,可能导致后续 endpoint 解析失败。

(这个问题在 #138 的评审中也被提出过。)

建议加一个条件判断:

    - |
      ocr config set llm.url $OCR_LLM_URL
      ocr config set llm.auth_token $OCR_LLM_AUTH_TOKEN
      if [ -n "$OCR_LLM_MODEL" ]; then
        ocr config set llm.model "$OCR_LLM_MODEL"
      fi
      ocr config set llm.use_anthropic false
      ocr config set llm.extra_body '{"thinking": {"type": "disabled"}}'

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 1dc279b — wrapped the model write in if [ -n "$OCR_LLM_MODEL" ] so an unset (optional) variable no longer writes an empty model.

Comment thread examples/gitflic_ci/post_review.py Outdated

def load_review_result(path):
"""Read the JSON produced by `ocr review --format json` (path '-' = stdin)."""
data = sys.stdin.read() if path == "-" else open(path, encoding="utf-8").read()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: 文件句柄未显式关闭。虽然 CPython 引用计数会立即回收,但在其他 Python 实现中可能泄漏。

建议改为:

if path == "-":
    data = sys.stdin.read()
else:
    with open(path, encoding="utf-8") as f:
        data = f.read()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 1dc279b — switched to a with open(...) block so the handle is closed explicitly.

--to "${CI_COMMIT_SHA}" \
--format json \
--audience agent \
> /tmp/ocr-result.json || true

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: || true 意味着即使 ocr review 完全失败(如 token 无效),pipeline 仍会继续执行 post_review.py,此时 JSON 文件可能为空或包含非法内容。

建议在之后加一个空文件检查:

    - |
      if [ ! -s /tmp/ocr-result.json ]; then
        echo "OCR review produced no output, skipping post."
        exit 0
      fi

或者如果这是有意为之(让 post_review.py 自行处理错误),可以在注释中说明意图。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 1dc279b — added if [ ! -s /tmp/ocr-result.json ] to skip posting on empty output, plus a comment explaining that the || true step can leave an empty/partial file.

with urllib.request.urlopen(req) as resp:
resp.read()
except urllib.error.HTTPError as e:
snippet = e.read(512).decode("utf-8", "replace").strip()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: 某些 API 在错误响应体中可能回显请求信息。如果 GitFlic 在 4xx/5xx 响应中包含了请求头片段,这里的 snippet 可能会将 token 泄漏到 CI 日志中。风险不高,但可以考虑对 snippet 做一下长度截断或脱敏。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 1dc279b — the token is now redacted from the snippet (snippet.replace(token, "***")) before it goes into the error message, so it can't reach the CI log.

Comment thread examples/README.md
- **[github_actions/](./github_actions/)** - GitHub Actions integration example
- **[gitlab_ci/](./gitlab_ci/)** - GitLab CI integration example
- **[gitflic_ci/](./gitflic_ci/)** - GitFlic CI integration example

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: 这个文件缺少末尾换行符(No newline at end of file)。既然本次已修改了此文件,可以顺便修复。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 1dc279b — added the trailing newline.

Apply the five review comments left on the PR:
- gitflic-ci.yaml: guard `ocr config set llm.model` behind a non-empty
  check so the documented-optional OCR_LLM_MODEL no longer breaks the
  config step when it is unset
- gitflic-ci.yaml: skip posting when `ocr review` produced no output
  (the step ends with `|| true`) instead of feeding empty/partial JSON
  to post_review.py
- post_review.py: redact the token from HTTP error snippets so it cannot
  leak into CI logs if GitFlic echoes the request back in an error body
- post_review.py: read the review-result file via a `with` block so the
  handle is closed explicitly
- examples/README.md: add the missing trailing newline
@revenant20

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough and kind review, @lizhengfeng101! All five comments are addressed in 1dc279b:

  1. gitflic-ci.yamlocr config set llm.model is now guarded behind a non-empty check, so the documented-optional OCR_LLM_MODEL no longer writes an empty model when unset (the same issue raised in feat(publish): add ocr publish gitflic to post reviews to GitFlic MRs #138).
  2. gitflic-ci.yaml — added an empty-file check after the || true review step; if ocr review produced no output we log and skip posting instead of feeding invalid JSON to post_review.py, with a comment explaining the intent.
  3. post_review.py — the token is now redacted from HTTP error snippets so it can't leak into CI logs if GitFlic echoes request details back in an error body.
  4. post_review.py — the review-result file is read via a with block so the handle is closed explicitly.
  5. examples/README.md — added the missing trailing newline.

Ready for another look whenever you have time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants