mirror of
https://github.com/anthropics/claude-code-action.git
synced 2026-01-23 06:54:13 +08:00
BREAKING CHANGES: - Remove review mode entirely - now handled via slash commands in agent mode - Remove all deprecated backward compatibility fields (mode, anthropic_model, override_prompt, direct_prompt) - Simplify mode detection: prompt overrides everything, then @claude mentions trigger tag mode, default is agent mode - Remove slash command resolution from GitHub Action - Claude Code handles natively - Remove variable substitution - prompts passed through as-is Architecture changes: - Only two modes now: tag (for @claude mentions) and agent (everything else) - Agent mode is the default for all events including PRs - Users configure behavior via prompts/slash commands (e.g. /review) - GitHub Action is now a thin wrapper that passes prompts to Claude Code - Mode names changed: 'experimental-review' → removed entirely This aligns with the philosophy that the GitHub Action should do minimal work and delegate to Claude Code for all intelligent behavior.
149 lines
4.3 KiB
TypeScript
149 lines
4.3 KiB
TypeScript
#!/usr/bin/env bun
|
|
|
|
import * as core from "@actions/core";
|
|
import {
|
|
isIssuesEvent,
|
|
isIssuesAssignedEvent,
|
|
isIssueCommentEvent,
|
|
isPullRequestEvent,
|
|
isPullRequestReviewEvent,
|
|
isPullRequestReviewCommentEvent,
|
|
} from "../context";
|
|
import type { ParsedGitHubContext } from "../context";
|
|
|
|
export function checkContainsTrigger(context: ParsedGitHubContext): boolean {
|
|
const {
|
|
inputs: { assigneeTrigger, labelTrigger, triggerPhrase, prompt },
|
|
} = context;
|
|
|
|
// If prompt is provided, always trigger
|
|
if (prompt) {
|
|
console.log(`Prompt provided, triggering action`);
|
|
return true;
|
|
}
|
|
|
|
// Check for assignee trigger
|
|
if (isIssuesAssignedEvent(context)) {
|
|
// Remove @ symbol from assignee_trigger if present
|
|
let triggerUser = assigneeTrigger.replace(/^@/, "");
|
|
const assigneeUsername = context.payload.assignee?.login || "";
|
|
|
|
if (triggerUser && assigneeUsername === triggerUser) {
|
|
console.log(`Issue assigned to trigger user '${triggerUser}'`);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Check for label trigger
|
|
if (isIssuesEvent(context) && context.eventAction === "labeled") {
|
|
const labelName = (context.payload as any).label?.name || "";
|
|
|
|
if (labelTrigger && labelName === labelTrigger) {
|
|
console.log(`Issue labeled with trigger label '${labelTrigger}'`);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Check for issue body and title trigger on issue creation
|
|
if (isIssuesEvent(context) && context.eventAction === "opened") {
|
|
const issueBody = context.payload.issue.body || "";
|
|
const issueTitle = context.payload.issue.title || "";
|
|
// Check for exact match with word boundaries or punctuation
|
|
const regex = new RegExp(
|
|
`(^|\\s)${escapeRegExp(triggerPhrase)}([\\s.,!?;:]|$)`,
|
|
);
|
|
|
|
// Check in body
|
|
if (regex.test(issueBody)) {
|
|
console.log(
|
|
`Issue body contains exact trigger phrase '${triggerPhrase}'`,
|
|
);
|
|
return true;
|
|
}
|
|
|
|
// Check in title
|
|
if (regex.test(issueTitle)) {
|
|
console.log(
|
|
`Issue title contains exact trigger phrase '${triggerPhrase}'`,
|
|
);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Check for pull request body and title trigger
|
|
if (isPullRequestEvent(context)) {
|
|
const prBody = context.payload.pull_request.body || "";
|
|
const prTitle = context.payload.pull_request.title || "";
|
|
// Check for exact match with word boundaries or punctuation
|
|
const regex = new RegExp(
|
|
`(^|\\s)${escapeRegExp(triggerPhrase)}([\\s.,!?;:]|$)`,
|
|
);
|
|
|
|
// Check in body
|
|
if (regex.test(prBody)) {
|
|
console.log(
|
|
`Pull request body contains exact trigger phrase '${triggerPhrase}'`,
|
|
);
|
|
return true;
|
|
}
|
|
|
|
// Check in title
|
|
if (regex.test(prTitle)) {
|
|
console.log(
|
|
`Pull request title contains exact trigger phrase '${triggerPhrase}'`,
|
|
);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Check for pull request review body trigger
|
|
if (
|
|
isPullRequestReviewEvent(context) &&
|
|
(context.eventAction === "submitted" || context.eventAction === "edited")
|
|
) {
|
|
const reviewBody = context.payload.review.body || "";
|
|
// Check for exact match with word boundaries or punctuation
|
|
const regex = new RegExp(
|
|
`(^|\\s)${escapeRegExp(triggerPhrase)}([\\s.,!?;:]|$)`,
|
|
);
|
|
if (regex.test(reviewBody)) {
|
|
console.log(
|
|
`Pull request review contains exact trigger phrase '${triggerPhrase}'`,
|
|
);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Check for comment trigger
|
|
if (
|
|
isIssueCommentEvent(context) ||
|
|
isPullRequestReviewCommentEvent(context)
|
|
) {
|
|
const commentBody = isIssueCommentEvent(context)
|
|
? context.payload.comment.body
|
|
: context.payload.comment.body;
|
|
// Check for exact match with word boundaries or punctuation
|
|
const regex = new RegExp(
|
|
`(^|\\s)${escapeRegExp(triggerPhrase)}([\\s.,!?;:]|$)`,
|
|
);
|
|
if (regex.test(commentBody)) {
|
|
console.log(`Comment contains exact trigger phrase '${triggerPhrase}'`);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
console.log(`No trigger was met for ${triggerPhrase}`);
|
|
|
|
return false;
|
|
}
|
|
|
|
export function escapeRegExp(string: string) {
|
|
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
}
|
|
|
|
export async function checkTriggerAction(context: ParsedGitHubContext) {
|
|
const containsTrigger = checkContainsTrigger(context);
|
|
core.setOutput("contains_trigger", containsTrigger.toString());
|
|
return containsTrigger;
|
|
}
|