Forgejo-patched claude-code-gitea-action (View-job URL uses per-repo run index)
Some checks failed
Test Custom Executables / test-custom-executables (push) Has been cancelled
CI / test (push) Has been cancelled
CI / prettier (push) Has been cancelled
CI / typecheck (push) Has been cancelled
Sync Base Action to claude-code-base-action / Sync base-action to claude-code-base-action repository (push) Has been cancelled
Test Claude Code Action / test-inline-prompt (push) Has been cancelled
Test Claude Code Action / test-prompt-file (push) Has been cancelled
Test Claude Env Feature / test-claude-env-with-comments (push) Has been cancelled
Test MCP Servers / test-mcp-integration (push) Has been cancelled
Test MCP Servers / test-mcp-config-flag (push) Has been cancelled
Test Settings Feature / test-settings-inline-allow (push) Has been cancelled
Test Settings Feature / test-settings-inline-deny (push) Has been cancelled
Test Settings Feature / test-settings-file-allow (push) Has been cancelled
Test Settings Feature / test-settings-file-deny (push) Has been cancelled
Some checks failed
Test Custom Executables / test-custom-executables (push) Has been cancelled
CI / test (push) Has been cancelled
CI / prettier (push) Has been cancelled
CI / typecheck (push) Has been cancelled
Sync Base Action to claude-code-base-action / Sync base-action to claude-code-base-action repository (push) Has been cancelled
Test Claude Code Action / test-inline-prompt (push) Has been cancelled
Test Claude Code Action / test-prompt-file (push) Has been cancelled
Test Claude Env Feature / test-claude-env-with-comments (push) Has been cancelled
Test MCP Servers / test-mcp-integration (push) Has been cancelled
Test MCP Servers / test-mcp-config-flag (push) Has been cancelled
Test Settings Feature / test-settings-inline-allow (push) Has been cancelled
Test Settings Feature / test-settings-inline-deny (push) Has been cancelled
Test Settings Feature / test-settings-file-allow (push) Has been cancelled
Test Settings Feature / test-settings-file-deny (push) Has been cancelled
Fork of markwylde/claude-code-gitea-action@b744372 (v1.0.21) with the 'View job' link fixed to use GITHUB_RUN_NUMBER (per-repo index) instead of GITHUB_RUN_ID (global id), because Forgejo routes run pages by per-repo index. See VENDOR.txt.
This commit is contained in:
commit
32685a740f
151 changed files with 23555 additions and 0 deletions
954
test/trigger-validation.test.ts
Normal file
954
test/trigger-validation.test.ts
Normal file
|
|
@ -0,0 +1,954 @@
|
|||
import {
|
||||
checkContainsTrigger,
|
||||
escapeRegExp,
|
||||
} from "../src/github/validation/trigger";
|
||||
import { describe, it, expect } from "bun:test";
|
||||
import {
|
||||
createMockContext,
|
||||
mockIssueAssignedContext,
|
||||
mockIssueLabeledContext,
|
||||
mockIssueCommentContext,
|
||||
mockIssueOpenedContext,
|
||||
mockPullRequestReviewContext,
|
||||
mockPullRequestReviewCommentContext,
|
||||
} from "./mockContext";
|
||||
import type {
|
||||
IssueCommentEvent,
|
||||
IssuesAssignedEvent,
|
||||
IssuesEvent,
|
||||
PullRequestEvent,
|
||||
PullRequestReviewEvent,
|
||||
} from "@octokit/webhooks-types";
|
||||
import type { ParsedGitHubContext } from "../src/github/context";
|
||||
|
||||
describe("checkContainsTrigger", () => {
|
||||
describe("direct prompt trigger", () => {
|
||||
it("should return true when direct prompt is provided", () => {
|
||||
const context = createMockContext({
|
||||
eventName: "issues",
|
||||
eventAction: "opened",
|
||||
inputs: {
|
||||
mode: "tag",
|
||||
triggerPhrase: "/claude",
|
||||
assigneeTrigger: "",
|
||||
labelTrigger: "",
|
||||
directPrompt: "Fix the bug in the login form",
|
||||
overridePrompt: "",
|
||||
allowedTools: [],
|
||||
disallowedTools: [],
|
||||
customInstructions: "",
|
||||
branchPrefix: "claude/",
|
||||
useStickyComment: false,
|
||||
additionalPermissions: new Map(),
|
||||
useCommitSigning: false,
|
||||
},
|
||||
});
|
||||
expect(checkContainsTrigger(context)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false when direct prompt is empty", () => {
|
||||
const context = createMockContext({
|
||||
eventName: "issues",
|
||||
eventAction: "opened",
|
||||
payload: {
|
||||
action: "opened",
|
||||
issue: {
|
||||
number: 1,
|
||||
title: "Test Issue",
|
||||
body: "Test body without trigger",
|
||||
created_at: "2023-01-01T00:00:00Z",
|
||||
user: { login: "testuser" },
|
||||
},
|
||||
} as IssuesEvent,
|
||||
inputs: {
|
||||
mode: "tag",
|
||||
triggerPhrase: "/claude",
|
||||
assigneeTrigger: "",
|
||||
labelTrigger: "",
|
||||
directPrompt: "",
|
||||
overridePrompt: "",
|
||||
allowedTools: [],
|
||||
disallowedTools: [],
|
||||
customInstructions: "",
|
||||
branchPrefix: "claude/",
|
||||
useStickyComment: false,
|
||||
additionalPermissions: new Map(),
|
||||
useCommitSigning: false,
|
||||
},
|
||||
});
|
||||
expect(checkContainsTrigger(context)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("assignee trigger", () => {
|
||||
it("should return true when issue is assigned to the trigger user", () => {
|
||||
const context = mockIssueAssignedContext;
|
||||
expect(checkContainsTrigger(context)).toBe(true);
|
||||
});
|
||||
|
||||
it("should add @ symbol from assignee trigger", () => {
|
||||
const context = {
|
||||
...mockIssueAssignedContext,
|
||||
inputs: {
|
||||
...mockIssueAssignedContext.inputs,
|
||||
assigneeTrigger: "claude-bot",
|
||||
},
|
||||
};
|
||||
expect(checkContainsTrigger(context)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false when issue is assigned to a different user", () => {
|
||||
const context = {
|
||||
...mockIssueAssignedContext,
|
||||
payload: {
|
||||
...mockIssueAssignedContext.payload,
|
||||
assignee: {
|
||||
...(mockIssueAssignedContext.payload as IssuesAssignedEvent)
|
||||
.assignee,
|
||||
login: "otherUser",
|
||||
},
|
||||
issue: {
|
||||
...(mockIssueAssignedContext.payload as IssuesAssignedEvent).issue,
|
||||
assignee: {
|
||||
...(mockIssueAssignedContext.payload as IssuesAssignedEvent).issue
|
||||
.assignee,
|
||||
login: "otherUser",
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ParsedGitHubContext;
|
||||
|
||||
expect(checkContainsTrigger(context)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("label trigger", () => {
|
||||
it("should return true when issue is labeled with the trigger label", () => {
|
||||
const context = mockIssueLabeledContext;
|
||||
expect(checkContainsTrigger(context)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false when issue is labeled with a different label", () => {
|
||||
const context = {
|
||||
...mockIssueLabeledContext,
|
||||
payload: {
|
||||
...mockIssueLabeledContext.payload,
|
||||
label: {
|
||||
...(mockIssueLabeledContext.payload as any).label,
|
||||
name: "bug",
|
||||
},
|
||||
},
|
||||
} as ParsedGitHubContext;
|
||||
expect(checkContainsTrigger(context)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for non-labeled events", () => {
|
||||
const context = {
|
||||
...mockIssueLabeledContext,
|
||||
eventAction: "opened",
|
||||
payload: {
|
||||
...mockIssueLabeledContext.payload,
|
||||
action: "opened",
|
||||
},
|
||||
} as ParsedGitHubContext;
|
||||
expect(checkContainsTrigger(context)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("issue body and title trigger", () => {
|
||||
it("should return true when issue body contains trigger phrase", () => {
|
||||
const context = mockIssueOpenedContext;
|
||||
expect(checkContainsTrigger(context)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true when issue title contains trigger phrase", () => {
|
||||
const context = {
|
||||
...mockIssueOpenedContext,
|
||||
payload: {
|
||||
...mockIssueOpenedContext.payload,
|
||||
issue: {
|
||||
...(mockIssueOpenedContext.payload as IssuesEvent).issue,
|
||||
title: "/claude Fix the login bug",
|
||||
body: "The login page is broken",
|
||||
},
|
||||
},
|
||||
} as ParsedGitHubContext;
|
||||
expect(checkContainsTrigger(context)).toBe(true);
|
||||
});
|
||||
|
||||
it("should handle trigger phrase with punctuation", () => {
|
||||
const baseContext = {
|
||||
...mockIssueOpenedContext,
|
||||
inputs: {
|
||||
...mockIssueOpenedContext.inputs,
|
||||
triggerPhrase: "@claude",
|
||||
},
|
||||
};
|
||||
|
||||
// Test various punctuation marks
|
||||
const testCases = [
|
||||
{ issueBody: "@claude, can you help?", expected: true },
|
||||
{ issueBody: "@claude. Please look at this", expected: true },
|
||||
{ issueBody: "@claude! This is urgent", expected: true },
|
||||
{ issueBody: "@claude? What do you think?", expected: true },
|
||||
{ issueBody: "@claude: here's the issue", expected: true },
|
||||
{ issueBody: "@claude; and another thing", expected: true },
|
||||
{ issueBody: "Hey @claude, can you help?", expected: true },
|
||||
{ issueBody: "claudette contains claude", expected: false },
|
||||
{ issueBody: "email@claude.com", expected: false },
|
||||
];
|
||||
|
||||
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 return false when trigger phrase is part of another word", () => {
|
||||
const context = {
|
||||
...mockIssueOpenedContext,
|
||||
payload: {
|
||||
...mockIssueOpenedContext.payload,
|
||||
issue: {
|
||||
...(mockIssueOpenedContext.payload as IssuesEvent).issue,
|
||||
body: "claudette helped me with this",
|
||||
},
|
||||
},
|
||||
} as ParsedGitHubContext;
|
||||
expect(checkContainsTrigger(context)).toBe(false);
|
||||
});
|
||||
|
||||
it("should handle trigger phrase in title with punctuation", () => {
|
||||
const baseContext = {
|
||||
...mockIssueOpenedContext,
|
||||
inputs: {
|
||||
...mockIssueOpenedContext.inputs,
|
||||
triggerPhrase: "@claude",
|
||||
},
|
||||
};
|
||||
|
||||
const testCases = [
|
||||
{ issueTitle: "@claude, can you help?", expected: true },
|
||||
{ issueTitle: "@claude: Fix this bug", expected: true },
|
||||
{ issueTitle: "Bug: @claude please review", expected: true },
|
||||
{ issueTitle: "email@claude.com issue", expected: false },
|
||||
{ issueTitle: "claudette needs help", expected: false },
|
||||
];
|
||||
|
||||
testCases.forEach(({ issueTitle, expected }) => {
|
||||
const context = {
|
||||
...baseContext,
|
||||
payload: {
|
||||
...baseContext.payload,
|
||||
issue: {
|
||||
...(baseContext.payload as IssuesEvent).issue,
|
||||
title: issueTitle,
|
||||
body: "No trigger in body",
|
||||
},
|
||||
},
|
||||
} as ParsedGitHubContext;
|
||||
expect(checkContainsTrigger(context)).toBe(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("pull request body and title trigger", () => {
|
||||
it("should return true when PR body contains trigger phrase", () => {
|
||||
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: {
|
||||
mode: "tag",
|
||||
triggerPhrase: "@claude",
|
||||
assigneeTrigger: "",
|
||||
labelTrigger: "",
|
||||
directPrompt: "",
|
||||
overridePrompt: "",
|
||||
allowedTools: [],
|
||||
disallowedTools: [],
|
||||
customInstructions: "",
|
||||
branchPrefix: "claude/",
|
||||
useStickyComment: false,
|
||||
additionalPermissions: new Map(),
|
||||
useCommitSigning: false,
|
||||
},
|
||||
});
|
||||
expect(checkContainsTrigger(context)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true when PR title contains trigger phrase", () => {
|
||||
const context = createMockContext({
|
||||
eventName: "pull_request",
|
||||
eventAction: "opened",
|
||||
isPR: true,
|
||||
payload: {
|
||||
action: "opened",
|
||||
pull_request: {
|
||||
number: 123,
|
||||
title: "@claude Review this PR",
|
||||
body: "This PR fixes a bug",
|
||||
created_at: "2023-01-01T00:00:00Z",
|
||||
user: { login: "testuser" },
|
||||
},
|
||||
} as PullRequestEvent,
|
||||
inputs: {
|
||||
mode: "tag",
|
||||
triggerPhrase: "@claude",
|
||||
assigneeTrigger: "",
|
||||
labelTrigger: "",
|
||||
directPrompt: "",
|
||||
overridePrompt: "",
|
||||
allowedTools: [],
|
||||
disallowedTools: [],
|
||||
customInstructions: "",
|
||||
branchPrefix: "claude/",
|
||||
useStickyComment: false,
|
||||
additionalPermissions: new Map(),
|
||||
useCommitSigning: false,
|
||||
},
|
||||
});
|
||||
expect(checkContainsTrigger(context)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false when PR body doesn't contain trigger phrase", () => {
|
||||
const context = createMockContext({
|
||||
eventName: "pull_request",
|
||||
eventAction: "opened",
|
||||
isPR: true,
|
||||
payload: {
|
||||
action: "opened",
|
||||
pull_request: {
|
||||
number: 123,
|
||||
title: "Test PR",
|
||||
body: "This PR fixes a bug",
|
||||
created_at: "2023-01-01T00:00:00Z",
|
||||
user: { login: "testuser" },
|
||||
},
|
||||
} as PullRequestEvent,
|
||||
inputs: {
|
||||
mode: "tag",
|
||||
triggerPhrase: "@claude",
|
||||
assigneeTrigger: "",
|
||||
labelTrigger: "",
|
||||
directPrompt: "",
|
||||
overridePrompt: "",
|
||||
allowedTools: [],
|
||||
disallowedTools: [],
|
||||
customInstructions: "",
|
||||
branchPrefix: "claude/",
|
||||
useStickyComment: false,
|
||||
additionalPermissions: new Map(),
|
||||
useCommitSigning: false,
|
||||
},
|
||||
});
|
||||
expect(checkContainsTrigger(context)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("pull request reviewer trigger", () => {
|
||||
it("should return true when PR has trigger user as requested reviewer (same as text mention)", () => {
|
||||
const context = createMockContext({
|
||||
eventName: "pull_request",
|
||||
eventAction: "opened",
|
||||
isPR: true,
|
||||
payload: {
|
||||
action: "opened",
|
||||
pull_request: {
|
||||
number: 123,
|
||||
title: "Test PR",
|
||||
body: "This PR fixes a bug",
|
||||
created_at: "2023-01-01T00:00:00Z",
|
||||
user: { login: "testuser" },
|
||||
requested_reviewers: [
|
||||
{ login: "claude", id: 1, type: "User" },
|
||||
{ login: "other-reviewer", id: 2, type: "User" },
|
||||
],
|
||||
},
|
||||
} as unknown as PullRequestEvent,
|
||||
inputs: {
|
||||
mode: "tag",
|
||||
triggerPhrase: "@claude",
|
||||
assigneeTrigger: "",
|
||||
labelTrigger: "",
|
||||
directPrompt: "",
|
||||
overridePrompt: "",
|
||||
allowedTools: [],
|
||||
disallowedTools: [],
|
||||
customInstructions: "",
|
||||
branchPrefix: "claude/",
|
||||
useStickyComment: false,
|
||||
additionalPermissions: new Map(),
|
||||
useCommitSigning: false,
|
||||
},
|
||||
});
|
||||
expect(checkContainsTrigger(context)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for synchronized PR with trigger user as reviewer", () => {
|
||||
const context = createMockContext({
|
||||
eventName: "pull_request",
|
||||
eventAction: "synchronized",
|
||||
isPR: true,
|
||||
payload: {
|
||||
action: "synchronized",
|
||||
pull_request: {
|
||||
number: 123,
|
||||
title: "Test PR",
|
||||
body: "This PR fixes a bug",
|
||||
created_at: "2023-01-01T00:00:00Z",
|
||||
user: { login: "testuser" },
|
||||
requested_reviewers: [
|
||||
{ login: "claude", id: 1, type: "User" },
|
||||
],
|
||||
},
|
||||
} as unknown as PullRequestEvent,
|
||||
inputs: {
|
||||
mode: "tag",
|
||||
triggerPhrase: "@claude",
|
||||
assigneeTrigger: "",
|
||||
labelTrigger: "",
|
||||
directPrompt: "",
|
||||
overridePrompt: "",
|
||||
allowedTools: [],
|
||||
disallowedTools: [],
|
||||
customInstructions: "",
|
||||
branchPrefix: "claude/",
|
||||
useStickyComment: false,
|
||||
additionalPermissions: new Map(),
|
||||
useCommitSigning: false,
|
||||
},
|
||||
});
|
||||
expect(checkContainsTrigger(context)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false when PR has no matching requested reviewers", () => {
|
||||
const context = createMockContext({
|
||||
eventName: "pull_request",
|
||||
eventAction: "opened",
|
||||
isPR: true,
|
||||
payload: {
|
||||
action: "opened",
|
||||
pull_request: {
|
||||
number: 123,
|
||||
title: "Test PR",
|
||||
body: "This PR fixes a bug",
|
||||
created_at: "2023-01-01T00:00:00Z",
|
||||
user: { login: "testuser" },
|
||||
requested_reviewers: [
|
||||
{ login: "other-reviewer", id: 2, type: "User" },
|
||||
],
|
||||
},
|
||||
} as unknown as PullRequestEvent,
|
||||
inputs: {
|
||||
mode: "tag",
|
||||
triggerPhrase: "@claude",
|
||||
assigneeTrigger: "",
|
||||
labelTrigger: "",
|
||||
directPrompt: "",
|
||||
overridePrompt: "",
|
||||
allowedTools: [],
|
||||
disallowedTools: [],
|
||||
customInstructions: "",
|
||||
branchPrefix: "claude/",
|
||||
useStickyComment: false,
|
||||
additionalPermissions: new Map(),
|
||||
useCommitSigning: false,
|
||||
},
|
||||
});
|
||||
expect(checkContainsTrigger(context)).toBe(false);
|
||||
});
|
||||
|
||||
it("should handle trigger phrase without @ symbol", () => {
|
||||
const context = createMockContext({
|
||||
eventName: "pull_request",
|
||||
eventAction: "opened",
|
||||
isPR: true,
|
||||
payload: {
|
||||
action: "opened",
|
||||
pull_request: {
|
||||
number: 123,
|
||||
title: "Test PR",
|
||||
body: "This PR fixes a bug",
|
||||
created_at: "2023-01-01T00:00:00Z",
|
||||
user: { login: "testuser" },
|
||||
requested_reviewers: [
|
||||
{ login: "claude", id: 1, type: "User" },
|
||||
],
|
||||
},
|
||||
} as unknown as PullRequestEvent,
|
||||
inputs: {
|
||||
mode: "tag",
|
||||
triggerPhrase: "claude", // No @ symbol
|
||||
assigneeTrigger: "",
|
||||
labelTrigger: "",
|
||||
directPrompt: "",
|
||||
overridePrompt: "",
|
||||
allowedTools: [],
|
||||
disallowedTools: [],
|
||||
customInstructions: "",
|
||||
branchPrefix: "claude/",
|
||||
useStickyComment: false,
|
||||
additionalPermissions: new Map(),
|
||||
useCommitSigning: false,
|
||||
},
|
||||
});
|
||||
expect(checkContainsTrigger(context)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it("should return true when PR has trigger user as requested reviewer for synchronized event", () => {
|
||||
const context = createMockContext({
|
||||
eventName: "pull_request",
|
||||
eventAction: "synchronized",
|
||||
isPR: true,
|
||||
payload: {
|
||||
action: "synchronized",
|
||||
pull_request: {
|
||||
number: 123,
|
||||
title: "Test PR",
|
||||
body: "This PR fixes a bug",
|
||||
created_at: "2023-01-01T00:00:00Z",
|
||||
user: { login: "testuser" },
|
||||
requested_reviewers: [
|
||||
{ login: "claude", id: 1, type: "User" },
|
||||
],
|
||||
requested_teams: [],
|
||||
},
|
||||
} as unknown as PullRequestEvent,
|
||||
inputs: {
|
||||
mode: "tag",
|
||||
triggerPhrase: "@claude",
|
||||
assigneeTrigger: "",
|
||||
labelTrigger: "",
|
||||
directPrompt: "",
|
||||
overridePrompt: "",
|
||||
allowedTools: [],
|
||||
disallowedTools: [],
|
||||
customInstructions: "",
|
||||
branchPrefix: "claude/",
|
||||
useStickyComment: false,
|
||||
additionalPermissions: new Map(),
|
||||
useCommitSigning: false,
|
||||
},
|
||||
});
|
||||
expect(checkContainsTrigger(context)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false when PR has no matching requested reviewers", () => {
|
||||
const context = createMockContext({
|
||||
eventName: "pull_request",
|
||||
eventAction: "opened",
|
||||
isPR: true,
|
||||
payload: {
|
||||
action: "opened",
|
||||
pull_request: {
|
||||
number: 123,
|
||||
title: "Test PR",
|
||||
body: "This PR fixes a bug",
|
||||
created_at: "2023-01-01T00:00:00Z",
|
||||
user: { login: "testuser" },
|
||||
requested_reviewers: [
|
||||
{ login: "other-reviewer", id: 2, type: "User" },
|
||||
],
|
||||
requested_teams: [],
|
||||
},
|
||||
} as unknown as PullRequestEvent,
|
||||
inputs: {
|
||||
mode: "tag",
|
||||
triggerPhrase: "@claude",
|
||||
assigneeTrigger: "",
|
||||
labelTrigger: "",
|
||||
directPrompt: "",
|
||||
overridePrompt: "",
|
||||
allowedTools: [],
|
||||
disallowedTools: [],
|
||||
customInstructions: "",
|
||||
branchPrefix: "claude/",
|
||||
useStickyComment: false,
|
||||
additionalPermissions: new Map(),
|
||||
useCommitSigning: false,
|
||||
},
|
||||
});
|
||||
expect(checkContainsTrigger(context)).toBe(false);
|
||||
});
|
||||
|
||||
it("should handle trigger phrase without @ symbol", () => {
|
||||
const context = createMockContext({
|
||||
eventName: "pull_request",
|
||||
eventAction: "opened",
|
||||
isPR: true,
|
||||
payload: {
|
||||
action: "opened",
|
||||
pull_request: {
|
||||
number: 123,
|
||||
title: "Test PR",
|
||||
body: "This PR fixes a bug",
|
||||
created_at: "2023-01-01T00:00:00Z",
|
||||
user: { login: "testuser" },
|
||||
requested_reviewers: [
|
||||
{ login: "claude", id: 1, type: "User" },
|
||||
],
|
||||
requested_teams: [],
|
||||
},
|
||||
} as unknown as PullRequestEvent,
|
||||
inputs: {
|
||||
mode: "tag",
|
||||
triggerPhrase: "claude", // No @ symbol
|
||||
assigneeTrigger: "",
|
||||
labelTrigger: "",
|
||||
directPrompt: "",
|
||||
overridePrompt: "",
|
||||
allowedTools: [],
|
||||
disallowedTools: [],
|
||||
customInstructions: "",
|
||||
branchPrefix: "claude/",
|
||||
useStickyComment: false,
|
||||
additionalPermissions: new Map(),
|
||||
useCommitSigning: false,
|
||||
},
|
||||
});
|
||||
expect(checkContainsTrigger(context)).toBe(true);
|
||||
});
|
||||
|
||||
it("should handle empty requested_reviewers and requested_teams arrays", () => {
|
||||
const context = createMockContext({
|
||||
eventName: "pull_request",
|
||||
eventAction: "opened",
|
||||
isPR: true,
|
||||
payload: {
|
||||
action: "opened",
|
||||
pull_request: {
|
||||
number: 123,
|
||||
title: "Test PR",
|
||||
body: "This PR fixes a bug",
|
||||
created_at: "2023-01-01T00:00:00Z",
|
||||
user: { login: "testuser" },
|
||||
requested_reviewers: [],
|
||||
requested_teams: [],
|
||||
},
|
||||
} as unknown as PullRequestEvent,
|
||||
inputs: {
|
||||
mode: "tag",
|
||||
triggerPhrase: "@claude",
|
||||
assigneeTrigger: "",
|
||||
labelTrigger: "",
|
||||
directPrompt: "",
|
||||
overridePrompt: "",
|
||||
allowedTools: [],
|
||||
disallowedTools: [],
|
||||
customInstructions: "",
|
||||
branchPrefix: "claude/",
|
||||
useStickyComment: false,
|
||||
additionalPermissions: new Map(),
|
||||
useCommitSigning: false,
|
||||
},
|
||||
});
|
||||
expect(checkContainsTrigger(context)).toBe(false);
|
||||
});
|
||||
|
||||
it("should handle missing requested_reviewers and requested_teams fields", () => {
|
||||
const context = createMockContext({
|
||||
eventName: "pull_request",
|
||||
eventAction: "opened",
|
||||
isPR: true,
|
||||
payload: {
|
||||
action: "opened",
|
||||
pull_request: {
|
||||
number: 123,
|
||||
title: "Test PR",
|
||||
body: "This PR fixes a bug",
|
||||
created_at: "2023-01-01T00:00:00Z",
|
||||
user: { login: "testuser" },
|
||||
// requested_reviewers and requested_teams are undefined
|
||||
},
|
||||
} as unknown as PullRequestEvent,
|
||||
inputs: {
|
||||
mode: "tag",
|
||||
triggerPhrase: "@claude",
|
||||
assigneeTrigger: "",
|
||||
labelTrigger: "",
|
||||
directPrompt: "",
|
||||
overridePrompt: "",
|
||||
allowedTools: [],
|
||||
disallowedTools: [],
|
||||
customInstructions: "",
|
||||
branchPrefix: "claude/",
|
||||
useStickyComment: false,
|
||||
additionalPermissions: new Map(),
|
||||
useCommitSigning: false,
|
||||
},
|
||||
});
|
||||
expect(checkContainsTrigger(context)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("comment trigger", () => {
|
||||
it("should return true for issue_comment with trigger phrase", () => {
|
||||
const context = mockIssueCommentContext;
|
||||
expect(checkContainsTrigger(context)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for pull_request_review_comment with trigger phrase", () => {
|
||||
const context = mockPullRequestReviewCommentContext;
|
||||
expect(checkContainsTrigger(context)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for pull_request_review with submitted action and trigger phrase", () => {
|
||||
const context = mockPullRequestReviewContext;
|
||||
expect(checkContainsTrigger(context)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for pull_request_review with edited action and trigger phrase", () => {
|
||||
const context = {
|
||||
...mockPullRequestReviewContext,
|
||||
eventAction: "edited",
|
||||
payload: {
|
||||
...mockPullRequestReviewContext.payload,
|
||||
action: "edited",
|
||||
},
|
||||
} as ParsedGitHubContext;
|
||||
expect(checkContainsTrigger(context)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false for pull_request_review with different action", () => {
|
||||
const context = {
|
||||
...mockPullRequestReviewContext,
|
||||
eventAction: "dismissed",
|
||||
payload: {
|
||||
...mockPullRequestReviewContext.payload,
|
||||
action: "dismissed",
|
||||
review: {
|
||||
...(mockPullRequestReviewContext.payload as PullRequestReviewEvent)
|
||||
.review,
|
||||
body: "/claude please review this PR",
|
||||
},
|
||||
},
|
||||
} as ParsedGitHubContext;
|
||||
expect(checkContainsTrigger(context)).toBe(false);
|
||||
});
|
||||
|
||||
it("should handle pull_request_review with punctuation", () => {
|
||||
const baseContext = {
|
||||
...mockPullRequestReviewContext,
|
||||
inputs: {
|
||||
...mockPullRequestReviewContext.inputs,
|
||||
triggerPhrase: "@claude",
|
||||
},
|
||||
};
|
||||
|
||||
const testCases = [
|
||||
{ commentBody: "@claude, please review", expected: true },
|
||||
{ commentBody: "@claude. fix this", expected: true },
|
||||
{ commentBody: "@claude!", expected: true },
|
||||
{ commentBody: "claude@example.com", expected: false },
|
||||
{ commentBody: "claudette", expected: false },
|
||||
];
|
||||
|
||||
testCases.forEach(({ commentBody, expected }) => {
|
||||
const context = {
|
||||
...baseContext,
|
||||
payload: {
|
||||
...baseContext.payload,
|
||||
review: {
|
||||
...(baseContext.payload as PullRequestReviewEvent).review,
|
||||
body: commentBody,
|
||||
},
|
||||
},
|
||||
} as ParsedGitHubContext;
|
||||
expect(checkContainsTrigger(context)).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it("should handle comment trigger with punctuation", () => {
|
||||
const baseContext = {
|
||||
...mockIssueCommentContext,
|
||||
inputs: {
|
||||
...mockIssueCommentContext.inputs,
|
||||
triggerPhrase: "@claude",
|
||||
},
|
||||
};
|
||||
|
||||
const testCases = [
|
||||
{ commentBody: "@claude, please review", expected: true },
|
||||
{ commentBody: "@claude. fix this", expected: true },
|
||||
{ commentBody: "@claude!", expected: true },
|
||||
{ commentBody: "claude@example.com", expected: false },
|
||||
{ commentBody: "claudette", expected: false },
|
||||
];
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("pull request review_requested action", () => {
|
||||
it("should return true when trigger user is requested as reviewer", () => {
|
||||
const context = createMockContext({
|
||||
eventName: "pull_request",
|
||||
eventAction: "review_requested",
|
||||
isPR: true,
|
||||
payload: {
|
||||
action: "review_requested",
|
||||
pull_request: {
|
||||
number: 123,
|
||||
title: "Test PR",
|
||||
body: "This PR fixes a bug",
|
||||
created_at: "2023-01-01T00:00:00Z",
|
||||
user: { login: "testuser" },
|
||||
requested_reviewers: [{ login: "claude", id: 1, type: "User" }],
|
||||
requested_teams: [],
|
||||
},
|
||||
requested_reviewer: { login: "claude", id: 1, type: "User" },
|
||||
} as unknown as PullRequestEvent,
|
||||
inputs: {
|
||||
mode: "tag",
|
||||
triggerPhrase: "@claude",
|
||||
assigneeTrigger: "",
|
||||
labelTrigger: "",
|
||||
directPrompt: "",
|
||||
overridePrompt: "",
|
||||
allowedTools: [],
|
||||
disallowedTools: [],
|
||||
customInstructions: "",
|
||||
branchPrefix: "claude/",
|
||||
useStickyComment: false,
|
||||
additionalPermissions: new Map(),
|
||||
useCommitSigning: false,
|
||||
},
|
||||
});
|
||||
expect(checkContainsTrigger(context)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false when different user is requested as reviewer", () => {
|
||||
const context = createMockContext({
|
||||
eventName: "pull_request",
|
||||
eventAction: "review_requested",
|
||||
isPR: true,
|
||||
payload: {
|
||||
action: "review_requested",
|
||||
pull_request: {
|
||||
number: 123,
|
||||
title: "Test PR",
|
||||
body: "This PR fixes a bug",
|
||||
created_at: "2023-01-01T00:00:00Z",
|
||||
user: { login: "testuser" },
|
||||
requested_reviewers: [{ login: "john", id: 2, type: "User" }],
|
||||
requested_teams: [],
|
||||
},
|
||||
requested_reviewer: { login: "john", id: 2, type: "User" },
|
||||
} as unknown as PullRequestEvent,
|
||||
inputs: {
|
||||
mode: "tag",
|
||||
triggerPhrase: "@claude",
|
||||
assigneeTrigger: "",
|
||||
labelTrigger: "",
|
||||
directPrompt: "",
|
||||
overridePrompt: "",
|
||||
allowedTools: [],
|
||||
disallowedTools: [],
|
||||
customInstructions: "",
|
||||
branchPrefix: "claude/",
|
||||
useStickyComment: false,
|
||||
additionalPermissions: new Map(),
|
||||
useCommitSigning: false,
|
||||
},
|
||||
});
|
||||
expect(checkContainsTrigger(context)).toBe(false);
|
||||
});
|
||||
|
||||
it("should handle trigger phrase without @ symbol", () => {
|
||||
const context = createMockContext({
|
||||
eventName: "pull_request",
|
||||
eventAction: "review_requested",
|
||||
isPR: true,
|
||||
payload: {
|
||||
action: "review_requested",
|
||||
pull_request: {
|
||||
number: 123,
|
||||
title: "Test PR",
|
||||
body: "This PR fixes a bug",
|
||||
created_at: "2023-01-01T00:00:00Z",
|
||||
user: { login: "testuser" },
|
||||
requested_reviewers: [{ login: "claude", id: 1, type: "User" }],
|
||||
requested_teams: [],
|
||||
},
|
||||
requested_reviewer: { login: "claude", id: 1, type: "User" },
|
||||
} as unknown as PullRequestEvent,
|
||||
inputs: {
|
||||
mode: "tag",
|
||||
triggerPhrase: "claude", // no @ symbol
|
||||
assigneeTrigger: "",
|
||||
labelTrigger: "",
|
||||
directPrompt: "",
|
||||
overridePrompt: "",
|
||||
allowedTools: [],
|
||||
disallowedTools: [],
|
||||
customInstructions: "",
|
||||
branchPrefix: "claude/",
|
||||
useStickyComment: false,
|
||||
additionalPermissions: new Map(),
|
||||
useCommitSigning: false,
|
||||
},
|
||||
});
|
||||
expect(checkContainsTrigger(context)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("non-matching events", () => {
|
||||
it("should return false for non-matching event type", () => {
|
||||
const context = createMockContext({
|
||||
eventName: "push",
|
||||
eventAction: "created",
|
||||
payload: {} as any,
|
||||
});
|
||||
expect(checkContainsTrigger(context)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("escapeRegExp", () => {
|
||||
it("should escape special regex characters", () => {
|
||||
expect(escapeRegExp(".*+?^${}()|[]\\")).toBe(
|
||||
"\\.\\*\\+\\?\\^\\$\\{\\}\\(\\)\\|\\[\\]\\\\",
|
||||
);
|
||||
});
|
||||
|
||||
it("should not escape regular characters", () => {
|
||||
expect(escapeRegExp("abc123")).toBe("abc123");
|
||||
});
|
||||
|
||||
it("should handle mixed characters", () => {
|
||||
expect(escapeRegExp("hello.world")).toBe("hello\\.world");
|
||||
expect(escapeRegExp("test[123]")).toBe("test\\[123\\]");
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue