logo
0
0
WeChat Login
ci: 更新 Docker 发布工作流至 CNB 仓库

OpenCode PR Review

OpenCode Docker Image License Go Multi-arch

中文文档 | English

An AI-powered automatic code review tool for Gitea / Forgejo / GitHub PRs, built on the OpenCode plugin system. Supports two runtime modes:

  • Actions Mode — Triggered by the bundled Gitea Actions workflow for single-run reviews; GitHub Actions requires manual workflow adaptation
  • Webhook Mode — Long-running Go HTTP server that receives Provider events, executes reviews asynchronously, and pushes WeCom notifications on completion

Table of Contents

Features

  • AI Code Review — Supports GPT, Claude, DeepSeek, GLM, and more via any OpenAI-compatible gateway
  • Line-Level Comments — Precise feedback on specific code lines with suggestion code blocks
  • Review Decisions — Automatically outputs approve, request_changes, or comment based on severity
  • Structured Tags — Categorizes issues with [BUG:HIGH], [SECURITY:CRITICAL], etc.
  • Incremental Review — Only reviews new changes since the last review on PR updates, avoiding duplicates
  • Multi-Provider Support — Unified adapter for Gitea / Forgejo / GitHub / GHES API, Diff, and Review semantics
  • Async Webhook Processing — Go Worker Pool with configurable queue size and concurrency, built-in delivery deduplication
  • Signature Verification — HMAC-SHA256 signature validation, compatible with sha256= prefix
  • WeCom Notification — Pushes markdown_v2 formatted review summaries to WeCom group bots
  • File Filtering — Glob-pattern-based scope control (e.g., *.go,src/**/*.ts)
  • Isolated Configuration — Uses a dedicated .opencode-review/ directory, no conflict with existing .opencode/ setups
  • Pre-built Docker Image — Multi-arch (linux/amd64 + linux/arm64), ready to use

Architecture

┌─────────────────────────────────────────────────────────────────────┐ │ Trigger Methods │ │ ┌──────────────────┐ ┌──────────────────────────────────────┐ │ │ │ Gitea Actions │ │ Gitea / GitHub Webhook POST │ │ │ │ (bundled) │ │ (pull_request / issue_comment / │ │ │ │ │ │ pull_request_review_comment) │ │ │ └────────┬─────────┘ └──────────────┬───────────────────────┘ │ └───────────┼─────────────────────────────┼──────────────────────────┘ │ │ ▼ ▼ ┌──────────────────┐ ┌────────────────────────┐ │ entrypoint.sh │ │ Go Webhook Server │ │ review command │ │ ┌──────────────────┐ │ │ │ │ │ Signature verify │ │ │ 1. TLS config │ │ │ + Dedup │ │ │ 2. Provider det.│ │ └───────┬──────────┘ │ │ 3. Build prompt │ │ ┌───────▼──────────┐ │ │ 4. opencode run │ │ │ Worker Pool │ │ └────────┬─────────┘ │ │ (queue+concurrency)│ │ │ │ └───────┬──────────┘ │ │ └──────────┼──────────────┘ │ │ ▼ ▼ ┌─────────────────────────────────────────────────┐ │ OpenCode CLI + Plugin System │ │ ┌────────────┐ ┌───────────────────────────┐ │ │ │code-review │ │ Tools │ │ │ │Agent │ │ • gitea-pr-diff │ │ │ │ │ │ • gitea-incremental-diff │ │ │ │ (AI review │ │ • gitea-pr-files │ │ │ │ strategy │ │ • gitea-review │ │ │ │ + decision│ │ • gitea-comment │ │ │ │ logic) │ │ • provider (API adapter) │ │ │ └─────┬──────┘ │ • diff-utils │ │ │ │ └───────────┬───────────────┘ │ └────────┼─────────────────────┼───────────────────┘ │ │ ▼ ▼ ┌─────────────────┐ ┌──────────────────────┐ │ Provider API │ │ WeCom Group Bot │ │ Gitea / GitHub │ │ (markdown_v2 notify) │ │ Submit Review │ └──────────────────────┘ │ Line Comments │ └─────────────────┘

Installation

Interactive Installation

Run in your project root:

curl -fsSL https://cnb.cool/zishuo/opencode-review-gitea/-/git/raw/main/install.sh | bash

