mirror of
https://github.com/anthropics/claude-code-action.git
synced 2026-01-22 22:44:13 +08:00
ensure tag mode can't work with workflow dispatch and schedule tasks
This commit is contained in:
@@ -449,12 +449,11 @@ export function getEventTypeAndContext(envVars: PreparedContext): {
|
|||||||
|
|
||||||
function getCommitInstructions(
|
function getCommitInstructions(
|
||||||
eventData: EventData,
|
eventData: EventData,
|
||||||
githubData: FetchDataResult | null,
|
githubData: FetchDataResult,
|
||||||
context: PreparedContext,
|
context: PreparedContext,
|
||||||
useCommitSigning: boolean,
|
useCommitSigning: boolean,
|
||||||
): string {
|
): string {
|
||||||
const coAuthorLine =
|
const coAuthorLine =
|
||||||
githubData &&
|
|
||||||
(githubData.triggerDisplayName ?? context.triggerUsername !== "Unknown")
|
(githubData.triggerDisplayName ?? context.triggerUsername !== "Unknown")
|
||||||
? `Co-authored-by: ${githubData.triggerDisplayName ?? context.triggerUsername} <${context.triggerUsername}@users.noreply.github.com>`
|
? `Co-authored-by: ${githubData.triggerDisplayName ?? context.triggerUsername} <${context.triggerUsername}@users.noreply.github.com>`
|
||||||
: "";
|
: "";
|
||||||
@@ -509,26 +508,8 @@ function getCommitInstructions(
|
|||||||
function substitutePromptVariables(
|
function substitutePromptVariables(
|
||||||
template: string,
|
template: string,
|
||||||
context: PreparedContext,
|
context: PreparedContext,
|
||||||
githubData: FetchDataResult | null,
|
githubData: FetchDataResult,
|
||||||
): string {
|
): string {
|
||||||
// Handle automation events without GitHub data
|
|
||||||
if (!githubData) {
|
|
||||||
const { eventData } = context;
|
|
||||||
const variables: Record<string, string> = {
|
|
||||||
EVENT_TYPE: eventData.eventName,
|
|
||||||
REPOSITORY: context.repository,
|
|
||||||
TRIGGER_USERNAME: context.triggerUsername ?? "automation",
|
|
||||||
CURRENT_BRANCH: eventData.claudeBranch || eventData.baseBranch || "main",
|
|
||||||
BASE_BRANCH: eventData.baseBranch || "main",
|
|
||||||
};
|
|
||||||
|
|
||||||
return Object.entries(variables).reduce(
|
|
||||||
(prompt, [key, value]) =>
|
|
||||||
prompt.replace(new RegExp(`{{${key}}}`, "g"), value),
|
|
||||||
template,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const { contextData, comments, reviewData, changedFilesWithSHA } = githubData;
|
const { contextData, comments, reviewData, changedFilesWithSHA } = githubData;
|
||||||
const { eventData } = context;
|
const { eventData } = context;
|
||||||
|
|
||||||
@@ -589,7 +570,7 @@ function substitutePromptVariables(
|
|||||||
|
|
||||||
export function generatePrompt(
|
export function generatePrompt(
|
||||||
context: PreparedContext,
|
context: PreparedContext,
|
||||||
githubData: FetchDataResult | null,
|
githubData: FetchDataResult,
|
||||||
useCommitSigning: boolean,
|
useCommitSigning: boolean,
|
||||||
): string {
|
): string {
|
||||||
if (context.overridePrompt) {
|
if (context.overridePrompt) {
|
||||||
@@ -601,58 +582,6 @@ export function generatePrompt(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { eventData } = context;
|
const { eventData } = context;
|
||||||
|
|
||||||
// Handle automation events that don't have GitHub data
|
|
||||||
if (!githubData) {
|
|
||||||
// For automation events, we have minimal context
|
|
||||||
const { eventType, triggerContext } = getEventTypeAndContext(context);
|
|
||||||
|
|
||||||
let promptContent = `You are Claude, an AI assistant designed to help with GitHub ${eventData.eventName === "workflow_dispatch" ? "workflow dispatch" : "scheduled automation"} tasks. Think carefully as you analyze the context and respond appropriately. Here's the context for your current task:
|
|
||||||
|
|
||||||
<formatted_context>
|
|
||||||
Repository: ${context.repository}
|
|
||||||
Event Type: ${eventData.eventName}
|
|
||||||
Current Branch: ${eventData.claudeBranch || eventData.baseBranch || "main"}
|
|
||||||
Base Branch: ${eventData.baseBranch || "main"}
|
|
||||||
Actor: ${context.triggerUsername ?? "automation"}
|
|
||||||
</formatted_context>
|
|
||||||
|
|
||||||
<event_type>${eventType}</event_type>
|
|
||||||
<is_pr>false</is_pr>
|
|
||||||
<trigger_context>${triggerContext}</trigger_context>
|
|
||||||
<repository>${context.repository}</repository>
|
|
||||||
<trigger_username>${context.triggerUsername ?? "automation"}</trigger_username>
|
|
||||||
${
|
|
||||||
context.directPrompt
|
|
||||||
? `<direct_prompt>
|
|
||||||
IMPORTANT: The following are direct instructions from the automation workflow:
|
|
||||||
|
|
||||||
${sanitizeContent(context.directPrompt)}
|
|
||||||
</direct_prompt>`
|
|
||||||
: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
<instructions>
|
|
||||||
You have been triggered by an automated workflow. Follow these guidelines:
|
|
||||||
|
|
||||||
1. **Context**: You are running in an automated context without a specific issue or PR.
|
|
||||||
2. **Branch**: You are currently on the ${eventData.claudeBranch || eventData.baseBranch || "main"} branch.
|
|
||||||
3. **Tools**: You have access to file system and Git tools to make changes.
|
|
||||||
${
|
|
||||||
useCommitSigning
|
|
||||||
? "4. **Commits**: Use the MCP file operations server for signed commits."
|
|
||||||
: "4. **Commits**: You can commit changes directly using Git."
|
|
||||||
}
|
|
||||||
5. **Scope**: Focus on the task described${context.directPrompt ? " in the direct_prompt above" : ""}.
|
|
||||||
|
|
||||||
Please proceed with the automated task.
|
|
||||||
</instructions>
|
|
||||||
|
|
||||||
${context.customInstructions || ""}`;
|
|
||||||
|
|
||||||
return promptContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
contextData,
|
contextData,
|
||||||
comments,
|
comments,
|
||||||
@@ -663,7 +592,7 @@ ${context.customInstructions || ""}`;
|
|||||||
|
|
||||||
const { eventType, triggerContext } = getEventTypeAndContext(context);
|
const { eventType, triggerContext } = getEventTypeAndContext(context);
|
||||||
|
|
||||||
const formattedContext = formatContext(contextData, eventData.isPR ?? false);
|
const formattedContext = formatContext(contextData, eventData.isPR!);
|
||||||
const formattedComments = formatComments(comments, imageUrlMap);
|
const formattedComments = formatComments(comments, imageUrlMap);
|
||||||
const formattedReviewComments = eventData.isPR
|
const formattedReviewComments = eventData.isPR
|
||||||
? formatReviewComments(reviewData, imageUrlMap)
|
? formatReviewComments(reviewData, imageUrlMap)
|
||||||
@@ -709,7 +638,7 @@ ${eventData.isPR ? formattedChangedFiles || "No files changed" : ""}
|
|||||||
</changed_files>${imagesInfo}
|
</changed_files>${imagesInfo}
|
||||||
|
|
||||||
<event_type>${eventType}</event_type>
|
<event_type>${eventType}</event_type>
|
||||||
<is_pr>${(eventData.isPR ?? false) ? "true" : "false"}</is_pr>
|
<is_pr>${eventData.isPR ? "true" : "false"}</is_pr>
|
||||||
<trigger_context>${triggerContext}</trigger_context>
|
<trigger_context>${triggerContext}</trigger_context>
|
||||||
<repository>${context.repository}</repository>
|
<repository>${context.repository}</repository>
|
||||||
${getEntityNumberXml(eventData)}
|
${getEntityNumberXml(eventData)}
|
||||||
@@ -906,7 +835,7 @@ f. If you are unable to complete certain steps, such as running a linter or test
|
|||||||
export async function createPrompt(
|
export async function createPrompt(
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
modeContext: ModeContext,
|
modeContext: ModeContext,
|
||||||
githubData: FetchDataResult | null,
|
githubData: FetchDataResult,
|
||||||
context: ParsedGitHubContext,
|
context: ParsedGitHubContext,
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -53,6 +53,17 @@ 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);
|
||||||
|
|
||||||
|
|||||||
@@ -713,78 +713,6 @@ describe("generatePrompt", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should generate prompt for workflow_dispatch event with null githubData", () => {
|
|
||||||
const envVars: PreparedContext = {
|
|
||||||
repository: "owner/repo",
|
|
||||||
triggerPhrase: "@claude",
|
|
||||||
eventData: {
|
|
||||||
eventName: "workflow_dispatch",
|
|
||||||
isPR: false,
|
|
||||||
baseBranch: "main",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const prompt = generatePrompt(envVars, null, false);
|
|
||||||
|
|
||||||
expect(prompt).toContain("<event_type>WORKFLOW_DISPATCH</event_type>");
|
|
||||||
expect(prompt).toContain("<is_pr>false</is_pr>");
|
|
||||||
expect(prompt).toContain(
|
|
||||||
"<trigger_context>workflow dispatch event</trigger_context>",
|
|
||||||
);
|
|
||||||
expect(prompt).toContain(
|
|
||||||
"You are running in an automated context without a specific issue or PR",
|
|
||||||
);
|
|
||||||
expect(prompt).not.toContain("<pr_number>");
|
|
||||||
expect(prompt).not.toContain("<issue_number>");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should generate prompt for schedule event with null githubData", () => {
|
|
||||||
const envVars: PreparedContext = {
|
|
||||||
repository: "owner/repo",
|
|
||||||
triggerPhrase: "@claude",
|
|
||||||
triggerUsername: "github-actions[bot]",
|
|
||||||
eventData: {
|
|
||||||
eventName: "schedule",
|
|
||||||
isPR: false,
|
|
||||||
baseBranch: "main",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const prompt = generatePrompt(envVars, null, false);
|
|
||||||
|
|
||||||
expect(prompt).toContain("<event_type>SCHEDULE</event_type>");
|
|
||||||
expect(prompt).toContain("<is_pr>false</is_pr>");
|
|
||||||
expect(prompt).toContain(
|
|
||||||
"<trigger_context>scheduled automation event</trigger_context>",
|
|
||||||
);
|
|
||||||
expect(prompt).toContain("scheduled automation");
|
|
||||||
expect(prompt).toContain(
|
|
||||||
"<trigger_username>github-actions[bot]</trigger_username>",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should include direct prompt for automation events", () => {
|
|
||||||
const envVars: PreparedContext = {
|
|
||||||
repository: "owner/repo",
|
|
||||||
triggerPhrase: "@claude",
|
|
||||||
directPrompt: "Run daily maintenance tasks",
|
|
||||||
eventData: {
|
|
||||||
eventName: "workflow_dispatch",
|
|
||||||
isPR: false,
|
|
||||||
baseBranch: "main",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const prompt = generatePrompt(envVars, null, false);
|
|
||||||
|
|
||||||
expect(prompt).toContain("<direct_prompt>");
|
|
||||||
expect(prompt).toContain("Run daily maintenance tasks");
|
|
||||||
expect(prompt).toContain("</direct_prompt>");
|
|
||||||
expect(prompt).toContain(
|
|
||||||
"IMPORTANT: The following are direct instructions from the automation workflow",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should handle pull_request event on closed PR with new branch", () => {
|
test("should handle pull_request event on closed PR with new branch", () => {
|
||||||
const envVars: PreparedContext = {
|
const envVars: PreparedContext = {
|
||||||
repository: "owner/repo",
|
repository: "owner/repo",
|
||||||
|
|||||||
Reference in New Issue
Block a user