From e50ddd8113123a1ce5b8fa4fff4ce95f25d84baf Mon Sep 17 00:00:00 2001 From: Isaac Suttell Date: Sun, 7 Dec 2025 12:05:17 -0800 Subject: [PATCH 1/4] refactor: consolidate reaction steps in code-review workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merge "React on success" and "React on failure" steps into a single "React to completion" step that uses job.status to determine the emoji. Also includes: - Add trigger_type input for auto vs comment-triggered reviews - Add gh run list to allowed tools - Update README with auto-trigger documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .github/workflows/code-review.yml | 31 ++++---- README.md | 119 ++++++++++++++++-------------- 2 files changed, 78 insertions(+), 72 deletions(-) diff --git a/.github/workflows/code-review.yml b/.github/workflows/code-review.yml index fa46f1b..2c22e2d 100644 --- a/.github/workflows/code-review.yml +++ b/.github/workflows/code-review.yml @@ -3,13 +3,20 @@ name: Code Review on: workflow_call: inputs: + trigger_type: + description: + 'How the review was triggered: "comment" for /review command, "auto" + for PR open/ready' + type: string + required: false + default: 'comment' allowed_tools: description: 'Comma-separated list of allowed tools for Claude' type: string required: false default: 'Read,Grep,Glob,LS,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr - view:*),Bash(gh run view:*)' + view:*),Bash(gh run list:*),Bash(gh run view:*)' prompt: description: 'Custom prompt to override the default review behavior (leave empty @@ -37,6 +44,7 @@ jobs: runs-on: ubuntu-latest steps: - name: React to comment + if: inputs.trigger_type == 'comment' uses: actions/github-script@v7 with: script: | @@ -203,7 +211,7 @@ jobs: Be witty and engaging.' }} - name: Complete check run - if: always() + if: always() && inputs.trigger_type == 'comment' uses: actions/github-script@v7 with: script: | @@ -220,26 +228,15 @@ jobs: completed_at: new Date().toISOString() }); - - name: React on success - if: success() - uses: actions/github-script@v7 - with: - script: | - await github.rest.reactions.createForIssueComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: context.payload.comment.id, - content: 'rocket' - }); - - - name: React on failure - if: failure() + - name: React to completion + if: always() && inputs.trigger_type == 'comment' uses: actions/github-script@v7 with: script: | + const emoji = '${{ job.status }}' === 'success' ? 'rocket' : 'confused'; await github.rest.reactions.createForIssueComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: context.payload.comment.id, - content: 'confused' + content: emoji }); diff --git a/README.md b/README.md index 9800571..6d7fa26 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,8 @@ repositories. | Workflow | Description | | ------------------ | ------------------------------------------------------- | | `claude.yml` | General-purpose Claude Code agent for issue/PR comments | -| `issue-triage.yml` | Automated issue triage with optional Linear integration | -| `code-review.yml` | Manual code review triggered by `/review` comment | +| `issue-triage.yml` | Automated issue triage with Linear integration | +| `code-review.yml` | Code review (manual `/review` or automatic on PR open) | ## Prerequisites @@ -53,7 +53,7 @@ on: jobs: claude: - uses: zaks-io/claude-code-action/.github/workflows/claude.yml@v1 + uses: zaks-io/claude-code-action/.github/workflows/claude.yml@main secrets: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }} @@ -70,48 +70,59 @@ on: jobs: triage: - uses: zaks-io/claude-code-action/.github/workflows/issue-triage.yml@v1 + uses: zaks-io/claude-code-action/.github/workflows/issue-triage.yml@main + with: + linear_team_prefix: 'PROJ' secrets: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }} + linear_api_token: ${{ secrets.LINEAR_API_KEY }} ``` -### With Linear Integration +### With Manual Code Review + +Triggered by `/review` comment on a PR: ```yaml name: Claude Code on: - issues: - types: [opened] + issue_comment: + types: [created] jobs: - triage: - uses: zaks-io/claude-code-action/.github/workflows/issue-triage.yml@v1 - with: - enable_linear: true - linear_team_prefix: 'PROJ' + review: + if: | + github.event.issue.pull_request && + contains(github.event.comment.body, '/review') + uses: zaks-io/claude-code-action/.github/workflows/code-review.yml@main secrets: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }} - linear_api_token: ${{ secrets.LINEAR_API_KEY }} ``` -### With Code Review +### With Automatic Code Review + +Triggered automatically on PR open/ready (use in CI pipeline): ```yaml -name: Claude Code +name: CI on: - issue_comment: - types: [created] + pull_request: + types: [opened, ready_for_review] jobs: - review: + # ... your other CI jobs ... + + code-review: + needs: [lint, test, build] if: | - github.event.issue.pull_request && - contains(github.event.comment.body, '/review') - uses: zaks-io/claude-code-action/.github/workflows/code-review.yml@v1 + github.event.pull_request.draft == false && + github.event.pull_request.auto_merge == null + uses: zaks-io/claude-code-action/.github/workflows/code-review.yml@main + with: + trigger_type: auto secrets: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }} @@ -152,24 +163,23 @@ permissions: ### issue-triage.yml -Automated issue triage with optional Linear integration. +Automated issue triage with Linear integration. #### Inputs -| Input | Type | Default | Description | -| -------------------- | ------- | -------------------------------------------------------------------- | ------------------------------------------------ | -| `linear_team_prefix` | string | `''` | Linear team prefix (e.g., `PROJ` for `PROJ-123`) | -| `allowed_tools` | string | `Read,Grep,Glob,LS,Bash(gh issue:*),Bash(gh label:*),mcp__linear__*` | Comma-separated list of allowed tools | -| `prompt` | string | `''` | Custom prompt (overrides default) | -| `enable_linear` | boolean | `false` | Enable Linear MCP integration | +| Input | Type | Default | Description | +| -------------------- | ------ | -------------------------------------------------------------------- | ------------------------------------------------ | +| `linear_team_prefix` | string | `''` | Linear team prefix (e.g., `PROJ` for `PROJ-123`) | +| `allowed_tools` | string | `Read,Grep,Glob,LS,Bash(gh issue:*),Bash(gh label:*),mcp__linear__*` | Comma-separated list of allowed tools | +| `prompt` | string | `''` | Custom prompt (overrides default) | #### Secrets -| Secret | Required | Description | -| ------------------------- | -------- | ---------------------------------------------------- | -| `claude_code_oauth_token` | Yes | Claude Code OAuth token | -| `github_token` | Yes | GitHub token | -| `linear_api_token` | No | Linear API token (required if `enable_linear: true`) | +| Secret | Required | Description | +| ------------------------- | -------- | ----------------------- | +| `claude_code_oauth_token` | Yes | Claude Code OAuth token | +| `github_token` | Yes | GitHub token | +| `linear_api_token` | Yes | Linear API token | #### Permissions @@ -190,21 +200,23 @@ When no custom `prompt` is provided, the workflow: 3. Researches related code in the repository 4. Asks clarifying questions if needed 5. Applies appropriate labels -6. Creates/links Linear tickets (if enabled) +6. Creates/links Linear tickets 7. Posts an analysis summary --- ### code-review.yml -Manual code review triggered by `/review` comment on a PR. +Code review workflow supporting both manual (`/review` comment) and automatic +(PR open) triggers. #### Inputs -| Input | Type | Default | Description | -| --------------- | ------ | --------------------------------------------------------------------------------------------------- | ------------------------------------- | -| `allowed_tools` | string | `Read,Grep,Glob,LS,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh run view:*)` | Comma-separated list of allowed tools | -| `prompt` | string | `''` | Custom prompt (overrides default) | +| Input | Type | Default | Description | +| --------------- | ------ | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | +| `trigger_type` | string | `comment` | `comment` for /review command, `auto` for PR open/ready | +| `allowed_tools` | string | `Read,Grep,Glob,LS,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh run list:*),Bash(gh run view:*)` | Comma-separated list of allowed tools | +| `prompt` | string | `''` | Custom prompt (overrides default) | #### Secrets @@ -234,11 +246,16 @@ When no custom `prompt` is provided, the review covers: 4. **Testing** - Coverage, test quality, edge cases 5. **Documentation** - Code docs, README updates, API docs -The workflow also: +**When `trigger_type: comment` (default):** - Creates a "Code Review" check run -- Reacts with eyes emoji on start -- Reacts with rocket (success) or confused (failure) on completion +- Reacts with 👀 emoji on start +- Gathers PR context (workflow runs, check runs) +- Reacts with 🚀 (success) or 😕 (failure) + +**When `trigger_type: auto`:** + +- Runs a streamlined review without comment reactions or check runs ## Complete Example @@ -263,7 +280,7 @@ jobs: if: | !contains(github.event.comment.body, '/review') && github.event_name != 'issues' - uses: zaks-io/claude-code-action/.github/workflows/claude.yml@v1 + uses: zaks-io/claude-code-action/.github/workflows/claude.yml@main secrets: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }} @@ -271,9 +288,8 @@ jobs: # Issue triage on new issues triage: if: github.event_name == 'issues' && github.event.action == 'opened' - uses: zaks-io/claude-code-action/.github/workflows/issue-triage.yml@v1 + uses: zaks-io/claude-code-action/.github/workflows/issue-triage.yml@main with: - enable_linear: true linear_team_prefix: 'PROJ' secrets: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} @@ -286,20 +302,12 @@ jobs: github.event_name == 'issue_comment' && github.event.issue.pull_request && contains(github.event.comment.body, '/review') - uses: zaks-io/claude-code-action/.github/workflows/code-review.yml@v1 + uses: zaks-io/claude-code-action/.github/workflows/code-review.yml@main secrets: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }} ``` -## Versioning - -Reference workflows using: - -- `@v1` - Latest v1.x.x release (recommended for production) -- `@v1.0.0` - Specific version -- `@main` - Latest commit (not recommended for production) - ## Custom Prompts All workflows support custom prompts to override default behavior: @@ -307,7 +315,7 @@ All workflows support custom prompts to override default behavior: ```yaml jobs: triage: - uses: zaks-io/claude-code-action/.github/workflows/issue-triage.yml@v1 + uses: zaks-io/claude-code-action/.github/workflows/issue-triage.yml@main with: prompt: | You are a helpful assistant. Analyze this issue and: @@ -317,6 +325,7 @@ jobs: secrets: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }} + linear_api_token: ${{ secrets.LINEAR_API_KEY }} ``` ## Development From 12d9a22095f4dbed59520636bf27eb592cbff9f7 Mon Sep 17 00:00:00 2001 From: Isaac Suttell Date: Sun, 7 Dec 2025 12:08:26 -0800 Subject: [PATCH 2/4] refactor: use pre-commit for CI checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidate actionlint and prettier checks into a single pre-commit step. This ensures CI uses the same checks as local development. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .github/workflows/ci.yml | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 93bdd76..fe2e9bf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,30 +6,17 @@ on: pull_request: jobs: - lint: - name: Lint Workflows + pre-commit: + name: Pre-commit Checks runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - - name: Run actionlint - uses: reviewdog/action-actionlint@v1 + - name: Setup Python + uses: actions/setup-python@v5 with: - reporter: github-pr-review - fail_level: error + python-version: '3.12' - format: - name: Check Formatting - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22' - - - name: Check formatting - run: npx prettier --check "**/*.{yml,yaml,md}" + - name: Run pre-commit + uses: pre-commit/action@v3.0.1 From 7e90117b4f3bcea2b2d0fce34cfb3e1c6fd98655 Mon Sep 17 00:00:00 2001 From: Isaac Suttell Date: Sun, 7 Dec 2025 12:08:53 -0800 Subject: [PATCH 3/4] docs: update CLAUDE.md to prioritize pre-commit workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- CLAUDE.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index f5c0e97..d0c63a7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -17,18 +17,18 @@ Claude Code into other repositories. It contains three workflows that wrap ## Commands ```bash -# Format YAML and Markdown files -npx prettier --write "**/*.{yml,yaml,md}" +# Setup pre-commit hooks (run once) +pip install pre-commit +pre-commit install -# Check formatting (used in CI) -npx prettier --check "**/*.{yml,yaml,md}" +# Run all checks manually +pre-commit run --all-files # Lint GitHub Actions workflows actionlint -# Setup pre-commit hooks -pip install pre-commit -pre-commit install +# Format YAML and Markdown files +npx prettier --write "**/*.{yml,yaml,md}" ``` ## Architecture From cfb4079dd4c44de0f977211b2d2566bdc592dc15 Mon Sep 17 00:00:00 2001 From: Isaac Suttell Date: Sun, 7 Dec 2025 12:43:24 -0800 Subject: [PATCH 4/4] fix: correct grammar in code review prompt Change 'do not like read' to 'do not like to read' --- .github/workflows/code-review.yml | 150 ++++++++---------------------- 1 file changed, 40 insertions(+), 110 deletions(-) diff --git a/.github/workflows/code-review.yml b/.github/workflows/code-review.yml index 2c22e2d..f5fefb4 100644 --- a/.github/workflows/code-review.yml +++ b/.github/workflows/code-review.yml @@ -60,38 +60,19 @@ jobs: with: fetch-depth: 1 - - name: Gather PR context and create check run - id: context + - name: Create check run + if: inputs.trigger_type == 'comment' + id: check uses: actions/github-script@v7 with: script: | - const prNumber = context.issue.number; - - // Get PR details const pr = await github.rest.pulls.get({ owner: context.repo.owner, repo: context.repo.repo, - pull_number: prNumber - }); - - // Get workflow runs for this PR - const workflowRuns = await github.rest.actions.listWorkflowRunsForRepo({ - owner: context.repo.owner, - repo: context.repo.repo, - branch: pr.data.head.ref, - per_page: 10 + pull_number: context.issue.number }); - // Get check runs for the head commit - const checkRuns = await github.rest.checks.listForRef({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: pr.data.head.sha, - per_page: 100 - }); - - // Create the review check run - const reviewCheck = await github.rest.checks.create({ + const check = await github.rest.checks.create({ owner: context.repo.owner, repo: context.repo.repo, name: 'Code Review', @@ -100,40 +81,7 @@ jobs: started_at: new Date().toISOString() }); - // Format workflow runs for easy reference - const formattedWorkflows = workflowRuns.data.workflow_runs - .filter(run => run.event === 'pull_request' || run.event === 'push') - .map(run => ({ - id: run.id, - name: run.name, - status: run.status, - conclusion: run.conclusion, - html_url: run.html_url, - created_at: run.created_at - })); - - // Format check runs for easy reference - const formattedChecks = checkRuns.data.check_runs.map(check => ({ - id: check.id, - name: check.name, - status: check.status, - conclusion: check.conclusion, - html_url: check.html_url, - started_at: check.started_at - })); - - // Output everything - core.setOutput('check_run_id', reviewCheck.data.id); - core.setOutput('pr_number', prNumber); - core.setOutput('pr_title', pr.data.title); - core.setOutput('pr_author', pr.data.user.login); - core.setOutput('pr_branch', pr.data.head.ref); - core.setOutput('pr_base_branch', pr.data.base.ref); - core.setOutput('pr_head_sha', pr.data.head.sha); - core.setOutput('workflow_runs', JSON.stringify(formattedWorkflows, null, 2)); - core.setOutput('check_runs', JSON.stringify(formattedChecks, null, 2)); - - return reviewCheck.data.id; + core.setOutput('check_run_id', check.data.id); - name: Claude Code Review uses: anthropics/claude-code-action@v1 @@ -143,71 +91,54 @@ jobs: track_progress: true claude_args: --allowedTools "${{ inputs.allowed_tools }}" prompt: | - **PR Context:** - - Repo: ${{ github.repository }} - - PR: #${{ steps.context.outputs.pr_number }} - "${{ steps.context.outputs.pr_title }}" - - Author: ${{ steps.context.outputs.pr_author }} - - Branch: ${{ steps.context.outputs.pr_branch }} -> ${{ steps.context.outputs.pr_base_branch }} - - Head SHA: ${{ steps.context.outputs.pr_head_sha }} - - Check Run ID: ${{ steps.context.outputs.check_run_id }} - - Triggered by: Manual `/review` comment - - **Workflow Runs:** - ```json - ${{ steps.context.outputs.workflow_runs }} - ``` - - **Check Runs:** - ```json - ${{ steps.context.outputs.check_runs }} - ``` - - **Instructions:** - Use the workflow run IDs above with `gh run view --log` to analyze test results. - Use `gh pr diff ${{ steps.context.outputs.pr_number }}` or `gh pr view ${{ steps.context.outputs.pr_number }} --json files` to see changed files. - - ${{ inputs.prompt || 'A PR review has been triggered. Review the current state of the PR - to determine if a review has already occured. If it has, review the - feedback and any changes made since then to see if they address the - feedback of the original review. Your purpose is to continue the - review and not start over. If no review has occured, perform a - comprehensive code review based on the following focus areas: + **Context:** + - Triggered by: ${{ inputs.trigger_type == 'comment' && 'Manual `/review` comment' || 'Automatic (PR opened/ready)' }} + **Task:** + You are Claude, reviewing this PR. Your previous comments may appear as the github-actions[bot] user. + + First, check the existing PR details and review comments to understand what has already been discussed. + If there are previous reviews or feedback, continue from where the conversation left off - address any new changes, + follow up on outstanding items, and avoid repeating points already made. + + Use `gh` CLI to get PR details, check CI status, and view workflow results. + + ${{ inputs.prompt || 'Perform a code review based on the following focus areas: 1. **Code Quality** - Clean code principles and best practices - Proper error handling and edge cases - Code readability and maintainability - - Code follows KISS and DRY principles - - Consistenty with the project style and conventions + - KISS and DRY principles + - Consistency with project style 2. **Security** - - Check for potential security vulnerabilities - - Validate input sanitization - - Review authentication/authorization logic - - Verify no secrets are commited to the repository + - Potential vulnerabilities + - Input sanitization + - Authentication/authorization logic + - No secrets committed 3. **Performance** - - Identify potential performance bottlenecks - - Review database queries for efficiency - - Check for memory leaks or resource issues - - Follows serverless best practices + - Bottlenecks + - Database query efficiency, O(n) vs O(log n) + - Memory leaks or resource issues + - Serverless best practices 4. **Testing & Coverage** - - Verify adequate test coverage - - Review test quality and edge cases - - Check for missing test scenarios - - Analyze workflow run logs using the IDs provided above - - Look for critical coverage regressions or gaps + - Adequate test coverage + - Test quality and edge cases + - Missing test scenarios + - Check CI results with `gh run list` and `gh run view` 5. **Documentation** - - Ensure code is properly documented - - Verify README updates for new features - - Check API documentation accuracy + - Code documentation + - README updates for new features + - API documentation accuracy + + Provide feedback using inline comments for specific issues and top-level comments for general observations. - Provide detailed feedback using inline comments for specific issues. - Use top-level comments for general observations. + Always include a tldr; summary of the review. Remember developers do not like to read. + Responses should be focused on significant improvements, not nitpicks or congratulations. - Be concise and to the point. Do not repeat previous comments. Be witty and engaging.' }} - name: Complete check run @@ -215,8 +146,7 @@ jobs: uses: actions/github-script@v7 with: script: | - const checkId = ${{ steps.context.outputs.check_run_id }}; - + const checkId = ${{ steps.check.outputs.check_run_id }}; const conclusion = '${{ job.status }}' === 'success' ? 'success' : 'failure'; await github.rest.checks.update({