From c458587cfc7c51ad845d6c994130c3c261641c9b Mon Sep 17 00:00:00 2001 From: Rodin Date: Fri, 1 May 2026 11:32:15 -0700 Subject: [PATCH] feat: add composite action for clean distribution - .gitea/actions/review/action.yml: composite action with caching Consumers just use: uses: https://gitea.weiker.me/rodin/review-bot/.gitea/actions/review@v0.1.0 No Go toolchain needed, binary cached by version tag. - Remove install.sh (replaced by composite action) - CI workflow: use matrix strategy to parallelize reviews - Self-review still builds from source (pre-release) --- .gitea/actions/review/action.yml | 103 +++++++++++++++++++++++++++++++ .gitea/workflows/ci.yml | 27 ++++---- install.sh | 75 ---------------------- 3 files changed, 116 insertions(+), 89 deletions(-) create mode 100644 .gitea/actions/review/action.yml delete mode 100755 install.sh diff --git a/.gitea/actions/review/action.yml b/.gitea/actions/review/action.yml new file mode 100644 index 0000000..d69428a --- /dev/null +++ b/.gitea/actions/review/action.yml @@ -0,0 +1,103 @@ +name: 'AI Code Review' +description: 'Run AI-powered code review on a pull request using review-bot' + +inputs: + gitea-url: + description: 'Gitea instance URL (defaults to server_url)' + required: false + default: '' + repo: + description: 'Repository (owner/name, defaults to current)' + required: false + default: '' + pr-number: + description: 'Pull request number (defaults to current PR)' + required: false + default: '' + reviewer-token: + description: 'Gitea token for posting the review' + required: true + reviewer-name: + description: 'Display name for the reviewer' + required: false + default: '' + llm-base-url: + description: 'OpenAI-compatible LLM API base URL' + required: true + llm-api-key: + description: 'LLM API key' + required: true + llm-model: + description: 'LLM model name' + required: true + conventions-file: + description: 'Path to conventions file in the repo (e.g. CLAUDE.md)' + required: false + default: '' + temperature: + description: 'LLM temperature (0 = server default)' + required: false + default: '0' + version: + description: 'review-bot version to install (e.g. v0.1.0, defaults to latest)' + required: false + default: 'latest' + dry-run: + description: 'Print review to stdout instead of posting' + required: false + default: 'false' + +runs: + using: 'composite' + steps: + - name: Determine version + id: version + shell: bash + run: | + GITEA_URL="${{ inputs.gitea-url || github.server_url }}" + if [ "${{ inputs.version }}" = "latest" ]; then + VERSION=$(curl -sSf "${GITEA_URL}/api/v1/repos/rodin/review-bot/releases?limit=1" | sed -n 's/.*"tag_name":"\([^"]*\)".*/\1/p' | head -1) + if [ -z "$VERSION" ]; then + echo "Failed to determine latest version" >&2 + exit 1 + fi + else + VERSION="${{ inputs.version }}" + fi + echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + + - name: Cache review-bot binary + id: cache + uses: actions/cache@v4 + with: + path: /usr/local/bin/review-bot + key: review-bot-linux-amd64-${{ steps.version.outputs.version }} + + - name: Install review-bot + if: steps.cache.outputs.cache-hit != 'true' + shell: bash + run: | + GITEA_URL="${{ inputs.gitea-url || github.server_url }}" + VERSION="${{ steps.version.outputs.version }}" + curl -sSfL "${GITEA_URL}/rodin/review-bot/releases/download/${VERSION}/review-bot-linux-amd64" -o /usr/local/bin/review-bot + chmod +x /usr/local/bin/review-bot + + - name: Run review + shell: bash + env: + GITEA_URL: ${{ inputs.gitea-url || github.server_url }} + GITEA_REPO: ${{ inputs.repo || github.repository }} + PR_NUMBER: ${{ inputs.pr-number || github.event.pull_request.number }} + REVIEWER_TOKEN: ${{ inputs.reviewer-token }} + REVIEWER_NAME: ${{ inputs.reviewer-name }} + LLM_BASE_URL: ${{ inputs.llm-base-url }} + LLM_API_KEY: ${{ inputs.llm-api-key }} + LLM_MODEL: ${{ inputs.llm-model }} + CONVENTIONS_FILE: ${{ inputs.conventions-file }} + LLM_TEMPERATURE: ${{ inputs.temperature }} + run: | + ARGS="" + if [ "${{ inputs.dry-run }}" = "true" ]; then + ARGS="--dry-run" + fi + review-bot $ARGS diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index d0ad8b0..c29b60d 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -18,35 +18,34 @@ jobs: - run: go vet ./... - run: go build -o review-bot ./cmd/review-bot + # Self-review: builds from source since we're pre-release review: runs-on: ubuntu-24.04 if: github.event_name == 'pull_request' needs: test + strategy: + matrix: + include: + - name: sonnet + token_secret: SONNET_REVIEW_TOKEN + model: gpt-5 + - name: gpt + token_secret: GPT_REVIEW_TOKEN + model: gpt-5-mini steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: '1.26' - run: go build -o review-bot ./cmd/review-bot - - name: Run Sonnet Review + - name: Run ${{ matrix.name }} review env: GITEA_URL: ${{ github.server_url }} GITEA_REPO: ${{ github.repository }} PR_NUMBER: ${{ github.event.pull_request.number }} - REVIEWER_TOKEN: ${{ secrets.SONNET_REVIEW_TOKEN }} + REVIEWER_TOKEN: ${{ secrets[matrix.token_secret] }} LLM_BASE_URL: ${{ secrets.LLM_BASE_URL }} LLM_API_KEY: ${{ secrets.LLM_API_KEY }} - LLM_MODEL: "gpt-5" - CONVENTIONS_FILE: "CONVENTIONS.md" - run: ./review-bot - - name: Run GPT Review - env: - GITEA_URL: ${{ github.server_url }} - GITEA_REPO: ${{ github.repository }} - PR_NUMBER: ${{ github.event.pull_request.number }} - REVIEWER_TOKEN: ${{ secrets.GPT_REVIEW_TOKEN }} - LLM_BASE_URL: ${{ secrets.LLM_BASE_URL }} - LLM_API_KEY: ${{ secrets.LLM_API_KEY }} - LLM_MODEL: "gpt-5-mini" + LLM_MODEL: ${{ matrix.model }} CONVENTIONS_FILE: "CONVENTIONS.md" run: ./review-bot diff --git a/install.sh b/install.sh deleted file mode 100755 index 20e9bdc..0000000 --- a/install.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash -# Install review-bot from latest Gitea release -# Usage: curl -sSfL https://gitea.weiker.me/rodin/review-bot/raw/branch/main/install.sh | bash - -set -euo pipefail - -GITEA_URL="${GITEA_URL:-https://gitea.weiker.me}" -REPO="rodin/review-bot" -INSTALL_DIR="${INSTALL_DIR:-}" - -# Determine install directory with fallback -if [ -z "$INSTALL_DIR" ]; then - if [ -w /usr/local/bin ]; then - INSTALL_DIR="/usr/local/bin" - else - INSTALL_DIR="${HOME}/.local/bin" - mkdir -p "$INSTALL_DIR" - echo "Note: Installing to $INSTALL_DIR (add to PATH if needed)" - fi -fi - -OS=$(uname -s | tr '[:upper:]' '[:lower:]') -ARCH=$(uname -m) -case "$ARCH" in - x86_64) ARCH="amd64" ;; - aarch64|arm64) ARCH="arm64" ;; - *) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;; -esac - -BINARY="review-bot-${OS}-${ARCH}" - -# Get latest release tag (POSIX-safe parsing without jq) -LATEST=$(curl -sSf "${GITEA_URL}/api/v1/repos/${REPO}/releases?limit=1" | sed -n 's/.*"tag_name":"\([^"]*\)".*/\1/p' | head -1) - -if [ -z "$LATEST" ]; then - echo "Failed to determine latest release" >&2 - exit 1 -fi - -echo "Installing review-bot ${LATEST} (${OS}/${ARCH})..." - -DOWNLOAD_URL="${GITEA_URL}/${REPO}/releases/download/${LATEST}/${BINARY}" -CHECKSUM_URL="${GITEA_URL}/${REPO}/releases/download/${LATEST}/checksums.txt" - -# Download binary and checksums -TMPDIR=$(mktemp -d) -trap 'rm -rf "$TMPDIR"' EXIT - -curl -sSfL -o "${TMPDIR}/${BINARY}" "$DOWNLOAD_URL" -curl -sSfL -o "${TMPDIR}/checksums.txt" "$CHECKSUM_URL" - -# Verify checksum -cd "$TMPDIR" -EXPECTED=$(grep "${BINARY}" checksums.txt | awk '{print $1}') -ACTUAL=$(sha256sum "${BINARY}" | awk '{print $1}') - -if [ -z "$EXPECTED" ]; then - echo "Error: no checksum found for ${BINARY} in checksums.txt" >&2 - exit 1 -fi - -if [ "$EXPECTED" != "$ACTUAL" ]; then - echo "Error: checksum mismatch!" >&2 - echo " Expected: $EXPECTED" >&2 - echo " Actual: $ACTUAL" >&2 - exit 1 -fi - -echo "Checksum verified ✓" - -# Install -cp "${TMPDIR}/${BINARY}" "${INSTALL_DIR}/review-bot" -chmod +x "${INSTALL_DIR}/review-bot" - -echo "Installed review-bot ${LATEST} to ${INSTALL_DIR}/review-bot"