The script guides you through choosing an installation method and auto-installs the review workflow to .gitea/workflows/ for Gitea Actions.

Direct Installation

# Docker-based — adds only 1 workflow file curl -fsSL https://cnb.cool/zishuo/opencode-review-gitea/-/git/raw/main/install.sh | bash -s -- --docker # Source-based — adds full .opencode-review/ directory + workflow curl -fsSL https://cnb.cool/zishuo/opencode-review-gitea/-/git/raw/main/install.sh | bash -s -- --source # Both methods curl -fsSL https://cnb.cool/zishuo/opencode-review-gitea/-/git/raw/main/install.sh | bash -s -- --both

Installation Methods Comparison

AspectDockerSource
Files added1 workflow file.opencode-review/ + workflow
CI speedFast (pre-built cached image)Slower (installs deps each run)
CustomizationEnvironment variables onlyFull control over Agents, Tools, Skills
UpdatesPull :latest imageManual sync of .opencode-review/
Best forQuick setup, standard useCustom review strategies, power users

Configuration

Required Environment Variables

Configure in repository Secrets (Actions mode) or container environment variables (Webhook/Local mode):

VariableDescriptionExample
API_ENDPOINTOpenAI-compatible model gateway base URLhttps://your-gateway.example.com/v1
API_TOKENModel gateway API tokensk-xxxxx
GITEA_TOKENGitea / Forgejo API token (with repo scope)gitea_xxxxx
GITHUB_TOKENGitHub / GHES Personal Access Tokenghp_xxxxx
OPENCODE_GIT_TOKENToken for actions/checkout in Gitea Actions runtime

Webhook mode additionally requires WEBHOOK_SECRET. See Webhook Server Configuration.

Model Configuration

Specify the model via the MODEL environment variable in provider/model-id format:

env: MODEL: openai/glm-5.0 # default # MODEL: openai/gpt-5.4 # MODEL: openai/claude-4.5 # MODEL: openai/deepseek-v3.1 # MODEL: openai/gemini-2.5-pro

The opencode.json pre-defines 20+ models (GPT-5.x, Claude 4.5/4.6, Gemini, DeepSeek, GLM, MiniMax, Kimi, Hunyuan, etc.) with cost set to 0 (billing via custom gateway). You can add new model definitions in opencode.json.

Review Behavior

VariableDefaultDescription
REVIEW_LANGUAGEautoReview response language: auto (detect from code) / en / zh-CN
REVIEW_STYLEbalancedReview depth: concise / balanced / thorough / security
FILE_PATTERNS(empty)File filter (glob patterns, comma-separated), e.g., *.go,src/**/*.ts

File filtering examples:

# Only review TypeScript files FILE_PATTERNS: "*.ts,*.tsx" # Only review Go files under src/ FILE_PATTERNS: "src/**/*.go" # Mixed patterns FILE_PATTERNS: "*.py,*.js"

Note: Only positive matching is supported. Negation patterns with ! are not available.

Webhook Server Configuration

VariableDefaultDescription
WEBHOOK_LISTEN_ADDR:8080HTTP listen address
WEBHOOK_PATH/webhookWebhook endpoint path
WEBHOOK_QUEUE_SIZE64Async queue buffer size
WEBHOOK_MAX_CONCURRENT2Maximum concurrent review workers
WEBHOOK_REVIEW_TIMEOUT30mPer-review timeout (Go duration format)
WEBHOOK_MAX_BODY_BYTES2MBMaximum request body size
WEBHOOK_ENTRYPOINT/entrypoint.shReview execution entrypoint script path
WEBHOOK_WORK_ROOT/tmp/opencode-review/jobsTemporary working directory for clones
WEBHOOK_COMMENT_COMMANDS/oc,/opencodeComment commands that trigger review (comma-separated)
WEBHOOK_PULL_REQUEST_ACTIONSopened,reopened,synchronize,ready_for_reviewPR action whitelist for auto-trigger
WEBHOOK_POST_FAILURE_COMMENTtruePost a PR comment when review fails
WEBHOOK_CLEANUP_WORKTREEtrueClean up temporary worktrees after review
WEBHOOK_ALLOW_INSECUREfalseAllow webhook requests without signature (dev only)

Webhook Secret (by priority):

