Compare commits

..

15 Commits

Author SHA1 Message Date
Julien Tanay
bcb072b63f docs: add FAQ entry about assigning in a private repo (#218) 2025-07-01 07:17:03 -07:00
GitHub Actions
e3b3e531a7 chore: update claude-code-base-action to v0.0.28 2025-07-01 02:57:05 +00:00
Derek Bredensteiner
a7665d3698 fix: resolve CI issues - formatting and TypeScript errors (#217)
* fixed file ingestion

* working binary files

* added replaced baseUrl

* fix: add type assertion for GitHub blob API response

Fixes TypeScript error where blobData was of type 'unknown' by adding
proper type assertion for the blob creation response.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Andrew Grosser <dioptre@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Andrew Grosser <dioptre@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-06-30 19:56:37 -07:00
taku.tsunose
91c510a769 fix: add missing LABEL_TRIGGER environment variable to prepare step (#209)
The label_trigger input was defined but not passed as an environment variable
to the prepare step, causing it to be undefined in the prepare script.
This adds the missing LABEL_TRIGGER environment variable mapping.

Co-authored-by: taku.tsunose <taku.tsunose@takutsunosenoMacBook-Pro.local>
2025-06-27 09:25:00 -07:00
GitHub Actions
1e006bf2d0 chore: update claude-code-base-action to v0.0.27 2025-06-26 01:00:41 +00:00
Stefano Amorelli
ece712ea81 chore(README): add base branch parameter (#201) 2025-06-25 14:21:46 -07:00
Stefano Amorelli
032008d3b6 feat(config): add branch prefix configuration (#197) 2025-06-25 14:01:25 -07:00
Tomohiro Ishibashi
b0d9b8c4cd Add label trigger functionality to Claude Code Action (#177)
- introduced a new input parameter `label_trigger` in `action.yml` to allow triggering actions based on specific labels applied to issues.
- Enhanced the context preparation and event handling in the code to support the new labled event.
2025-06-25 10:25:26 -07:00
GitHub Actions
c831be8f54 chore: update claude-code-base-action to v0.0.26 2025-06-24 23:47:06 +00:00
Tomohiro Ishibashi
38254908ae fix: allow direct_prompt with issue assignment without requiring assignee_trigger (#192)
- Modified validation logic to only require assignee_trigger when direct_prompt is not provided
- Made assigneeTrigger optional in IssueAssignedEvent type definition
- Enhanced context generation to handle missing assigneeTrigger gracefully
- Added comprehensive test coverage for the new behavior

This enables direct_prompt workflows on issue assignment events without
requiring assignee_trigger configuration, fixing the error:
"ASSIGNEE_TRIGGER is required for issue assigned event"

Fixes #113

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-06-23 17:41:25 -07:00
Tomohiro Ishibashi
882586e496 chore: remove unwanted files added in commit 91f620f (#193)
Remove example-dispatch-workflow.yml and pr-summary.md that were
unintentionally added to the root directory in commit 91f620f.
These files should not be in the repository root.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-06-23 17:39:14 -07:00
GitHub Actions
28aaa5404d chore: update claude-code-base-action to v0.0.25 2025-06-24 00:35:11 +00:00
GitHub Actions
ebbd9e9be4 chore: update claude-code-base-action to v0.0.24 2025-06-20 21:50:00 +00:00
GitHub Actions
237de9d329 chore: update claude-code-base-action to v0.0.23 2025-06-20 15:38:21 +00:00
Ashwin Bhat
91f620f8c2 docs: remove references to non-existent test-local.sh script (#187)
All tests for this repo can be run with `bun test` - the test-local.sh script was a holdover from the base action repo.

Fixes #172

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Ashwin Bhat <ashwin-ant@users.noreply.github.com>
2025-06-19 07:52:42 -07:00
15 changed files with 337 additions and 37 deletions

View File

@@ -50,20 +50,6 @@ Thank you for your interest in contributing to Claude Code Action! This document
bun test
```
2. **Integration Tests** (using GitHub Actions locally):
```bash
./test-local.sh
```
This script:
- Installs `act` if not present (requires Homebrew on macOS)
- Runs the GitHub Action workflow locally using Docker
- Requires your `ANTHROPIC_API_KEY` to be set
On Apple Silicon Macs, the script automatically adds the `--container-architecture linux/amd64` flag to avoid compatibility issues.
## Pull Request Process
1. Create a new branch from `main`:
@@ -103,13 +89,7 @@ Thank you for your interest in contributing to Claude Code Action! This document
When modifying the action:
1. Test locally with the test script:
```bash
./test-local.sh
```
2. Test in a real GitHub Actions workflow by:
1. Test in a real GitHub Actions workflow by:
- Creating a test repository
- Using your branch as the action source:
```yaml

4
FAQ.md
View File

@@ -12,6 +12,10 @@ The `github-actions` user cannot trigger subsequent GitHub Actions workflows. Th
Only users with **write permissions** to the repository can trigger Claude. This is a security feature to prevent unauthorized use. Make sure the user commenting has at least write access to the repository.
### Why can't I assign @claude to an issue on my repository?
If you're in a public repository, you should be able to assign to Claude without issue. If it's a private organization repository, you can only assign to users in your own organization, which Claude isn't. In this case, you'll need to make a custom user in that case.
### Why am I getting OIDC authentication errors?
If you're using the default GitHub App authentication, you must add the `id-token: write` permission to your workflow:

View File

@@ -49,7 +49,7 @@ on:
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
types: [opened, assigned, labeled]
pull_request_review:
types: [submitted]
@@ -65,6 +65,8 @@ jobs:
# trigger_phrase: "/claude"
# Optional: add assignee trigger for issues
# assignee_trigger: "claude"
# Optional: add label trigger for issues
# label_trigger: "claude"
# Optional: add custom environment variables (YAML format)
# claude_env: |
# NODE_ENV: test
@@ -80,6 +82,7 @@ jobs:
| --------------------- | -------------------------------------------------------------------------------------------------------------------- | -------- | --------- |
| `anthropic_api_key` | Anthropic API key (required for direct API, not needed for Bedrock/Vertex) | No\* | - |
| `direct_prompt` | Direct prompt for Claude to execute automatically without needing a trigger (for automated workflows) | No | - |
| `base_branch` | The base branch to use for creating new branches (e.g., 'main', 'develop') | No | - |
| `max_turns` | Maximum number of conversation turns Claude can take (limits back-and-forth exchanges) | No | - |
| `timeout_minutes` | Timeout in minutes for execution | No | `30` |
| `github_token` | GitHub token for Claude to operate with. **Only include this if you're connecting a custom GitHub app of your own!** | No | - |
@@ -92,7 +95,9 @@ jobs:
| `custom_instructions` | Additional custom instructions to include in the prompt for Claude | No | "" |
| `mcp_config` | Additional MCP configuration (JSON string) that merges with the built-in GitHub MCP servers | No | "" |
| `assignee_trigger` | The assignee username that triggers the action (e.g. @claude). Only used for issue assignment | No | - |
| `label_trigger` | The label name that triggers the action when applied to an issue (e.g. "claude") | No | - |
| `trigger_phrase` | The trigger phrase to look for in comments, issue/PR bodies, and issue titles | No | `@claude` |
| `branch_prefix` | The prefix to use for Claude branches (defaults to 'claude/', use 'claude-' for dash format) | No | `claude/` |
| `claude_env` | Custom environment variables to pass to Claude Code execution (YAML format) | No | "" |
\*Required when using direct Anthropic API (default and when not using Bedrock or Vertex)

View File

@@ -12,9 +12,17 @@ inputs:
assignee_trigger:
description: "The assignee username that triggers the action (e.g. @claude)"
required: false
label_trigger:
description: "The label that triggers the action (e.g. claude)"
required: false
default: "claude"
base_branch:
description: "The branch to use as the base/source when creating new branches (defaults to repository default branch)"
required: false
branch_prefix:
description: "The prefix to use for Claude branches (defaults to 'claude/', use 'claude-' for dash format)"
required: false
default: "claude/"
# Claude Code configuration
model:
@@ -98,7 +106,9 @@ runs:
env:
TRIGGER_PHRASE: ${{ inputs.trigger_phrase }}
ASSIGNEE_TRIGGER: ${{ inputs.assignee_trigger }}
LABEL_TRIGGER: ${{ inputs.label_trigger }}
BASE_BRANCH: ${{ inputs.base_branch }}
BRANCH_PREFIX: ${{ inputs.branch_prefix }}
ALLOWED_TOOLS: ${{ inputs.allowed_tools }}
DISALLOWED_TOOLS: ${{ inputs.disallowed_tools }}
CUSTOM_INSTRUCTIONS: ${{ inputs.custom_instructions }}
@@ -110,7 +120,7 @@ runs:
- name: Run Claude Code
id: claude-code
if: steps.prepare.outputs.contains_trigger == 'true'
uses: anthropics/claude-code-base-action@bb2ef1d9768b9e94083d377778120f8f27958a72 # v0.0.22
uses: anthropics/claude-code-base-action@f6ef8c1000c0197b625af70349f68cb212e34fc1 # v0.0.28
with:
prompt_file: ${{ runner.temp }}/claude-prompts/claude-prompt.txt
allowed_tools: ${{ env.ALLOWED_TOOLS }}

View File

@@ -81,6 +81,7 @@ export function prepareContext(
const eventAction = context.eventAction;
const triggerPhrase = context.inputs.triggerPhrase || "@claude";
const assigneeTrigger = context.inputs.assigneeTrigger;
const labelTrigger = context.inputs.labelTrigger;
const customInstructions = context.inputs.customInstructions;
const allowedTools = context.inputs.allowedTools;
const disallowedTools = context.inputs.disallowedTools;
@@ -242,7 +243,7 @@ export function prepareContext(
}
if (eventAction === "assigned") {
if (!assigneeTrigger) {
if (!assigneeTrigger && !directPrompt) {
throw new Error(
"ASSIGNEE_TRIGGER is required for issue assigned event",
);
@@ -254,7 +255,20 @@ export function prepareContext(
issueNumber,
baseBranch,
claudeBranch,
assigneeTrigger,
...(assigneeTrigger && { assigneeTrigger }),
};
} else if (eventAction === "labeled") {
if (!labelTrigger) {
throw new Error("LABEL_TRIGGER is required for issue labeled event");
}
eventData = {
eventName: "issues",
eventAction: "labeled",
isPR: false,
issueNumber,
baseBranch,
claudeBranch,
labelTrigger,
};
} else if (eventAction === "opened") {
eventData = {
@@ -328,10 +342,17 @@ export function getEventTypeAndContext(envVars: PreparedContext): {
eventType: "ISSUE_CREATED",
triggerContext: `new issue with '${envVars.triggerPhrase}' in body`,
};
} else if (eventData.eventAction === "labeled") {
return {
eventType: "ISSUE_LABELED",
triggerContext: `issue labeled with '${eventData.labelTrigger}'`,
};
}
return {
eventType: "ISSUE_ASSIGNED",
triggerContext: `issue assigned to '${eventData.assigneeTrigger}'`,
triggerContext: eventData.assigneeTrigger
? `issue assigned to '${eventData.assigneeTrigger}'`
: `issue assigned event`,
};
case "pull_request":
@@ -465,6 +486,7 @@ Follow these steps:
- Analyze the pre-fetched data provided above.
- For ISSUE_CREATED: Read the issue body to find the request after the trigger phrase.
- For ISSUE_ASSIGNED: Read the entire issue body to understand the task.
- For ISSUE_LABELED: Read the entire issue body to understand the task.
${eventData.eventName === "issue_comment" || eventData.eventName === "pull_request_review_comment" || eventData.eventName === "pull_request_review" ? ` - For comment/review events: Your instructions are in the <trigger_comment> tag above.` : ""}
${context.directPrompt ? ` - DIRECT INSTRUCTION: A direct instruction was provided and is shown in the <direct_prompt> tag above. This is not from any GitHub comment but a direct instruction to execute.` : ""}
- IMPORTANT: Only the comment/issue containing '${context.triggerPhrase}' has your instructions.

View File

@@ -65,7 +65,17 @@ type IssueAssignedEvent = {
issueNumber: string;
baseBranch: string;
claudeBranch: string;
assigneeTrigger: string;
assigneeTrigger?: string;
};
type IssueLabeledEvent = {
eventName: "issues";
eventAction: "labeled";
isPR: false;
issueNumber: string;
baseBranch: string;
claudeBranch: string;
labelTrigger: string;
};
type PullRequestEvent = {
@@ -85,6 +95,7 @@ export type EventData =
| IssueCommentEvent
| IssueOpenedEvent
| IssueAssignedEvent
| IssueLabeledEvent
| PullRequestEvent;
// Combined type with separate eventData field

View File

@@ -29,11 +29,13 @@ export type ParsedGitHubContext = {
inputs: {
triggerPhrase: string;
assigneeTrigger: string;
labelTrigger: string;
allowedTools: string[];
disallowedTools: string[];
customInstructions: string;
directPrompt: string;
baseBranch?: string;
branchPrefix: string;
};
};
@@ -53,11 +55,13 @@ export function parseGitHubContext(): ParsedGitHubContext {
inputs: {
triggerPhrase: process.env.TRIGGER_PHRASE ?? "@claude",
assigneeTrigger: process.env.ASSIGNEE_TRIGGER ?? "",
labelTrigger: process.env.LABEL_TRIGGER ?? "",
allowedTools: parseMultilineInput(process.env.ALLOWED_TOOLS ?? ""),
disallowedTools: parseMultilineInput(process.env.DISALLOWED_TOOLS ?? ""),
customInstructions: process.env.CUSTOM_INSTRUCTIONS ?? "",
directPrompt: process.env.DIRECT_PROMPT ?? "",
baseBranch: process.env.BASE_BRANCH,
branchPrefix: process.env.BRANCH_PREFIX ?? "claude/",
},
};

View File

@@ -26,7 +26,7 @@ export async function setupBranch(
): Promise<BranchInfo> {
const { owner, repo } = context.repository;
const entityNumber = context.entityNumber;
const { baseBranch } = context.inputs;
const { baseBranch, branchPrefix } = context.inputs;
const isPR = context.isPR;
if (isPR) {
@@ -97,7 +97,7 @@ export async function setupBranch(
.split("T")
.join("_");
const newBranch = `claude/${entityType}-${entityNumber}-${timestamp}`;
const newBranch = `${branchPrefix}${entityType}-${entityNumber}-${timestamp}`;
try {
// Get the SHA of the source branch

View File

@@ -13,7 +13,7 @@ import type { ParsedGitHubContext } from "../context";
export function checkContainsTrigger(context: ParsedGitHubContext): boolean {
const {
inputs: { assigneeTrigger, triggerPhrase, directPrompt },
inputs: { assigneeTrigger, labelTrigger, triggerPhrase, directPrompt },
} = context;
// If direct prompt is provided, always trigger
@@ -34,6 +34,16 @@ export function checkContainsTrigger(context: ParsedGitHubContext): boolean {
}
}
// 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 || "";

View File

@@ -125,13 +125,58 @@ server.tool(
? filePath
: join(REPO_DIR, filePath);
const content = await readFile(fullPath, "utf-8");
return {
path: filePath,
mode: "100644",
type: "blob",
content: content,
};
// Check if file is binary (images, etc.)
const isBinaryFile =
/\.(png|jpg|jpeg|gif|webp|ico|pdf|zip|tar|gz|exe|bin|woff|woff2|ttf|eot)$/i.test(
filePath,
);
if (isBinaryFile) {
// For binary files, create a blob first using the Blobs API
const binaryContent = await readFile(fullPath);
// Create blob using Blobs API (supports encoding parameter)
const blobUrl = `${GITHUB_API_URL}/repos/${owner}/${repo}/git/blobs`;
const blobResponse = await fetch(blobUrl, {
method: "POST",
headers: {
Accept: "application/vnd.github+json",
Authorization: `Bearer ${githubToken}`,
"X-GitHub-Api-Version": "2022-11-28",
"Content-Type": "application/json",
},
body: JSON.stringify({
content: binaryContent.toString("base64"),
encoding: "base64",
}),
});
if (!blobResponse.ok) {
const errorText = await blobResponse.text();
throw new Error(
`Failed to create blob for ${filePath}: ${blobResponse.status} - ${errorText}`,
);
}
const blobData = (await blobResponse.json()) as { sha: string };
// Return tree entry with blob SHA
return {
path: filePath,
mode: "100644",
type: "blob",
sha: blobData.sha,
};
} else {
// For text files, include content directly in tree
const content = await readFile(fullPath, "utf-8");
return {
path: filePath,
mode: "100644",
type: "blob",
content: content,
};
}
}),
);

View File

@@ -226,6 +226,33 @@ describe("generatePrompt", () => {
);
});
test("should generate prompt for issue labeled event", () => {
const envVars: PreparedContext = {
repository: "owner/repo",
claudeCommentId: "12345",
triggerPhrase: "@claude",
eventData: {
eventName: "issues",
eventAction: "labeled",
isPR: false,
issueNumber: "888",
baseBranch: "main",
claudeBranch: "claude/issue-888-20240101_120000",
labelTrigger: "claude-task",
},
};
const prompt = generatePrompt(envVars, mockGitHubData);
expect(prompt).toContain("<event_type>ISSUE_LABELED</event_type>");
expect(prompt).toContain(
"<trigger_context>issue labeled with 'claude-task'</trigger_context>",
);
expect(prompt).toContain(
"[Create a PR](https://github.com/owner/repo/compare/main",
);
});
test("should include direct prompt when provided", () => {
const envVars: PreparedContext = {
repository: "owner/repo",
@@ -614,6 +641,51 @@ describe("getEventTypeAndContext", () => {
expect(result.eventType).toBe("ISSUE_ASSIGNED");
expect(result.triggerContext).toBe("issue assigned to 'claude-bot'");
});
test("should return correct type and context for issue labeled", () => {
const envVars: PreparedContext = {
repository: "owner/repo",
claudeCommentId: "12345",
triggerPhrase: "@claude",
eventData: {
eventName: "issues",
eventAction: "labeled",
isPR: false,
issueNumber: "888",
baseBranch: "main",
claudeBranch: "claude/issue-888-20240101_120000",
labelTrigger: "claude-task",
},
};
const result = getEventTypeAndContext(envVars);
expect(result.eventType).toBe("ISSUE_LABELED");
expect(result.triggerContext).toBe("issue labeled with 'claude-task'");
});
test("should return correct type and context for issue assigned without assigneeTrigger", () => {
const envVars: PreparedContext = {
repository: "owner/repo",
claudeCommentId: "12345",
triggerPhrase: "@claude",
directPrompt: "Please assess this issue",
eventData: {
eventName: "issues",
eventAction: "assigned",
isPR: false,
issueNumber: "999",
baseBranch: "main",
claudeBranch: "claude/issue-999-20240101_120000",
// No assigneeTrigger when using directPrompt
},
};
const result = getEventTypeAndContext(envVars);
expect(result.eventType).toBe("ISSUE_ASSIGNED");
expect(result.triggerContext).toBe("issue assigned event");
});
});
describe("buildAllowedToolsString", () => {

View File

@@ -10,6 +10,7 @@ import type {
const defaultInputs = {
triggerPhrase: "/claude",
assigneeTrigger: "",
labelTrigger: "",
anthropicModel: "claude-3-7-sonnet-20250219",
allowedTools: [] as string[],
disallowedTools: [] as string[],
@@ -18,6 +19,7 @@ const defaultInputs = {
useBedrock: false,
useVertex: false,
timeoutMinutes: 30,
branchPrefix: "claude/",
};
const defaultRepository = {
@@ -128,6 +130,46 @@ export const mockIssueAssignedContext: ParsedGitHubContext = {
inputs: { ...defaultInputs, assigneeTrigger: "@claude-bot" },
};
export const mockIssueLabeledContext: ParsedGitHubContext = {
runId: "1234567890",
eventName: "issues",
eventAction: "labeled",
repository: defaultRepository,
actor: "admin-user",
payload: {
action: "labeled",
issue: {
number: 1234,
title: "Enhancement: Improve search functionality",
body: "The current search is too slow and needs optimization",
user: {
login: "alice-wonder",
id: 54321,
avatar_url: "https://avatars.githubusercontent.com/u/54321",
html_url: "https://github.com/alice-wonder",
},
assignee: null,
},
label: {
id: 987654321,
name: "claude-task",
color: "f29513",
description: "Label for Claude AI interactions",
},
repository: {
name: "test-repo",
full_name: "test-owner/test-repo",
private: false,
owner: {
login: "test-owner",
},
},
} as IssuesEvent,
entityNumber: 1234,
isPR: false,
inputs: { ...defaultInputs, labelTrigger: "claude-task" },
};
// Issue comment on issue event
export const mockIssueCommentContext: ParsedGitHubContext = {
runId: "1234567890",

View File

@@ -62,10 +62,12 @@ describe("checkWritePermissions", () => {
inputs: {
triggerPhrase: "@claude",
assigneeTrigger: "",
labelTrigger: "",
allowedTools: [],
disallowedTools: [],
customInstructions: "",
directPrompt: "",
branchPrefix: "claude/",
},
});

View File

@@ -219,6 +219,55 @@ describe("parseEnvVarsWithContext", () => {
),
).toThrow("BASE_BRANCH is required for issues event");
});
test("should allow issue assigned event with direct_prompt and no assigneeTrigger", () => {
const contextWithDirectPrompt = createMockContext({
...mockIssueAssignedContext,
inputs: {
...mockIssueAssignedContext.inputs,
assigneeTrigger: "", // No assignee trigger
directPrompt: "Please assess this issue", // But direct prompt is provided
},
});
const result = prepareContext(
contextWithDirectPrompt,
"12345",
"main",
"claude/issue-123-20240101_120000",
);
expect(result.eventData.eventName).toBe("issues");
expect(result.eventData.isPR).toBe(false);
expect(result.directPrompt).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 directPrompt provided for issue assigned event", () => {
const contextWithoutTriggers = createMockContext({
...mockIssueAssignedContext,
inputs: {
...mockIssueAssignedContext.inputs,
assigneeTrigger: "", // No assignee trigger
directPrompt: "", // No direct prompt
},
});
expect(() =>
prepareContext(
contextWithoutTriggers,
"12345",
"main",
"claude/issue-123-20240101_120000",
),
).toThrow("ASSIGNEE_TRIGGER is required for issue assigned event");
});
});
describe("optional fields", () => {

View File

@@ -6,6 +6,7 @@ import { describe, it, expect } from "bun:test";
import {
createMockContext,
mockIssueAssignedContext,
mockIssueLabeledContext,
mockIssueCommentContext,
mockIssueOpenedContext,
mockPullRequestReviewContext,
@@ -29,10 +30,12 @@ describe("checkContainsTrigger", () => {
inputs: {
triggerPhrase: "/claude",
assigneeTrigger: "",
labelTrigger: "",
directPrompt: "Fix the bug in the login form",
allowedTools: [],
disallowedTools: [],
customInstructions: "",
branchPrefix: "claude/",
},
});
expect(checkContainsTrigger(context)).toBe(true);
@@ -55,10 +58,12 @@ describe("checkContainsTrigger", () => {
inputs: {
triggerPhrase: "/claude",
assigneeTrigger: "",
labelTrigger: "",
directPrompt: "",
allowedTools: [],
disallowedTools: [],
customInstructions: "",
branchPrefix: "claude/",
},
});
expect(checkContainsTrigger(context)).toBe(false);
@@ -107,6 +112,39 @@ describe("checkContainsTrigger", () => {
});
});
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;
@@ -232,10 +270,12 @@ describe("checkContainsTrigger", () => {
inputs: {
triggerPhrase: "@claude",
assigneeTrigger: "",
labelTrigger: "",
directPrompt: "",
allowedTools: [],
disallowedTools: [],
customInstructions: "",
branchPrefix: "claude/",
},
});
expect(checkContainsTrigger(context)).toBe(true);
@@ -259,10 +299,12 @@ describe("checkContainsTrigger", () => {
inputs: {
triggerPhrase: "@claude",
assigneeTrigger: "",
labelTrigger: "",
directPrompt: "",
allowedTools: [],
disallowedTools: [],
customInstructions: "",
branchPrefix: "claude/",
},
});
expect(checkContainsTrigger(context)).toBe(true);
@@ -286,10 +328,12 @@ describe("checkContainsTrigger", () => {
inputs: {
triggerPhrase: "@claude",
assigneeTrigger: "",
labelTrigger: "",
directPrompt: "",
allowedTools: [],
disallowedTools: [],
customInstructions: "",
branchPrefix: "claude/",
},
});
expect(checkContainsTrigger(context)).toBe(false);