-
Notifications
You must be signed in to change notification settings - Fork 1
Add code review to closedloop-electron #158
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,12 @@ | ||
| name: Claude Code Review | ||
|
|
||
| on: | ||
| pull_request: | ||
| types: [opened] | ||
| pull_request_target: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ensure this does not cause a double review |
||
| types: [opened] | ||
| workflow_dispatch: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. BLOCKING — Manual triggers can't target a specific PR.
Fix: workflow_dispatch:
inputs:
pr_number:
description: 'PR number to review'
required: true
type: numberThen update the checkout ref and prompt to use |
||
|
|
||
| # Cancel in-progress runs for the same PR to prevent duplicate reviews | ||
| concurrency: | ||
| group: claude-review-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| claude-review: | ||
| # Filter by PR author or allow bot actors like Dependabot | ||
|
|
@@ -32,7 +31,7 @@ jobs: | |
| steps: | ||
| - name: Generate GitHub App Token | ||
| id: generate_token | ||
| uses: actions/create-github-app-token@v2 | ||
| uses: actions/create-github-app-token@v3 | ||
| with: | ||
| app-id: ${{ secrets.CLOSEDLOOP_APP_ID_STAGE }} | ||
| private-key: ${{ secrets.CLOSEDLOOP_APP_SECRET_STAGE }} | ||
|
|
@@ -80,10 +79,40 @@ jobs: | |
| run: | | ||
| git config --global url."https://x-access-token:${{ steps.generate_token.outputs.token }}@github.com/".insteadOf "https://github.com/" | ||
|
|
||
| - name: Install Claude CLI | ||
| shell: bash | ||
| run: | | ||
| set -e | ||
| # claude.ai/install.sh redirects here; use direct URL to avoid Cloudflare bot challenge in CI | ||
| for i in 1 2 3; do | ||
| echo "Attempt $i: Installing Claude CLI..." | ||
| if curl -fsSL https://downloads.claude.ai/claude-code-releases/bootstrap.sh | bash; then | ||
| break | ||
| fi | ||
| [ "$i" -eq 3 ] && { echo "::error::Failed to install Claude CLI"; exit 1; } | ||
| sleep 5 | ||
| done | ||
| echo "$HOME/.local/bin" >> "$GITHUB_PATH" | ||
|
|
||
| - name: Verify Claude CLI | ||
| shell: bash | ||
| run: | | ||
| if ! command -v claude &> /dev/null; then | ||
| echo "::error::Claude CLI not found in PATH" | ||
| exit 1 | ||
| fi | ||
| claude --version | ||
|
|
||
| - name: Ensure ClosedLoop Workspace | ||
| shell: bash | ||
| run: mkdir -p .closedloop-ai | ||
|
|
||
| - name: Run Claude Code Review | ||
| id: claude-review | ||
| continue-on-error: true | ||
| uses: anthropics/claude-code-action@v1 | ||
| env: | ||
| CR_GLOBAL_CACHE: 1 | ||
| with: | ||
| github_token: ${{ steps.generate_token.outputs.token }} | ||
| anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY_NEW }} | ||
|
|
@@ -113,7 +142,7 @@ jobs: | |
| GH_TOKEN: ${{ steps.generate_token.outputs.token }} | ||
| shell: bash | ||
| run: | | ||
| THREADS_FILE=".claude/code-review-threads.json" | ||
| THREADS_FILE=".closedloop-ai/code-review-threads.json" | ||
| if [ ! -f "$THREADS_FILE" ]; then | ||
| echo "No threads file — skipping." | ||
| exit 0 | ||
|
|
@@ -132,7 +161,7 @@ jobs: | |
| GITHUB_REPOSITORY: ${{ github.repository }} | ||
| shell: bash | ||
| run: | | ||
| FINDINGS_FILE=".claude/code-review-findings.json" | ||
| FINDINGS_FILE=".closedloop-ai/code-review-findings.json" | ||
| if [ ! -f "$FINDINGS_FILE" ]; then | ||
| echo "No findings file — skipping." | ||
| exit 0 | ||
|
|
@@ -144,6 +173,29 @@ jobs: | |
| fi | ||
| python3 "$HELPERS" post-comments --findings "$FINDINGS_FILE" | ||
|
|
||
| - name: Validate migrated review artifacts | ||
| id: validate-review-artifacts | ||
| if: always() && steps.claude-review.outcome == 'success' | ||
| shell: bash | ||
| run: | | ||
| ARTIFACT_COUNT=0 | ||
| for FILE in \ | ||
| ".closedloop-ai/code-review-findings.json" \ | ||
| ".closedloop-ai/code-review-threads.json" \ | ||
| ".closedloop-ai/code-review-summary.md"; do | ||
| if [ -f "$FILE" ]; then | ||
| ARTIFACT_COUNT=$((ARTIFACT_COUNT + 1)) | ||
| fi | ||
| done | ||
|
|
||
| if [ "$ARTIFACT_COUNT" -eq 0 ]; then | ||
| echo "::warning::Claude review completed successfully but produced no .closedloop-ai/code-review-* artifacts." | ||
| echo "::warning::This usually means the runtime/plugin path contract is out of sync." | ||
| echo "missing=true" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "missing=false" >> "$GITHUB_OUTPUT" | ||
| fi | ||
|
|
||
| - name: Post code review summary | ||
| id: post-summary | ||
| if: always() | ||
|
|
@@ -160,7 +212,7 @@ jobs: | |
| exit 0 | ||
| fi | ||
|
|
||
| SUMMARY_FILE=".claude/code-review-summary.md" | ||
| SUMMARY_FILE=".closedloop-ai/code-review-summary.md" | ||
|
|
||
| if [ -f "$SUMMARY_FILE" ]; then | ||
| SUMMARY=$(cat "$SUMMARY_FILE") | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| name: Claude Code | ||
|
|
||
| on: | ||
| issue_comment: | ||
| types: [created] | ||
| pull_request_review_comment: | ||
| types: [created] | ||
| issues: | ||
| types: [opened, assigned] | ||
| pull_request_review: | ||
| types: [submitted] | ||
|
|
||
| jobs: | ||
| claude: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. HIGH — No actor protection. Any GitHub user can burn API credits via
Fix — restrict to collaborators: if: |
(
github.event_name == 'issue_comment' &&
contains(github.event.comment.body, '@claude') &&
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)
) || ...
|
||
| if: | | ||
| (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || | ||
| (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || | ||
| (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || | ||
| (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| pull-requests: read | ||
| issues: read | ||
| id-token: write | ||
| actions: read # Required for Claude to read CI results on PRs | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 1 | ||
|
|
||
| - name: Run Claude Code | ||
| id: claude | ||
| uses: anthropics/claude-code-action@v1 | ||
| with: | ||
| claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | ||
|
|
||
| # This is an optional setting that allows Claude to read CI results on PRs | ||
| additional_permissions: | | ||
| actions: read | ||
| # Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it. | ||
| # prompt: 'Update the pull request description to include a summary of changes.' | ||
|
|
||
| # Optional: Add claude_args to customize behavior and configuration | ||
| # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md | ||
| # or https://code.claude.com/docs/en/cli-reference for available options | ||
| # claude_args: '--allowed-tools Bash(gh pr *)' | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BLOCKING — Fork PRs fail hard instead of skipping gracefully.
pull_requestfires for fork PRs. Secrets are (correctly) withheld by GitHub, so there's no security leak. But the job still runs and fails at thecreate-github-app-tokenstep becausesecrets.CLOSEDLOOP_APP_ID_STAGEis empty. This creates a red X check on every fork PR.If branch protection requires this check to pass, fork PRs become unmergeable. Even without branch protection, it's confusing UX.
Fix — graceful skip for forks:
Fork PRs would then skip this job entirely (green skip, not red failure). Fork reviews would only happen via
workflow_dispatchby a collaborator.