mirror of
https://github.com/anthropics/claude-code.git
synced 2025-10-19 03:17:50 +03:00
Merge pull request #794 from anthropics/ashwin/triageaction
Add GitHub workflow for issue triage with available labels
This commit is contained in:
136
.github/actions/claude-code-action/action.yml
vendored
Normal file
136
.github/actions/claude-code-action/action.yml
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
name: "Claude Code Action"
|
||||
description: "Run Claude Code in GitHub Actions workflows"
|
||||
|
||||
inputs:
|
||||
github_token:
|
||||
description: "GitHub token with repo and issues permissions"
|
||||
required: true
|
||||
anthropic_api_key:
|
||||
description: "Anthropic API key"
|
||||
required: true
|
||||
prompt:
|
||||
description: "The prompt to send to Claude Code"
|
||||
required: false
|
||||
default: ""
|
||||
prompt_file:
|
||||
description: "Path to a file containing the prompt to send to Claude Code"
|
||||
required: false
|
||||
default: ""
|
||||
allowed_tools:
|
||||
description: "Comma-separated list of allowed tools for Claude Code to use"
|
||||
required: false
|
||||
default: ""
|
||||
output_file:
|
||||
description: "File to save Claude Code output to (optional)"
|
||||
required: false
|
||||
default: ""
|
||||
timeout_minutes:
|
||||
description: "Timeout in minutes for Claude Code execution"
|
||||
required: false
|
||||
default: "10"
|
||||
install_github_mcp:
|
||||
description: "Whether to install the GitHub MCP server"
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Install Claude Code
|
||||
shell: bash
|
||||
run: npm install -g @anthropic-ai/claude-code
|
||||
|
||||
- name: Install GitHub MCP Server
|
||||
if: inputs.install_github_mcp == 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
claude mcp add-json github '{
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
"-i",
|
||||
"--rm",
|
||||
"-e",
|
||||
"GITHUB_PERSONAL_ACCESS_TOKEN",
|
||||
"ghcr.io/github/github-mcp-server:sha-ff3036d"
|
||||
],
|
||||
"env": {
|
||||
"GITHUB_PERSONAL_ACCESS_TOKEN": "${{ inputs.GITHUB_TOKEN }}"
|
||||
}
|
||||
}'
|
||||
|
||||
- name: Prepare Prompt File
|
||||
shell: bash
|
||||
id: prepare_prompt
|
||||
run: |
|
||||
# Check if either prompt or prompt_file is provided
|
||||
if [ -z "${{ inputs.prompt }}" ] && [ -z "${{ inputs.prompt_file }}" ]; then
|
||||
echo "::error::Neither 'prompt' nor 'prompt_file' was provided. At least one is required."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Determine which prompt source to use
|
||||
if [ ! -z "${{ inputs.prompt_file }}" ]; then
|
||||
# Check if the prompt file exists
|
||||
if [ ! -f "${{ inputs.prompt_file }}" ]; then
|
||||
echo "::error::Prompt file '${{ inputs.prompt_file }}' does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Use the provided prompt file
|
||||
PROMPT_PATH="${{ inputs.prompt_file }}"
|
||||
else
|
||||
mkdir -p /tmp/claude-action
|
||||
PROMPT_PATH="/tmp/claude-action/prompt.txt"
|
||||
echo "${{ inputs.prompt }}" > "$PROMPT_PATH"
|
||||
fi
|
||||
|
||||
# Verify the prompt file is not empty
|
||||
if [ ! -s "$PROMPT_PATH" ]; then
|
||||
echo "::error::Prompt is empty. Please provide a non-empty prompt."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Save the prompt path for the next step
|
||||
echo "PROMPT_PATH=$PROMPT_PATH" >> $GITHUB_ENV
|
||||
|
||||
- name: Run Claude Code
|
||||
shell: bash
|
||||
id: run_claude
|
||||
run: |
|
||||
ALLOWED_TOOLS_ARG=""
|
||||
if [ ! -z "${{ inputs.allowed_tools }}" ]; then
|
||||
ALLOWED_TOOLS_ARG="--allowedTools ${{ inputs.allowed_tools }}"
|
||||
fi
|
||||
|
||||
# Set a timeout to ensure the command doesn't run indefinitely
|
||||
timeout_seconds=$((${{ inputs.timeout_minutes }} * 60))
|
||||
|
||||
if [ -z "${{ inputs.output_file }}" ]; then
|
||||
# Run Claude Code and output to console
|
||||
timeout $timeout_seconds claude \
|
||||
-p \
|
||||
--verbose \
|
||||
--output-format stream-json \
|
||||
"$(cat ${{ env.PROMPT_PATH }})" \
|
||||
${{ inputs.allowed_tools != '' && format('--allowedTools "{0}"', inputs.allowed_tools) || '' }}
|
||||
else
|
||||
# Run Claude Code and tee output to console and file
|
||||
timeout $timeout_seconds claude \
|
||||
-p \
|
||||
--verbose \
|
||||
--output-format stream-json \
|
||||
"$(cat ${{ env.PROMPT_PATH }})" \
|
||||
${{ inputs.allowed_tools != '' && format('--allowedTools "{0}"', inputs.allowed_tools) || '' }} | tee output.txt
|
||||
|
||||
# Process output.txt into JSON in a separate step
|
||||
jq -s '.' output.txt > output.json
|
||||
|
||||
# Extract the result from the last item in the array (system message)
|
||||
jq -r '.[-1].result' output.json > "${{ inputs.output_file }}"
|
||||
|
||||
echo "Complete output saved to output.json, final response saved to ${{ inputs.output_file }}"
|
||||
fi
|
||||
env:
|
||||
ANTHROPIC_API_KEY: ${{ inputs.anthropic_api_key }}
|
||||
GITHUB_TOKEN: ${{ inputs.github_token }}
|
||||
87
.github/actions/claude-issue-triage-action/action.yml
vendored
Normal file
87
.github/actions/claude-issue-triage-action/action.yml
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
name: "Claude Issue Triage Action"
|
||||
description: "Automatically triage GitHub issues using Claude Code"
|
||||
|
||||
inputs:
|
||||
timeout_minutes:
|
||||
description: "Timeout in minutes for execution"
|
||||
required: false
|
||||
default: "5"
|
||||
anthropic_api_key:
|
||||
description: "Anthropic API key"
|
||||
required: true
|
||||
github_token:
|
||||
description: "GitHub token with repo and issues permissions"
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Checkout repository code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Create prompt file
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p /tmp/claude-prompts
|
||||
cat > /tmp/claude-prompts/claude-issue-triage-prompt.txt << 'EOF'
|
||||
You're an issue triage assistant for GitHub issues. Your task is to analyze the issue and select appropriate labels from the provided list.
|
||||
|
||||
IMPORTANT: Don't post any comments or messages to the issue. Your only action should be to apply labels.
|
||||
|
||||
Issue Information:
|
||||
- REPO: ${{ github.repository }}
|
||||
- ISSUE_NUMBER: ${{ github.event.issue.number }}
|
||||
|
||||
TASK OVERVIEW:
|
||||
|
||||
1. First, fetch the list of labels available in this repository by running: `gh label list`. Run exactly this command with nothing else.
|
||||
|
||||
2. Next, use the GitHub tools to get context about the issue:
|
||||
- You have access to these tools:
|
||||
- mcp__github__get_issue: Use this to retrieve the current issue's details including title, description, and existing labels
|
||||
- mcp__github__get_issue_comments: Use this to read any discussion or additional context provided in the comments
|
||||
- mcp__github__update_issue: Use this to apply labels to the issue (do not use this for commenting)
|
||||
- mcp__github__search_issues: Use this to find similar issues that might provide context for proper categorization and to identify potential duplicate issues
|
||||
- mcp__github__list_issues: Use this to understand patterns in how other issues are labeled
|
||||
- Start by using mcp__github__get_issue to get the issue details
|
||||
|
||||
3. Analyze the issue content, considering:
|
||||
- The issue title and description
|
||||
- The type of issue (bug report, feature request, question, etc.)
|
||||
- Technical areas mentioned
|
||||
- Severity or priority indicators
|
||||
- User impact
|
||||
- Components affected
|
||||
|
||||
4. Select appropriate labels from the available labels list provided above:
|
||||
- Choose labels that accurately reflect the issue's nature
|
||||
- Be specific but comprehensive
|
||||
- Select priority labels if you can determine urgency (high-priority, med-priority, or low-priority)
|
||||
- Consider platform labels (android, ios) if applicable
|
||||
- If you find similar issues using mcp__github__search_issues, consider using a "duplicate" label if appropriate. Only do so if the issue is a duplicate of another OPEN issue.
|
||||
|
||||
5. Apply the selected labels:
|
||||
- Use mcp__github__update_issue to apply your selected labels
|
||||
- DO NOT post any comments explaining your decision
|
||||
- DO NOT communicate directly with users
|
||||
- If no labels are clearly applicable, do not apply any labels
|
||||
|
||||
IMPORTANT GUIDELINES:
|
||||
- Be thorough in your analysis
|
||||
- Only select labels from the provided list above
|
||||
- DO NOT post any comments to the issue
|
||||
- Your ONLY action should be to apply labels using mcp__github__update_issue
|
||||
- It's okay to not add any labels if none are clearly applicable
|
||||
EOF
|
||||
|
||||
- name: Run Claude Code
|
||||
uses: ./.github/actions/claude-code-action
|
||||
with:
|
||||
prompt_file: /tmp/claude-prompts/claude-issue-triage-prompt.txt
|
||||
allowed_tools: "Bash(gh label list),mcp__github__get_issue,mcp__github__get_issue_comments,mcp__github__update_issue,mcp__github__search_issues,mcp__github__list_issues"
|
||||
install_github_mcp: "true"
|
||||
timeout_minutes: ${{ inputs.timeout_minutes }}
|
||||
anthropic_api_key: ${{ inputs.anthropic_api_key }}
|
||||
github_token: ${{ inputs.github_token }}
|
||||
23
.github/workflows/claude-issue-triage.yml
vendored
Normal file
23
.github/workflows/claude-issue-triage.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: Claude Issue Triage
|
||||
description: "Automatically triage GitHub issues using Claude Code"
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
triage-issue:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run Claude Issue Triage
|
||||
uses: ./.github/actions/claude-issue-triage-action
|
||||
with:
|
||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
Reference in New Issue
Block a user