Compare commits

..

2 Commits

Author SHA1 Message Date
claude[bot]
853107da75 docs: add claude_env input documentation with clear syntax examples
Added comprehensive documentation for the new claude_env input including:
- Entry in the Inputs table with description
- Example in the basic workflow configuration
- Detailed section in Advanced Configuration with practical use cases

This makes it clear how users can pass custom environment variables
to Claude Code execution in YAML format for CI/test setups.

Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com>
2025-06-02 20:49:22 -07:00
claude[bot]
39c280bfdb feat: add claude_env input for custom environment variables
Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com>
2025-06-02 20:49:21 -07:00
19 changed files with 101 additions and 250 deletions

View File

@@ -29,4 +29,4 @@ jobs:
Be constructive and specific in your feedback. Give inline comments where applicable.
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
allowed_tools: "mcp__github__create_pending_pull_request_review,mcp__github__add_pull_request_review_comment_to_pending_review,mcp__github__submit_pending_pull_request_review,mcp__github__get_pull_request_diff"
allowed_tools: "mcp__github__add_pull_request_review_comment"

View File

@@ -23,20 +23,18 @@ jobs:
mkdir -p /tmp/mcp-config
cat > /tmp/mcp-config/mcp-servers.json << 'EOF'
{
"mcpServers": {
"github": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server:sha-7aced2b"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}"
}
"github": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server:sha-7aced2b"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}"
}
}
}

View File

@@ -70,8 +70,6 @@ jobs:
# NODE_ENV: test
# DEBUG: true
# API_URL: https://api.example.com
# Optional: limit the number of conversation turns
# max_turns: "5"
```
## Inputs
@@ -80,7 +78,6 @@ jobs:
| --------------------- | -------------------------------------------------------------------------------------------------------------------- | -------- | --------- |
| `anthropic_api_key` | Anthropic API key (required for direct API, not needed for Bedrock/Vertex) | No\* | - |
| `direct_prompt` | Direct prompt for Claude to execute automatically without needing a trigger (for automated workflows) | No | - |
| `max_turns` | Maximum number of conversation turns Claude can take (limits back-and-forth exchanges) | No | - |
| `timeout_minutes` | Timeout in minutes for execution | No | `30` |
| `github_token` | GitHub token for Claude to operate with. **Only include this if you're connecting a custom GitHub app of your own!** | No | - |
| `model` | Model to use (provider-specific format required for Bedrock/Vertex) | No | - |
@@ -314,24 +311,6 @@ You can pass custom environment variables to Claude Code execution using the `cl
The `claude_env` input accepts YAML format where each line defines a key-value pair. These environment variables will be available to Claude Code during execution, allowing it to run tests, build processes, or other commands that depend on specific environment configurations.
### Limiting Conversation Turns
You can use the `max_turns` parameter to limit the number of back-and-forth exchanges Claude can have during task execution. This is useful for:
- Controlling costs by preventing runaway conversations
- Setting time boundaries for automated workflows
- Ensuring predictable behavior in CI/CD pipelines
```yaml
- uses: anthropics/claude-code-action@beta
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
max_turns: "5" # Limit to 5 conversation turns
# ... other inputs
```
When the turn limit is reached, Claude will stop execution gracefully. Choose a value that gives Claude enough turns to complete typical tasks while preventing excessive usage.
### Custom Tools
By default, Claude only has access to:

View File

@@ -1,20 +0,0 @@
# Claude Code GitHub Action Roadmap
Thank you for trying out the beta of our GitHub Action! This document outlines our path to `v1.0`. Items are not necessarily in priority order.
## Path to 1.0
- **Ability to see GitHub Action CI results** - This will enable Claude to look at CI failures and make updates to PRs to fix test failures, lint errors, and the like.
- **Cross-repo support** - Enable Claude to work across multiple repositories in a single session
- **Ability to modify workflow files** - Let Claude update GitHub Actions workflows and other CI configuration files
- **Support for workflow_dispatch and repository_dispatch events** - Dispatch Claude on events triggered via API from other workflows or from other services
- **Ability to disable commit signing** - Option to turn off GPG signing for environments where it's not required. This will enable Claude to use normal `git` bash commands for committing. This will likely become the default behavior once added.
- **Better code review behavior** - Support inline comments on specific lines, provide higher quality reviews with more actionable feedback
- **Support triggering @claude from bot users** - Allow automation and bot accounts to invoke Claude
- **Customizable base prompts** - Full control over Claude's initial context with template variables like `$PR_COMMENTS`, `$PR_FILES`, etc. Users can replace our default prompt entirely while still accessing key contextual data
---
**Note:** This roadmap represents our current vision for reaching `v1.0` and is subject to change based on user feedback and development priorities.
We welcome feedback on these planned features! If you're interested in contributing to any of these features, please open an issue to discuss implementation details with us. We're also open to suggestions for new features not listed here.

