mirror of
https://github.com/anthropics/claude-code-action.git
synced 2026-01-22 22:44:13 +08:00
* feat: add use_commit_signing input with default false - Add new input 'use_commit_signing' to action.yml (defaults to false) - Separate comment update functionality into standalone github-comment-server.ts - Update MCP server configuration to conditionally load servers based on signing preference - When commit signing is disabled, use specific Bash git commands (e.g., Bash(git add:*)) - When commit signing is enabled, use github-file-ops-server for atomic commits with signing - Always include github-comment-server for comment updates regardless of signing mode - Update prompt generation to provide appropriate instructions based on signing preference - Add comprehensive test coverage for new functionality This change simplifies the default setup for users who don't need commit signing, while maintaining the option to enable it for those who require GitHub's commit signature verification. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: auto-commit uncommitted changes when commit signing is disabled - Check for uncommitted changes after Claude finishes (non-signing mode only) - Automatically commit and push any uncommitted work to preserve Claude's changes - Update tests to avoid actual git operations during test runs - Pass use_commit_signing flag to branch cleanup logic --------- Co-authored-by: Claude <noreply@anthropic.com>
152 lines
4.3 KiB
TypeScript
152 lines
4.3 KiB
TypeScript
import { describe, test, expect, beforeEach, afterEach, spyOn } from "bun:test";
|
|
import { checkAndCommitOrDeleteBranch } from "../src/github/operations/branch-cleanup";
|
|
import type { Octokits } from "../src/github/api/client";
|
|
import { GITHUB_SERVER_URL } from "../src/github/api/config";
|
|
|
|
describe("checkAndCommitOrDeleteBranch", () => {
|
|
let consoleLogSpy: any;
|
|
let consoleErrorSpy: any;
|
|
|
|
beforeEach(() => {
|
|
// Spy on console methods
|
|
consoleLogSpy = spyOn(console, "log").mockImplementation(() => {});
|
|
consoleErrorSpy = spyOn(console, "error").mockImplementation(() => {});
|
|
});
|
|
|
|
afterEach(() => {
|
|
consoleLogSpy.mockRestore();
|
|
consoleErrorSpy.mockRestore();
|
|
});
|
|
|
|
const createMockOctokit = (
|
|
compareResponse?: any,
|
|
deleteRefError?: Error,
|
|
): Octokits => {
|
|
return {
|
|
rest: {
|
|
repos: {
|
|
compareCommitsWithBasehead: async () => ({
|
|
data: compareResponse || { total_commits: 0 },
|
|
}),
|
|
},
|
|
git: {
|
|
deleteRef: async () => {
|
|
if (deleteRefError) {
|
|
throw deleteRefError;
|
|
}
|
|
return { data: {} };
|
|
},
|
|
},
|
|
},
|
|
} as any as Octokits;
|
|
};
|
|
|
|
test("should return no branch link and not delete when branch is undefined", async () => {
|
|
const mockOctokit = createMockOctokit();
|
|
const result = await checkAndCommitOrDeleteBranch(
|
|
mockOctokit,
|
|
"owner",
|
|
"repo",
|
|
undefined,
|
|
"main",
|
|
false,
|
|
);
|
|
|
|
expect(result.shouldDeleteBranch).toBe(false);
|
|
expect(result.branchLink).toBe("");
|
|
expect(consoleLogSpy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test("should mark branch for deletion when commit signing is enabled and no commits", async () => {
|
|
const mockOctokit = createMockOctokit({ total_commits: 0 });
|
|
const result = await checkAndCommitOrDeleteBranch(
|
|
mockOctokit,
|
|
"owner",
|
|
"repo",
|
|
"claude/issue-123-20240101_123456",
|
|
"main",
|
|
true, // commit signing enabled
|
|
);
|
|
|
|
expect(result.shouldDeleteBranch).toBe(true);
|
|
expect(result.branchLink).toBe("");
|
|
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
"Branch claude/issue-123-20240101_123456 has no commits from Claude, will delete it",
|
|
);
|
|
});
|
|
|
|
test("should not delete branch and return link when branch has commits", async () => {
|
|
const mockOctokit = createMockOctokit({ total_commits: 3 });
|
|
const result = await checkAndCommitOrDeleteBranch(
|
|
mockOctokit,
|
|
"owner",
|
|
"repo",
|
|
"claude/issue-123-20240101_123456",
|
|
"main",
|
|
false,
|
|
);
|
|
|
|
expect(result.shouldDeleteBranch).toBe(false);
|
|
expect(result.branchLink).toBe(
|
|
`\n[View branch](${GITHUB_SERVER_URL}/owner/repo/tree/claude/issue-123-20240101_123456)`,
|
|
);
|
|
expect(consoleLogSpy).not.toHaveBeenCalledWith(
|
|
expect.stringContaining("has no commits"),
|
|
);
|
|
});
|
|
|
|
test("should handle branch comparison errors gracefully", async () => {
|
|
const mockOctokit = {
|
|
rest: {
|
|
repos: {
|
|
compareCommitsWithBasehead: async () => {
|
|
throw new Error("API error");
|
|
},
|
|
},
|
|
git: {
|
|
deleteRef: async () => ({ data: {} }),
|
|
},
|
|
},
|
|
} as any as Octokits;
|
|
|
|
const result = await checkAndCommitOrDeleteBranch(
|
|
mockOctokit,
|
|
"owner",
|
|
"repo",
|
|
"claude/issue-123-20240101_123456",
|
|
"main",
|
|
false,
|
|
);
|
|
|
|
expect(result.shouldDeleteBranch).toBe(false);
|
|
expect(result.branchLink).toBe(
|
|
`\n[View branch](${GITHUB_SERVER_URL}/owner/repo/tree/claude/issue-123-20240101_123456)`,
|
|
);
|
|
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
"Error checking for commits on Claude branch:",
|
|
expect.any(Error),
|
|
);
|
|
});
|
|
|
|
test("should handle branch deletion errors gracefully", async () => {
|
|
const deleteError = new Error("Delete failed");
|
|
const mockOctokit = createMockOctokit({ total_commits: 0 }, deleteError);
|
|
|
|
const result = await checkAndCommitOrDeleteBranch(
|
|
mockOctokit,
|
|
"owner",
|
|
"repo",
|
|
"claude/issue-123-20240101_123456",
|
|
"main",
|
|
true, // commit signing enabled - will try to delete
|
|
);
|
|
|
|
expect(result.shouldDeleteBranch).toBe(true);
|
|
expect(result.branchLink).toBe("");
|
|
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
"Failed to delete branch claude/issue-123-20240101_123456:",
|
|
deleteError,
|
|
);
|
|
});
|
|
});
|