Commit graph

9 commits

Author SHA1 Message Date
kite
980f21d6f2
chore: remove leftover Chinese from the Go core, CI examples and pages comments (#861)
* docs(comments): translate Chinese comments to English

Rewrite the remaining Chinese code comments outside the VSCode extension
in English, so the Go core and the pages site read consistently.

- allowed_ext.go: translate the default_exclude_patterns.json package doc.
  Quote the wildcards ("*", "**", "{a,b,c}") so gofmt stops reflowing the
  leading "*" as a markdown bullet, which had swallowed the first entry's
  wildcard and broken the list alignment in godoc.
- HighlightsSection.tsx: translate three comments in parseStatValue and
  CountUpValue.

* docs(examples): use "Chinese" instead of "中文" in OCR_LANGUAGE examples

The language config value is fed to the LLM, which understands "Chinese"
just as well, and "Chinese" is what the rest of the project already uses
(skills/open-code-review/SKILL.md, config_cmd_test.go, ApplyLanguage).
Keeps the GitLab CI example's inline docs fully English.

* fix(agent): drop the unreachable Chinese branch from planBlockPattern

task_template.json ships a single English template ("### Review Plan
(Optional)") and is embedded via go:embed with no override path, so the
"审查计划" alternative could never match anything. It came from the
pre-open-source template and survived the #33 fix as dead defensive code.

Drops the two test cases that only exercised that alternative.
2026-08-12 15:58:23 +08:00
Lei Zhang
84be9d0413
feat(examples/gitlab): align GitLab CI review posting with the GitHub Action (#767)
* 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.
2026-08-07 15:58:03 +08:00
Seonggwan Ahn
e75601d2e6
feat(examples/gitlab): add fail-open category/severity publication controls (#685)
* feat(examples/gitlab): add fail-open category/severity publication controls

Port the GitHub Action publication policy (#478/#529) to the GitLab CI
example so MRs can badge findings and optionally route low-signal
categories/severities to summary notes without dropping them.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(examples/gitlab): sanitize metadata in route_comment

Align routing with build_badge so control characters in LLM
category/severity values do not desync badge labels from policy matching.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-03 19:52:44 +08:00
侯雨希
e670b3b3f6
refactor(examples): extract GitLab CI heredoc into testable post_review.py with unit tests (#539)
Some checks are pending
CI / test (push) Waiting to run
CI / cross-compile (amd64, darwin) (push) Waiting to run
CI / cross-compile (amd64, windows) (push) Waiting to run
CI / cross-compile (arm64, darwin) (push) Waiting to run
CI / cross-compile (arm64, linux) (push) Waiting to run
CI / cross-compile (arm64, windows) (push) Waiting to run
* refactor(examples): extract GitLab CI heredoc into post_review.py with unit tests

Extracts the ~270-line inline heredoc from .gitlab-ci.yml into a standalone,
testable post_review.py module, matching the publish() + make_poster() pattern
established by gerrit_ci/ and gitflic_ci/.

Key design decisions (from spec issue #1 and wayfinder tickets #3, #4, #5):
- publish(result, diff_refs, post, config, sleep) — transport-agnostic
- make_poster(api_base, token, auth_header, config) — GitLab REST transport
- fetch_diff_refs(api_base, token, auth_header, config) — /versions GET with retry
- Single config dict built by main() from env vars; no module-level config state
- post() returns {success, rate_limit_remaining, is_rate_limit_exhausted}
  to preserve failure-pacing behavior (rate-limit vs non-rate-limit delays)
- _sleep = time.sleep module-level pattern for testability

All existing heredoc behavior preserved 1:1:
- GitLab suggestion:-0+0 syntax and <details> fallback format
- Retry on 429/403-rate-limit/5xx/408 with exponential backoff + ±25% jitter
- Retry-After header honoring, MAX_RETRY_DELAY cap
- Proactive RateLimit-Remaining throttling (success path only)
- Failure pacing: rate-limit-exhausted → SUCCESS_DELAY, other → FAILURE_DELAY
- PRIVATE-TOKEN vs JOB-TOKEN auth selection
- Inline → fallback → summary ordering
- Parse failure → post stderr as error note
- All 6 env vars (OCR_RETRY_BASE_DELAY, OCR_MAX_RETRIES, OCR_MAX_RETRY_DELAY,
  OCR_SUCCESS_DELAY, OCR_FAILURE_DELAY, OCR_RATE_LIMIT_THRESHOLD)

48 unit tests (stdlib unittest, no network, no real time.sleep):
- Seam 1: publish() with Recorder fake poster — inline/fallback/summary flow,
  proactive throttling, failure pacing
- Seam 2: make_poster() with mocked urlopen + _sleep — retry/backoff/jitter,
  Retry-After, delay cap, auth headers, is_rate_limit_exhausted classification
- fetch_diff_refs() with mocked urlopen — success/failure/retry
- build_config() defaults and env overrides
- Dry-run poster — no HTTP calls

Implements #534.

* fix(examples): address code review findings on gitlab_ci post_review

- Add missing-required check for CI_PROJECT_ID and CI_MERGE_REQUEST_IID
  in main(), matching gerrit_ci/gitflic_ci pattern. The heredoc used
  os.environ[...] (KeyError on missing); the extraction silently used
  env.get(..., "") which constructs a malformed API URL. Now fails fast
  with a clear error message.
- Change transient_base_delay from int 2 to float 2.0 to match spec
  config-dict type annotation.
- Add 5 end-to-end tests for main()'s auth-header env resolution:
  PRIVATE-TOKEN when GITLAB_API_TOKEN set, JOB-TOKEN when only
  CI_JOB_TOKEN set, PRIVATE-TOKEN wins when both set, missing CI vars
  fails fast, missing token fails fast.

Addresses review findings: #3 (TP, medium), #4 (Edge), #5 (TP, low).

* fix(examples): handle URLError in gitlab_ci post_review retry logic

_api_request_with_retry only caught HTTPError, not URLError. Network-layer
failures (DNS resolution failure, connection refused, connection reset)
raised URLError which propagated uncaught, crashing the script and losing
all pending review comments.

The original heredoc had the same gap, but the gerrit_ci sibling already
handles this correctly (lines 250-259: retry on connection errors, propagate
timeouts). This fix follows the gerrit_ci pattern adapted to our return-dict
contract:

- Add 'except urllib.error.URLError' handler after HTTPError handler
- Timeout (socket.timeout/TimeoutError): return failure dict, don't retry
  (ambiguous — server may have processed the request)
- Connection errors (DNS, refused, reset): retry with transient_base_delay
  backoff + ±25% jitter, same as 5xx/408 handling
- Exhaustion: return failure dict with is_rate_limit_exhausted=False

3 new tests:
- test_retry_urlerror_then_success: ConnectionRefused → retry → success
- test_urlerror_exhausts_retries: 4 ConnectionRefused → failure after 4 attempts
- test_urlerror_timeout_not_retried: socket.timeout → immediate failure, no retry

Found by OCR (open-code-review) AI code review.

* fix(examples): handle non-UTF-8 HTTP error bodies in gitlab_ci post_review

e.read().decode('utf-8') raises UnicodeDecodeError when the GitLab server
returns a non-UTF-8 error body (e.g., an HTML error page in latin-1 from
a misconfigured proxy or load balancer). This exception propagated uncaught,
crashing the entire posting loop — no further inline comments, fallback notes,
or summary notes would be posted.

Both gerrt_ci (line 242: decode('utf-8', 'replace')) and gitflic_ci (line 344:
decode('utf-8', 'replace')) siblings already handle this correctly. The
original heredoc had the same gap.

Fix: add errors='replace' to both decode() calls (success path line 248 +
error path line 260). For valid UTF-8 input (the normal case), behavior is
identical. The error body is only used for keyword matching and logging,
both of which work fine with replacement characters (U+FFFD).

1 new test:
- test_non_utf8_error_body_does_not_crash: HTTPError with invalid UTF-8 body
  → no crash, returns failure dict

Found by OCR (open-code-review) AI code review on PR #539.
2026-07-28 10:16:16 +08:00
chethanuk
83dacc2725
docs(examples): OCR_LLM_MODEL is required, not optional (#431) 2026-07-22 09:14:39 +08:00
Lei Zhang
7f22ba867d
fix: actions rate limit (#164)
* ci: add rate limit handling and version verification to GitHub Actions workflow

- Add version check after OCR installation to verify successful setup
- Implement exponential backoff retry logic for GitHub API rate limits
- Add delays between individual comment posts to avoid secondary rate limits
- GitHub enforces ~80 content-generating requests per minute; spacing calls
  helps stay under that threshold with 2-second base delay and up to 3 retries

* ci: refine rate limit handling in GitHub Actions workflow

- Add `|| true` to ocr version check for error isolation
- Narrow rate limit detection to 429 and 403 with rate-limit
  message matching, avoiding retries on permission/auth failures
- Extract hardcoded delay constants into env-configurable
  variables (OCR_RETRY_BASE_DELAY, OCR_MAX_RETRIES,
  OCR_SUCCESS_DELAY, OCR_FAILURE_DELAY) with sensible defaults
- Document optional environment variables in workflow header

* docs: add environment variable configuration guide for retry and delay settings

* ci: add rate-limit resilience and version check to GitLab CI pipeline

- Add `ocr version || true` after install for diagnostic logging
- Add `api_request_with_retry` function with exponential backoff
  for 429 and 403 (rate-limit message matching) errors
- Respect GitLab `Retry-After` header when present
- Extract delay constants into CI/CD-configurable variables
  (OCR_RETRY_BASE_DELAY, OCR_MAX_RETRIES,
  OCR_SUCCESS_DELAY, OCR_FAILURE_DELAY) with defaults
- Add pacing delays between successful/failed discussion posts
- Document optional CI/CD variables in pipeline header comments

* docs: add retry/delay settings section to GitLab CI README

* ci: fix rate-limit retry delay exhaustion handling in CI workflows

- GitHub Actions: distinguish exhausted rate-limit retries from other errors, apply SUCCESS_DELAY (2s) instead of FAILURE_DELAY (1s) when retries exhausted
- GitLab CI: return structured result from api_request_with_retry to differentiate failure types, apply context-aware delays based on rate-limit exhaustion status
- Both: prevent perpetuating rate-limit failures by using longer delays after retry exhaustion

* ci: align GitHub Actions rate-limit retry with header-based strategy

Derive wait durations from response headers (retry-after, x-ratelimit-reset)
instead of fixed exponential backoff, add proactive throttle when remaining
quota is low, honor batch-level rate limits before per-comment retry, and add
support for transient 5xx/408 errors.

* feat(gitlab-ci): enhance rate-limit handling with jitter, max retry delay, and proactive throttling

- Add ±25% jitter on retry delays to avoid thundering herd problems
- Add OCR_MAX_RETRY_DELAY (default 60s) to cap per-retry wait time
- Add OCR_RATE_LIMIT_THRESHOLD (default 10) for proactive throttling
  based on GitLab RateLimit-Remaining response header
- Parse Retry-After header properly (handle non-numeric values)
- Apply retry logic to all API requests (notes, versions, discussions)
- Parse and log RateLimit-Remaining/Limit headers for observability
- Double pacing delay when remaining quota drops below threshold
- Update README with new configuration variables and behavior docs

* fix(examples): sync rate-limit docs with script defaults and add missing variables

- GitHub Actions README: fix OCR_RETRY_BASE_DELAY default from 2000 to 60000
  (matching script code and header comments)
- GitHub Actions README: add missing OCR_RETRY_MAX_DELAY, OCR_LOW_REMAINING_THRESHOLD,
  OCR_LOW_REMAINING_SPACING variables
- GitHub Actions README: add GitHub Rate Limits doc reference link
- GitHub Actions yml header: add OCR_LLM_USE_ANTHROPIC and llm.extra_body notes
- GitLab CI yml header: add llm.extra_body note
- GitLab CI README: add GitLab Rate Limits doc reference link

* ci(examples): unify header lookup and add transient retry backoff

- GitHub Actions: extract inline header closure into a reusable getHeader
  helper; use it in both computeRetryDelayMs and logRateLimitQuota for
  consistent case-insensitive header access.
- GitHub Actions: use a 2s transientBase for 5xx/408 exponential backoff
  instead of the 60s rate-limit base, since server hiccups are typically
  short-lived and the longer base stalled CI jobs unnecessarily.
- GitLab CI: add a _get_header helper and route all header access
  (Retry-After, RateLimit-*) through it, matching the GitHub Actions
  approach.
- GitLab CI: add transient retry logic for 5xx/408 errors with a 2s
  base delay, so server errors no longer fail immediately.
2026-06-22 10:10:47 +08:00
Lei Zhang
a32b8c7e30
docs(examples): add concurrency control to CI workflow examples (#60)
* docs(examples): add concurrency control to CI workflow examples

- GitHub Actions: add concurrency group with cancel-in-progress to avoid
  redundant review runs on rapid pushes
- GitLab CI: add interruptible and resource_group to cancel outdated
  review jobs when new commits are pushed to the same MR

* docs(examples): improve GitLab CI example with fork MR and concurrency support

- Support forked MR pipelines by using CI_COMMIT_SHA as --to target
- Fall back to CI_JOB_TOKEN when GITLAB_API_TOKEN is unavailable
- Use appropriate auth header (JOB-TOKEN vs PRIVATE-TOKEN) based on token source
- Add --audience agent flag for machine-consumable review output
- Make diff_refs required for inline comments, simplify post_discussion signature
- Improve summary with inline vs fallback comment breakdown
- Add documentation comments for fork MR setup requirements

* docs(examples): use pull_request_target and SHA refs for fork PR support

- Switch trigger from pull_request to pull_request_target so secrets
  are available for PRs from forks
- Use head SHA instead of branch ref for checkout and ocr --to, since
  fork branches don't exist on the origin remote
- Add explicit fetch step to ensure fork commits are available
- Update condition checks and comments to reflect the new event name

* docs: sync READMEs with CI script changes for fork PR/MR support
2026-06-08 21:33:20 +08:00
Lei Zhang
55c6bca1f8
chore: update ci pipeline examples (#45)
* chore: remove --audience agent flag and simplify JSON parsing in CI examples

- Remove --audience agent flag from ocr review commands in CI examples
- Simplify JSON output parsing by reading directly without skipping first line
- Update README docs to reflect the simplified CLI usage

* fix: correct typo in .gitlab-ci.yml comment

Change 'confuring' to 'setting' in CI variable configuration comment.
2026-06-04 23:57:05 +08:00
Lei Zhang
128787b627
Add CI/CD integration section and examples to documentation (#11)
* docs: add CI/CD integration section and examples

- Add CI/CD Integration section to README.md and README.zh-CN.md
- Add GitHub Actions workflow example (examples/github_actions/)
- Add GitLab CI pipeline example (examples/gitlab_ci/)
- Add examples README with overview of integration options

* feat(examples): enhance GitHub Actions demo with comment trigger and improved error handling

- Add issue_comment event trigger with /open-code-review and @open-code-review keywords
- Add PR context resolution for comment-triggered events via GitHub API
- Improve ref handling to support both PR events and comment events
- Add individual comment fallback with retry when batch review fails
- Add posting statistics (success/failed counts) to summary comment
- Update README with comment trigger flow and customization guide

* docs(examples): add --background flag usage guide for GitHub Actions and GitLab CI

Explain how to pass PR/MR title as background context to help OCR
provide more relevant and context-aware review comments.

* feat(examples): simplify PR trigger and add skip-existing-review guide for GitLab CI

- Reduce GitHub Actions PR trigger to 'opened' only (avoid redundant
  reviews on synchronize/reopened events)
- Add GitLab CI documentation for checking existing OCR comments before
  running review to save LLM tokens
2026-06-01 16:44:24 +08:00