Files
goose/.github/workflows/code-review.yml
2026-03-14 13:04:11 -04:00

175 lines
6.1 KiB
YAML

name: Code Review
on:
# pull_request_target:
# types: [opened, synchronize]
workflow_dispatch:
inputs:
pr_number:
description: 'Pull request number to review'
required: true
type: number
instructions:
description: 'Instructions for the code review'
required: false
type: string
default: 'Review the changes for correctness'
workflow_call:
inputs:
pr_number:
description: 'Pull request number to review'
required: true
type: number
instructions:
description: 'Instructions for the code review'
required: false
type: string
default: 'Review the changes for correctness'
secrets:
ANTHROPIC_API_KEY:
required: true
permissions:
contents: read
pull-requests: write
concurrency:
group: code-review-${{ github.event.pull_request.number || inputs.pr_number }}
cancel-in-progress: true
jobs:
review-pr:
runs-on: ubuntu-latest
timeout-minutes: 15
container:
image: ghcr.io/block/goose:latest
options: --user root
env:
HOME: /tmp/goose-home
steps:
- name: Checkout base branch
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Install tools
run: |
apt-get update
apt-get install -y gettext curl ripgrep jq
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
| dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
| tee /etc/apt/sources.list.d/github-cli.list > /dev/null
apt-get update
apt-get install -y gh
git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Get PR metadata and diff
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number || inputs.pr_number }}
run: |
mkdir -p /tmp/code-review
TITLE=$(gh pr view "$PR_NUMBER" --json title --jq '.title')
BODY=$(gh pr view "$PR_NUMBER" --json body --jq '.body // "(no description)"')
COMMIT_ID=$(gh pr view "$PR_NUMBER" --json headRefOid --jq '.headRefOid')
echo "COMMIT_ID=$COMMIT_ID" >> "$GITHUB_ENV"
printf '# %s\n\n## Description\n\n%s\n' "$TITLE" "$BODY" > /tmp/code-review/pr.md
gh pr diff "$PR_NUMBER" > /tmp/code-review/pr.diff
- name: Run goose review
id: goose
env:
PR_NUMBER: ${{ github.event.pull_request.number || inputs.pr_number }}
REVIEW_INSTRUCTIONS: ${{ inputs.instructions }}
GOOSE_PROVIDER: ${{ vars.GOOSE_PROVIDER || 'anthropic' }}
GOOSE_MODEL: ${{ vars.GOOSE_MODEL || 'claude-sonnet-4-20250514' }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GOOSE_SHELL_ENV_SCRUB: ANTHROPIC_API_KEY,GITHUB_TOKEN
GOOSE_SKIP_CONTEXT_FILES: AGENTS.md
GOOSE_SHELL_ALLOWED_COMMANDS: cat,grep,rg,head,tail,wc,ls,git
run: |
mkdir -p "$HOME/.local/share/goose/sessions"
mkdir -p "$HOME/.config/goose"
goose run \
--recipe .github/recipes/code-review.yaml \
--params pr_directory=/tmp/code-review \
--params instructions="$REVIEW_INSTRUCTIONS"
- name: Upload review artifacts
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: code-review-output
path: |
/tmp/conclusion.json
/tmp/comments.json
if-no-files-found: ignore
retention-days: 30
- name: Submit review
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number || inputs.pr_number }}
run: |
CONCLUSION="/tmp/conclusion.json"
COMMENTS="/tmp/comments.json"
if [ ! -f "$COMMENTS" ]; then
echo "No comments produced, skipping review submission."
exit 0
fi
# Default conclusion if finish_review was never called
if [ ! -f "$CONCLUSION" ]; then
echo '{"body":"","event":"COMMENT"}' > "$CONCLUSION"
fi
# Build payload using jq file inputs to avoid shell interpolation issues
# Omit body when empty for a cleaner review
jq -n \
--arg commit_id "$COMMIT_ID" \
--slurpfile conclusion "$CONCLUSION" \
--slurpfile comments "$COMMENTS" \
'{
commit_id: $commit_id,
event: $conclusion[0].event,
comments: $comments[0]
}
| if $conclusion[0].body != "" then .body = $conclusion[0].body else . end
' > /tmp/review-payload.json
# Try submitting with inline comments first
if gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews" \
--input /tmp/review-payload.json; then
echo "Review submitted with inline comments."
exit 0
fi
echo "Inline comments failed, folding into review body."
# Fold inline comments into the review body as a fallback
jq -n \
--arg commit_id "$COMMIT_ID" \
--slurpfile conclusion "$CONCLUSION" \
--slurpfile comments "$COMMENTS" \
'{
commit_id: $commit_id,
body: (
$conclusion[0].body + "\n\n---\n\n## Inline Comments\n\n" +
([$comments[0][] |
"### `" + .path + "` (line " + (.line | tostring) + ")\n\n" + .body
] | join("\n\n---\n\n"))
),
event: $conclusion[0].event
}' \
| gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews" \
--input -