mirror of
https://github.com/block/goose.git
synced 2026-07-17 12:56:20 +02:00
175 lines
6.1 KiB
YAML
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 -
|