View File

@@ -62,10 +62,6 @@ inputs:
required: false
default: "false"
max_turns:
description: "Maximum number of conversation turns"
required: false
default: ""
timeout_minutes:
description: "Timeout in minutes for execution"
required: false
@@ -87,20 +83,19 @@ runs:
- name: Install Dependencies
shell: bash
run: |
cd ${GITHUB_ACTION_PATH}
cd ${{ github.action_path }}
bun install
- name: Prepare action
id: prepare
shell: bash
run: |
bun run ${GITHUB_ACTION_PATH}/src/entrypoints/prepare.ts
bun run ${{ github.action_path }}/src/entrypoints/prepare.ts
env:
TRIGGER_PHRASE: ${{ inputs.trigger_phrase }}
ASSIGNEE_TRIGGER: ${{ inputs.assignee_trigger }}
BASE_BRANCH: ${{ inputs.base_branch }}
ALLOWED_TOOLS: ${{ inputs.allowed_tools }}
DISALLOWED_TOOLS: ${{ inputs.disallowed_tools }}
CUSTOM_INSTRUCTIONS: ${{ inputs.custom_instructions }}
DIRECT_PROMPT: ${{ inputs.direct_prompt }}
MCP_CONFIG: ${{ inputs.mcp_config }}
@@ -110,13 +105,12 @@ runs:
- name: Run Claude Code
id: claude-code
if: steps.prepare.outputs.contains_trigger == 'true'
uses: anthropics/claude-code-base-action@a0d79f9c1798b06292dbc80f8f95cf742ce7a213 # v0.0.14
uses: anthropics/claude-code-base-action@c8e31bd52d9a149b3f8309d7978c6edaa282688d # v0.0.8
with:
prompt_file: ${{ runner.temp }}/claude-prompts/claude-prompt.txt
prompt_file: /tmp/claude-prompts/claude-prompt.txt
allowed_tools: ${{ env.ALLOWED_TOOLS }}
disallowed_tools: ${{ env.DISALLOWED_TOOLS }}
timeout_minutes: ${{ inputs.timeout_minutes }}
max_turns: ${{ inputs.max_turns }}
model: ${{ inputs.model || inputs.anthropic_model }}
mcp_config: ${{ steps.prepare.outputs.mcp_config }}
use_bedrock: ${{ inputs.use_bedrock }}
@@ -153,7 +147,7 @@ runs:
if: steps.prepare.outputs.contains_trigger == 'true' && steps.prepare.outputs.claude_comment_id && always()
shell: bash
run: |
bun run ${GITHUB_ACTION_PATH}/src/entrypoints/update-comment-link.ts
bun run ${{ github.action_path }}/src/entrypoints/update-comment-link.ts
env:
REPOSITORY: ${{ github.repository }}
PR_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }}

View File

