Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.ja-JP.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ ocr review \

- [`github_actions/`](./examples/github_actions/) — GitHub Actions統合の例
- [`gitlab_ci/`](./examples/gitlab_ci/) — GitLab CI統合の例
- [`gitflic_ci/`](./examples/gitflic_ci/) — GitFlic CI統合の例

## コマンド

Expand Down
1 change: 1 addition & 0 deletions README.ko-KR.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ ocr review \

- [`github_actions/`](./examples/github_actions/): GitHub Actions 통합 예시
- [`gitlab_ci/`](./examples/gitlab_ci/): GitLab CI 통합 예시
- [`gitflic_ci/`](./examples/gitflic_ci/): GitFlic CI 통합 예시

## Commands

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ See the [`examples/`](./examples/) directory for integration examples:

- [`github_actions/`](./examples/github_actions/) — GitHub Actions integration example
- [`gitlab_ci/`](./examples/gitlab_ci/) — GitLab CI integration example
- [`gitflic_ci/`](./examples/gitflic_ci/) — GitFlic CI integration example

## Commands

Expand Down
1 change: 1 addition & 0 deletions README.ru-RU.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ ocr review \

- [`github_actions/`](./examples/github_actions/) — пример интеграции с GitHub Actions
- [`gitlab_ci/`](./examples/gitlab_ci/) — пример интеграции с GitLab CI
- [`gitflic_ci/`](./examples/gitflic_ci/) — пример интеграции с GitFlic CI

## Команды

Expand Down
1 change: 1 addition & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ ocr review \

- [`github_actions/`](./examples/github_actions/) — GitHub Actions 集成示例
- [`gitlab_ci/`](./examples/gitlab_ci/) — GitLab CI 集成示例
- [`gitflic_ci/`](./examples/gitflic_ci/) — GitFlic CI 集成示例

## 命令

Expand Down
3 changes: 2 additions & 1 deletion examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ This directory contains examples for integrating OpenCodeReview (OCR) into vario

