mirror of
https://github.com/alibaba/open-code-review.git
synced 2026-07-09 17:28:58 +00:00
* feat(action): extract reusable OpenCodeReview PR review GitHub Action
Consolidate the reusable-action work into one commit:
- Add composite action (action.yml at repo root for GitHub Marketplace;
helper at scripts/github-actions/post-review-comments.js) porting the
sticky summary, incremental posting, and retry idempotency logic.
- Add unit tests covering the ported idempotency behavior.
- Switch the in-repo CI workflow to use the reusable action.
- Add and refine example reusable workflows for consumers.
* ci(workflow): point ocr-review at root action.yml and quote boolean inputs
- Fix uses: to ./ now that action.yml lives at the repo root.
- Quote sticky_summary/incremental/upload_artifacts as strings to
match action.yml's input declarations (composite-action inputs are
always strings) and silence actionlint.
- Enable upload_artifacts for this workflow.
* docs(examples): point reusable demo at root action.yml
The example workflow referenced alibaba/open-code-review/action@v1,
but action.yml now lives at the repo root, so the /action subpath no
longer resolves. Use alibaba/open-code-review@v1 and update the stale
action/README.md comment to point at the root action.yml.
* docs(examples): sync README to root action.yml references
The example README still pointed at the relocated/deleted locations:
action.yml is now at the repo root, so update all 11
alibaba/open-code-review/action@v1 references to
alibaba/open-code-review@v1, and repoint the action/ directory and
action/README.md links to the root action.yml.
* fix(examples): prevent unrelated PR comments from canceling ocr-review
GitHub Actions evaluates concurrency before the job-level if-condition.
The flat group mapped every issue_comment event on a PR into the review's
group, so any comment (even a skipped conversation reply) canceled any
in-progress review.
Match the reusable demo's conditional group: PR events and human-authored
/open-code-review/@open-code-review comments share a per-PR group, while
non-matching comments fall back to a unique noop-<run_id> group that can
never collide with a real review.
* fix(action): address code-review findings across reusable PR review
- post-review-comments: parse retry delays via parseNonNegInt (0/negative fix);
paginate findExistingSummaryComment through readAllPages; remove dead
rangeOf and hasIssueCommentWithId (plus duplicated comment block)
- action.yml: move ${{ }} interpolations into env: (resolve refs, PR_NUM,
ocr_version); fail fast on PR head fetch instead of swallowing errors
- workflows: add timeout-minutes: 30; gate issue_comment on
author_association; tighten pr-context if to == 'issue_comment'
* fix(action): harden review posting after code review
- pass incremental_overlap_threshold via env to avoid github-script injection
- capture ocr review exit code directly instead of &&/|| chain
- drop redundant SUMMARY_MARKER prepend in postSummary (callers already add it)
- align example job if-condition bot check with its concurrency group
* fix(action): always upload review artifacts and capture ocr exit code
* fix(action): merge posting statistics into the summary header
The PR summary issue comment used to present two overlapping breakdowns:
a leading "posted as inline / posted as summary" header and a trailing
"📊 Posting Statistics" block. Their definitions overlapped (the header's
"summary" count included failures the trailer also listed as failed), and
when incremental filtering skipped comments the header counts no longer
summed to the total, making the summary hard to interpret.
Merge them into a single header whose four counts (inline / summary /
skipped / failed) are mutually exclusive and sum to the total, and drop
the trailing Posting Statistics section. buildSummaryBody now takes an
options object.
* fix(action): support local action resolution in container/self-hosted setups
- Checkout trusted base + mark workspace safe for pull_request_target so
the local `uses: ./` action can be resolved and loaded
- Check for git/Node.js and install git when missing, making the
composite action resilient across runner images
- Move Setup Node.js earlier and make it conditional on availability
- Resolve post-review-comments helper at runtime via
GITHUB_ACTION_PATH falling back to GITHUB_WORKSPACE, fixing helper
lookup for local actions where the action path is a host path
invisible inside containers
* refactor(examples): consolidate github_actions demo to reusable action
Drop the inline-script full-control demo; the renamed ocr-review.yml
(from ocr-review-reusable.yml) is now the single demo, invoking
alibaba/open-code-review@main.
Sync the README to the current implementation:
- normalize action refs to @main; point self-hosted-runner users to the
repo's own workflow (noting uses: ./ is internal-only)
- document config via action inputs (posting modes: sticky/incremental)
- update the comment-trigger if with defensive bot/author_association
guards and the concurrency mirror
- fix Example Output to cover the summary comment + inline comments
- replace the non-existent OCR_DEBUG debugging with
artifacts/outputs/ACTIONS_STEP_DEBUG
- use --replace-all for safe.directory
* fix(action): harden withRetry against silent undefined return
withRetry's for loop had no terminal return/throw after the loop body.
Although the current loop invariant (last attempt always throws, and
parseNonNegInt guards against negative MAX_RETRIES) makes fall-through
unreachable, an async function that falls through resolves to undefined,
which would surface as a confusing downstream TypeError for the read-API
callers that rely on it.
Capture lastErr in the loop and add an explicit terminal throw so any
future break of the invariant fails loudly instead of silently returning
undefined.
* docs(readme): document the reusable GitHub Action in CI/CD section
* fix(action): restore language config via a language input
The old inline workflow ran `ocr config set language English`, but the
composite action's Configure OCR step only set llm.extra_body, with no
language input. Add a language input (default English) and write it via
`ocr config set language` so review output language is no longer left
to the tool's default.
Addresses #337 (discussion_r3550069843).
* fix(action): warn when incremental comment listing hits page cap
listExistingReviewComments silently dropped comments beyond its 10-page
cap, unlike readAllPages which logs when truncation occurs. Add the
same max-page-limit warning after the loop so a partial walk during
incremental dedup is visible in the logs.
Addresses #337 (discussion_r3550069871).
* docs(readme): sync GitHub Action section to localized READMEs
123 lines
5 KiB
YAML
123 lines
5 KiB
YAML
# OpenCodeReview - GitHub Actions PR Auto-Review Demo
|
|
#
|
|
# Demonstrates invoking the reusable action for both automatic PR review
|
|
# (pull_request_target: opened/synchronize/reopened) and on-demand re-review
|
|
# via comments starting with '/open-code-review' or '@open-code-review'.
|
|
#
|
|
# Required secrets/vars (Settings -> Secrets and variables -> Actions):
|
|
# secret OCR_LLM_URL LLM API endpoint
|
|
# secret OCR_LLM_AUTH_TOKEN LLM auth token (mapped to OCR_LLM_TOKEN)
|
|
# variable OCR_LLM_MODEL model name
|
|
# variable OCR_LLM_USE_ANTHROPIC 'true' for Anthropic, 'false' for OpenAI-compatible
|
|
#
|
|
# For the full list of action inputs/outputs and the four comment-posting modes
|
|
# (sticky / incremental), see action.yml at the repo root.
|
|
|
|
name: OpenCodeReview PR Review
|
|
|
|
# Conditional concurrency group.
|
|
#
|
|
# GitHub Actions evaluates concurrency BEFORE job-level if-conditions. With a
|
|
# flat group (ocr-<pr_number>), every comment on the PR — even an unrelated
|
|
# conversation reply that will be skipped — enters the same group and, because
|
|
# cancel-in-progress is true, cancels any in-progress review. The result: a
|
|
# single normal comment kills a running review, and you see "two runs, one
|
|
# cancelled" in the Actions tab.
|
|
#
|
|
# Fix: matching events (PR events + /open-code-review comments) share a per-PR
|
|
# group so a new review cancels any stale one for the same PR. Non-matching
|
|
# comments land in a unique noop-<run_id> group that can never collide with a
|
|
# real review, so they are skipped instantly without disrupting anything.
|
|
concurrency:
|
|
group: >-
|
|
${{
|
|
(
|
|
github.event_name == 'pull_request_target'
|
|
|| (
|
|
github.event_name == 'issue_comment'
|
|
&& github.event.issue.pull_request
|
|
&& github.event.comment.user.type != 'Bot'
|
|
&& (
|
|
github.event.comment.author_association == 'MEMBER'
|
|
|| github.event.comment.author_association == 'OWNER'
|
|
|| github.event.comment.author_association == 'COLLABORATOR'
|
|
)
|
|
&& (
|
|
startsWith(github.event.comment.body, '/open-code-review')
|
|
|| startsWith(github.event.comment.body, '@open-code-review')
|
|
)
|
|
)
|
|
)
|
|
&& format('ocr-{0}', github.event.pull_request.number || github.event.issue.number)
|
|
|| format('noop-{0}', github.run_id)
|
|
}}
|
|
cancel-in-progress: true
|
|
|
|
on:
|
|
# Use pull_request_target instead of pull_request so that secrets are
|
|
# available even for PRs from forks. This is safe because the reusable
|
|
# action only reads the diff and does not execute any code from the PR.
|
|
pull_request_target:
|
|
types: [opened, synchronize, reopened]
|
|
issue_comment:
|
|
types: [created]
|
|
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write
|
|
|
|
jobs:
|
|
code-review:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
# Run on PR events, or on human-authored comments starting with trigger
|
|
# keywords. Bot comments are excluded as a safety net: GITHUB_TOKEN already
|
|
# suppresses events from bot-posted comments, but a PAT/App token would not.
|
|
# issue_comment triggers are further gated on author_association so only
|
|
# MEMBER/OWNER/COLLABORATOR users can spend LLM quota via re-review.
|
|
if: |
|
|
github.event_name == 'pull_request_target'
|
|
|| (
|
|
github.event_name == 'issue_comment'
|
|
&& github.event.issue.pull_request
|
|
&& github.event.comment.user.type != 'Bot'
|
|
&& (
|
|
github.event.comment.author_association == 'MEMBER'
|
|
|| github.event.comment.author_association == 'OWNER'
|
|
|| github.event.comment.author_association == 'COLLABORATOR'
|
|
)
|
|
&& (
|
|
startsWith(github.event.comment.body, '/open-code-review')
|
|
|| startsWith(github.event.comment.body, '@open-code-review')
|
|
)
|
|
)
|
|
steps:
|
|
- name: Get PR context
|
|
id: pr-context
|
|
if: github.event_name == 'issue_comment'
|
|
uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
// For issue_comment events, resolve PR base/head so the action
|
|
// can review the right diff (issue_comment has no top-level
|
|
// pull_request payload fields).
|
|
const prNumber = context.issue.number;
|
|
const { data: pullRequest } = await github.rest.pulls.get({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
pull_number: prNumber
|
|
});
|
|
core.setOutput('base_ref', pullRequest.base.ref);
|
|
core.setOutput('head_sha', pullRequest.head.sha);
|
|
|
|
- name: Run OpenCodeReview
|
|
uses: alibaba/open-code-review@main
|
|
with:
|
|
llm_url: ${{ secrets.OCR_LLM_URL }}
|
|
llm_auth_token: ${{ secrets.OCR_LLM_AUTH_TOKEN }}
|
|
llm_model: ${{ vars.OCR_LLM_MODEL }}
|
|
llm_use_anthropic: ${{ vars.OCR_LLM_USE_ANTHROPIC }}
|
|
# For issue_comment triggers, pass the resolved refs; for
|
|
# pull_request_target the action resolves them from the event.
|
|
base_ref: ${{ steps.pr-context.outputs.base_ref }}
|
|
head_sha: ${{ steps.pr-context.outputs.head_sha }}
|