@@ -2,7 +2,7 @@
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "@anthropic-ai/claude-code-action",
"name": "claude-pr-action",
"dependencies": {
"@actions/core": "^1.10.1",
"@actions/github": "^6.0.1",

View File

@@ -35,4 +35,4 @@ jobs:
Provide constructive feedback with specific suggestions for improvement.
Use inline comments to highlight specific areas of concern.
# allowed_tools: "mcp__github__create_pending_pull_request_review,mcp__github__add_pull_request_review_comment_to_pending_review,mcp__github__submit_pending_pull_request_review,mcp__github__get_pull_request_diff"
# allowed_tools: "mcp__github__add_pull_request_review_comment"

View File

@@ -1,5 +1,5 @@
{
"name": "@anthropic-ai/claude-code-action",
"name": "claude-pr-action",
"version": "1.0.0",
"private": true,
"scripts": {

View File

@@ -35,35 +35,38 @@ const BASE_ALLOWED_TOOLS = [
];
const DISALLOWED_TOOLS = ["WebSearch", "WebFetch"];
export function buildAllowedToolsString(customAllowedTools?: string[]): string {
export function buildAllowedToolsString(customAllowedTools?: string): string {
let baseTools = [...BASE_ALLOWED_TOOLS];
let allAllowedTools = baseTools.join(",");
if (customAllowedTools && customAllowedTools.length > 0) {
allAllowedTools = `${allAllowedTools},${customAllowedTools.join(",")}`;
if (customAllowedTools) {
allAllowedTools = `${allAllowedTools},${customAllowedTools}`;
}
return allAllowedTools;
}
export function buildDisallowedToolsString(
customDisallowedTools?: string[],
allowedTools?: string[],
customDisallowedTools?: string,
allowedTools?: string,
): string {
let disallowedTools = [...DISALLOWED_TOOLS];
// If user has explicitly allowed some hardcoded disallowed tools, remove them from disallowed list
if (allowedTools && allowedTools.length > 0) {
if (allowedTools) {
const allowedToolsArray = allowedTools
.split(",")
.map((tool) => tool.trim());
disallowedTools = disallowedTools.filter(
(tool) => !allowedTools.includes(tool),
(tool) => !allowedToolsArray.includes(tool),
);
}
let allDisallowedTools = disallowedTools.join(",");
if (customDisallowedTools && customDisallowedTools.length > 0) {
if (customDisallowedTools) {
if (allDisallowedTools) {
allDisallowedTools = `${allDisallowedTools},${customDisallowedTools.join(",")}`;
allDisallowedTools = `${allDisallowedTools},${customDisallowedTools}`;
} else {
allDisallowedTools = customDisallowedTools.join(",");
allDisallowedTools = customDisallowedTools;
}
}
return allDisallowedTools;
@@ -117,10 +120,8 @@ export function prepareContext(
triggerPhrase,
...(triggerUsername && { triggerUsername }),
...(customInstructions && { customInstructions }),
...(allowedTools.length > 0 && { allowedTools: allowedTools.join(",") }),
...(disallowedTools.length > 0 && {
disallowedTools: disallowedTools.join(","),
}),
...(allowedTools && { allowedTools }),
...(disallowedTools && { disallowedTools }),
...(directPrompt && { directPrompt }),
...(claudeBranch && { claudeBranch }),
};
@@ -620,9 +621,7 @@ export async function createPrompt(
claudeBranch,
);
await mkdir(`${process.env.RUNNER_TEMP}/claude-prompts`, {
recursive: true,
});
await mkdir("/tmp/claude-prompts", { recursive: true });
// Generate the prompt
const promptContent = generatePrompt(preparedContext, githubData);
@@ -633,18 +632,15 @@ export async function createPrompt(
console.log("=======================");
// Write the prompt file
await writeFile(
`${process.env.RUNNER_TEMP}/claude-prompts/claude-prompt.txt`,
promptContent,
);
await writeFile("/tmp/claude-prompts/claude-prompt.txt", promptContent);
// Set allowed tools
const allAllowedTools = buildAllowedToolsString(
context.inputs.allowedTools,
preparedContext.allowedTools,
);
const allDisallowedTools = buildDisallowedToolsString(
context.inputs.disallowedTools,
context.inputs.allowedTools,
preparedContext.disallowedTools,
preparedContext.allowedTools,
);
core.exportVariable("ALLOWED_TOOLS", allAllowedTools);

View File

@@ -92,7 +92,6 @@ async function run() {
branch: branchInfo.currentBranch,
additionalMcpConfig,
claudeCommentId: commentId.toString(),
allowedTools: context.inputs.allowedTools,
});
core.setOutput("mcp_config", mcpConfig);
} catch (error) {

View File

@@ -28,8 +28,8 @@ export type ParsedGitHubContext = {
inputs: {
triggerPhrase: string;
assigneeTrigger: string;
allowedTools: string[];
disallowedTools: string[];
allowedTools: string;
disallowedTools: string;
customInstructions: string;
directPrompt: string;
baseBranch?: string;
@@ -52,14 +52,8 @@ export function parseGitHubContext(): ParsedGitHubContext {
inputs: {
triggerPhrase: process.env.TRIGGER_PHRASE ?? "@claude",
assigneeTrigger: process.env.ASSIGNEE_TRIGGER ?? "",
allowedTools: (process.env.ALLOWED_TOOLS ?? "")
.split(",")
.map((tool) => tool.trim())
.filter((tool) => tool.length > 0),
disallowedTools: (process.env.DISALLOWED_TOOLS ?? "")
.split(",")
.map((tool) => tool.trim())
.filter((tool) => tool.length > 0),
allowedTools: process.env.ALLOWED_TOOLS ?? "",
disallowedTools: process.env.DISALLOWED_TOOLS ?? "",
customInstructions: process.env.CUSTOM_INSTRUCTIONS ?? "",
directPrompt: process.env.DIRECT_PROMPT ?? "",
baseBranch: process.env.BASE_BRANCH,

View File

@@ -1,17 +1,17 @@
import { execSync } from "child_process";
import type { Octokits } from "../api/client";
import { ISSUE_QUERY, PR_QUERY } from "../api/queries/github";
import type {
GitHubPullRequest,
GitHubIssue,
GitHubComment,
GitHubFile,
GitHubIssue,
GitHubPullRequest,
GitHubReview,
IssueQueryResponse,
PullRequestQueryResponse,
IssueQueryResponse,
} from "../types";
import type { CommentWithImages } from "../utils/image-downloader";
import { PR_QUERY, ISSUE_QUERY } from "../api/queries/github";
import type { Octokits } from "../api/client";
import { downloadCommentImages } from "../utils/image-downloader";
import type { CommentWithImages } from "../utils/image-downloader";
type FetchDataParams = {
octokits: Octokits;
@@ -101,14 +101,6 @@ export async function fetchGitHubData({
let changedFilesWithSHA: GitHubFileWithSHA[] = [];
if (isPR && changedFiles.length > 0) {
changedFilesWithSHA = changedFiles.map((file) => {
// Don't compute SHA for deleted files
if (file.changeType === "DELETED") {
return {
...file,
sha: "deleted",
};
}
try {
// Use git hash-object to compute the SHA for the current file content
const sha = execSync(`git hash-object "${file.path}"`, {

View File

@@ -7,7 +7,6 @@ type PrepareConfigParams = {
branch: string;
additionalMcpConfig?: string;
claudeCommentId?: string;
allowedTools: string[];
};
export async function prepareMcpConfig(
@@ -20,17 +19,24 @@ export async function prepareMcpConfig(
branch,
additionalMcpConfig,
claudeCommentId,
allowedTools,
} = params;
try {
const allowedToolsList = allowedTools || [];
const hasGitHubMcpTools = allowedToolsList.some((tool) =>
tool.startsWith("mcp__github__"),
);
const baseMcpConfig: { mcpServers: Record<string, unknown> } = {
const baseMcpConfig = {
mcpServers: {
github: {
command: "docker",
args: [
"run",
"-i",
"--rm",
"-e",
"GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/anthropics/github-mcp-server:sha-7382253",
],
env: {
GITHUB_PERSONAL_ACCESS_TOKEN: githubToken,
},
},
github_file_ops: {
command: "bun",
args: [
@@ -51,23 +57,6 @@ export async function prepareMcpConfig(
},
};
if (hasGitHubMcpTools) {
baseMcpConfig.mcpServers.github = {
command: "docker",
args: [
"run",
"-i",
"--rm",
"-e",
"GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server:sha-e9f748f", // https://github.com/github/github-mcp-server/releases/tag/v0.4.0
],
env: {
GITHUB_PERSONAL_ACCESS_TOKEN: githubToken,
},
};
}
// Merge with additional MCP config if provided
if (additionalMcpConfig && additionalMcpConfig.trim()) {
try {

View File

@@ -652,7 +652,7 @@ describe("buildAllowedToolsString", () => {
});
test("should append custom tools when provided", () => {
const customTools = ["Tool1", "Tool2", "Tool3"];
const customTools = "Tool1,Tool2,Tool3";
const result = buildAllowedToolsString(customTools);
// Base tools should be present
@@ -683,7 +683,7 @@ describe("buildDisallowedToolsString", () => {
});
test("should append custom disallowed tools when provided", () => {
const customDisallowedTools = ["BadTool1", "BadTool2"];
const customDisallowedTools = "BadTool1,BadTool2";
const result = buildDisallowedToolsString(customDisallowedTools);
// Base disallowed tools should be present
@@ -701,8 +701,8 @@ describe("buildDisallowedToolsString", () => {
});
test("should remove hardcoded disallowed tools if they are in allowed tools", () => {
const customDisallowedTools = ["BadTool1", "BadTool2"];
const allowedTools = ["WebSearch", "SomeOtherTool"];
const customDisallowedTools = "BadTool1,BadTool2";
const allowedTools = "WebSearch,SomeOtherTool";
const result = buildDisallowedToolsString(
customDisallowedTools,
allowedTools,
@@ -720,7 +720,7 @@ describe("buildDisallowedToolsString", () => {
});
test("should remove all hardcoded disallowed tools if they are all in allowed tools", () => {
const allowedTools = ["WebSearch", "WebFetch", "SomeOtherTool"];
const allowedTools = "WebSearch,WebFetch,SomeOtherTool";
const result = buildDisallowedToolsString(undefined, allowedTools);
// Both hardcoded disallowed tools should be removed
@@ -732,8 +732,8 @@ describe("buildDisallowedToolsString", () => {
});
test("should handle custom disallowed tools when all hardcoded tools are overridden", () => {
const customDisallowedTools = ["BadTool1", "BadTool2"];
const allowedTools = ["WebSearch", "WebFetch"];
const customDisallowedTools = "BadTool1,BadTool2";
const allowedTools = "WebSearch,WebFetch";
const result = buildDisallowedToolsString(
customDisallowedTools,
allowedTools,

View File

@@ -24,19 +24,21 @@ describe("prepareMcpConfig", () => {
processExitSpy.mockRestore();
});
test("should return base config when no additional config is provided and no allowed_tools", async () => {
test("should return base config when no additional config is provided", async () => {
const result = await prepareMcpConfig({
githubToken: "test-token",
owner: "test-owner",
repo: "test-repo",
branch: "test-branch",
allowedTools: [],
});
const parsed = JSON.parse(result);
expect(parsed.mcpServers).toBeDefined();
expect(parsed.mcpServers.github).not.toBeDefined();
expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined();
expect(parsed.mcpServers.github.env.GITHUB_PERSONAL_ACCESS_TOKEN).toBe(
"test-token",
);
expect(parsed.mcpServers.github_file_ops.env.GITHUB_TOKEN).toBe(
"test-token",
);
@@ -47,60 +49,6 @@ describe("prepareMcpConfig", () => {
);
});
test("should include github MCP server when mcp__github__ tools are allowed", async () => {
const result = await prepareMcpConfig({
githubToken: "test-token",
owner: "test-owner",
repo: "test-repo",
branch: "test-branch",
allowedTools: [
"mcp__github__create_issue",
"mcp__github_file_ops__commit_files",
],
});
const parsed = JSON.parse(result);
expect(parsed.mcpServers).toBeDefined();
expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined();
expect(parsed.mcpServers.github.env.GITHUB_PERSONAL_ACCESS_TOKEN).toBe(
"test-token",
);
});
test("should not include github MCP server when only file_ops tools are allowed", async () => {
const result = await prepareMcpConfig({
githubToken: "test-token",
owner: "test-owner",
repo: "test-repo",
branch: "test-branch",
allowedTools: [
"mcp__github_file_ops__commit_files",
"mcp__github_file_ops__update_claude_comment",
],
});
const parsed = JSON.parse(result);
expect(parsed.mcpServers).toBeDefined();
expect(parsed.mcpServers.github).not.toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined();
});
test("should include file_ops server even when no GitHub tools are allowed", async () => {
const result = await prepareMcpConfig({
githubToken: "test-token",
owner: "test-owner",
repo: "test-repo",
branch: "test-branch",
allowedTools: ["Edit", "Read", "Write"],
});
const parsed = JSON.parse(result);
expect(parsed.mcpServers).toBeDefined();
expect(parsed.mcpServers.github).not.toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined();
});
test("should return base config when additional config is empty string", async () => {
const result = await prepareMcpConfig({
githubToken: "test-token",
@@ -108,12 +56,11 @@ describe("prepareMcpConfig", () => {
repo: "test-repo",
branch: "test-branch",
additionalMcpConfig: "",
allowedTools: [],
});
const parsed = JSON.parse(result);
expect(parsed.mcpServers).toBeDefined();
expect(parsed.mcpServers.github).not.toBeDefined();
expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined();
expect(consoleWarningSpy).not.toHaveBeenCalled();
});
@@ -125,12 +72,11 @@ describe("prepareMcpConfig", () => {
repo: "test-repo",
branch: "test-branch",
additionalMcpConfig: " \n\t ",
allowedTools: [],
});
const parsed = JSON.parse(result);
expect(parsed.mcpServers).toBeDefined();
expect(parsed.mcpServers.github).not.toBeDefined();
expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined();
expect(consoleWarningSpy).not.toHaveBeenCalled();
});
@@ -154,10 +100,6 @@ describe("prepareMcpConfig", () => {
repo: "test-repo",
branch: "test-branch",
additionalMcpConfig: additionalConfig,
allowedTools: [
"mcp__github__create_issue",
"mcp__github_file_ops__commit_files",
],
});
const parsed = JSON.parse(result);
@@ -191,10 +133,6 @@ describe("prepareMcpConfig", () => {
repo: "test-repo",
branch: "test-branch",
additionalMcpConfig: additionalConfig,
allowedTools: [
"mcp__github__create_issue",
"mcp__github_file_ops__commit_files",
],
});
const parsed = JSON.parse(result);
@@ -231,13 +169,12 @@ describe("prepareMcpConfig", () => {
repo: "test-repo",
branch: "test-branch",
additionalMcpConfig: additionalConfig,
allowedTools: [],
});
const parsed = JSON.parse(result);
expect(parsed.customProperty).toBe("custom-value");
expect(parsed.anotherProperty).toEqual({ nested: "value" });
expect(parsed.mcpServers.github).not.toBeDefined();
expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.custom_server).toBeDefined();
});
@@ -250,14 +187,13 @@ describe("prepareMcpConfig", () => {
repo: "test-repo",
branch: "test-branch",
additionalMcpConfig: invalidJson,
allowedTools: [],
});
const parsed = JSON.parse(result);
expect(consoleWarningSpy).toHaveBeenCalledWith(
expect.stringContaining("Failed to parse additional MCP config:"),
);
expect(parsed.mcpServers.github).not.toBeDefined();
expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined();
});
@@ -270,7 +206,6 @@ describe("prepareMcpConfig", () => {
repo: "test-repo",
branch: "test-branch",
additionalMcpConfig: nonObjectJson,
allowedTools: [],
});
const parsed = JSON.parse(result);
@@ -280,7 +215,7 @@ describe("prepareMcpConfig", () => {
expect(consoleWarningSpy).toHaveBeenCalledWith(
expect.stringContaining("MCP config must be a valid JSON object"),
);
expect(parsed.mcpServers.github).not.toBeDefined();
expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined();
});
@@ -293,7 +228,6 @@ describe("prepareMcpConfig", () => {
repo: "test-repo",
branch: "test-branch",
additionalMcpConfig: nullJson,
allowedTools: [],
});
const parsed = JSON.parse(result);
@@ -303,7 +237,7 @@ describe("prepareMcpConfig", () => {
expect(consoleWarningSpy).toHaveBeenCalledWith(
expect.stringContaining("MCP config must be a valid JSON object"),
);
expect(parsed.mcpServers.github).not.toBeDefined();
expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined();
});
@@ -316,7 +250,6 @@ describe("prepareMcpConfig", () => {
repo: "test-repo",
branch: "test-branch",
additionalMcpConfig: arrayJson,
allowedTools: [],
});
const parsed = JSON.parse(result);
@@ -325,7 +258,7 @@ describe("prepareMcpConfig", () => {
expect(consoleInfoSpy).toHaveBeenCalledWith(
"Merging additional MCP server configuration with built-in servers",
);
expect(parsed.mcpServers.github).not.toBeDefined();
expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined();
// The array will be spread into the config (0: 1, 1: 2, 2: 3)
expect(parsed[0]).toBe(1);
@@ -362,13 +295,12 @@ describe("prepareMcpConfig", () => {
repo: "test-repo",
branch: "test-branch",
additionalMcpConfig: additionalConfig,
allowedTools: [],
});
const parsed = JSON.parse(result);
expect(parsed.mcpServers.server1).toBeDefined();
expect(parsed.mcpServers.server2).toBeDefined();
expect(parsed.mcpServers.github).not.toBeDefined();
expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.github_file_ops.command).toBe("overridden");
expect(parsed.mcpServers.github_file_ops.env.CUSTOM).toBe("value");
expect(parsed.otherConfig.nested.deeply).toBe("value");
@@ -383,7 +315,6 @@ describe("prepareMcpConfig", () => {
owner: "test-owner",
repo: "test-repo",
branch: "test-branch",
allowedTools: [],
});
const parsed = JSON.parse(result);
@@ -403,7 +334,6 @@ describe("prepareMcpConfig", () => {
owner: "test-owner",
repo: "test-repo",
branch: "test-branch",
allowedTools: [],
});
const parsed = JSON.parse(result);

View File

@@ -11,8 +11,8 @@ const defaultInputs = {
triggerPhrase: "/claude",
assigneeTrigger: "",
anthropicModel: "claude-3-7-sonnet-20250219",
allowedTools: [] as string[],
disallowedTools: [] as string[],
allowedTools: "",
disallowedTools: "",
customInstructions: "",
directPrompt: "",
useBedrock: false,

View File

@@ -62,8 +62,8 @@ describe("checkWritePermissions", () => {
inputs: {
triggerPhrase: "@claude",
assigneeTrigger: "",
allowedTools: [],
disallowedTools: [],
allowedTools: "",
disallowedTools: "",
customInstructions: "",
directPrompt: "",
},

View File

@@ -242,7 +242,7 @@ describe("parseEnvVarsWithContext", () => {
...mockPullRequestCommentContext,
inputs: {
...mockPullRequestCommentContext.inputs,
allowedTools: ["Tool1", "Tool2"],
allowedTools: "Tool1,Tool2",
},
});
const result = prepareContext(contextWithAllowedTools, "12345");

View File

@@ -30,8 +30,8 @@ describe("checkContainsTrigger", () => {
triggerPhrase: "/claude",
assigneeTrigger: "",
directPrompt: "Fix the bug in the login form",
allowedTools: [],
disallowedTools: [],
allowedTools: "",
disallowedTools: "",
customInstructions: "",
},
});
@@ -56,8 +56,8 @@ describe("checkContainsTrigger", () => {
triggerPhrase: "/claude",
assigneeTrigger: "",
directPrompt: "",
allowedTools: [],
disallowedTools: [],
allowedTools: "",
disallowedTools: "",
customInstructions: "",
},
});
@@ -228,8 +228,8 @@ describe("checkContainsTrigger", () => {
triggerPhrase: "@claude",
assigneeTrigger: "",
directPrompt: "",
allowedTools: [],
disallowedTools: [],
allowedTools: "",
disallowedTools: "",
customInstructions: "",
},
});
@@ -255,8 +255,8 @@ describe("checkContainsTrigger", () => {
triggerPhrase: "@claude",
assigneeTrigger: "",
directPrompt: "",
allowedTools: [],
disallowedTools: [],
allowedTools: "",
disallowedTools: "",
customInstructions: "",
},
});
@@ -282,8 +282,8 @@ describe("checkContainsTrigger", () => {
triggerPhrase: "@claude",
assigneeTrigger: "",
directPrompt: "",
allowedTools: [],
disallowedTools: [],
allowedTools: "",
disallowedTools: "",
customInstructions: "",
},
});