Skip to content

Commit 022e6fe

Browse files
committed
Update Claude Code Action to enhance input options and streamline prompt extraction from GitHub context. Remove redundant GitHub token and MCP installation steps in workflow for improved clarity and efficiency.
1 parent 5d07d7d commit 022e6fe

File tree

2 files changed

+192
-105
lines changed

2 files changed

+192
-105
lines changed

.github/actions/claude-code-action/action.yml

Lines changed: 192 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,61 @@ name: "Claude Code Action"
22
description: "Run Claude Code in GitHub Actions workflows"
33

44
inputs:
5-
github_token:
6-
description: "GitHub token with repo and issues permissions"
7-
required: true
85
anthropic_api_key:
96
description: "Anthropic API key"
10-
required: true
11-
prompt:
12-
description: "The prompt to send to Claude Code"
7+
required: false
8+
github_token:
9+
description: "GitHub token for Claude to operate with"
10+
required: false
11+
default: ${{ github.token }}
12+
trigger_phrase:
13+
description: "The trigger phrase to look for in comments, issue/PR bodies, and issue titles"
14+
required: false
15+
default: "@claude"
16+
assignee_trigger:
17+
description: "The assignee username that triggers the action (e.g. @claude). Only used for issue assignment"
18+
required: false
19+
max_turns:
20+
description: "Maximum number of conversation turns Claude can take"
21+
required: false
22+
timeout_minutes:
23+
description: "Timeout in minutes for execution"
24+
required: false
25+
default: "30"
26+
model:
27+
description: "Model to use (provider-specific format required for Bedrock/Vertex)"
28+
required: false
29+
use_bedrock:
30+
description: "Use Amazon Bedrock with OIDC authentication instead of direct Anthropic API"
31+
required: false
32+
default: "false"
33+
use_vertex:
34+
description: "Use Google Vertex AI with OIDC authentication instead of direct Anthropic API"
35+
required: false
36+
default: "false"
37+
allowed_tools:
38+
description: "Additional tools for Claude to use (the base GitHub tools will always be included)"
1339
required: false
1440
default: ""
15-
prompt_file:
16-
description: "Path to a file containing the prompt to send to Claude Code"
41+
disallowed_tools:
42+
description: "Tools that Claude should never use"
1743
required: false
1844
default: ""
19-
allowed_tools:
20-
description: "Comma-separated list of allowed tools for Claude Code to use"
45+
custom_instructions:
46+
description: "Additional custom instructions to include in the prompt for Claude"
2147
required: false
2248
default: ""
23-
output_file:
24-
description: "File to save Claude Code output to (optional)"
49+
mcp_config:
50+
description: "Additional MCP configuration (JSON string) that merges with the built-in GitHub MCP servers"
2551
required: false
2652
default: ""
27-
timeout_minutes:
28-
description: "Timeout in minutes for Claude Code execution"
53+
claude_env:
54+
description: "Custom environment variables to pass to Claude Code execution (YAML format)"
2955
required: false
30-
default: "10"
31-
install_github_mcp:
32-
description: "Whether to install the GitHub MCP server"
56+
default: ""
57+
direct_prompt:
58+
description: "Direct prompt for Claude to execute automatically without needing a trigger (for automated workflows)"
3359
required: false
34-
default: "false"
3560

3661
runs:
3762
using: "composite"
@@ -41,7 +66,6 @@ runs:
4166
run: npm install -g @anthropic-ai/claude-code
4267

