mirror of
https://github.com/anthropics/claude-code-action.git
synced 2026-01-23 06:54:13 +08:00
* fix: `commentBody` may be `null` This handles the cases where `pull_request_review` events have no comments (`commentBody` field is `null`). In those cases, the `null` value is converted to the empty string. The issue was testing `!commentBody` which was triggerring on empty strings as well. This guard was removed (which is the fix), but for clarity, the `commentBody` field was also made optional to make it clear that the comment may be missing. * fix: bun run format
312 lines
10 KiB
TypeScript
312 lines
10 KiB
TypeScript
#!/usr/bin/env bun
|
|
|
|
import { describe, test, expect, beforeEach, afterEach } from "bun:test";
|
|
import { prepareContext } from "../src/create-prompt";
|
|
import {
|
|
createMockContext,
|
|
mockIssueOpenedContext,
|
|
mockIssueAssignedContext,
|
|
mockIssueCommentContext,
|
|
mockPullRequestCommentContext,
|
|
mockPullRequestReviewContext,
|
|
mockPullRequestReviewCommentContext,
|
|
mockPullRequestReviewWithoutCommentContext,
|
|
} from "./mockContext";
|
|
|
|
const BASE_ENV = {
|
|
CLAUDE_COMMENT_ID: "12345",
|
|
GITHUB_TOKEN: "test-token",
|
|
};
|
|
|
|
describe("parseEnvVarsWithContext", () => {
|
|
let originalEnv: typeof process.env;
|
|
|
|
beforeEach(() => {
|
|
originalEnv = { ...process.env };
|
|
process.env = {};
|
|
});
|
|
|
|
afterEach(() => {
|
|
process.env = originalEnv;
|
|
});
|
|
|
|
describe("issue_comment event", () => {
|
|
describe("on issue", () => {
|
|
beforeEach(() => {
|
|
process.env = {
|
|
...BASE_ENV,
|
|
BASE_BRANCH: "main",
|
|
CLAUDE_BRANCH: "claude/issue-67890-20240101-1200",
|
|
};
|
|
});
|
|
|
|
test("should parse issue_comment event correctly", () => {
|
|
const result = prepareContext(
|
|
mockIssueCommentContext,
|
|
"12345",
|
|
"main",
|
|
"claude/issue-67890-20240101-1200",
|
|
);
|
|
|
|
expect(result.repository).toBe("test-owner/test-repo");
|
|
expect(result.claudeCommentId).toBe("12345");
|
|
expect(result.triggerPhrase).toBe("@claude");
|
|
expect(result.triggerUsername).toBe("contributor-user");
|
|
expect(result.eventData.eventName).toBe("issue_comment");
|
|
expect(result.eventData.isPR).toBe(false);
|
|
if (
|
|
result.eventData.eventName === "issue_comment" &&
|
|
!result.eventData.isPR
|
|
) {
|
|
expect(result.eventData.issueNumber).toBe("55");
|
|
expect(result.eventData.commentId).toBe("12345678");
|
|
expect(result.eventData.claudeBranch).toBe(
|
|
"claude/issue-67890-20240101-1200",
|
|
);
|
|
expect(result.eventData.baseBranch).toBe("main");
|
|
expect(result.eventData.commentBody).toBe(
|
|
"@claude can you help explain how to configure the logging system?",
|
|
);
|
|
}
|
|
});
|
|
|
|
test("should throw error when CLAUDE_BRANCH is missing", () => {
|
|
expect(() =>
|
|
prepareContext(mockIssueCommentContext, "12345", "main"),
|
|
).toThrow("CLAUDE_BRANCH is required for issue_comment event");
|
|
});
|
|
|
|
test("should throw error when BASE_BRANCH is missing", () => {
|
|
expect(() =>
|
|
prepareContext(
|
|
mockIssueCommentContext,
|
|
"12345",
|
|
undefined,
|
|
"claude/issue-67890-20240101-1200",
|
|
),
|
|
).toThrow("BASE_BRANCH is required for issue_comment event");
|
|
});
|
|
});
|
|
|
|
describe("on PR", () => {
|
|
test("should parse PR issue_comment event correctly", () => {
|
|
process.env = BASE_ENV;
|
|
const result = prepareContext(mockPullRequestCommentContext, "12345");
|
|
|
|
expect(result.eventData.eventName).toBe("issue_comment");
|
|
expect(result.eventData.isPR).toBe(true);
|
|
expect(result.triggerUsername).toBe("reviewer-user");
|
|
if (
|
|
result.eventData.eventName === "issue_comment" &&
|
|
result.eventData.isPR
|
|
) {
|
|
expect(result.eventData.prNumber).toBe("789");
|
|
expect(result.eventData.commentId).toBe("87654321");
|
|
expect(result.eventData.commentBody).toBe(
|
|
"/claude please review the changes and ensure we're not introducing any new memory issues",
|
|
);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("pull_request_review event", () => {
|
|
test("should parse pull_request_review event correctly", () => {
|
|
process.env = BASE_ENV;
|
|
const result = prepareContext(mockPullRequestReviewContext, "12345");
|
|
|
|
expect(result.eventData.eventName).toBe("pull_request_review");
|
|
expect(result.eventData.isPR).toBe(true);
|
|
expect(result.triggerUsername).toBe("senior-developer");
|
|
if (result.eventData.eventName === "pull_request_review") {
|
|
expect(result.eventData.prNumber).toBe("321");
|
|
expect(result.eventData.commentBody).toBe(
|
|
"@claude can you check if the error handling is comprehensive enough in this PR?",
|
|
);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("pull_request_review event without comment", () => {
|
|
test("should parse pull_request_review event correctly", () => {
|
|
process.env = BASE_ENV;
|
|
const result = prepareContext(
|
|
mockPullRequestReviewWithoutCommentContext,
|
|
"12345",
|
|
);
|
|
|
|
expect(result.eventData.eventName).toBe("pull_request_review");
|
|
expect(result.eventData.isPR).toBe(true);
|
|
expect(result.triggerUsername).toBe("senior-developer");
|
|
if (result.eventData.eventName === "pull_request_review") {
|
|
expect(result.eventData.prNumber).toBe("321");
|
|
expect(result.eventData.commentBody).toBe("");
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("pull_request_review_comment event", () => {
|
|
test("should parse pull_request_review_comment event correctly", () => {
|
|
process.env = BASE_ENV;
|
|
const result = prepareContext(
|
|
mockPullRequestReviewCommentContext,
|
|
"12345",
|
|
);
|
|
|
|
expect(result.eventData.eventName).toBe("pull_request_review_comment");
|
|
expect(result.eventData.isPR).toBe(true);
|
|
expect(result.triggerUsername).toBe("code-reviewer");
|
|
if (result.eventData.eventName === "pull_request_review_comment") {
|
|
expect(result.eventData.prNumber).toBe("999");
|
|
expect(result.eventData.commentId).toBe("99988877");
|
|
expect(result.eventData.commentBody).toBe(
|
|
"/claude is this the most efficient way to implement this algorithm?",
|
|
);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("issues event", () => {
|
|
beforeEach(() => {
|
|
process.env = {
|
|
...BASE_ENV,
|
|
BASE_BRANCH: "main",
|
|
CLAUDE_BRANCH: "claude/issue-42-20240101-1200",
|
|
};
|
|
});
|
|
|
|
test("should parse issue opened event correctly", () => {
|
|
const result = prepareContext(
|
|
mockIssueOpenedContext,
|
|
"12345",
|
|
"main",
|
|
"claude/issue-42-20240101-1200",
|
|
);
|
|
|
|
expect(result.eventData.eventName).toBe("issues");
|
|
expect(result.eventData.isPR).toBe(false);
|
|
expect(result.triggerUsername).toBe("john-doe");
|
|
if (
|
|
result.eventData.eventName === "issues" &&
|
|
result.eventData.eventAction === "opened"
|
|
) {
|
|
expect(result.eventData.issueNumber).toBe("42");
|
|
expect(result.eventData.baseBranch).toBe("main");
|
|
expect(result.eventData.claudeBranch).toBe(
|
|
"claude/issue-42-20240101-1200",
|
|
);
|
|
}
|
|
});
|
|
|
|
test("should parse issue assigned event correctly", () => {
|
|
const result = prepareContext(
|
|
mockIssueAssignedContext,
|
|
"12345",
|
|
"main",
|
|
"claude/issue-123-20240101-1200",
|
|
);
|
|
|
|
expect(result.eventData.eventName).toBe("issues");
|
|
expect(result.eventData.isPR).toBe(false);
|
|
expect(result.triggerUsername).toBe("jane-smith");
|
|
if (
|
|
result.eventData.eventName === "issues" &&
|
|
result.eventData.eventAction === "assigned"
|
|
) {
|
|
expect(result.eventData.issueNumber).toBe("123");
|
|
expect(result.eventData.baseBranch).toBe("main");
|
|
expect(result.eventData.claudeBranch).toBe(
|
|
"claude/issue-123-20240101-1200",
|
|
);
|
|
expect(result.eventData.assigneeTrigger).toBe("@claude-bot");
|
|
}
|
|
});
|
|
|
|
test("should throw error when CLAUDE_BRANCH is missing for issues", () => {
|
|
expect(() =>
|
|
prepareContext(mockIssueOpenedContext, "12345", "main"),
|
|
).toThrow("CLAUDE_BRANCH is required for issues event");
|
|
});
|
|
|
|
test("should throw error when BASE_BRANCH is missing for issues", () => {
|
|
expect(() =>
|
|
prepareContext(
|
|
mockIssueOpenedContext,
|
|
"12345",
|
|
undefined,
|
|
"claude/issue-42-20240101-1200",
|
|
),
|
|
).toThrow("BASE_BRANCH is required for issues event");
|
|
});
|
|
|
|
test("should allow issue assigned event with prompt and no assigneeTrigger", () => {
|
|
const contextWithDirectPrompt = createMockContext({
|
|
...mockIssueAssignedContext,
|
|
inputs: {
|
|
...mockIssueAssignedContext.inputs,
|
|
assigneeTrigger: "", // No assignee trigger
|
|
prompt: "Please assess this issue", // But prompt is provided
|
|
},
|
|
});
|
|
|
|
const result = prepareContext(
|
|
contextWithDirectPrompt,
|
|
"12345",
|
|
"main",
|
|
"claude/issue-123-20240101-1200",
|
|
);
|
|
|
|
expect(result.eventData.eventName).toBe("issues");
|
|
expect(result.eventData.isPR).toBe(false);
|
|
expect(result.prompt).toBe("Please assess this issue");
|
|
if (
|
|
result.eventData.eventName === "issues" &&
|
|
result.eventData.eventAction === "assigned"
|
|
) {
|
|
expect(result.eventData.issueNumber).toBe("123");
|
|
expect(result.eventData.assigneeTrigger).toBeUndefined();
|
|
}
|
|
});
|
|
|
|
test("should throw error when neither assigneeTrigger nor prompt provided for issue assigned event", () => {
|
|
const contextWithoutTriggers = createMockContext({
|
|
...mockIssueAssignedContext,
|
|
inputs: {
|
|
...mockIssueAssignedContext.inputs,
|
|
assigneeTrigger: "", // No assignee trigger
|
|
prompt: "", // No prompt
|
|
},
|
|
});
|
|
|
|
expect(() =>
|
|
prepareContext(
|
|
contextWithoutTriggers,
|
|
"12345",
|
|
"main",
|
|
"claude/issue-123-20240101-1200",
|
|
),
|
|
).toThrow("ASSIGNEE_TRIGGER is required for issue assigned event");
|
|
});
|
|
});
|
|
|
|
describe("context generation", () => {
|
|
test("should generate context without legacy fields", () => {
|
|
process.env = BASE_ENV;
|
|
const context = createMockContext({
|
|
...mockPullRequestCommentContext,
|
|
inputs: {
|
|
...mockPullRequestCommentContext.inputs,
|
|
},
|
|
});
|
|
const result = prepareContext(context, "12345");
|
|
|
|
// Verify context is created without legacy fields
|
|
expect(result.repository).toBe("test-owner/test-repo");
|
|
expect(result.claudeCommentId).toBe("12345");
|
|
expect(result.triggerPhrase).toBe("/claude");
|
|
expect((result as any).customInstructions).toBeUndefined();
|
|
expect((result as any).allowedTools).toBeUndefined();
|
|
});
|
|
});
|
|
});
|