mirror of
https://github.com/anthropics/claude-code-action.git
synced 2026-01-22 22:44:13 +08:00
test + formatting fixes
This commit is contained in:
@@ -534,14 +534,21 @@ export async function generatePrompt(
|
||||
mode: Mode,
|
||||
): Promise<string> {
|
||||
// Check for unified prompt field first (v1.0)
|
||||
let prompt = context.prompt || context.overridePrompt || context.directPrompt || "";
|
||||
let prompt =
|
||||
context.prompt || context.overridePrompt || context.directPrompt || "";
|
||||
|
||||
// Handle slash commands
|
||||
if (prompt.startsWith("/")) {
|
||||
const variables = {
|
||||
repository: context.repository,
|
||||
pr_number: context.eventData.isPR && 'prNumber' in context.eventData ? context.eventData.prNumber : "",
|
||||
issue_number: !context.eventData.isPR && 'issueNumber' in context.eventData ? context.eventData.issueNumber : "",
|
||||
pr_number:
|
||||
context.eventData.isPR && "prNumber" in context.eventData
|
||||
? context.eventData.prNumber
|
||||
: "",
|
||||
issue_number:
|
||||
!context.eventData.isPR && "issueNumber" in context.eventData
|
||||
? context.eventData.issueNumber
|
||||
: "",
|
||||
branch: context.eventData.claudeBranch || "",
|
||||
base_branch: context.eventData.baseBranch || "",
|
||||
trigger_user: context.triggerUsername,
|
||||
@@ -553,13 +560,18 @@ export async function generatePrompt(
|
||||
if (resolved.tools && resolved.tools.length > 0) {
|
||||
const currentAllowedTools = process.env.ALLOWED_TOOLS || "";
|
||||
const newTools = resolved.tools.join(",");
|
||||
const combinedTools = currentAllowedTools ? `${currentAllowedTools},${newTools}` : newTools;
|
||||
const combinedTools = currentAllowedTools
|
||||
? `${currentAllowedTools},${newTools}`
|
||||
: newTools;
|
||||
core.exportVariable("ALLOWED_TOOLS", combinedTools);
|
||||
}
|
||||
|
||||
// Apply any settings from the slash command
|
||||
if (resolved.settings) {
|
||||
core.exportVariable("SLASH_COMMAND_SETTINGS", JSON.stringify(resolved.settings));
|
||||
core.exportVariable(
|
||||
"SLASH_COMMAND_SETTINGS",
|
||||
JSON.stringify(resolved.settings),
|
||||
);
|
||||
}
|
||||
|
||||
prompt = resolved.expandedPrompt;
|
||||
|
||||
@@ -29,9 +29,7 @@ async function run() {
|
||||
// For review mode, use the default GitHub Action token
|
||||
githubToken = process.env.DEFAULT_WORKFLOW_TOKEN || "";
|
||||
if (!githubToken) {
|
||||
throw new Error(
|
||||
"DEFAULT_WORKFLOW_TOKEN not found for review mode",
|
||||
);
|
||||
throw new Error("DEFAULT_WORKFLOW_TOKEN not found for review mode");
|
||||
}
|
||||
console.log("Using default GitHub Action token for review mode");
|
||||
core.setOutput("GITHUB_TOKEN", githubToken);
|
||||
@@ -41,7 +39,6 @@ async function run() {
|
||||
}
|
||||
const octokit = createOctokit(githubToken);
|
||||
|
||||
|
||||
// Step 3: Check write permissions (only for entity contexts)
|
||||
if (isEntityContext(context)) {
|
||||
const hasWritePermissions = await checkWritePermissions(
|
||||
|
||||
@@ -106,7 +106,9 @@ export function parseGitHubContext(): GitHubContext {
|
||||
const context = github.context;
|
||||
|
||||
// Mode is optional in v1.0 (auto-detected)
|
||||
const modeInput = process.env.MODE ? process.env.MODE as ModeName : undefined;
|
||||
const modeInput = process.env.MODE
|
||||
? (process.env.MODE as ModeName)
|
||||
: undefined;
|
||||
|
||||
const commonFields = {
|
||||
runId: process.env.GITHUB_RUN_ID!,
|
||||
@@ -120,9 +122,11 @@ export function parseGitHubContext(): GitHubContext {
|
||||
inputs: {
|
||||
mode: modeInput,
|
||||
// v1.0: Unified prompt field with fallback to legacy fields
|
||||
prompt: process.env.PROMPT ||
|
||||
process.env.OVERRIDE_PROMPT ||
|
||||
process.env.DIRECT_PROMPT || "",
|
||||
prompt:
|
||||
process.env.PROMPT ||
|
||||
process.env.OVERRIDE_PROMPT ||
|
||||
process.env.DIRECT_PROMPT ||
|
||||
"",
|
||||
triggerPhrase: process.env.TRIGGER_PHRASE ?? "@claude",
|
||||
assigneeTrigger: process.env.ASSIGNEE_TRIGGER ?? "",
|
||||
labelTrigger: process.env.LABEL_TRIGGER ?? "",
|
||||
|
||||
@@ -30,10 +30,7 @@ const modes = {
|
||||
* @param explicitMode Optional explicit mode override (for backward compatibility)
|
||||
* @returns The appropriate mode for the context
|
||||
*/
|
||||
export function getMode(
|
||||
context: GitHubContext,
|
||||
explicitMode?: string,
|
||||
): Mode {
|
||||
export function getMode(context: GitHubContext, explicitMode?: string): Mode {
|
||||
let modeName: AutoDetectedMode;
|
||||
|
||||
if (explicitMode && isValidModeV1(explicitMode)) {
|
||||
@@ -41,7 +38,9 @@ export function getMode(
|
||||
modeName = mapLegacyMode(explicitMode);
|
||||
} else {
|
||||
modeName = detectMode(context);
|
||||
console.log(`Auto-detected mode: ${modeName} for event: ${context.eventName}`);
|
||||
console.log(
|
||||
`Auto-detected mode: ${modeName} for event: ${context.eventName}`,
|
||||
);
|
||||
}
|
||||
|
||||
const mode = modes[modeName];
|
||||
|
||||
@@ -52,10 +52,7 @@ export async function resolveSlashCommand(
|
||||
let expandedContent = command.content;
|
||||
|
||||
if (args.length > 0) {
|
||||
expandedContent = expandedContent.replace(
|
||||
/\{args\}/g,
|
||||
args.join(" "),
|
||||
);
|
||||
expandedContent = expandedContent.replace(/\{args\}/g, args.join(" "));
|
||||
}
|
||||
|
||||
if (variables) {
|
||||
@@ -107,7 +104,7 @@ function parseCommandFile(name: string, content: string): SlashCommand {
|
||||
if (frontmatterMatch && frontmatterMatch[1]) {
|
||||
try {
|
||||
const parsedYaml = yaml.load(frontmatterMatch[1]);
|
||||
if (parsedYaml && typeof parsedYaml === 'object') {
|
||||
if (parsedYaml && typeof parsedYaml === "object") {
|
||||
metadata = parsedYaml as SlashCommandMetadata;
|
||||
}
|
||||
commandContent = frontmatterMatch[2]?.trim() || content;
|
||||
|
||||
@@ -157,7 +157,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
expect(prompt).toContain("You are Claude, an AI assistant");
|
||||
expect(prompt).toContain("<event_type>GENERAL_COMMENT</event_type>");
|
||||
@@ -185,7 +190,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
expect(prompt).toContain("<event_type>PR_REVIEW</event_type>");
|
||||
expect(prompt).toContain("<is_pr>true</is_pr>");
|
||||
@@ -211,7 +221,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
expect(prompt).toContain("<event_type>ISSUE_CREATED</event_type>");
|
||||
expect(prompt).toContain(
|
||||
@@ -239,7 +254,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
expect(prompt).toContain("<event_type>ISSUE_ASSIGNED</event_type>");
|
||||
expect(prompt).toContain(
|
||||
@@ -266,7 +286,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
expect(prompt).toContain("<event_type>ISSUE_LABELED</event_type>");
|
||||
expect(prompt).toContain(
|
||||
@@ -293,9 +318,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = generateDefaultPrompt(envVars, mockGitHubData, false);
|
||||
|
||||
expect(prompt).toContain("<direct_prompt>");
|
||||
expect(prompt).toContain(
|
||||
"IMPORTANT: The following are direct instructions",
|
||||
);
|
||||
expect(prompt).toContain("Fix the bug in the login form");
|
||||
expect(prompt).toContain("</direct_prompt>");
|
||||
expect(prompt).toContain(
|
||||
@@ -316,7 +344,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
expect(prompt).toContain("<event_type>PULL_REQUEST</event_type>");
|
||||
expect(prompt).toContain("<is_pr>true</is_pr>");
|
||||
@@ -341,7 +374,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
expect(prompt).toContain("CUSTOM INSTRUCTIONS:\nAlways use TypeScript");
|
||||
});
|
||||
@@ -360,7 +398,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
expect(prompt).toBe("Simple prompt for owner/repo PR #123");
|
||||
expect(prompt).not.toContain("You are Claude, an AI assistant");
|
||||
@@ -395,7 +438,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
expect(prompt).toContain("Repository: test/repo");
|
||||
expect(prompt).toContain("PR: 456");
|
||||
@@ -442,7 +490,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, issueGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
issueGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
expect(prompt).toBe("Issue #789: Bug: Login form broken in owner/repo");
|
||||
});
|
||||
@@ -462,7 +515,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
expect(prompt).toBe("PR: 123, Issue: , Comment: ");
|
||||
});
|
||||
@@ -482,7 +540,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
expect(prompt).toContain("You are Claude, an AI assistant");
|
||||
expect(prompt).toContain("<event_type>ISSUE_CREATED</event_type>");
|
||||
@@ -505,7 +568,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
expect(prompt).toContain("<trigger_username>johndoe</trigger_username>");
|
||||
// With commit signing disabled, co-author info appears in git commit instructions
|
||||
@@ -527,7 +595,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
// Should contain PR-specific instructions (git commands when not using signing)
|
||||
expect(prompt).toContain("git push");
|
||||
@@ -558,7 +631,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
// Should contain Issue-specific instructions
|
||||
expect(prompt).toContain(
|
||||
@@ -597,7 +675,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
// Should contain the actual branch name with timestamp
|
||||
expect(prompt).toContain(
|
||||
@@ -627,7 +710,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
// Should contain branch-specific instructions like issues
|
||||
expect(prompt).toContain(
|
||||
@@ -665,7 +753,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
// Should contain open PR instructions (git commands when not using signing)
|
||||
expect(prompt).toContain("git push");
|
||||
@@ -696,7 +789,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
// Should contain new branch instructions
|
||||
expect(prompt).toContain(
|
||||
@@ -724,7 +822,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
// Should contain new branch instructions
|
||||
expect(prompt).toContain(
|
||||
@@ -752,7 +855,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
// Should contain new branch instructions
|
||||
expect(prompt).toContain(
|
||||
@@ -776,7 +884,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, false, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
false,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
// Should have git command instructions
|
||||
expect(prompt).toContain("Use git commands via the Bash tool");
|
||||
@@ -805,7 +918,12 @@ describe("generatePrompt", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const prompt = await generatePrompt(envVars, mockGitHubData, true, mockTagMode);
|
||||
const prompt = await generatePrompt(
|
||||
envVars,
|
||||
mockGitHubData,
|
||||
true,
|
||||
mockTagMode,
|
||||
);
|
||||
|
||||
// Should have commit signing tool instructions
|
||||
expect(prompt).toContain("mcp__github_file_ops__commit_files");
|
||||
|
||||
@@ -7,6 +7,12 @@ import { createMockContext, createMockAutomationContext } from "../mockContext";
|
||||
describe("Mode Registry", () => {
|
||||
const mockContext = createMockContext({
|
||||
eventName: "issue_comment",
|
||||
payload: {
|
||||
action: "created",
|
||||
comment: {
|
||||
body: "Test comment without trigger",
|
||||
},
|
||||
} as any,
|
||||
});
|
||||
|
||||
const mockWorkflowDispatchContext = createMockAutomationContext({
|
||||
@@ -17,9 +23,9 @@ describe("Mode Registry", () => {
|
||||
eventName: "schedule",
|
||||
});
|
||||
|
||||
test("getMode auto-detects tag mode for issue_comment", () => {
|
||||
test("getMode auto-detects agent mode for issue_comment without trigger", () => {
|
||||
const mode = getMode(mockContext);
|
||||
// Issue comment without trigger won't activate tag mode, defaults to agent
|
||||
// Agent mode is the default when no trigger is found
|
||||
expect(mode).toBe(agentMode);
|
||||
expect(mode.name).toBe("agent");
|
||||
});
|
||||
@@ -33,7 +39,7 @@ describe("Mode Registry", () => {
|
||||
test("getMode can use explicit mode override for review", () => {
|
||||
const mode = getMode(mockContext, "review");
|
||||
expect(mode).toBe(reviewMode);
|
||||
expect(mode.name).toBe("review");
|
||||
expect(mode.name).toBe("experimental-review");
|
||||
});
|
||||
|
||||
test("getMode auto-detects agent for workflow_dispatch", () => {
|
||||
@@ -51,7 +57,7 @@ describe("Mode Registry", () => {
|
||||
test("getMode supports legacy experimental-review mode name", () => {
|
||||
const mode = getMode(mockContext, "experimental-review");
|
||||
expect(mode).toBe(reviewMode);
|
||||
expect(mode.name).toBe("review");
|
||||
expect(mode.name).toBe("experimental-review");
|
||||
});
|
||||
|
||||
test("getMode auto-detects review mode for PR opened", () => {
|
||||
@@ -62,13 +68,14 @@ describe("Mode Registry", () => {
|
||||
});
|
||||
const mode = getMode(prContext);
|
||||
expect(mode).toBe(reviewMode);
|
||||
expect(mode.name).toBe("agent");
|
||||
expect(mode.name).toBe("experimental-review");
|
||||
});
|
||||
|
||||
test("getMode throws error for invalid mode override", () => {
|
||||
expect(() => getMode(mockContext, "invalid")).toThrow(
|
||||
"Mode 'agent' not found. This should not happen. Please report this issue.",
|
||||
);
|
||||
test("getMode falls back to auto-detection for invalid mode override", () => {
|
||||
const mode = getMode(mockContext, "invalid");
|
||||
// Should fall back to auto-detection, which returns agent for issue_comment without trigger
|
||||
expect(mode).toBe(agentMode);
|
||||
expect(mode.name).toBe("agent");
|
||||
});
|
||||
|
||||
test("isValidMode returns true for all valid modes", () => {
|
||||
|
||||
Reference in New Issue
Block a user