mirror of
https://github.com/alibaba/open-code-review.git
synced 2026-08-21 14:44:56 +00:00
* feat(gitlab-ci): align review posting with the GitHub Action behaviors
Port the production-hardening of scripts/github-actions/post-review-comments.js
into examples/gitlab_ci/post_review.py so the GitLab example matches the
GitHub Action's publication semantics.
Refactor the transport from a single post() callable into a Poster object
(GitLabPoster / DryRunPoster) exposing post_note / post_discussion / list_notes
/ update_note / list_discussions / get_mr_diffs, so reads (sticky upsert,
incremental history, idempotent reconciliation) and the 400-fallback diff
inventory can flow through it.
Pure-logic ports (Group A):
- category/severity badge [category · severity] on every inline discussion
and fallback entry (byte-matching the CLI's buildBadge)
- publication policy routing findings to the summary by severity
(OCR_ROUTE_SEVERITY_BELOW) and category (OCR_ROUTE_CATEGORIES), fail-open
on unknown metadata; routed findings never enter the inline write path
- deterministic sort (path -> start_line -> end_line -> index) before posting
- detailed warning rendering (file (type): message bullets)
- backtick-safe fenced code blocks in the fallback Before/After; inline
suggestion keeps the fixed suggestion:-0+0 fence so the Apply-suggestion
button keeps working
Read-API features (Group B):
- sticky summary (default ON): the summary note is updated in place across
runs via a <!-- ocr-summary --> marker (find-then-PUT), instead of
accumulating one note per run; a pre-review anchor pins it above the
discussions on the first run
- incremental mode (OCR_INCREMENTAL, default off): skip comments whose line
range overlaps a prior bot discussion on the same path, using IoU above
OCR_INCREMENTAL_OVERLAP_THRESHOLD (default 0.6); single-line vs multi-line
never match; bot discussions detected by the <!-- ocr- marker
- idempotent retry: each inline discussion carries an invisible
<!-- ocr-<pipeline>-<job>-<hex> --> id tag; on a 5xx/408/network failure
(maybe-reached-server) the script GETs /discussions and skips the retry
when the id is found (no duplicate); when the read API is unavailable it
skips the retry and surfaces the reason rather than risk a duplicate
C group (minus batched createReview):
- 400 line-resolution fallback: when a discussion POST returns 400 with a
position error, fetch GET /merge_requests/:iid/diffs, classify the comment
(valid/invalid/unknown), and drop provably-out-of-diff findings to the
summary instead of blindly retrying; unknown keeps the existing fallback
- wait-until-reset: when RateLimit-Remaining == 0, sleep until
RateLimit-Reset (defensively handling both epoch-seconds and
seconds-until-reset formats), ahead of Retry-After / backoff
D group (pipeline alignment):
- dotenv stats output (/tmp/ocr-stats.env) with OCR_COMMENTS_{TOTAL,INLINE,
SUMMARY,ROUTED,SKIPPED,FAILED} and OCR_SUMMARY_URL, exposed via a
reports: dotenv artifact
- artifacts (when: always, 1 week): /tmp/ocr-result.json and
/tmp/ocr-stderr.log so a failed review is still inspectable
- severity fail gating (OCR_FAIL_ON_SEVERITY): non-zero exit when a comment
severity is at/above the threshold; the summary note is still posted first
Tests: 57 -> 117 (stdlib unittest, no network, no wall-clock). New coverage
for badge/policy/sort/warnings/safe-fence, sticky upsert (cold start + reuse),
incremental IoU (single/multi/cross-type/read-failure), idempotent
reconciliation (posted/unavailable/not-posted/400-no-reconcile), 400
classification (valid/invalid/unknown/truncated patch), wait-until-reset
(seconds/epoch/non-zero-remaining), stats file, severity gating.
The only behavior change for existing users: the summary note now updates in
place by default (sticky_summary default true, matching the GitHub Action);
incremental/routing/gating default to off / no-op.
* fix(gitlab-ci): harden OCR_INCREMENTAL_OVERLAP_THRESHOLD parsing, drop dead regex
- build_config used a bare float() on OCR_INCREMENTAL_OVERLAP_THRESHOLD,
which raised an unhandled ValueError and crashed the script when a user
set a non-numeric value. Reuse resolve_threshold, which already handles
non-numeric / out-of-range values and falls back to the default.
- Remove the unused _COMMENT_ID_RE module-level regex; the idempotency
check in _is_comment_posted uses a plain substring match, so the regex
was dead code.
Tests: +2 covering non-numeric and out-of-range env values (117 -> 119).
* fix(gitlab-ci): strip control chars in route_comment, drop dead badge init
- route_comment read category/severity via str(...).strip().lower() without
stripping C0/C1 control characters, while build_badge uses sanitize_metadata
for the same fields. If the LLM emits embedded control chars (e.g. "bug\r"),
the badge rendered [bug · high] but routing classified it as "unknown" and
skipped policy routing. Reuse sanitize_metadata to stay consistent.
- format_comment_fallback had a duplicate md/badge initialization block
immediately overwritten by an identical block, a merge artifact. Removed
the redundant first block.
* fix(gitlab-ci): classify line_code 400s, match MR version to OCR-reviewed SHAs
- LINE_RESOLUTION_PATTERNS missed the `line_code` substring, so GitLab's
`:line_code=>["can't be blank", "must be a valid line code"]` 400 was never
classified as a line-resolution failure. The per-comment diff-inventory
fallback never fired, and the raw error JSON leaked into the summary note
as `⚠️ Could not be posted inline: {"message":"400 Bad request - Note ..."}`
instead of a friendly "out of diff" / "line resolution failure" reason. Add
`line_code` to the pattern list.
- fetch_diff_refs took `versions[0]` blindly. After a force-push or follow-up
commit, that version's head_commit_sha no longer matches the diff OCR
actually reviewed, so the position's base_sha/head_sha describe the wrong
diff and every inline position fails to resolve on GitLab's side — the root
cause of the line_code 400 above. Now read resolved_head/resolved_base from
the OCR result manifest and pick the matching MR version, falling back to
newest-by-created_at with a warning when no version matches.
- Migrate artifact paths /tmp -> .ocr (GitLab Runner refuses to upload
artifacts outside the build directory) and drop the now-redundant temporary
sticky-summary diagnostic block.
- Add 7 tests: line_code pattern positive, version matching by head /
head+base / no-match-fallback / no-expected-shas-sorts-newest, and
_extract_expected_shas with/without manifest.
* feat(gitlab-ci): close GitHub Action parity gaps (config, flags, exit gate, pacing, per-run summary)
Brings the GitLab CI example to feature parity with the GitHub Action
(action.yml + scripts/github-actions/post-review-comments.js).
- .gitlab-ci.yml: expose action.yml inputs as CI/CD variables.
- OCR_VERSION pins the npm spec (default latest) for reproducible reviews.
- Optional LLM config written via `ocr config set` only when the CI var is
non-empty (no clobbering): OCR_LANGUAGE, OCR_LLM_AUTH_HEADER,
OCR_LLM_EXTRA_HEADERS. OCR_LLM_TIMEOUT is read natively by OCR from env.
- Review flags threaded env→flag: OCR_REVIEW_CONCURRENCY, OCR_BACKGROUND,
OCR_RULE.
- OCR exit-code gate: drop `|| true`, capture OCR_EXIT_CODE, run
post_review.py unconditionally (so stderr still posts to MR), then exit
non-zero on OCR failure — mirrors the Action's "Fail job on OCR error".
- Document `llm.use_anthropic` as a hardcoded (not CI-configurable) value
under a separate "Not a CI/CD variable" header; the false listing as a
required CI var was misleading.
- post_review.py: posting-logic parity.
- Read-API pacing: `_read_with_pacing` wraps list_notes/list_discussions/
get_mr_diffs with read_success_delay (0.5s default) and
read_low_remaining_spacing (5s default) when RateLimit-Remaining is
at/below rate_limit_threshold — mirrors readWithPacing so a large MR
does not hammer the read API.
- Non-sticky per-run summary matching: `summary_tag_for(run_tag)` /
`wrap_summary_body` embed both SUMMARY_MARKER and a per-run
`<!-- ocr-summary-run:TAG -->`; find_summary_note/upsert_summary/
ensure_summary_anchor/finalize_summary take a `tag` param. The pre-review
anchor now runs in non-sticky mode too (was sticky-only), so non-sticky
shows the "⏳ Posting…" live state and finalize updates the same note
instead of creating a duplicate.
- build_config exposes read_success_delay / read_low_remaining_spacing.
- tests (+12, 142 total, 0.01s):
- ReadPacingTest: success-delay pacing, low-quota long spacing, no pacing
sleep on failed read.
- NonStickySummaryTest: cold-start anchor→update same note; same-run reuse;
different-run not reused.
- SummaryTagPureTest: tag format, wrap embeds both markers, newest-first
find by tag/marker, None on no match.
- BuildConfigTest: read-pacing defaults & overrides.
- Recorder.final_summary_body / summary_call_count helpers adapt existing
assertions to the two-phase anchor→finalize flow.
- MainAuthHeaderTest: mock urlopen with canned responses — was making real
DNS lookups to gitlab.example, amplified 3x by the new always-on anchor
(13.7s → 0.01s).
- README.md: document the 9 new CI vars in the variables table, add
read-pacing vars to the retry/delay table, convert the version/rules/
concurrency/background recipes from "edit the YAML" to "set this CI var".
* fix(gitlab-ci): if-guard optional vars, capture post_review exit code, split diff-refs reason
- Replace [ -n "$VAR" ] && cmd with if-guards so FF_ENABLE_BASH_EXIT_CODE_CHECK
cannot abort on an empty optional variable (|| true would mask real failures)
- Capture post_review.py exit code (POST_EXIT_CODE) so the OCR_EXIT_CODE gate
runs regardless of severity-gate or posting failures
- Split 'not path or not end_line or not diff_refs' into two checks so
diff-refs-unavailable comments get an accurate reason in the summary
* fix(gitlab-ci): default OCR/POST exit codes to guard against unset gate vars
Without a default, an unset OCR_EXIT_CODE/POST_EXIT_CODE makes the gate
`[ "" != "0" ]` evaluate true and `exit ""` fail with
'numeric argument required'. Default both to 0 so the gate is always safe.
|
||
|---|---|---|
| .. | ||
| bitbucket_pipelines | ||
| codeup_ci | ||
| gerrit_ci | ||
| gitflic_ci | ||
| github_actions | ||
| gitlab_ci | ||
| README.md | ||
CI/CD Integration Examples
This directory contains examples for integrating OpenCodeReview (OCR) into various CI/CD pipelines.
Contents
- github_actions/ - GitHub Actions integration example
- gitlab_ci/ - GitLab CI integration example
- bitbucket_pipelines/ - Bitbucket Pipelines integration example
- gitflic_ci/ - GitFlic CI integration example
- gerrit_ci/ - Gerrit (Jenkins / Gerrit Trigger) integration example
Each subdirectory contains its own README with detailed setup instructions.