mirror of
https://github.com/anthropics/claude-code-action.git
synced 2026-01-22 22:44:13 +08:00
Merge branch 'main' into v1-dev
Resolved conflicts: - src/modes/agent/index.ts: Kept v1-dev approach (user controls via claude_args) - src/modes/review/index.ts: Kept deleted (review mode removed in v1-dev)
This commit is contained in:
13
README.md
13
README.md
@@ -14,6 +14,19 @@ A general-purpose [Claude Code](https://claude.ai/code) action for GitHub PRs an
|
|||||||
- 📋 **Progress Tracking**: Visual progress indicators with checkboxes that dynamically update as Claude completes tasks
|
- 📋 **Progress Tracking**: Visual progress indicators with checkboxes that dynamically update as Claude completes tasks
|
||||||
- 🏃 **Runs on Your Infrastructure**: The action executes entirely on your own GitHub runner (Anthropic API calls go to your chosen provider)
|
- 🏃 **Runs on Your Infrastructure**: The action executes entirely on your own GitHub runner (Anthropic API calls go to your chosen provider)
|
||||||
|
|
||||||
|
## ⚠️ **BREAKING CHANGES COMING IN v1.0** ⚠️
|
||||||
|
|
||||||
|
**We're planning a major update that will significantly change how this action works.** The new version will:
|
||||||
|
|
||||||
|
- ✨ Automatically select the appropriate mode (no more `mode` input)
|
||||||
|
- 🔧 Simplify configuration with unified `prompt` and `claude_args`
|
||||||
|
- 🚀 Align more closely with the Claude Code SDK capabilities
|
||||||
|
- 💥 Remove multiple inputs like `direct_prompt`, `custom_instructions`, and others
|
||||||
|
|
||||||
|
**[→ Read the full v1.0 roadmap and provide feedback](https://github.com/anthropics/claude-code-action/discussions/428)**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Quickstart
|
## Quickstart
|
||||||
|
|
||||||
The easiest way to set up this action is through [Claude Code](https://claude.ai/code) in the terminal. Just open `claude` and run `/install-github-app`.
|
The easiest way to set up this action is through [Claude Code](https://claude.ai/code) in the terminal. Just open `claude` and run `/install-github-app`.
|
||||||
|
|||||||
@@ -207,15 +207,8 @@ Claude does **not** have access to execute arbitrary Bash commands by default. I
|
|||||||
```yaml
|
```yaml
|
||||||
- uses: anthropics/claude-code-action@beta
|
- uses: anthropics/claude-code-action@beta
|
||||||
with:
|
with:
|
||||||
allowed_tools: |
|
allowed_tools: "Bash(npm install),Bash(npm run test),Edit,Replace,NotebookEditCell"
|
||||||
Bash(npm install)
|
disallowed_tools: "TaskOutput,KillTask"
|
||||||
Bash(npm run test)
|
|
||||||
Edit
|
|
||||||
Replace
|
|
||||||
NotebookEditCell
|
|
||||||
disallowed_tools: |
|
|
||||||
TaskOutput
|
|
||||||
KillTask
|
|
||||||
# ... other inputs
|
# ... other inputs
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,29 @@
|
|||||||
import { describe, test, expect, beforeEach } from "bun:test";
|
import { describe, test, expect, beforeEach, afterEach, spyOn } from "bun:test";
|
||||||
import { agentMode } from "../../src/modes/agent";
|
import { agentMode } from "../../src/modes/agent";
|
||||||
import type { GitHubContext } from "../../src/github/context";
|
import type { GitHubContext } from "../../src/github/context";
|
||||||
import { createMockContext, createMockAutomationContext } from "../mockContext";
|
import { createMockContext, createMockAutomationContext } from "../mockContext";
|
||||||
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
describe("Agent Mode", () => {
|
describe("Agent Mode", () => {
|
||||||
let mockContext: GitHubContext;
|
let mockContext: GitHubContext;
|
||||||
|
let exportVariableSpy: any;
|
||||||
|
let setOutputSpy: any;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockContext = createMockAutomationContext({
|
mockContext = createMockAutomationContext({
|
||||||
eventName: "workflow_dispatch",
|
eventName: "workflow_dispatch",
|
||||||
});
|
});
|
||||||
|
exportVariableSpy = spyOn(core, "exportVariable").mockImplementation(
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
|
setOutputSpy = spyOn(core, "setOutput").mockImplementation(() => {});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
exportVariableSpy?.mockClear();
|
||||||
|
setOutputSpy?.mockClear();
|
||||||
|
exportVariableSpy?.mockRestore();
|
||||||
|
setOutputSpy?.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("agent mode has correct properties", () => {
|
test("agent mode has correct properties", () => {
|
||||||
@@ -80,4 +94,67 @@ describe("Agent Mode", () => {
|
|||||||
expect(agentMode.shouldTrigger(contextWithPrompt)).toBe(true);
|
expect(agentMode.shouldTrigger(contextWithPrompt)).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("prepare method sets up tools environment variables correctly", async () => {
|
||||||
|
// Clear any previous calls before this test
|
||||||
|
exportVariableSpy.mockClear();
|
||||||
|
setOutputSpy.mockClear();
|
||||||
|
|
||||||
|
const contextWithCustomTools = createMockAutomationContext({
|
||||||
|
eventName: "workflow_dispatch",
|
||||||
|
});
|
||||||
|
contextWithCustomTools.inputs.allowedTools = ["CustomTool1", "CustomTool2"];
|
||||||
|
contextWithCustomTools.inputs.disallowedTools = ["BadTool"];
|
||||||
|
|
||||||
|
const mockOctokit = {} as any;
|
||||||
|
const result = await agentMode.prepare({
|
||||||
|
context: contextWithCustomTools,
|
||||||
|
octokit: mockOctokit,
|
||||||
|
githubToken: "test-token",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verify that both ALLOWED_TOOLS and DISALLOWED_TOOLS are set
|
||||||
|
expect(exportVariableSpy).toHaveBeenCalledWith(
|
||||||
|
"ALLOWED_TOOLS",
|
||||||
|
"Edit,MultiEdit,Glob,Grep,LS,Read,Write,CustomTool1,CustomTool2",
|
||||||
|
);
|
||||||
|
expect(exportVariableSpy).toHaveBeenCalledWith(
|
||||||
|
"DISALLOWED_TOOLS",
|
||||||
|
"WebSearch,WebFetch,BadTool",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify MCP config is set
|
||||||
|
expect(setOutputSpy).toHaveBeenCalledWith("mcp_config", expect.any(String));
|
||||||
|
|
||||||
|
// Verify return structure
|
||||||
|
expect(result).toEqual({
|
||||||
|
commentId: undefined,
|
||||||
|
branchInfo: {
|
||||||
|
baseBranch: "",
|
||||||
|
currentBranch: "",
|
||||||
|
claudeBranch: undefined,
|
||||||
|
},
|
||||||
|
mcpConfig: expect.any(String),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("prepare method creates prompt file with correct content", async () => {
|
||||||
|
const contextWithPrompts = createMockAutomationContext({
|
||||||
|
eventName: "workflow_dispatch",
|
||||||
|
});
|
||||||
|
contextWithPrompts.inputs.overridePrompt = "Custom override prompt";
|
||||||
|
contextWithPrompts.inputs.directPrompt =
|
||||||
|
"Direct prompt (should be ignored)";
|
||||||
|
|
||||||
|
const mockOctokit = {} as any;
|
||||||
|
await agentMode.prepare({
|
||||||
|
context: contextWithPrompts,
|
||||||
|
octokit: mockOctokit,
|
||||||
|
githubToken: "test-token",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Note: We can't easily test file creation in this unit test,
|
||||||
|
// but we can verify the method completes without errors
|
||||||
|
expect(setOutputSpy).toHaveBeenCalledWith("mcp_config", expect.any(String));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user