4368
- name: Install GitHub MCP Server
44-
if: inputs.install_github_mcp == 'true'
4569
shell: bash
4670
run: |
4771
claude mcp add-json github '{
@@ -59,106 +83,171 @@ runs:
5983
}
6084
}'
6185
62-
- name: Prepare Prompt File
86+
- name: Extract GitHub Context and Create Prompt
6387
shell: bash
64-
id: prepare_prompt
88+
id: prepare_context
6589
run: |
66-
# If neither prompt nor prompt_file is provided, auto-generate from GitHub context
67-
if [ -z "${{ inputs.prompt }}" ] && [ -z "${{ inputs.prompt_file }}" ]; then
68-
echo "Auto-generating prompt from GitHub context..."
69-
mkdir -p /tmp/claude-action
70-
71-
# Extract the user's request from the GitHub event (mimicking official behavior)
72-
if [[ "${{ github.event_name }}" == "issue_comment" ]]; then
73-
PROMPT_TEXT="${{ github.event.comment.body }}"
74-
CONTEXT="Issue Comment on: ${{ github.event.issue.title }}"
75-
elif [[ "${{ github.event_name }}" == "pull_request_review_comment" ]]; then
76-
PROMPT_TEXT="${{ github.event.comment.body }}"
77-
CONTEXT="PR Comment on: ${{ github.event.pull_request.title }}"
78-
elif [[ "${{ github.event_name }}" == "pull_request_review" ]]; then
79-
PROMPT_TEXT="${{ github.event.review.body }}"
80-
CONTEXT="PR Review on: ${{ github.event.pull_request.title }}"
81-
elif [[ "${{ github.event_name }}" == "issues" ]]; then
82-
PROMPT_TEXT="${{ github.event.issue.body }}"
83-
CONTEXT="Issue: ${{ github.event.issue.title }}"
84-
else
85-
PROMPT_TEXT="Help with this repository"
86-
CONTEXT="Repository assistance requested"
90+
echo "🔍 Extracting GitHub context from event: ${{ github.event_name }}"
91+
92+
# Function to check for trigger phrase
93+
check_trigger() {
94+
local text="$1"
95+
local trigger="${{ inputs.trigger_phrase }}"
96+
if [[ "$text" == *"$trigger"* ]]; then
97+
return 0
8798
fi
88-
89-
# Create GitHub context prompt (similar to official action)
90-
cat > /tmp/claude-action/github-context-prompt.txt << EOF
99+
return 1
100+
}
101+
102+
# Extract context based on event type
103+
TRIGGER_FOUND="false"
104+
USER_REQUEST=""
105+
CONTEXT_INFO=""
106+
107+
case "${{ github.event_name }}" in
108+
"issue_comment")
109+
COMMENT_BODY="${{ github.event.comment.body }}"
110+
ISSUE_TITLE="${{ github.event.issue.title }}"
111+
ISSUE_NUMBER="${{ github.event.issue.number }}"
112+
113+
if check_trigger "$COMMENT_BODY"; then
114+
TRIGGER_FOUND="true"
115+
USER_REQUEST="$COMMENT_BODY"
116+
CONTEXT_INFO="Issue Comment on #$ISSUE_NUMBER: $ISSUE_TITLE"
117+
fi
118+
;;
119+
120+
"pull_request_review_comment")
121+
COMMENT_BODY="${{ github.event.comment.body }}"
122+
PR_TITLE="${{ github.event.pull_request.title }}"
123+
PR_NUMBER="${{ github.event.pull_request.number }}"
124+
125+
if check_trigger "$COMMENT_BODY"; then
126+
TRIGGER_FOUND="true"
127+
USER_REQUEST="$COMMENT_BODY"
128+
CONTEXT_INFO="PR Comment on #$PR_NUMBER: $PR_TITLE"
129+
fi
130+
;;
131+
132+
"pull_request_review")
133+
REVIEW_BODY="${{ github.event.review.body }}"
134+
PR_TITLE="${{ github.event.pull_request.title }}"
135+
PR_NUMBER="${{ github.event.pull_request.number }}"
136+
137+
if check_trigger "$REVIEW_BODY"; then
138+
TRIGGER_FOUND="true"
139+
USER_REQUEST="$REVIEW_BODY"
140+
CONTEXT_INFO="PR Review on #$PR_NUMBER: $PR_TITLE"
141+
fi
142+
;;
143+
144+
"issues")
145+
ISSUE_BODY="${{ github.event.issue.body }}"
146+
ISSUE_TITLE="${{ github.event.issue.title }}"
147+
ISSUE_NUMBER="${{ github.event.issue.number }}"
148+
149+
if check_trigger "$ISSUE_TITLE" || check_trigger "$ISSUE_BODY"; then
150+
TRIGGER_FOUND="true"
151+
USER_REQUEST="$ISSUE_BODY"
152+
CONTEXT_INFO="Issue #$ISSUE_NUMBER: $ISSUE_TITLE"
153+
elif [[ "${{ github.event.action }}" == "assigned" && -n "${{ inputs.assignee_trigger }}" ]]; then
154+
ASSIGNEE="${{ github.event.assignee.login }}"
155+
if [[ "$ASSIGNEE" == "${{ inputs.assignee_trigger }}" ]]; then
156+
TRIGGER_FOUND="true"
157+
USER_REQUEST="$ISSUE_BODY"
158+
CONTEXT_INFO="Issue #$ISSUE_NUMBER assigned to $ASSIGNEE: $ISSUE_TITLE"
159+
fi
160+
fi
161+
;;
162+
esac
163+
164+
# Check for direct prompt override
165+
if [[ -n "${{ inputs.direct_prompt }}" ]]; then
166+
TRIGGER_FOUND="true"
167+
USER_REQUEST="${{ inputs.direct_prompt }}"
168+
CONTEXT_INFO="Automated GitHub workflow"
169+
fi
170+
171+
if [[ "$TRIGGER_FOUND" != "true" ]]; then
172+
echo "❌ No trigger phrase found or direct prompt provided. Exiting gracefully."
173+
echo "SKIP_EXECUTION=true" >> $GITHUB_ENV
174+
exit 0
175+
fi
176+
177+
echo "✅ Trigger found! Context: $CONTEXT_INFO"
178+
179+
# Create comprehensive prompt
180+
mkdir -p /tmp/claude-action
181+
cat > /tmp/claude-action/github-context-prompt.txt << EOF
91182
You are Claude Code, an AI assistant helping with GitHub workflows and code.
92183
93184
Repository: ${{ github.repository }}
94-
Context: $CONTEXT
185+
Context: $CONTEXT_INFO
186+
Event: ${{ github.event_name }}
95187
96188
User Request:
97-
$PROMPT_TEXT
189+
$USER_REQUEST
190+
191+
Please analyze the request and provide helpful assistance. You have access to repository tools and can help with:
192+
- Code analysis and implementation
193+
- GitHub workflows and automation
194+
- Pull request reviews and feedback
195+
- Issue resolution and bug fixes
196+
- Documentation updates
197+
- Testing and deployment
98198
99-
Please analyze the request and provide helpful assistance. You have access to repository tools and can help with code analysis, implementations, and GitHub workflows.
199+
Respond naturally and helpfully to the user's request using the available tools.
100200
EOF
101-
102-
PROMPT_PATH="/tmp/claude-action/github-context-prompt.txt"
103-
elif [ ! -z "${{ inputs.prompt_file }}" ]; then
104-
# Check if the prompt file exists
105-
if [ ! -f "${{ inputs.prompt_file }}" ]; then
106-
echo "::error::Prompt file '${{ inputs.prompt_file }}' does not exist."
107-
exit 1
108-
fi
109-
PROMPT_PATH="${{ inputs.prompt_file }}"
110-
else
111-
mkdir -p /tmp/claude-action
112-
PROMPT_PATH="/tmp/claude-action/prompt.txt"
113-
echo "${{ inputs.prompt }}" > "$PROMPT_PATH"
114-
fi
115-
116-
# Verify the prompt file is not empty
117-
if [ ! -s "$PROMPT_PATH" ]; then
118-
echo "::error::Prompt is empty. Please provide a non-empty prompt."
119-
exit 1
120-
fi
121-
122-
# Save the prompt path for the next step
123-
echo "PROMPT_PATH=$PROMPT_PATH" >> $GITHUB_ENV
201+
202+
echo "PROMPT_FILE=/tmp/claude-action/github-context-prompt.txt" >> $GITHUB_ENV
203+
echo "SKIP_EXECUTION=false" >> $GITHUB_ENV
124204
125205
- name: Run Claude Code
206+
if: env.SKIP_EXECUTION != 'true'
126207
shell: bash
127-
id: run_claude
128208
run: |
129-
ALLOWED_TOOLS_ARG=""
130-
if [ ! -z "${{ inputs.allowed_tools }}" ]; then
131-
ALLOWED_TOOLS_ARG="--allowedTools ${{ inputs.allowed_tools }}"
209+
echo "🚀 Running Claude Code with GitHub context..."
210+
211+
# Build command arguments
212+
CMD_ARGS=("-p" "--verbose" "--output-format" "stream-json")
213+
214+
# Add timeout if specified
215+
if [[ -n "${{ inputs.timeout_minutes }}" ]]; then
216+
CMD_ARGS+=("--timeout" "${{ inputs.timeout_minutes }}m")
132217
fi
133-
134-
# Set a timeout to ensure the command doesn't run indefinitely
135-
timeout_seconds=$((${{ inputs.timeout_minutes }} * 60))
136-
137-
if [ -z "${{ inputs.output_file }}" ]; then
138-
# Run Claude Code and output to console
139-
timeout $timeout_seconds claude \
140-
-p \
141-
--verbose \
142-
--output-format stream-json \
143-
"$(cat ${{ env.PROMPT_PATH }})" \
144-
${{ inputs.allowed_tools != '' && format('--allowedTools "{0}"', inputs.allowed_tools) || '' }}
145-
else
146-
# Run Claude Code and tee output to console and file
147-
timeout $timeout_seconds claude \
148-
-p \
149-
--verbose \
150-
--output-format stream-json \
151-
"$(cat ${{ env.PROMPT_PATH }})" \
152-
${{ inputs.allowed_tools != '' && format('--allowedTools "{0}"', inputs.allowed_tools) || '' }} | tee output.txt
153-
154-
# Process output.txt into JSON in a separate step
155-
jq -s '.' output.txt > output.json
156-
157-
# Extract the result from the last item in the array (system message)
158-
jq -r '.[-1].result' output.json > "${{ inputs.output_file }}"
159-
160-
echo "Complete output saved to output.json, final response saved to ${{ inputs.output_file }}"
218+
219+
# Add max turns if specified
220+
if [[ -n "${{ inputs.max_turns }}" ]]; then
221+
CMD_ARGS+=("--max-turns" "${{ inputs.max_turns }}")
222+
fi
223+
224+
# Add allowed tools (include GitHub tools by default)
225+
TOOLS="mcp__github__get_issue,mcp__github__get_issue_comments,mcp__github__update_issue,mcp__github__search_issues,mcp__github__list_issues,mcp__github__create_comment,Read,Write,Edit,Bash"
226+
if [[ -n "${{ inputs.allowed_tools }}" ]]; then
227+
TOOLS="$TOOLS,${{ inputs.allowed_tools }}"
228+
fi
229+
CMD_ARGS+=("--allowedTools" "$TOOLS")
230+
231+
# Add disallowed tools
232+
if [[ -n "${{ inputs.disallowed_tools }}" ]]; then
233+
CMD_ARGS+=("--disallowedTools" "${{ inputs.disallowed_tools }}")
161234
fi
235+
236+
# Add custom instructions
237+
if [[ -n "${{ inputs.custom_instructions }}" ]]; then
238+
CMD_ARGS+=("--custom-instructions" "${{ inputs.custom_instructions }}")
239+
fi
240+
241+
# Read the prompt content
242+
PROMPT_CONTENT=$(cat "${{ env.PROMPT_FILE }}")
243+
244+
echo "📝 Executing: claude ${CMD_ARGS[*]} \"[prompt content]\""
245+
246+
# Execute Claude Code with timeout
247+
TIMEOUT_SECONDS=$((${{ inputs.timeout_minutes }} * 60))
248+
timeout $TIMEOUT_SECONDS claude "${CMD_ARGS[@]}" "$PROMPT_CONTENT"
249+
250+
echo "✅ Claude Code execution completed"
162251
env:
163252
ANTHROPIC_API_KEY: ${{ inputs.anthropic_api_key }}
164253
GITHUB_TOKEN: ${{ inputs.github_token }}

.github/workflows/claude.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,4 @@ jobs:
3434
uses: ./.github/actions/claude-code-action
3535
with:
3636
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
37-
github_token: ${{ secrets.GITHUB_TOKEN }}
38-
install_github_mcp: "true"
3937

0 commit comments

Comments
 (0)