- **[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.

Each subdirectory contains its own README with detailed setup instructions.
Each subdirectory contains its own README with detailed setup instructions.
80 changes: 80 additions & 0 deletions examples/gitflic_ci/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# OpenCodeReview - GitFlic CI Demo

This demo shows how to integrate OpenCodeReview into a [GitFlic](https://gitflic.ru) CI/CD pipeline to automatically review Merge Requests and post the findings as MR discussions — inline on the changed lines where possible.

Like the GitHub Actions and GitLab CI examples, the posting glue lives in the CI layer rather than in the `ocr` binary. Here it is a small, dependency-free Python script — [`post_review.py`](post_review.py) — that reads `ocr review --format json` and posts to the GitFlic Discussions API. The only GitFlic-specific wrinkle it handles is the **old-side line**: GitFlic requires it even for a comment on the new side of the diff, and `ocr review` reports new-side positions only, so the script recomputes it from the same merge-base diff the review ran on.

## How It Works

```
MR Created/Updated → Merge Request Pipeline → ocr review → post_review.py → Discussions on MR
```

1. A Merge Request Pipeline triggers the `code-review` job
2. It installs OCR via npm in a `node:20` image (which also ships `python3` and `git`)
3. Runs `ocr review --from origin/<target> --to $CI_COMMIT_SHA --format json --audience agent`
4. Runs `python3 post_review.py`, which reads the JSON and posts:
- **Inline discussions** on the changed lines (`POST .../discussions/create` with `newLine`/`oldLine`/`newPath`/`oldPath`)
- **A fallback note** collecting comments that could not be placed inline
- **A summary note** with the totals

The MR context (owner, project, MR id, branch refs) is picked up automatically from the predefined GitFlic CI variables (`CI_PROJECT_NAMESPACE`, `CI_PROJECT_NAME`, `CI_MERGE_REQUEST_LOCAL_ID`, `CI_MERGE_REQUEST_TARGET_BRANCH_NAME`, `CI_COMMIT_SHA`), so `post_review.py` needs no arguments in CI. Outside CI every value can be passed via flags — run `python3 post_review.py -h`.

## Setup

### 1. Enable Merge Request Pipelines

Go to **Project Settings → CI/CD Settings** and enable **Merge Request Pipeline**. New merge requests will then trigger the pipeline automatically.

### 2. Copy the pipeline files

Copy **both** `gitflic-ci.yaml` (GitFlic expects this exact file name at the repository root) and `post_review.py` into your repository. If you keep `post_review.py` somewhere other than the repo root, adjust the `python3 post_review.py` path in `gitflic-ci.yaml` accordingly.

### 3. Configure CI/CD Variables

Go to **Settings → CI/CD → Variables** and add:

| Variable | Required | Description |
|----------|----------|-------------|
| `OCR_LLM_URL` | Yes | LLM API endpoint URL |
| `OCR_LLM_AUTH_TOKEN` | Yes | LLM API authentication token |
| `GITFLIC_TOKEN` | Yes | GitFlic access token used to post discussions |
| `OCR_LLM_MODEL` | No | Model name (e.g., `gpt-4o`) |
| `GITFLIC_API_URL` | No | REST API base URL for self-hosted GitFlic (default: `https://api.gitflic.ru`) |

> **Note:** GitFlic CI/CD does not accept variables with values shorter than 8 characters, so `use_anthropic` cannot be set as a CI variable. The pipeline sets it to `false`; to use Anthropic Claude models, edit `gitflic-ci.yaml` directly.

### 4. Create a GitFlic Access Token

Create a token in **User Settings → Access Tokens** (or a dedicated service account — its name becomes the bot name shown in discussions) and store it in the `GITFLIC_TOKEN` variable. The token owner must have access to the project sufficient for commenting on merge requests.

## Notes & Limitations

- **Inline positioning** — GitFlic requires all four of `newLine`/`oldLine`/`newPath`/`oldPath` for a code comment; if any is missing it silently creates a general comment. `post_review.py` computes the old-side position from the same merge-base diff the review ran on (`git diff merge-base(from, to)..to`), and anchors added lines to the closest preceding old line.
- **Rate limit** — the GitFlic cloud API allows 500 requests/hour per token. One review posts `comments + 2` requests at most, which fits comfortably.
- **Self-hosted GitFlic** — set `GITFLIC_API_URL` to your instance's REST API base URL.
- **Re-reviews** — every push to the MR triggers a new pipeline and a new review. To skip already-reviewed MRs, check existing discussions for the `OpenCodeReview` marker before running the review step.

## Tests

`post_review.py` ships with [`post_review_test.py`](post_review_test.py) — standard-library `unittest`, no network or git required:

```bash
cd examples/gitflic_ci
python3 post_review_test.py
```

The line-mapping cases are ported from the upstream Go tests so the script keeps proven parity with the binary.

## Debugging

Test the posting step locally without touching the MR:

```bash
ocr review --from origin/main --to HEAD --format json > /tmp/r.json
python3 post_review.py /tmp/r.json \
--owner <owner> --project <project> --mr <id> \
--from origin/main --to HEAD --dry-run
```

`--dry-run` prints every discussion (with the computed positions) instead of posting, and does not require `GITFLIC_TOKEN`.
84 changes: 84 additions & 0 deletions examples/gitflic_ci/gitflic-ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# OpenCodeReview - GitFlic CI Merge Request Auto-Review Demo
#
# Reviews Merge Requests with OpenCodeReview and posts the findings onto the
# MR as discussions (inline where possible). The posting glue lives in the CI
# layer, in post_review.py next to this file -- consistent with the GitHub and
# GitLab examples, which keep platform-specific publishing out of the `ocr`
# binary.
#
# Setup:
# - Commit BOTH this file and post_review.py into your repository (adjust the
# `python3 post_review.py` path below if you place the script elsewhere).
# - Enable "Merge Request Pipeline" in Project Settings -> CI/CD Settings.
# - Use a runner able to run the node:20 image (it ships node, python3 and git),
# or any shell runner with node 20+, python3 and git available.
#
# Required CI/CD Variables (Settings -> CI/CD -> Variables):
# OCR_LLM_URL - LLM API endpoint (e.g., https://api.openai.com/v1/chat/completions)
# OCR_LLM_AUTH_TOKEN - Authentication token for the LLM API
# GITFLIC_TOKEN - GitFlic access token used to post MR discussions
#
# Optional CI/CD Variables:
# OCR_LLM_MODEL - Model name (e.g., gpt-4o)
# GITFLIC_API_URL - GitFlic REST API base URL; only needed for self-hosted
# instances (defaults to https://api.gitflic.ru)
#
# post_review.py picks up the MR context automatically from the predefined
# GitFlic CI variables: CI_PROJECT_NAMESPACE, CI_PROJECT_NAME,
# CI_MERGE_REQUEST_LOCAL_ID, CI_MERGE_REQUEST_TARGET_BRANCH_NAME, CI_COMMIT_SHA.

stages:
- review

code-review:
stage: review
image: node:20
script:
# Run only in merge request pipelines
- |
if [ -z "$CI_MERGE_REQUEST_LOCAL_ID" ]; then
echo "Not a merge request pipeline, skipping review."
exit 0
fi

# Install OpenCodeReview
- npm install -g @alibaba-group/open-code-review

# Configure OCR
- |
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"}}'

# Make sure the target branch and full history are available for merge-base diff
- git fetch --unshallow 2>/dev/null || true
- git fetch origin "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME"

# Run OCR review (CI_COMMIT_SHA as head supports forked MRs as well)
- |
ocr review \
--from "origin/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}" \
--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.

echo "OCR review completed."

# Post review comments onto the MR (inline discussions + summary note).
# post_review.py recomputes the old-side line for each comment from the
# merge-base diff, which the GitFlic Discussions API requires for inline
# (code) comments.
#
# The review step above ends with `|| true`, so a failed `ocr review` (bad
# token, network error) leaves an empty or partial file. Skip posting in
# that case instead of feeding invalid JSON to post_review.py.
- |
if [ ! -s /tmp/ocr-result.json ]; then
echo "OCR review produced no output, skipping post."
exit 0
fi
python3 post_review.py /tmp/ocr-result.json
Loading
Loading