VariableDescription
GITEA_WEBHOOK_SECRETGitea-specific secret (overrides shared)
GITHUB_WEBHOOK_SECRETGitHub-specific secret (overrides shared)
WEBHOOK_SECRETShared secret for both providers

TLS & Security

TLS certificate verification is skipped by default for self-signed certificates in internal networks. Set any of the following to false to enforce strict validation:

  • SKIP_TLS_VERIFY
  • WEBHOOK_SKIP_TLS_VERIFY
  • REVIEW_SKIP_TLS_VERIFY
  • GIT_SSL_NO_VERIFY

WeCom Notification

VariableDescription
WECOM_BOT_WEBHOOK_URLWeCom group bot webhook URL
WECOM_WEBHOOK_URLAlias (equivalent, lower priority)

Notification content includes: repository name, submitter, PR link, review verdict with a short hint, optional PR summary, feedback overview (comment count / suggestion count), model used, duration, and result link.

Usage

Choosing a Runtime Mode

ScenarioRecommended ModeNotes
Gitea / Forgejo, quickest setup inside the repoActions ModeThe bundled installer writes .gitea/workflows/opencode-review.yaml automatically
Gitea / Forgejo, centralized service across multiple reposWebhook ModeBetter if you want one long-running service and unified notifications
GitHub / GHES, automated reviews with the shipped setupWebhook ModeThis is the documented default for GitHub because the server natively handles GitHub webhook headers, API base URLs, and PR review submission
GitHub / GHES, Actions-based executionManual adaptation requiredThe shipped workflow templates are Gitea-oriented and must be adjusted before use in GitHub Actions

Actions Mode

After installation, creating or updating a PR automatically triggers review (if the workflow is configured for those events). You can also manually trigger via comment:

/oc

Or with custom instructions:

/opencode please focus on concurrency safety issues

Custom instructions after the command are extracted and passed to the AI review agent.

The bundled installer currently provisions a Gitea Actions workflow. For GitHub / GHES, prefer Webhook Mode unless you plan to adapt the workflow templates manually, because the shipped templates reference Gitea runtime variables.

Webhook Mode

Webhook Mode is the recommended automation path for GitHub / GHES today, and it also works well for Gitea / Forgejo when you want a centralized review service instead of per-repo workflows.

Start the webhook server:

docker run --rm -p 8080:8080 \ -e GITEA_TOKEN="your-gitea-token" \ -e GITHUB_TOKEN="your-github-token" \ -e WEBHOOK_SECRET="your-webhook-secret" \ -e API_ENDPOINT="https://your-llm-gateway.example.com/v1" \ -e API_TOKEN="your-api-token" \ -e MODEL="openai/glm-5.0" \ -e WECOM_BOT_WEBHOOK_URL="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxx" \ -e WEBHOOK_PATH="/webhook" \ docker.cnb.cool/zishuo/opencode-review-gitea:latest webhook

Then configure in your Gitea / GitHub repository webhook settings:

  • URL: http://your-server:8080/webhook
  • Content Type: application/json
  • Secret: Match your WEBHOOK_SECRET
  • Events: Pull Request events, Issue Comment events, Pull Request Review Comment events

By default, pull_request events with actions opened/reopened/synchronize/ready_for_review auto-trigger reviews. You can also trigger via PR comments /oc or /opencode.

Local Testing

Docker single review:

docker run --rm \ -v $(pwd):/workspace \ -e GITEA_TOKEN="your-token" \ -e GITEA_SERVER_URL="https://your-gitea.example.com" \ -e API_ENDPOINT="https://your-llm-gateway.example.com/v1" \ -e API_TOKEN="your-api-token" \ -e MODEL="openai/glm-5.0" \ -e PR_NUMBER=123 \ -e REPO_OWNER="your-org" \ -e REPO_NAME="your-repo" \ docker.cnb.cool/zishuo/opencode-review-gitea:latest

REPO_NAME accepts both repo and owner/repo formats — the entrypoint normalizes it automatically.

Docker Compose:

# Single review docker compose run review # Webhook server docker compose up webhook # Interactive shell docker compose run dev

Source-based:

