Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions src/github/validation/trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ export function checkContainsTrigger(context: ParsedGitHubContext): boolean {
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
// Check for exact match with word boundaries or punctuation (case-insensitive)
const regex = new RegExp(
`(^|\\s)${escapeRegExp(triggerPhrase)}([\\s.,!?;:]|$)`,
"i",
);

// Check in body
Expand All @@ -74,9 +75,10 @@ export function checkContainsTrigger(context: ParsedGitHubContext): boolean {
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
// Check for exact match with word boundaries or punctuation (case-insensitive)
const regex = new RegExp(
`(^|\\s)${escapeRegExp(triggerPhrase)}([\\s.,!?;:]|$)`,
"i",
);

// Check in body
Expand All @@ -102,9 +104,10 @@ export function checkContainsTrigger(context: ParsedGitHubContext): boolean {
(context.eventAction === "submitted" || context.eventAction === "edited")
) {
const reviewBody = context.payload.review.body || "";
// Check for exact match with word boundaries or punctuation
// Check for exact match with word boundaries or punctuation (case-insensitive)
const regex = new RegExp(
`(^|\\s)${escapeRegExp(triggerPhrase)}([\\s.,!?;:]|$)`,
"i",
);
if (regex.test(reviewBody)) {
console.log(
Expand All @@ -122,9 +125,10 @@ export function checkContainsTrigger(context: ParsedGitHubContext): boolean {
const commentBody = isIssueCommentEvent(context)
? context.payload.comment.body
: context.payload.comment.body;
// Check for exact match with word boundaries or punctuation
// Check for exact match with word boundaries or punctuation (case-insensitive)
const regex = new RegExp(
`(^|\\s)${escapeRegExp(triggerPhrase)}([\\s.,!?;:]|$)`,
"i",
);
if (regex.test(commentBody)) {
console.log(`Comment contains exact trigger phrase '${triggerPhrase}'`);
Expand Down
114 changes: 114 additions & 0 deletions test/trigger-validation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,120 @@ describe("checkContainsTrigger", () => {
});
});
});

describe("case-insensitive trigger matching", () => {
it("should match trigger phrase regardless of case in issue comments", () => {
const baseContext = {
...mockIssueCommentContext,
inputs: {
...mockIssueCommentContext.inputs,
triggerPhrase: "@claude",
},
};

const testCases = [
{ commentBody: "@Claude do this", expected: true },
{ commentBody: "@CLAUDE fix the bug", expected: true },
{ commentBody: "@cLaUdE help me", expected: true },
{ commentBody: "@claude review this", expected: true },
];

testCases.forEach(({ commentBody, expected }) => {
const context = {
...baseContext,
payload: {
...baseContext.payload,
comment: {
...(baseContext.payload as IssueCommentEvent).comment,
body: commentBody,
},
},
} as ParsedGitHubContext;
expect(checkContainsTrigger(context)).toBe(expected);
});
});

it("should match trigger phrase regardless of case in issue body", () => {
const baseContext = {
...mockIssueOpenedContext,
inputs: {
...mockIssueOpenedContext.inputs,
triggerPhrase: "@claude",
},
};

const testCases = [
{ issueBody: "@Claude, can you help?", expected: true },
{ issueBody: "@CLAUDE fix this", expected: true },
{ issueBody: "Hey @Claude! This is urgent", expected: true },
];

testCases.forEach(({ issueBody, expected }) => {
const context = {
...baseContext,
payload: {
...baseContext.payload,
issue: {
...(baseContext.payload as IssuesEvent).issue,
body: issueBody,
},
},
} as ParsedGitHubContext;
expect(checkContainsTrigger(context)).toBe(expected);
});
});

it("should match trigger phrase regardless of case in PR body", () => {
const context = createMockContext({
eventName: "pull_request",
eventAction: "opened",
isPR: true,
payload: {
action: "opened",
pull_request: {
number: 123,
title: "Test PR",
body: "@Claude can you review this?",
created_at: "2023-01-01T00:00:00Z",
user: { login: "testuser" },
},
} as PullRequestEvent,
inputs: {
prompt: "",
triggerPhrase: "@claude",
assigneeTrigger: "",
labelTrigger: "",
branchPrefix: "claude/",
useStickyComment: false,
useCommitSigning: false,
allowedBots: "",
},
});
expect(checkContainsTrigger(context)).toBe(true);
});

it("should match trigger phrase regardless of case in PR review body", () => {
const baseContext = {
...mockPullRequestReviewContext,
inputs: {
...mockPullRequestReviewContext.inputs,
triggerPhrase: "@claude",
},
};

const context = {
...baseContext,
payload: {
...baseContext.payload,
review: {
...(baseContext.payload as PullRequestReviewEvent).review,
body: "@Claude, please review",
},
},
} as ParsedGitHubContext;
expect(checkContainsTrigger(context)).toBe(true);
});
});
});

describe("escapeRegExp", () => {
Expand Down