diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fe2e9bf..d854c71 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,16 @@ on: push: branches: [main] pull_request: + types: [opened, ready_for_review] + issue_comment: + types: [created] + +permissions: + contents: read + pull-requests: write + checks: write + id-token: write + actions: read jobs: pre-commit: @@ -20,3 +30,27 @@ jobs: - name: Run pre-commit uses: pre-commit/action@v3.0.1 + + code-review-auto: + name: Code Review (Auto) + needs: [pre-commit] + if: | + github.event_name == 'pull_request' && + github.event.pull_request.draft == false + uses: ./.github/workflows/code-review.yml + with: + trigger_type: auto + secrets: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + + code-review-manual: + name: Code Review (Manual) + if: | + github.event_name == 'issue_comment' && + github.event.issue.pull_request && + contains(github.event.comment.body, '/review') + uses: ./.github/workflows/code-review.yml + with: + trigger_type: comment + secrets: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} diff --git a/.github/workflows/issue-followup.yml b/.github/workflows/issue-followup.yml new file mode 100644 index 0000000..24f0ee6 --- /dev/null +++ b/.github/workflows/issue-followup.yml @@ -0,0 +1,121 @@ +name: Issue Follow-up + +on: + workflow_call: + inputs: + allowed_tools: + description: 'Comma-separated list of allowed tools for Claude' + type: string + required: false + default: + 'Read,Write,Edit,Grep,Glob,LS,Bash(git:*),Bash(gh + pr:*),Bash(npm:*),Bash(bun:*),mcp__linear__*' + prompt: + description: + 'Custom prompt to override the default follow-up behavior (leave empty + for default)' + type: string + required: false + default: '' + secrets: + claude_code_oauth_token: + description: 'Claude Code OAuth token' + required: true + linear_api_token: + description: 'Linear API token' + required: true + + repository_dispatch: + types: [linear-followup] + +permissions: + contents: write + pull-requests: write + issues: write + id-token: write + +jobs: + followup: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Process Follow-up + uses: anthropics/claude-code-action@v1 + env: + LINEAR_API_TOKEN: + ${{ secrets.linear_api_token || secrets.LINEAR_API_TOKEN }} + with: + claude_code_oauth_token: + ${{ secrets.claude_code_oauth_token || + secrets.CLAUDE_CODE_OAUTH_TOKEN }} + github_token: ${{ secrets.GITHUB_TOKEN }} + track_progress: true + settings: | + { + "mcpServers": { + "linear": { + "command": "npx", + "args": ["-y", "@tacticlaunch/mcp-linear"] + } + } + } + claude_args: + --allowedTools "${{ inputs.allowed_tools || + github.event.client_payload.allowed_tools || + 'Read,Write,Edit,Grep,Glob,LS,Bash(git:*),Bash(gh + pr:*),Bash(npm:*),Bash(bun:*),mcp__linear__*' }}" + prompt: | + ${{ inputs.prompt || github.event.client_payload.prompt || format('**Linear Issue Follow-up** + + Issue: {0} + Issue ID: {1} + Title: {2} + + The user has sent you a follow-up message: + + --- + {3} + --- + + ## Instructions + + ### 1. Understand the Context + - Use Linear MCP to fetch the full issue details for {1} + - Review the issue description, previous comments, and any existing work + - Check if there are any open PRs related to this issue + + ### 2. Process the Request + Based on what the user is asking, take the appropriate action: + + **If they are asking a question:** + - Research the codebase to find the answer + - Provide a clear, helpful response + + **If they want code changes:** + - Make the requested changes + - If there is an existing PR, update it + - If not, create a new branch and PR + + **If they want to update an existing PR:** + - Find the existing PR for this issue + - Make the requested changes on that branch + - Push the updates + + **If they are providing feedback:** + - Acknowledge the feedback + - Make any necessary adjustments + + ### 3. Respond via Linear + - Add a comment to the Linear ticket with your response + - Include any relevant details (code changes made, PR links, answers to questions) + - Be concise but thorough + + Be helpful and responsive. Focus on what the user is asking.', + github.event.client_payload.issue_url, + github.event.client_payload.issue_id, + github.event.client_payload.issue_title, + github.event.client_payload.user_prompt) }} diff --git a/.github/workflows/issue-implement.yml b/.github/workflows/issue-implement.yml new file mode 100644 index 0000000..560a435 --- /dev/null +++ b/.github/workflows/issue-implement.yml @@ -0,0 +1,111 @@ +name: Issue Implementation + +on: + workflow_call: + inputs: + allowed_tools: + description: 'Comma-separated list of allowed tools for Claude' + type: string + required: false + default: + 'Read,Write,Edit,Grep,Glob,LS,Bash(git:*),Bash(gh + pr:*),Bash(npm:*),Bash(bun:*),mcp__linear__*' + prompt: + description: + 'Custom prompt to override the default implementation behavior (leave + empty for default)' + type: string + required: false + default: '' + secrets: + claude_code_oauth_token: + description: 'Claude Code OAuth token' + required: true + linear_api_token: + description: 'Linear API token' + required: true + + repository_dispatch: + types: [linear-implement] + +permissions: + contents: write + pull-requests: write + issues: write + id-token: write + +jobs: + implement: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Implement Issue + uses: anthropics/claude-code-action@v1 + env: + LINEAR_API_TOKEN: + ${{ secrets.linear_api_token || secrets.LINEAR_API_TOKEN }} + with: + claude_code_oauth_token: + ${{ secrets.claude_code_oauth_token || + secrets.CLAUDE_CODE_OAUTH_TOKEN }} + github_token: ${{ secrets.GITHUB_TOKEN }} + track_progress: true + settings: | + { + "mcpServers": { + "linear": { + "command": "npx", + "args": ["-y", "@tacticlaunch/mcp-linear"] + } + } + } + claude_args: + --allowedTools "${{ inputs.allowed_tools || + github.event.client_payload.allowed_tools || + 'Read,Write,Edit,Grep,Glob,LS,Bash(git:*),Bash(gh + pr:*),Bash(npm:*),Bash(bun:*),mcp__linear__*' }}" + prompt: | + ${{ inputs.prompt || github.event.client_payload.prompt || format('**Linear Issue Implementation Task** + + A Linear issue needs implementation: {0} + Issue ID: {1} + Title: {2} + + ## Your Tasks + + ### 1. Fetch Issue Details + - Use Linear MCP to fetch the full issue details for {1} + - Review the issue description, acceptance criteria, and any comments + + ### 2. Understand the Codebase + - Search for related code, components, or existing implementations + - Identify the files that need to be modified or created + - Understand the existing patterns and conventions + + ### 3. Implement the Feature/Fix + - Create a new branch for this work (use git) + - Implement the changes following existing code patterns + - Write clean, well-structured code + - Add or update tests as appropriate + - Ensure the code compiles and tests pass + + ### 4. Create Pull Request + - Commit your changes with a clear commit message + - Push the branch and create a pull request using gh cli + - Include a description of the changes and link to the Linear issue + + ### 5. Update Linear Ticket + - Add a comment to the Linear ticket with: + - Link to the pull request + - Summary of changes made + - Any notes for reviewers + - Update the ticket status to "In Review" + + Be thorough but efficient. Follow existing code conventions.', + github.event.client_payload.url, + github.event.client_payload.issue_id, + github.event.client_payload.title) }} diff --git a/.github/workflows/issue-triage.yml b/.github/workflows/issue-triage.yml index 647d526..a8bf281 100644 --- a/.github/workflows/issue-triage.yml +++ b/.github/workflows/issue-triage.yml @@ -3,12 +3,6 @@ name: Issue Triage on: workflow_call: inputs: - linear_team_prefix: - description: - 'Linear team prefix for ticket references (e.g., "PROJ" for PROJ-123)' - type: string - required: false - default: '' allowed_tools: description: 'Comma-separated list of allowed tools for Claude' type: string @@ -30,6 +24,9 @@ on: description: 'Linear API token' required: true + repository_dispatch: + types: [linear-triage] + permissions: contents: read pull-requests: read @@ -48,9 +45,12 @@ jobs: - name: Triage Issue uses: anthropics/claude-code-action@v1 env: - LINEAR_API_TOKEN: ${{ secrets.linear_api_token }} + LINEAR_API_TOKEN: + ${{ secrets.linear_api_token || secrets.LINEAR_API_TOKEN }} with: - claude_code_oauth_token: ${{ secrets.claude_code_oauth_token }} + claude_code_oauth_token: + ${{ secrets.claude_code_oauth_token || + secrets.CLAUDE_CODE_OAUTH_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }} track_progress: true settings: | @@ -62,53 +62,41 @@ jobs: } } } - claude_args: --allowedTools "${{ inputs.allowed_tools }}" + claude_args: + --allowedTools "${{ inputs.allowed_tools || + github.event.client_payload.allowed_tools || + 'Read,Grep,Glob,LS,Bash(gh issue:*),Bash(gh label:*),mcp__linear__*' + }}" prompt: | - ${{ inputs.prompt || format('**Issue Triage Task** + ${{ inputs.prompt || github.event.client_payload.prompt || format('**Linear Issue Triage Task** - A new GitHub issue has been created. Linear is the source of truth for all tickets. + A Linear issue needs triage: {0} + Issue ID: {1} + Title: {2} ## Your Tasks - ### 1. Understand the Request - - Read the issue title and description - - Identify type: bug, feature, enhancement, or question - - Determine scope and complexity + ### 1. Fetch Issue Details + - Use Linear MCP to fetch the full issue details for {1} + - Review the issue description, labels, and current status ### 2. Research the Codebase - Search for related code, components, or existing implementations - Identify files that would likely need changes - Check for similar functionality - ### 3. Ask Clarifying Questions (if needed) - - If vague or missing key info, ask specific questions - - For bugs: request reproduction steps, expected vs actual behavior - - For features: clarify acceptance criteria - - ### 4. Apply Labels - Use `gh label list` to see available labels, then apply appropriate ones: - ```bash - gh issue edit $ISSUE_NUMBER --add-label "bug" --add-label "priority:high" - ``` - - ### 5. Linear Integration - Check if this issue is already linked to a Linear ticket (look for {0}-XXX in the issue body or comments). - - **If NO Linear ticket exists:** - - Use the Linear MCP tools to create a new ticket - - Link it back to this GitHub issue - - Add a comment with the Linear ticket ID (e.g., "Created Linear ticket: {0}-123") - - **If a Linear ticket already exists:** - - Fetch the ticket details using Linear MCP - - Update the GitHub issue with any additional context from Linear - - ### 6. Provide Analysis Summary - Comment with: - - Your understanding of the request + ### 3. Update Linear Ticket + Update the Linear ticket with your analysis: - Files/components likely involved - Complexity estimate (small/medium/large) - Any dependencies or blockers - - Linear ticket reference + - Implementation suggestions or approach + + ### 4. Update Ticket Status + - Move the ticket from Triage to the appropriate next status + - Add any relevant labels if needed - Be concise and actionable.', inputs.linear_team_prefix) }} + Be concise and actionable.', + github.event.client_payload.url, + github.event.client_payload.issue_id, + github.event.client_payload.title) }} diff --git a/CLAUDE.md b/CLAUDE.md index 39b9dd1..51aa4a5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -49,9 +49,9 @@ Each workflow defines: for triage) - `permissions` - GitHub token scopes needed -The `issue-triage.yml` workflow has conditional steps based on `enable_linear` -and `prompt` inputs to handle four combinations: with/without Linear, -with/without custom prompt. +The `issue-triage.yml` workflow is triggered via `repository_dispatch` (type: +`linear-triage`) for Linear webhook integration. It uses the `format()` function +to inject `client_payload` fields (issue_id, url, title) into the prompt. The `code-review.yml` workflow includes additional `actions/github-script` steps for check run management and emoji reactions. diff --git a/README.md b/README.md index 011db3e..a95c2ad 100644 --- a/README.md +++ b/README.md @@ -60,25 +60,42 @@ jobs: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} ``` -### With Issue Triage +### With Linear Issue Triage (Repository Dispatch) + +Trigger issue triage from Linear webhooks via repository dispatch: ```yaml -name: Claude Code +name: Linear Issue Triage on: - issues: - types: [opened] + repository_dispatch: + types: [linear-triage] jobs: triage: 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 }} linear_api_token: ${{ secrets.LINEAR_API_KEY }} ``` +To trigger, send a POST request to GitHub's repository dispatch API: + +```bash +curl -X POST \ + -H "Authorization: token $GITHUB_TOKEN" \ + -H "Accept: application/vnd.github.v3+json" \ + https://api.github.com/repos/OWNER/REPO/dispatches \ + -d '{ + "event_type": "linear-triage", + "client_payload": { + "issue_id": "PROJ-123", + "url": "https://linear.app/team/issue/PROJ-123", + "title": "Issue title" + } + }' +``` + ### With Manual Code Review Triggered by `/review` comment on a PR: @@ -160,15 +177,28 @@ permissions: ### issue-triage.yml -Automated issue triage with Linear integration. +Automated Linear issue triage via repository dispatch. + +#### Triggers + +- `repository_dispatch` with type `linear-triage` +- `workflow_call` for reusable workflow usage #### 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) | +| Input | Type | Default | Description | +| --------------- | ------ | -------------------------------------------------------------------- | --------------------------------- | +| `allowed_tools` | string | `Read,Grep,Glob,LS,Bash(gh issue:*),Bash(gh label:*),mcp__linear__*` | Comma-separated list of tools | +| `prompt` | string | `''` | Custom prompt (overrides default) | + +#### Repository Dispatch Payload + +| Field | Required | Description | +| ---------- | -------- | ---------------------------------- | +| `issue_id` | Yes | Linear issue ID (e.g., `PROJ-123`) | +| `url` | Yes | Linear issue URL | +| `title` | Yes | Linear issue title | +| `prompt` | No | Custom prompt override | #### Secrets @@ -191,13 +221,11 @@ permissions: When no custom `prompt` is provided, the workflow: -1. Analyzes the issue title and description -2. Identifies the issue type (bug, feature, enhancement, question) -3. Researches related code in the repository -4. Asks clarifying questions if needed -5. Applies appropriate labels -6. Creates/links Linear tickets -7. Posts an analysis summary +1. Fetches full issue details from Linear via MCP +2. Researches related code in the repository +3. Updates the Linear ticket with analysis (files involved, complexity, + implementation suggestions) +4. Moves the ticket from Triage to the appropriate status --- @@ -264,27 +292,25 @@ on: types: [created] pull_request_review_comment: types: [created] - issues: - types: [opened, labeled] pull_request_review: types: [submitted] + repository_dispatch: + types: [linear-triage] jobs: # General Claude agent for comments claude: if: | - !contains(github.event.comment.body, '/review') && - github.event_name != 'issues' + github.event_name != 'repository_dispatch' && + !contains(github.event.comment.body, '/review') uses: zaks-io/claude-code-action/.github/workflows/claude.yml@main secrets: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - # Issue triage on new issues + # Issue triage via repository dispatch (triggered by Linear webhook) triage: - if: github.event_name == 'issues' && github.event.action == 'opened' + if: github.event_name == 'repository_dispatch' 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 }} linear_api_token: ${{ secrets.LINEAR_API_KEY }}