diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 716f86d..e811b26 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -1,69 +1,114 @@ name: CI - -on: +true: push: - branches: [main] + branches: + - main pull_request: - types: [opened, synchronize] - + types: + - opened + - synchronize jobs: test: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 - with: - go-version: '1.26' - - run: go test ./... - - run: go vet ./... - - run: go build -o review-bot ./cmd/review-bot - - # Self-review using native SAP AI Core provider - # Models must match SAP AI Core deployments - # Available models: gpt-5, anthropic--claude-4.6-sonnet, anthropic--claude-4.6-opus - # Removed gpt-4.1, gpt-5-mini, gpt-4.1-mini - not deployed on AI Core + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: '1.26' + - run: go test ./... + - run: go vet ./... + - run: go build -o review-bot ./cmd/review-bot review: runs-on: ubuntu-24.04 - if: github.event_name == 'pull_request' - needs: test + if: github.event_name == 'pull_request' && needs.review-gate.outputs.allow_review + == 'true' + needs: + - test + - review-gate 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 - - name: security - token_secret: SECURITY_REVIEW_TOKEN - model: gpt-5 - patterns_repo: rodin/security-patterns - patterns_files: "." - system_prompt_file: SECURITY_REVIEW.md + - name: sonnet + token_secret: SONNET_REVIEW_TOKEN + model: anthropic--claude-4.6-sonnet + - name: gpt + token_secret: GPT_REVIEW_TOKEN + model: gpt-5 + - name: security + token_secret: SECURITY_REVIEW_TOKEN + model: gpt-5 + patterns_repo: rodin/security-patterns + patterns_files: . + system_prompt_file: SECURITY_REVIEW.md 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 ${{ matrix.name }} review - env: - VCS_URL: ${{ github.server_url }} - GITEA_REPO: ${{ github.repository }} - PR_NUMBER: ${{ github.event.pull_request.number }} - REVIEWER_TOKEN: ${{ secrets[matrix.token_secret] }} - REVIEWER_NAME: ${{ matrix.name }} - LLM_PROVIDER: aicore - LLM_MODEL: ${{ matrix.model }} - 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: ${{ matrix.patterns_repo || 'rodin/go-patterns' }} - PATTERNS_FILES: ${{ matrix.patterns_files || 'README.md,patterns/' }} - LLM_TIMEOUT: "600" - SYSTEM_PROMPT_FILE: ${{ matrix.system_prompt_file }} - run: ./review-bot + - 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 ${{ matrix.name }} review + env: + VCS_URL: ${{ github.server_url }} + GITEA_REPO: ${{ github.repository }} + PR_NUMBER: ${{ github.event.pull_request.number }} + REVIEWER_TOKEN: ${{ secrets[matrix.token_secret] }} + REVIEWER_NAME: ${{ matrix.name }} + LLM_PROVIDER: aicore + LLM_MODEL: ${{ matrix.model }} + 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: ${{ matrix.patterns_repo || 'rodin/go-patterns' }} + PATTERNS_FILES: ${{ matrix.patterns_files || 'README.md,patterns/' }} + LLM_TIMEOUT: '600' + SYSTEM_PROMPT_FILE: ${{ matrix.system_prompt_file }} + run: ./review-bot + review-gate: + runs-on: ubuntu-24.04 + if: github.event_name == 'pull_request' + outputs: + allow_review: ${{ steps.gate.outputs.allow_review }} + reason: ${{ steps.gate.outputs.reason }} + steps: + - name: Check self-review gate + id: gate + env: + GITEA_TOKEN: ${{ secrets.RODIN_TOKEN }} + run: 'REPO=${{ github.repository }} + + PR=${{ github.event.pull_request.number }} + + SHA=${{ github.event.pull_request.head.sha }} + + TTL_MIN=${SELF_REVIEW_TTL_MIN} + + API="${{ github.server_url }}/api/v1" + + PR_JSON=$(curl -sS -H "Authorization: token $GITEA_TOKEN" "$API/repos/$REPO/pulls/$PR") + + UPDATED_AT=$(echo "$PR_JSON" | jq -r .updated_at) + + NOW=$(date -u +%s) + + PR_TS=$(date -u -d "$UPDATED_AT" +%s) + + AGE_MIN=$(( (NOW - PR_TS) / 60 )) + + COMMENTS=$(curl -sS -H "Authorization: token $GITEA_TOKEN" "$API/repos/$REPO/issues/$PR/comments?limit=200") + + HAS_SR=$(echo "$COMMENTS" | jq -r --arg sha "$SHA" "[.[] | select(.user.login=="rodin") + | select(.body|contains("Self-review against "+\$sha)) | select(.body|test("(?im)^### + \\s+Doc consistency\\b"))] | length") + + if [ "$HAS_SR" -gt 0 ]; then ALLOW=true; REASON=self-review; elif [ "$AGE_MIN" + -ge "$TTL_MIN" ]; then ALLOW=true; REASON=ttl; else ALLOW=false; REASON=missing; + fi + + echo "allow_review=$ALLOW" >> $GITHUB_OUTPUT + + echo "reason=$REASON" >> $GITHUB_OUTPUT' +env: + SELF_REVIEW_TTL_MIN: '45'