Compare commits

...

8 Commits

Author SHA1 Message Date
GitHub Actions
ebbd9e9be4 chore: update claude-code-base-action to v0.0.24 2025-06-20 21:50:00 +00:00
GitHub Actions
237de9d329 chore: update claude-code-base-action to v0.0.23 2025-06-20 15:38:21 +00:00
Ashwin Bhat
91f620f8c2 docs: remove references to non-existent test-local.sh script (#187)
All tests for this repo can be run with `bun test` - the test-local.sh script was a holdover from the base action repo.

Fixes #172

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Ashwin Bhat <ashwin-ant@users.noreply.github.com>
2025-06-19 07:52:42 -07:00
GitHub Actions
3486c33ebf chore: update claude-code-base-action to v0.0.22 2025-06-17 21:59:57 +00:00
Kuma Taro
13ccdab2f8 fix: correct assignee trigger test to handle different assignee properly (#178)
* fix: use direct assignee field

* fix: correct assignee trigger test to handle different assignee properly

The test was failing because the mockIssueAssignedContext was missing the
top-level assignee field that the trigger validation logic checks. Added
the missing assignee field to the mock context and updated the test to
properly override both the top-level assignee and issue.assignee fields
when testing assignment to a different user.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Adjust IssuesAssignedEvent import position (#2)

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-06-17 10:06:06 -07:00
GitHub Actions
bcf2fe94f8 chore: update claude-code-base-action to v0.0.21 2025-06-17 13:39:54 +00:00
Ashwin Bhat
2dab3f2afe Revert "feat: enhance error reporting with specific error types from Claude e…" (#179)
This reverts commit 1b94b9e5a8.
2025-06-16 16:52:07 -07:00
Ashwin Bhat
1b94b9e5a8 feat: enhance error reporting with specific error types from Claude execution (#164)
* feat: enhance error reporting with specific error types from Claude execution

- Extract error subtypes (error_during_execution, error_max_turns) from result object
- Display specific error messages in comment header based on error type
- Use total_cost_usd field from SDKResultMessage type
- Prevent showing redundant error details when already displayed in header

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* chore: update claude-code-base-action to v0.0.19

* feat: use GitHub display name in Co-authored-by trailers (#163)

* feat: use GitHub display name in Co-authored-by trailers

- Add name field to GitHubAuthor type
- Update GraphQL queries to fetch user display names
- Add triggerDisplayName to CommonFields type
- Extract display name from fetched GitHub data in prepareContext
- Update Co-authored-by trailer generation to use display name when available

This ensures consistency with GitHub's web interface behavior where
Co-authored-by trailers use the user's display name rather than username.

Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com>

* fix: update GraphQL queries to handle Actor type correctly

The name field is only available on the User subtype of Actor in GitHub's
GraphQL API. This commit updates the queries to use inline fragments
(... on User) to conditionally access the name field when the actor is
a User type.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: clarify Co-authored-by instructions in prompt

Replace interpolated values with clear references to XML tags and add
explicit formatting instructions. This makes it clearer how to use the
GitHub display name when available while maintaining the username for
the email portion.

Changes:
- Use explicit references to <trigger_display_name> and <trigger_username> tags
- Add clear formatting instructions and example
- Explain fallback behavior when display name is not available

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: fetch trigger user display name via dedicated GraphQL query

Instead of trying to extract the display name from existing data (which
was incomplete due to Actor type limitations), we now:

- Add a dedicated USER_QUERY to fetch user display names
- Pass the trigger username to fetchGitHubData
- Fetch the display name during data collection phase
- Simplify prepareContext to use the pre-fetched display name

This ensures we always get the correct display name for Co-authored-by
trailers, regardless of where the trigger came from.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>

* feat: use dynamic fetch depth based on PR commit count (#169)

- Replace fixed depth of 20 with dynamic calculation
- Use Math.max(commitCount, 20) to ensure minimum context

* Accept multiline input for allowed_tools and disallowed_tools (#168)

* docs: add uv example for Python MCP servers in mcp_config section (#170)

Added documentation showing how to configure Python-based MCP servers using uv
with the --directory argument, as requested in issue #130.

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Ashwin Bhat <ashwin-ant@users.noreply.github.com>

* feat: add release workflow with beta tag management (#171)

- Auto-increment patch version for new releases
- Update beta tag to point to latest release
- Update major version tag (v0) for simplified action usage
- Support dry run mode for testing
- Keep beta as the "latest" release channel

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude <noreply@anthropic.com>

* chore: update claude-code-base-action to v0.0.20

* update MCP server image to version 0.5.0 (#175)

* refactor: convert error subtype check to switch case

Replace if-else chain with switch statement for better readability
and maintainability when handling error subtypes.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: GitHub Actions <actions@github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com>
Co-authored-by: Bastian Gutschke <bge@medicuja.com>
Co-authored-by: Hidetake Iwata <int128@gmail.com>
Co-authored-by: Tomohiro Ishibashi <103555868+tomoish@users.noreply.github.com>
2025-06-16 15:31:43 -07:00
8 changed files with 214 additions and 24 deletions

View File

@@ -50,20 +50,6 @@ Thank you for your interest in contributing to Claude Code Action! This document
bun test bun test
``` ```
2. **Integration Tests** (using GitHub Actions locally):
```bash
./test-local.sh
```
This script:
- Installs `act` if not present (requires Homebrew on macOS)
- Runs the GitHub Action workflow locally using Docker
- Requires your `ANTHROPIC_API_KEY` to be set
On Apple Silicon Macs, the script automatically adds the `--container-architecture linux/amd64` flag to avoid compatibility issues.
## Pull Request Process ## Pull Request Process
1. Create a new branch from `main`: 1. Create a new branch from `main`:
@@ -103,13 +89,7 @@ Thank you for your interest in contributing to Claude Code Action! This document
When modifying the action: When modifying the action:
1. Test locally with the test script: 1. Test in a real GitHub Actions workflow by:
```bash
./test-local.sh
```
2. Test in a real GitHub Actions workflow by:
- Creating a test repository - Creating a test repository
- Using your branch as the action source: - Using your branch as the action source:
```yaml ```yaml

View File

@@ -110,7 +110,7 @@ runs:
- name: Run Claude Code - name: Run Claude Code
id: claude-code id: claude-code
if: steps.prepare.outputs.contains_trigger == 'true' if: steps.prepare.outputs.contains_trigger == 'true'
uses: anthropics/claude-code-base-action@f481f924b73a7085d9efea0e50a3ba171ed1d74b # v0.0.20 uses: anthropics/claude-code-base-action@f382bd1ea00f26043eb461ebabebe0d850572a71 # v0.0.24
with: with:
prompt_file: ${{ runner.temp }}/claude-prompts/claude-prompt.txt prompt_file: ${{ runner.temp }}/claude-prompts/claude-prompt.txt
allowed_tools: ${{ env.ALLOWED_TOOLS }} allowed_tools: ${{ env.ALLOWED_TOOLS }}

View File

@@ -0,0 +1,73 @@
name: Claude Task Executor
on:
repository_dispatch:
types: [claude-task]
permissions:
contents: write
pull-requests: write
issues: write
id-token: write # Required for OIDC authentication
jobs:
execute-claude-task:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Execute Claude Task
uses: anthropics/claude-code-action@main
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
# Base branch for creating task branches
base_branch: main
# Optional: Custom instructions for Claude
custom_instructions: |
Follow the CLAUDE.md guidelines strictly.
Commit changes with descriptive messages.
# Optional: Tool restrictions
allowed_tools: |
file_editor
bash_command
github_comment
mcp__github__create_or_update_file
# Optional: Anthropic API configuration
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
# Or use AWS Bedrock
# aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }}
# aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
# aws_region: us-east-1
# Or use Google Vertex AI
# google_credentials: ${{ secrets.GOOGLE_CREDENTIALS }}
# vertex_project: my-project
# vertex_location: us-central1
# Example: Triggering this workflow from another service
#
# curl -X POST \
# https://api.github.com/repos/owner/repo/dispatches \
# -H "Authorization: token $GITHUB_TOKEN" \
# -H "Accept: application/vnd.github.v3+json" \
# -d '{
# "event_type": "claude-task",
# "client_payload": {
# "description": "Analyze the codebase and create a comprehensive test suite for the authentication module",
# "progress_endpoint": "https://api.example.com/claude/progress",
# "correlation_id": "task-auth-tests-2024-01-17"
# }
# }'
#
# The progress_endpoint will receive POST requests with:
# {
# "repository": "owner/repo",
# "run_id": "123456789",
# "correlation_id": "task-auth-tests-2024-01-17",
# "status": "in_progress" | "completed" | "failed",
# "message": "Current progress description",
# "completed_tasks": ["task1", "task2"],
# "current_task": "Working on task3",
# "timestamp": "2024-01-17T12:00:00Z"
# }
#
# Authentication: Progress updates include a GitHub OIDC token in the Authorization header

118
pr-summary.md Normal file
View File

@@ -0,0 +1,118 @@
## Summary
Adds support for `repository_dispatch` events, enabling backend services to programmatically trigger Claude to perform tasks and receive progress updates via API.
## Architecture
```mermaid
sequenceDiagram
participant Backend as Backend Service
participant GH as GitHub
participant Action as Claude Action
participant Claude as Claude
participant MCP as Progress MCP Server
participant API as Progress API
Backend->>GH: POST /repos/{owner}/{repo}/dispatches
Note over Backend,GH: Payload includes:<br/>- description (task)<br/>- progress_endpoint<br/>- correlation_id
GH->>Action: Trigger workflow<br/>(repository_dispatch)
Action->>Action: Parse dispatch payload
Note over Action: Extract task description,<br/>endpoint, correlation_id
Action->>MCP: Install Progress Server
Note over MCP: Configure with:<br/>- PROGRESS_ENDPOINT<br/>- CORRELATION_ID<br/>- GITHUB_RUN_ID
Action->>Claude: Execute task with<br/>MCP tools available
loop Task Execution
Claude->>MCP: update_claude_progress()
MCP->>MCP: Get OIDC token
MCP->>API: POST progress update
Note over API: Payload includes:<br/>- correlation_id<br/>- status<br/>- message<br/>- completed_tasks
API->>Backend: Forward update
end
Claude->>Action: Task complete
Action->>GH: Commit changes
```
## Key Features
### 1. Repository Dispatch Support
- New event handler for `repository_dispatch` events
- Extracts task description, progress endpoint, and correlation ID from `client_payload`
- Bypasses GitHub UI interaction for fully programmatic operation
### 2. Progress Reporting MCP Server
- New MCP server (`progress-server.ts`) for sending progress updates
- OIDC authentication for secure API communication
- Includes correlation ID in all updates for request tracking
### 3. Simplified Dispatch Prompts
- Focused instructions for dispatch events (no PR/issue context)
- Clear directives: answer questions or implement changes
- Automatic progress updates at start and completion
## Implementation Details
### Triggering a Dispatch
```bash
curl -X POST \
https://api.github.com/repos/{owner}/{repo}/dispatches \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
-d '{
"event_type": "claude-task",
"client_payload": {
"description": "Implement a new feature that...",
"progress_endpoint": "https://api.example.com/progress",
"correlation_id": "req-123-abc"
}
}'
```
### Progress Update Payload
```json
{
"repository": "owner/repo",
"run_id": "123456789",
"correlation_id": "req-123-abc",
"status": "in_progress",
"message": "Implementing feature...",
"completed_tasks": ["Setup environment", "Created base structure"],
"current_task": "Writing tests",
"timestamp": "2024-01-17T12:00:00Z"
}
```
## Security
- **OIDC Authentication**: All progress updates use GitHub OIDC tokens
- **Correlation IDs**: Included in request body (not URL) for security
- **Endpoint Validation**: Progress endpoint must be explicitly provided
- **No Credential Storage**: Tokens are generated per-request
## Testing
To test the repository_dispatch flow:
1. Configure workflow with `repository_dispatch` trigger
2. Send dispatch event with required payload
3. Monitor GitHub Actions logs for execution
4. Verify progress updates at configured endpoint
## Changes
- Added `repository_dispatch` event handling in `context.ts`
- Created new `progress-server.ts` MCP server
- Updated `isDispatch` flag across all event types
- Modified prompt generation for dispatch events
- Made `githubData` optional for dispatch workflows
- Added correlation ID support throughout the pipeline

View File

@@ -1,6 +1,7 @@
import * as github from "@actions/github"; import * as github from "@actions/github";
import type { import type {
IssuesEvent, IssuesEvent,
IssuesAssignedEvent,
IssueCommentEvent, IssueCommentEvent,
PullRequestEvent, PullRequestEvent,
PullRequestReviewEvent, PullRequestReviewEvent,
@@ -147,3 +148,9 @@ export function isPullRequestReviewCommentEvent(
): context is ParsedGitHubContext & { payload: PullRequestReviewCommentEvent } { ): context is ParsedGitHubContext & { payload: PullRequestReviewCommentEvent } {
return context.eventName === "pull_request_review_comment"; return context.eventName === "pull_request_review_comment";
} }
export function isIssuesAssignedEvent(
context: ParsedGitHubContext,
): context is ParsedGitHubContext & { payload: IssuesAssignedEvent } {
return isIssuesEvent(context) && context.eventAction === "assigned";
}

View File

@@ -3,6 +3,7 @@
import * as core from "@actions/core"; import * as core from "@actions/core";
import { import {
isIssuesEvent, isIssuesEvent,
isIssuesAssignedEvent,
isIssueCommentEvent, isIssueCommentEvent,
isPullRequestEvent, isPullRequestEvent,
isPullRequestReviewEvent, isPullRequestReviewEvent,
@@ -22,10 +23,10 @@ export function checkContainsTrigger(context: ParsedGitHubContext): boolean {
} }
// Check for assignee trigger // Check for assignee trigger
if (isIssuesEvent(context) && context.eventAction === "assigned") { if (isIssuesAssignedEvent(context)) {
// Remove @ symbol from assignee_trigger if present // Remove @ symbol from assignee_trigger if present
let triggerUser = assigneeTrigger.replace(/^@/, ""); let triggerUser = assigneeTrigger.replace(/^@/, "");
const assigneeUsername = context.payload.issue.assignee?.login || ""; const assigneeUsername = context.payload.assignee?.login || "";
if (triggerUser && assigneeUsername === triggerUser) { if (triggerUser && assigneeUsername === triggerUser) {
console.log(`Issue assigned to trigger user '${triggerUser}'`); console.log(`Issue assigned to trigger user '${triggerUser}'`);

View File

@@ -91,6 +91,12 @@ export const mockIssueAssignedContext: ParsedGitHubContext = {
actor: "admin-user", actor: "admin-user",
payload: { payload: {
action: "assigned", action: "assigned",
assignee: {
login: "claude-bot",
id: 11111,
avatar_url: "https://avatars.githubusercontent.com/u/11111",
html_url: "https://github.com/claude-bot",
},
issue: { issue: {
number: 123, number: 123,
title: "Feature: Add dark mode support", title: "Feature: Add dark mode support",

View File

@@ -87,6 +87,11 @@ describe("checkContainsTrigger", () => {
...mockIssueAssignedContext, ...mockIssueAssignedContext,
payload: { payload: {
...mockIssueAssignedContext.payload, ...mockIssueAssignedContext.payload,
assignee: {
...(mockIssueAssignedContext.payload as IssuesAssignedEvent)
.assignee,
login: "otherUser",
},
issue: { issue: {
...(mockIssueAssignedContext.payload as IssuesAssignedEvent).issue, ...(mockIssueAssignedContext.payload as IssuesAssignedEvent).issue,
assignee: { assignee: {