Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 103 additions & 2 deletions .github/workflows/claude-code-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,48 @@ on:
type: string
description: "If this label is set on the PR, the review will be skipped"
default: "skip-claude-review"
model:
type: string
description: Claude model to use for the review
default: claude-opus-4-6
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we default to 4.7 ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure : I prefer to be conservative for now, can be more easily changed/tested afterwards...

plugins:
type: string
description: Comma-separated list of skills to use from the agent hub (e.g. scality-skills@scality-agent-hub)
default: scality-skills@scality-agent-hub
plugin_marketplaces:
type: string
description: |
Marketplace to pull plugin from. Defaults to agent-hub, but possible to use another repo
or branch of the marketplace to pull the skills from (e.g. main):
https://github.com/scality/agent-hub.git#<my-branch>
Especially useful for testing a new version of a skill before it's merged to the default branch.
default: scality/agent-hub
summary-mode:
type: string
description: >
How the review output should be posted:
- check: post as a check run (requires checks: write permission)
- comment: post as a PR comment
- auto: check if allowed, otherwise post as a comment
default: auto
allowed-tools:
type: string
description: >
Space-separated list of allowed tools for the review. By default, a set of safe tools is allowed, but you can customize this list to enable or disable specific tools based on your needs and risk tolerance.
NOTE: should not be needed if the skill already indicates the appropriate allowed tools. Keeping default value for compatibility.
default: >-
"Read"
"Bash(git diff *)"
"Bash(git log *)"
"Bash(git show *)"
"Bash(gh repo view *)"
"Bash(gh pr view *)"
"Bash(gh pr diff *)"
"Bash(gh pr checks *)"
"Bash(gh pr comment *)"
"Bash(gh api *repos/*/pulls/*/comments*)"
"Bash(gh api *issues/*/comments*)"
"Bash(gh api *repos/*/check-runs*)"
secrets:
GCP_WORKLOAD_IDENTITY_PROVIDER:
required: true
Expand All @@ -20,6 +62,9 @@ on:
CLOUD_ML_REGION:
required: true
description: GCP region for Vertex AI
ACTIONS_APP_PRIVATE_KEY:
required: false
description: Private key of the GitHub App used to check out marketplace repositories

jobs:
claude-review:
Expand All @@ -37,6 +82,57 @@ jobs:
with:
fetch-depth: 1

- name: Identify marketplaces needing local checkout
id: marketplaces
uses: actions/github-script@v7
env:
PLUGIN_MARKETPLACES: ${{ inputs.plugin_marketplaces }}
with:
script: |
// Entries using `<url>#<ref>` syntax are not supported natively by
// the claude-code plugin loader. Extract them so we can clone the
// repo locally and substitute the entry with the local path.
const entryPattern = /^(?:https?:\/\/github\.com\/)?([^/#]+)\/([^/#]+?)(?:\.git)?#(.+)$/;
const checkouts = [];
const marketplaces = (process.env.PLUGIN_MARKETPLACES || '').split(/[,\n]/).map(entry => {
const m = entry.trim().match(entryPattern);
if (!m) {
return entry;
}

const [, owner, repo, ref] = m;
const path = `.marketplaces/${owner}-${repo}`;
checkouts.push({ repository: `${owner}/${repo}`, repo, ref, path });

return `./${path}`;
});
core.setOutput('checkouts', JSON.stringify(checkouts));
core.setOutput('repositories', checkouts.map(c => c.repo).join('\n'));
core.setOutput('marketplaces', marketplaces.join('\n'));

- name: Get token for marketplace repositories
if: steps.marketplaces.outputs.repositories != ''
id: app-token
uses: actions/create-github-app-token@v3
with:
app-id: ${{ vars.ACTIONS_APP_ID }}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this one should have technically be a input, if it works great, but technically the workflow should be given all its parameter. (even if we unfortunately add an extra one here).

private-key: ${{ secrets.ACTIONS_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: ${{ steps.marketplaces.outputs.repositories }}

- name: Checkout marketplace repositories
if: steps.marketplaces.outputs.repositories != ''
env:
CHECKOUTS: ${{ steps.marketplaces.outputs.checkouts }}
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
jq -r '.[] | [.repository, .ref, .path] | @tsv' <<< "$CHECKOUTS" | while IFS=$'\t' read -r repo ref path; do
git clone --depth 1 --branch "$ref" "https://x-access-token:${GH_TOKEN}@github.com/${repo}.git" "$path"

# remove token from git config
git -C "$path" remote remove origin
done

- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v2
with:
Expand All @@ -51,8 +147,13 @@ jobs:
use_vertex: "true"
prompt: "/review-pr REPO: ${{ github.repository }} PR_NUMBER: ${{ github.event.pull_request.number }}"
claude_args: |
--allowedTools "Read" "Bash(git diff *)" "Bash(git log *)" "Bash(git show *)" "Bash(gh repo view *)" "Bash(gh pr view *)" "Bash(gh pr diff *)" "Bash(gh pr checks *)" "Bash(gh pr comment *)" "Bash(gh api *repos/*/pulls/*/comments*)" "Bash(gh api *issues/*/comments*)" "Bash(gh api *repos/*/check-runs*)"
--model "claude-opus-4-6"
--allowedTools ${{ inputs.allowed-tools }}
--model "${{ inputs.model }}"
plugin_marketplaces: ${{ steps.marketplaces.outputs.marketplaces }}
plugins: ${{ inputs.plugins }}
additional_permissions: |
${{ inputs.summary-mode != 'comment' && 'checks: write' || '' }}
env:
ANTHROPIC_VERTEX_PROJECT_ID: ${{ secrets.ANTHROPIC_VERTEX_PROJECT_ID }}
CLOUD_ML_REGION: ${{ secrets.CLOUD_ML_REGION }}
PUBLISH_MODE: ${{ inputs.summary-mode }}
Loading