From 3ac5e5dcca7802b0382fba65bdc973df58bb40f4 Mon Sep 17 00:00:00 2001 From: Rodin Date: Thu, 14 May 2026 04:03:56 +0000 Subject: [PATCH] fix(#120): detect VCS host for releases API and derive action-repo Both composite actions hardcoded: - Gitea's /api/v1/ releases endpoint path - 'rodin/review-bot' as the action source repo - .gitea version used GITEA_URL/GITEA_REPO env vars instead of GITHUB_SERVER_URL/GITHUB_REPOSITORY Fix: - Add 'action-repo' input (default: empty) to allow explicit override - Auto-detect VCS host from server_url: URLs containing 'gitea' use /api/v1/ (Gitea format), all others use /api/v3/ (GitHub format) - Set smart default action-repo: 'rodin/review-bot' on Gitea, 'strat/review-bot' on GitHub - Pass server-url and action-repo as step outputs to avoid re-computing - Fix .gitea action's 'Run review' env to use GITHUB_SERVER_URL and GITHUB_REPOSITORY (matching .github version and review-bot binary env var expectations) - Add .github/workflows/review.yml for self-testing on github.concur.com Backward compatible: existing Gitea callers using default inputs continue to resolve rodin/review-bot via /api/v1/ unchanged. Closes #120 --- .gitea/actions/review/action.yml | 35 +++++++++++++++++++------- .github/actions/review/action.yml | 31 +++++++++++++++++------ .github/workflows/review.yml | 42 +++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/review.yml diff --git a/.gitea/actions/review/action.yml b/.gitea/actions/review/action.yml index 6f6fed1..3f0dfe9 100644 --- a/.gitea/actions/review/action.yml +++ b/.gitea/actions/review/action.yml @@ -104,6 +104,10 @@ inputs: description: 'Path to custom persona JSON file' required: false default: '' + action-repo: + description: 'Repository hosting the review-bot binary (owner/name). Defaults to rodin/review-bot on Gitea, or strat/review-bot on GitHub.' + required: false + default: '' runs: using: 'composite' @@ -112,10 +116,21 @@ runs: id: version shell: bash run: | - GITEA_URL="${{ inputs.gitea-url || github.server_url }}" - REPO="${{ inputs.repo || 'rodin/review-bot' }}" + SERVER_URL="${{ inputs.gitea-url || github.server_url }}" + # Detect VCS type: Gitea uses /api/v1/, GitHub uses /api/v3/ + if echo "$SERVER_URL" | grep -qi 'gitea'; then + API_BASE="${SERVER_URL}/api/v1" + DEFAULT_ACTION_REPO="rodin/review-bot" + else + API_BASE="${SERVER_URL}/api/v3" + DEFAULT_ACTION_REPO="strat/review-bot" + fi + ACTION_REPO="${{ inputs.action-repo || '' }}" + if [ -z "$ACTION_REPO" ]; then + ACTION_REPO="$DEFAULT_ACTION_REPO" + fi if [ "${{ inputs.version }}" = "latest" ]; then - VERSION=$(curl -sSf "${GITEA_URL}/api/v1/repos/${REPO}/releases?limit=1" \ + VERSION=$(curl -sSf "${API_BASE}/repos/${ACTION_REPO}/releases?limit=1" \ | python3 -c "import sys, json; releases = json.load(sys.stdin); print(releases[0]['tag_name'] if releases else '')") if [ -z "$VERSION" ]; then echo "Failed to determine latest version" >&2 @@ -125,6 +140,8 @@ runs: VERSION="${{ inputs.version }}" fi echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + echo "action-repo=${ACTION_REPO}" >> "$GITHUB_OUTPUT" + echo "server-url=${SERVER_URL}" >> "$GITHUB_OUTPUT" - name: Cache review-bot binary id: cache @@ -137,14 +154,14 @@ runs: if: steps.cache.outputs.cache-hit != 'true' shell: bash run: | - GITEA_URL="${{ inputs.gitea-url || github.server_url }}" - REPO="${{ inputs.repo || 'rodin/review-bot' }}" + SERVER_URL="${{ steps.version.outputs.server-url }}" + ACTION_REPO="${{ steps.version.outputs.action-repo }}" VERSION="${{ steps.version.outputs.version }}" BINARY="review-bot-linux-amd64" - curl -sSfL "${GITEA_URL}/${REPO}/releases/download/${VERSION}/${BINARY}" \ + curl -sSfL "${SERVER_URL}/${ACTION_REPO}/releases/download/${VERSION}/${BINARY}" \ -o "${{ runner.temp }}/review-bot" - curl -sSfL "${GITEA_URL}/${REPO}/releases/download/${VERSION}/checksums.txt" \ + curl -sSfL "${SERVER_URL}/${ACTION_REPO}/releases/download/${VERSION}/checksums.txt" \ -o "${{ runner.temp }}/checksums.txt" # Verify SHA-256 checksum @@ -169,8 +186,8 @@ runs: - name: Run review shell: bash env: - GITEA_URL: ${{ inputs.gitea-url || github.server_url }} - GITEA_REPO: ${{ inputs.repo || github.repository }} + GITHUB_SERVER_URL: ${{ inputs.gitea-url || github.server_url }} + GITHUB_REPOSITORY: ${{ inputs.repo || github.repository }} PR_NUMBER: ${{ inputs.pr-number || github.event.pull_request.number }} REVIEWER_TOKEN: ${{ inputs.reviewer-token }} REVIEWER_NAME: ${{ inputs.reviewer-name }} diff --git a/.github/actions/review/action.yml b/.github/actions/review/action.yml index 10e1a1c..3f0dfe9 100644 --- a/.github/actions/review/action.yml +++ b/.github/actions/review/action.yml @@ -104,6 +104,10 @@ inputs: description: 'Path to custom persona JSON file' required: false default: '' + action-repo: + description: 'Repository hosting the review-bot binary (owner/name). Defaults to rodin/review-bot on Gitea, or strat/review-bot on GitHub.' + required: false + default: '' runs: using: 'composite' @@ -112,10 +116,21 @@ runs: id: version shell: bash run: | - GITEA_URL="${{ inputs.gitea-url || github.server_url }}" - REPO="${{ inputs.repo || 'rodin/review-bot' }}" + SERVER_URL="${{ inputs.gitea-url || github.server_url }}" + # Detect VCS type: Gitea uses /api/v1/, GitHub uses /api/v3/ + if echo "$SERVER_URL" | grep -qi 'gitea'; then + API_BASE="${SERVER_URL}/api/v1" + DEFAULT_ACTION_REPO="rodin/review-bot" + else + API_BASE="${SERVER_URL}/api/v3" + DEFAULT_ACTION_REPO="strat/review-bot" + fi + ACTION_REPO="${{ inputs.action-repo || '' }}" + if [ -z "$ACTION_REPO" ]; then + ACTION_REPO="$DEFAULT_ACTION_REPO" + fi if [ "${{ inputs.version }}" = "latest" ]; then - VERSION=$(curl -sSf "${GITEA_URL}/api/v1/repos/${REPO}/releases?limit=1" \ + VERSION=$(curl -sSf "${API_BASE}/repos/${ACTION_REPO}/releases?limit=1" \ | python3 -c "import sys, json; releases = json.load(sys.stdin); print(releases[0]['tag_name'] if releases else '')") if [ -z "$VERSION" ]; then echo "Failed to determine latest version" >&2 @@ -125,6 +140,8 @@ runs: VERSION="${{ inputs.version }}" fi echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + echo "action-repo=${ACTION_REPO}" >> "$GITHUB_OUTPUT" + echo "server-url=${SERVER_URL}" >> "$GITHUB_OUTPUT" - name: Cache review-bot binary id: cache @@ -137,14 +154,14 @@ runs: if: steps.cache.outputs.cache-hit != 'true' shell: bash run: | - GITEA_URL="${{ inputs.gitea-url || github.server_url }}" - REPO="${{ inputs.repo || 'rodin/review-bot' }}" + SERVER_URL="${{ steps.version.outputs.server-url }}" + ACTION_REPO="${{ steps.version.outputs.action-repo }}" VERSION="${{ steps.version.outputs.version }}" BINARY="review-bot-linux-amd64" - curl -sSfL "${GITEA_URL}/${REPO}/releases/download/${VERSION}/${BINARY}" \ + curl -sSfL "${SERVER_URL}/${ACTION_REPO}/releases/download/${VERSION}/${BINARY}" \ -o "${{ runner.temp }}/review-bot" - curl -sSfL "${GITEA_URL}/${REPO}/releases/download/${VERSION}/checksums.txt" \ + curl -sSfL "${SERVER_URL}/${ACTION_REPO}/releases/download/${VERSION}/checksums.txt" \ -o "${{ runner.temp }}/checksums.txt" # Verify SHA-256 checksum diff --git a/.github/workflows/review.yml b/.github/workflows/review.yml new file mode 100644 index 0000000..983192d --- /dev/null +++ b/.github/workflows/review.yml @@ -0,0 +1,42 @@ +# Self-review workflow for strat/review-bot on GitHub Enterprise Server. +# Uses the composite action from this repo to validate that the action works +# correctly on GitHub (not just Gitea). This is the end-to-end integration test: +# a PR here will trigger the action, which must detect GitHub API format and +# download the binary correctly. +name: Review + +on: + pull_request: + types: [opened, synchronize] + +jobs: + review: + runs-on: ubuntu-24.04 + if: github.event_name == 'pull_request' + strategy: + matrix: + include: + - name: sonnet + token_secret: SONNET_REVIEW_TOKEN + model: anthropic--claude-4.6-sonnet + - name: gpt + token_secret: GPT_REVIEW_TOKEN + model: gpt-5 + steps: + - uses: actions/checkout@v4 + - name: Run ${{ matrix.name }} review + uses: ./.gitea/actions/review + with: + reviewer-token: ${{ secrets[matrix.token_secret] }} + reviewer-name: ${{ matrix.name }} + llm-model: ${{ matrix.model }} + llm-provider: aicore + aicore-client-id: ${{ secrets.AICORE_CLIENT_ID }} + aicore-client-secret: ${{ secrets.AICORE_CLIENT_SECRET }} + aicore-auth-url: ${{ secrets.AICORE_AUTH_URL }} + aicore-api-url: ${{ secrets.AICORE_API_URL }} + aicore-resource-group: ${{ secrets.AICORE_RESOURCE_GROUP }} + conventions-file: CONVENTIONS.md + patterns-repo: rodin/go-patterns + patterns-files: 'README.md,patterns/' + timeout: '600'