export GITEA_TOKEN="your-token" export GITEA_SERVER_URL="https://your-gitea.example.com" export API_ENDPOINT="https://your-llm-gateway.example.com/v1" export API_TOKEN="your-api-token" export MODEL="openai/glm-5.0" export OPENCODE_CONFIG_DIR="$(pwd)/.opencode-review" opencode run --agent code-review \ "Please review PR #123 in owner/repo"

For GitHub / GHES, replace GITEA_TOKEN with GITHUB_TOKEN and optionally set GITHUB_SERVER_URL (defaults to https://github.com).

Webhook Server API Reference

Routes

MethodPathDescription
GET/HTML guide page (runtime status + configuration)
GET/healthzHealth check (returns {"status":"ok","queue":N})
GET${WEBHOOK_PATH}HTML guide page (same as /)
POST${WEBHOOK_PATH}Webhook event receiver

Trigger Rules

The webhook server only processes the following events:

Event TypeTrigger Condition
pull_requestAction is in the whitelist (default: opened,reopened,synchronize,ready_for_review)
issue_commentComment body matches a trigger command (default: /oc or /opencode)
pull_request_review_commentComment body matches a trigger command

Non-matching events return 202 Accepted + {"status":"ignored"}.

Provider Header Verification

ProviderEvent HeaderDelivery HeaderSignature Header
Gitea / ForgejoX-Gitea-EventX-Gitea-DeliveryX-Gitea-Signature
GitHub / GHESX-GitHub-EventX-GitHub-DeliveryX-Hub-Signature-256

Signature verification uses HMAC-SHA256 and is compatible with the sha256= prefix. To skip verification (development only), set WEBHOOK_ALLOW_INSECURE=true.

Response Format

Successfully queued (202 Accepted):

{ "status": "queued", "delivery": "uuid-delivery-id", "provider": "gitea", "repository": "owner/repo", "pull": 42, "trigger": "pull_request/opened" }

Duplicate delivery (202 Accepted):

{ "status": "ignored", "reason": "duplicate delivery", "delivery": "uuid-delivery-id" }

Signature error401 Unauthorized

Queue full503 Service Unavailable

Review Workflow Details

  1. Signature Verification — HMAC-SHA256 validates the webhook signature
  2. Deduplication — 24-hour TTL deduplication based on delivery ID
  3. Queueing — Buffered channel with Worker Pool for async processing
  4. go-git Clone — Pure Go git clone to a temporary directory (no system git required)
  5. Checkout head SHA — Exact checkout to the PR's latest commit
  6. Prompt Construction — Assembles review instructions from env vars (language, style, file patterns)
  7. opencode run — Launches OpenCode CLI with the code-review agent
  8. Submit Review — Calls Provider API with review decision and line-level comments
  9. WeCom Notification — Pushes review result summary to the group bot

The review agent's tool selection strategy:

  • With FILE_PATTERNS filter → uses gitea-pr-diff (filtered diff retrieval)
  • Without filter → prefers gitea-incremental-diff (incremental review, new changes only)
  • For file listings → uses gitea-pr-files

Decision matrix:

  • CRITICAL or HIGH severity issues found → request_changes
  • Non-blocking actionable issues, questions, or follow-up items → comment
  • No actionable issues, or only very minor optional suggestions → approve

Customization

Modifying the Review Agent

Edit .opencode-review/agents/code-review.md — the main review agent definition (413 lines of detailed prompt covering review discipline, priority rules, tool strategy, decision matrix, and 6 few-shot examples).

Key configuration is in the frontmatter:

--- description: AI code reviewer for Gitea/Forgejo PRs tools: "*": false "gitea-review": true "gitea-pr-diff": true "gitea-incremental-diff": true "gitea-pr-files": true "gitea-comment": true ---

You can modify the review focus, language style, severity thresholds, and more.

Adding Custom Tools

Create a TypeScript file in .opencode-review/tools/:

import { tool } from "@opencode-ai/plugin"; export default tool({ description: "Tool description", args: { param: tool.schema.string().describe("Parameter description"), }, async execute(args, context) { return "Result"; }, });

Create a matching .txt file for the tool description (helps the agent understand the tool's purpose), then enable it in the agent's frontmatter:

tools: "your-tool-name": true

Tools can use getProviderConfig() from provider.ts to auto-detect the current provider and call providerFetch() / providerFetchJson() for unified API interactions with Gitea/GitHub.

Project Structure

. ├── Dockerfile # Two-stage build: Go compile + Bun runtime ├── docker-compose.yaml # Local testing (review / webhook / dev) ├── entrypoint.sh # Container entrypoint (review / webhook / shell commands) ├── install.sh # Interactive installation script ├── .cnb.yml # CNB CI config for the primary docker.cnb.cool image pipeline ├── .github/ │ └── workflows/ │ └── docker-publish.yaml # GitHub Actions: publish the same image to docker.cnb.cool using CNB credentials ├── .gitea/ │ └── workflows/ │ └── opencode-review.yaml # Gitea Actions: source-based review workflow ├── templates/ │ ├── workflow-docker.yaml # Docker-based workflow template │ └── workflow-source.yaml # Source-based workflow template ├── backend/ # Go backend (Webhook Server) │ ├── go.mod # Module: cnb.cool/zishuo/opencode-review-gitea │ ├── cmd/webhook-server/ │ │ └── main.go # HTTP server entry + Worker Pool + deduplication │ └── internal/ │ ├── config/ │ │ └── config.go # Env var loading (all config definitions) │ ├── webhook/ │ │ ├── model.go # Provider / ReviewRequest types │ │ ├── verify.go # Provider detection + HMAC-SHA256 signature verification │ │ └── parse.go # Event parsing + filtering + comment command matching │ ├── review/ │ │ ├── runner.go # Review executor (clone + opencode + notification) │ │ └── notifier.go # WeCom markdown_v2 notification sender │ └── webui/ │ ├── guide.go # Go embed guide page renderer │ └── guide.html # Embedded HTML guide page ├── docs/ # Reference documentation │ ├── webhook-review-service.md # Webhook deployment deep-dive │ ├── gitea-webhooks-reference.md # Gitea Webhook API reference │ ├── github-webhooks-reference.md # GitHub Webhook API reference │ ├── wecom-group-bot-webhook.md # WeCom group bot API reference │ ├── opencode-sdk-reference.md # OpenCode SDK reference │ └── gitea-plugin-redoc-2.yaml # Gitea API 1.25.5 OpenAPI spec └── .opencode-review/ # OpenCode plugin (isolated config directory) ├── opencode.json # Model definitions / Provider / permissions config ├── package.json # Dependency: @opencode-ai/plugin ├── agents/ │ ├── code-review.md # Main review agent (prompt + strategy + few-shots) │ └── gitea-assistant.md # General assistant agent ├── tools/ │ ├── provider.ts # Provider abstraction (API adapter / line mapping) │ ├── diff-utils.ts # Diff parsing / formatting / file filtering │ ├── gitea-review.ts # Submit review (line comments + suggestions) │ ├── gitea-pr-diff.ts # Fetch full PR diff │ ├── gitea-incremental-diff.ts # Fetch incremental diff (new change detection) │ ├── gitea-pr-files.ts # List changed files │ ├── gitea-comment.ts # Post issue/PR comments │ └── *.txt # Tool description files ├── skills/ │ └── pr-review/SKILL.md # Reusable PR review skill └── tests/ # Bun unit tests ├── gitea-incremental-diff.test.ts ├── gitea-pr-diff.test.ts ├── gitea-review-stats.test.ts └── gitea-review-tags.test.ts

Development Guide

Tech Stack

ComponentTechnology
Runtime imageoven/bun:1-alpine
Go backendGo 1.26, go-git/v5 (only direct dependency)
Plugin systemOpenCode Plugin SDK (@opencode-ai/plugin)
Test frameworksBun Test (plugin), Go testing (backend)
CI/CDCNB Build (primary multi-arch publish path for docker.cnb.cool), GitHub Actions (alternate CNB publish path for GitHub-hosted automation)

The published image referenced throughout this README is docker.cnb.cool/zishuo/opencode-review-gitea. Both the CNB pipeline and the GitHub Actions publish workflow now target the same CNB registry image; the GitHub workflow requires CNB_TOKEN_USER_NAME and CNB_TOKEN secrets.

Local Development

# Start interactive dev environment docker compose run dev # Run Go backend tests cd backend && go test ./... # Run plugin tests cd .opencode-review && bun test

Building Docker Image

docker build -t opencode-review-gitea:latest .

Related Links

License

MIT License - See LICENSE