mirror of
https://github.com/anthropics/claude-code-action.git
synced 2026-01-22 22:44:13 +08:00
simplify: remove workflow_dispatch/schedule from create-prompt
- Remove workflow_dispatch and schedule event handling from create-prompt since agent mode doesn't use the standard prompt generation flow - Enforce mode compatibility at selection time in the registry instead of runtime validation in tag mode - Add explanatory comment in agent mode about why prompt file is needed - Update tests to reflect simplified event handling This reduces code duplication and makes the separation between tag mode (entity-based events) and agent mode (automation events) clearer.
This commit is contained in:
@@ -350,24 +350,6 @@ export function prepareContext(
|
|||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "workflow_dispatch":
|
|
||||||
eventData = {
|
|
||||||
eventName: "workflow_dispatch",
|
|
||||||
isPR: false,
|
|
||||||
...(baseBranch && { baseBranch }),
|
|
||||||
...(claudeBranch && { claudeBranch }),
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "schedule":
|
|
||||||
eventData = {
|
|
||||||
eventName: "schedule",
|
|
||||||
isPR: false,
|
|
||||||
...(baseBranch && { baseBranch }),
|
|
||||||
...(claudeBranch && { claudeBranch }),
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported event type: ${eventName}`);
|
throw new Error(`Unsupported event type: ${eventName}`);
|
||||||
}
|
}
|
||||||
@@ -430,18 +412,6 @@ export function getEventTypeAndContext(envVars: PreparedContext): {
|
|||||||
: `pull request event`,
|
: `pull request event`,
|
||||||
};
|
};
|
||||||
|
|
||||||
case "workflow_dispatch":
|
|
||||||
return {
|
|
||||||
eventType: "WORKFLOW_DISPATCH",
|
|
||||||
triggerContext: `workflow dispatch event`,
|
|
||||||
};
|
|
||||||
|
|
||||||
case "schedule":
|
|
||||||
return {
|
|
||||||
eventType: "SCHEDULE",
|
|
||||||
triggerContext: `scheduled automation event`,
|
|
||||||
};
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unexpected event type`);
|
throw new Error(`Unexpected event type`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,20 +88,6 @@ type PullRequestEvent = {
|
|||||||
baseBranch?: string;
|
baseBranch?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type WorkflowDispatchEvent = {
|
|
||||||
eventName: "workflow_dispatch";
|
|
||||||
isPR?: false;
|
|
||||||
baseBranch?: string;
|
|
||||||
claudeBranch?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ScheduleEvent = {
|
|
||||||
eventName: "schedule";
|
|
||||||
isPR?: false;
|
|
||||||
baseBranch?: string;
|
|
||||||
claudeBranch?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Union type for all possible event types
|
// Union type for all possible event types
|
||||||
export type EventData =
|
export type EventData =
|
||||||
| PullRequestReviewCommentEvent
|
| PullRequestReviewCommentEvent
|
||||||
@@ -111,9 +97,7 @@ export type EventData =
|
|||||||
| IssueOpenedEvent
|
| IssueOpenedEvent
|
||||||
| IssueAssignedEvent
|
| IssueAssignedEvent
|
||||||
| IssueLabeledEvent
|
| IssueLabeledEvent
|
||||||
| PullRequestEvent
|
| PullRequestEvent;
|
||||||
| WorkflowDispatchEvent
|
|
||||||
| ScheduleEvent;
|
|
||||||
|
|
||||||
// Combined type with separate eventData field
|
// Combined type with separate eventData field
|
||||||
export type PreparedContext = CommonFields & {
|
export type PreparedContext = CommonFields & {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ async function run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Step 4: Get mode and check trigger conditions
|
// Step 4: Get mode and check trigger conditions
|
||||||
const mode = getMode(context.inputs.mode);
|
const mode = getMode(context.inputs.mode, context);
|
||||||
const containsTrigger = mode.shouldTrigger(context);
|
const containsTrigger = mode.shouldTrigger(context);
|
||||||
|
|
||||||
// Set output for action.yml to check
|
// Set output for action.yml to check
|
||||||
|
|||||||
@@ -53,7 +53,10 @@ export const agentMode: Mode = {
|
|||||||
recursive: true,
|
recursive: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Write the prompt - either override_prompt, direct_prompt, or a minimal default
|
// Write the prompt file - the base action requires a prompt_file parameter,
|
||||||
|
// so we must create this file even though agent mode typically uses
|
||||||
|
// override_prompt or direct_prompt. If neither is provided, we write
|
||||||
|
// a minimal prompt with just the repository information.
|
||||||
const promptContent =
|
const promptContent =
|
||||||
context.inputs.overridePrompt ||
|
context.inputs.overridePrompt ||
|
||||||
context.inputs.directPrompt ||
|
context.inputs.directPrompt ||
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
import type { Mode, ModeName } from "./types";
|
import type { Mode, ModeName } from "./types";
|
||||||
import { tagMode } from "./tag";
|
import { tagMode } from "./tag";
|
||||||
import { agentMode } from "./agent";
|
import { agentMode } from "./agent";
|
||||||
|
import type { ParsedGitHubContext } from "../github/context";
|
||||||
|
|
||||||
export const DEFAULT_MODE = "tag" as const;
|
export const DEFAULT_MODE = "tag" as const;
|
||||||
export const VALID_MODES = ["tag", "agent"] as const;
|
export const VALID_MODES = ["tag", "agent"] as const;
|
||||||
@@ -27,12 +28,13 @@ const modes = {
|
|||||||
} as const satisfies Record<ModeName, Mode>;
|
} as const satisfies Record<ModeName, Mode>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a mode by name.
|
* Retrieves a mode by name and validates it can handle the event type.
|
||||||
* @param name The mode name to retrieve
|
* @param name The mode name to retrieve
|
||||||
|
* @param context The GitHub context to validate against
|
||||||
* @returns The requested mode
|
* @returns The requested mode
|
||||||
* @throws Error if the mode is not found
|
* @throws Error if the mode is not found or cannot handle the event
|
||||||
*/
|
*/
|
||||||
export function getMode(name: ModeName): Mode {
|
export function getMode(name: ModeName, context: ParsedGitHubContext): Mode {
|
||||||
const mode = modes[name];
|
const mode = modes[name];
|
||||||
if (!mode) {
|
if (!mode) {
|
||||||
const validModes = VALID_MODES.join("', '");
|
const validModes = VALID_MODES.join("', '");
|
||||||
@@ -40,6 +42,18 @@ export function getMode(name: ModeName): Mode {
|
|||||||
`Invalid mode '${name}'. Valid modes are: '${validModes}'. Please check your workflow configuration.`,
|
`Invalid mode '${name}'. Valid modes are: '${validModes}'. Please check your workflow configuration.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate mode can handle the event type
|
||||||
|
if (
|
||||||
|
name === "tag" &&
|
||||||
|
(context.eventName === "workflow_dispatch" ||
|
||||||
|
context.eventName === "schedule")
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
`Tag mode cannot handle ${context.eventName} events. Use 'agent' mode for automation events.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,17 +53,6 @@ export const tagMode: Mode = {
|
|||||||
}: ModeOptions): Promise<ModeResult> {
|
}: ModeOptions): Promise<ModeResult> {
|
||||||
// Tag mode handles entity-based events (issues, PRs, comments)
|
// Tag mode handles entity-based events (issues, PRs, comments)
|
||||||
|
|
||||||
// Validate this mode can handle the event
|
|
||||||
if (
|
|
||||||
context.eventName === "workflow_dispatch" ||
|
|
||||||
context.eventName === "schedule"
|
|
||||||
) {
|
|
||||||
throw new Error(
|
|
||||||
`Tag mode cannot handle ${context.eventName} events. ` +
|
|
||||||
`Use 'agent' mode for automation events.`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if actor is human
|
// Check if actor is human
|
||||||
await checkHumanActor(octokit.rest, context);
|
await checkHumanActor(octokit.rest, context);
|
||||||
|
|
||||||
|
|||||||
@@ -3,23 +3,60 @@ import { getMode, isValidMode } from "../../src/modes/registry";
|
|||||||
import type { ModeName } from "../../src/modes/types";
|
import type { ModeName } from "../../src/modes/types";
|
||||||
import { tagMode } from "../../src/modes/tag";
|
import { tagMode } from "../../src/modes/tag";
|
||||||
import { agentMode } from "../../src/modes/agent";
|
import { agentMode } from "../../src/modes/agent";
|
||||||
|
import { createMockContext } from "../mockContext";
|
||||||
|
|
||||||
describe("Mode Registry", () => {
|
describe("Mode Registry", () => {
|
||||||
test("getMode returns tag mode by default", () => {
|
const mockContext = createMockContext({
|
||||||
const mode = getMode("tag");
|
eventName: "issue_comment",
|
||||||
|
});
|
||||||
|
|
||||||
|
const mockWorkflowDispatchContext = createMockContext({
|
||||||
|
eventName: "workflow_dispatch",
|
||||||
|
});
|
||||||
|
|
||||||
|
const mockScheduleContext = createMockContext({
|
||||||
|
eventName: "schedule",
|
||||||
|
});
|
||||||
|
|
||||||
|
test("getMode returns tag mode for standard events", () => {
|
||||||
|
const mode = getMode("tag", mockContext);
|
||||||
expect(mode).toBe(tagMode);
|
expect(mode).toBe(tagMode);
|
||||||
expect(mode.name).toBe("tag");
|
expect(mode.name).toBe("tag");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("getMode returns agent mode", () => {
|
test("getMode returns agent mode", () => {
|
||||||
const mode = getMode("agent");
|
const mode = getMode("agent", mockContext);
|
||||||
|
expect(mode).toBe(agentMode);
|
||||||
|
expect(mode.name).toBe("agent");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("getMode throws error for tag mode with workflow_dispatch event", () => {
|
||||||
|
expect(() => getMode("tag", mockWorkflowDispatchContext)).toThrow(
|
||||||
|
"Tag mode cannot handle workflow_dispatch events. Use 'agent' mode for automation events.",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("getMode throws error for tag mode with schedule event", () => {
|
||||||
|
expect(() => getMode("tag", mockScheduleContext)).toThrow(
|
||||||
|
"Tag mode cannot handle schedule events. Use 'agent' mode for automation events.",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("getMode allows agent mode for workflow_dispatch event", () => {
|
||||||
|
const mode = getMode("agent", mockWorkflowDispatchContext);
|
||||||
|
expect(mode).toBe(agentMode);
|
||||||
|
expect(mode.name).toBe("agent");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("getMode allows agent mode for schedule event", () => {
|
||||||
|
const mode = getMode("agent", mockScheduleContext);
|
||||||
expect(mode).toBe(agentMode);
|
expect(mode).toBe(agentMode);
|
||||||
expect(mode.name).toBe("agent");
|
expect(mode.name).toBe("agent");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("getMode throws error for invalid mode", () => {
|
test("getMode throws error for invalid mode", () => {
|
||||||
const invalidMode = "invalid" as unknown as ModeName;
|
const invalidMode = "invalid" as unknown as ModeName;
|
||||||
expect(() => getMode(invalidMode)).toThrow(
|
expect(() => getMode(invalidMode, mockContext)).toThrow(
|
||||||
"Invalid mode 'invalid'. Valid modes are: 'tag', 'agent'. Please check your workflow configuration.",
|
"Invalid mode 'invalid'. Valid modes are: 'tag', 'agent'. Please check your workflow configuration.",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -29,83 +29,6 @@ describe("parseEnvVarsWithContext", () => {
|
|||||||
process.env = originalEnv;
|
process.env = originalEnv;
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("workflow_dispatch event", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
process.env = {
|
|
||||||
...BASE_ENV,
|
|
||||||
BASE_BRANCH: "main",
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should parse workflow_dispatch event correctly", () => {
|
|
||||||
const mockWorkflowDispatchContext = createMockContext({
|
|
||||||
eventName: "workflow_dispatch",
|
|
||||||
payload: {
|
|
||||||
inputs: {
|
|
||||||
task: "Run automated task",
|
|
||||||
},
|
|
||||||
repository: {
|
|
||||||
name: "test-repo",
|
|
||||||
owner: {
|
|
||||||
login: "test-owner",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
sender: {
|
|
||||||
login: "test-user",
|
|
||||||
},
|
|
||||||
workflow: "test.yml",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = prepareContext(
|
|
||||||
mockWorkflowDispatchContext,
|
|
||||||
"",
|
|
||||||
"main",
|
|
||||||
undefined,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(result.repository).toBe("test-owner/test-repo");
|
|
||||||
expect(result.eventData.eventName).toBe("workflow_dispatch");
|
|
||||||
expect(result.eventData.isPR).toBe(false);
|
|
||||||
expect(result.eventData.baseBranch).toBe("main");
|
|
||||||
// triggerUsername is not extracted for workflow_dispatch events
|
|
||||||
expect(result.triggerUsername).toBeUndefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("schedule event", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
process.env = {
|
|
||||||
...BASE_ENV,
|
|
||||||
BASE_BRANCH: "main",
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should parse schedule event correctly", () => {
|
|
||||||
const mockScheduleContext = createMockContext({
|
|
||||||
eventName: "schedule",
|
|
||||||
payload: {
|
|
||||||
schedule: "0 0 * * *",
|
|
||||||
repository: {
|
|
||||||
name: "test-repo",
|
|
||||||
owner: {
|
|
||||||
login: "test-owner",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = prepareContext(mockScheduleContext, "", "main", undefined);
|
|
||||||
|
|
||||||
expect(result.repository).toBe("test-owner/test-repo");
|
|
||||||
expect(result.eventData.eventName).toBe("schedule");
|
|
||||||
expect(result.eventData.isPR).toBe(false);
|
|
||||||
expect(result.eventData.baseBranch).toBe("main");
|
|
||||||
// triggerUsername is not extracted for schedule events
|
|
||||||
expect(result.triggerUsername).toBeUndefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("issue_comment event", () => {
|
describe("issue_comment event", () => {
|
||||||
describe("on issue", () => {
|
describe("on issue", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user