mirror of
https://github.com/anthropics/claude-code-action.git
synced 2026-01-28 02:42:25 +08:00
Compare commits
3 Commits
v1.0.35
...
ashwin/unr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d090d03da6 | ||
|
|
fe72061e16 | ||
|
|
231bd75b71 |
10
action.yml
10
action.yml
@@ -35,6 +35,14 @@ inputs:
|
||||
description: "Comma-separated list of usernames to allow without write permissions, or '*' to allow all users. Only works when github_token input is provided. WARNING: Use with extreme caution - this bypasses security checks and should only be used for workflows with very limited permissions (e.g., issue labeling)."
|
||||
required: false
|
||||
default: ""
|
||||
include_comments_by_actor:
|
||||
description: "Comma-separated list of actor usernames to INCLUDE in comments. Supports wildcards: '*[bot]' matches all bots, 'dependabot[bot]' matches specific bot. Empty (default) includes all actors."
|
||||
required: false
|
||||
default: ""
|
||||
exclude_comments_by_actor:
|
||||
description: "Comma-separated list of actor usernames to EXCLUDE from comments. Supports wildcards: '*[bot]' matches all bots, 'renovate[bot]' matches specific bot. Empty (default) excludes none. If actor is in both lists, exclusion takes priority."
|
||||
required: false
|
||||
default: ""
|
||||
|
||||
# Claude Code configuration
|
||||
prompt:
|
||||
@@ -186,6 +194,8 @@ runs:
|
||||
OVERRIDE_GITHUB_TOKEN: ${{ inputs.github_token }}
|
||||
ALLOWED_BOTS: ${{ inputs.allowed_bots }}
|
||||
ALLOWED_NON_WRITE_USERS: ${{ inputs.allowed_non_write_users }}
|
||||
INCLUDE_COMMENTS_BY_ACTOR: ${{ inputs.include_comments_by_actor }}
|
||||
EXCLUDE_COMMENTS_BY_ACTOR: ${{ inputs.exclude_comments_by_actor }}
|
||||
GITHUB_RUN_ID: ${{ github.run_id }}
|
||||
USE_STICKY_COMMENT: ${{ inputs.use_sticky_comment }}
|
||||
DEFAULT_WORKFLOW_TOKEN: ${{ github.token }}
|
||||
|
||||
@@ -98,6 +98,8 @@ type BaseContext = {
|
||||
allowedNonWriteUsers: string;
|
||||
trackProgress: boolean;
|
||||
includeFixLinks: boolean;
|
||||
includeCommentsByActor: string;
|
||||
excludeCommentsByActor: string;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -156,6 +158,8 @@ export function parseGitHubContext(): GitHubContext {
|
||||
allowedNonWriteUsers: process.env.ALLOWED_NON_WRITE_USERS ?? "",
|
||||
trackProgress: process.env.TRACK_PROGRESS === "true",
|
||||
includeFixLinks: process.env.INCLUDE_FIX_LINKS === "true",
|
||||
includeCommentsByActor: process.env.INCLUDE_COMMENTS_BY_ACTOR ?? "",
|
||||
excludeCommentsByActor: process.env.EXCLUDE_COMMENTS_BY_ACTOR ?? "",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -20,6 +20,10 @@ import type {
|
||||
} from "../types";
|
||||
import type { CommentWithImages } from "../utils/image-downloader";
|
||||
import { downloadCommentImages } from "../utils/image-downloader";
|
||||
import {
|
||||
parseActorFilter,
|
||||
shouldIncludeCommentByActor,
|
||||
} from "../utils/actor-filter";
|
||||
|
||||
/**
|
||||
* Extracts the trigger timestamp from the GitHub webhook payload.
|
||||
@@ -166,6 +170,35 @@ export function isBodySafeToUse(
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters comments by actor username based on include/exclude patterns
|
||||
* @param comments - Array of comments to filter
|
||||
* @param includeActors - Comma-separated actors to include
|
||||
* @param excludeActors - Comma-separated actors to exclude
|
||||
* @returns Filtered array of comments
|
||||
*/
|
||||
export function filterCommentsByActor<T extends { author: { login: string } }>(
|
||||
comments: T[],
|
||||
includeActors: string = "",
|
||||
excludeActors: string = "",
|
||||
): T[] {
|
||||
const includeParsed = parseActorFilter(includeActors);
|
||||
const excludeParsed = parseActorFilter(excludeActors);
|
||||
|
||||
// No filters = return all
|
||||
if (includeParsed.length === 0 && excludeParsed.length === 0) {
|
||||
return comments;
|
||||
}
|
||||
|
||||
return comments.filter((comment) =>
|
||||
shouldIncludeCommentByActor(
|
||||
comment.author.login,
|
||||
includeParsed,
|
||||
excludeParsed,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
type FetchDataParams = {
|
||||
octokits: Octokits;
|
||||
repository: string;
|
||||
@@ -174,6 +207,8 @@ type FetchDataParams = {
|
||||
triggerUsername?: string;
|
||||
triggerTime?: string;
|
||||
originalTitle?: string;
|
||||
includeCommentsByActor?: string;
|
||||
excludeCommentsByActor?: string;
|
||||
};
|
||||
|
||||
export type GitHubFileWithSHA = GitHubFile & {
|
||||
@@ -198,6 +233,8 @@ export async function fetchGitHubData({
|
||||
triggerUsername,
|
||||
triggerTime,
|
||||
originalTitle,
|
||||
includeCommentsByActor,
|
||||
excludeCommentsByActor,
|
||||
}: FetchDataParams): Promise<FetchDataResult> {
|
||||
const [owner, repo] = repository.split("/");
|
||||
if (!owner || !repo) {
|
||||
@@ -225,9 +262,13 @@ export async function fetchGitHubData({
|
||||
const pullRequest = prResult.repository.pullRequest;
|
||||
contextData = pullRequest;
|
||||
changedFiles = pullRequest.files.nodes || [];
|
||||
comments = filterCommentsToTriggerTime(
|
||||
pullRequest.comments?.nodes || [],
|
||||
triggerTime,
|
||||
comments = filterCommentsByActor(
|
||||
filterCommentsToTriggerTime(
|
||||
pullRequest.comments?.nodes || [],
|
||||
triggerTime,
|
||||
),
|
||||
includeCommentsByActor,
|
||||
excludeCommentsByActor,
|
||||
);
|
||||
reviewData = pullRequest.reviews || [];
|
||||
|
||||
@@ -248,9 +289,13 @@ export async function fetchGitHubData({
|
||||
|
||||
if (issueResult.repository.issue) {
|
||||
contextData = issueResult.repository.issue;
|
||||
comments = filterCommentsToTriggerTime(
|
||||
contextData?.comments?.nodes || [],
|
||||
triggerTime,
|
||||
comments = filterCommentsByActor(
|
||||
filterCommentsToTriggerTime(
|
||||
contextData?.comments?.nodes || [],
|
||||
triggerTime,
|
||||
),
|
||||
includeCommentsByActor,
|
||||
excludeCommentsByActor,
|
||||
);
|
||||
|
||||
console.log(`Successfully fetched issue #${prNumber} data`);
|
||||
@@ -318,7 +363,27 @@ export async function fetchGitHubData({
|
||||
body: r.body,
|
||||
}));
|
||||
|
||||
// Filter review comments to trigger time
|
||||
// Filter review comments to trigger time and by actor
|
||||
if (reviewData && reviewData.nodes) {
|
||||
// Filter reviews by actor
|
||||
reviewData.nodes = filterCommentsByActor(
|
||||
reviewData.nodes,
|
||||
includeCommentsByActor,
|
||||
excludeCommentsByActor,
|
||||
);
|
||||
|
||||
// Also filter inline review comments within each review
|
||||
reviewData.nodes.forEach((review) => {
|
||||
if (review.comments?.nodes) {
|
||||
review.comments.nodes = filterCommentsByActor(
|
||||
review.comments.nodes,
|
||||
includeCommentsByActor,
|
||||
excludeCommentsByActor,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const allReviewComments =
|
||||
reviewData?.nodes?.flatMap((r) => r.comments?.nodes ?? []) ?? [];
|
||||
const filteredReviewComments = filterCommentsToTriggerTime(
|
||||
|
||||
65
src/github/utils/actor-filter.ts
Normal file
65
src/github/utils/actor-filter.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Parses actor filter string into array of patterns
|
||||
* @param filterString - Comma-separated actor names (e.g., "user1,user2,*[bot]")
|
||||
* @returns Array of actor patterns
|
||||
*/
|
||||
export function parseActorFilter(filterString: string): string[] {
|
||||
if (!filterString.trim()) return [];
|
||||
return filterString
|
||||
.split(",")
|
||||
.map((actor) => actor.trim())
|
||||
.filter((actor) => actor.length > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an actor matches a pattern
|
||||
* Supports wildcards: "*[bot]" matches all bots, "dependabot[bot]" matches specific
|
||||
* @param actor - Actor username to check
|
||||
* @param pattern - Pattern to match against
|
||||
* @returns true if actor matches pattern
|
||||
*/
|
||||
export function actorMatchesPattern(actor: string, pattern: string): boolean {
|
||||
// Exact match
|
||||
if (actor === pattern) return true;
|
||||
|
||||
// Wildcard bot pattern: "*[bot]" matches any username ending with [bot]
|
||||
if (pattern === "*[bot]" && actor.endsWith("[bot]")) return true;
|
||||
|
||||
// No match
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a comment should be included based on actor filters
|
||||
* @param actor - Comment author username
|
||||
* @param includeActors - Array of actors to include (empty = include all)
|
||||
* @param excludeActors - Array of actors to exclude (empty = exclude none)
|
||||
* @returns true if comment should be included
|
||||
*/
|
||||
export function shouldIncludeCommentByActor(
|
||||
actor: string,
|
||||
includeActors: string[],
|
||||
excludeActors: string[],
|
||||
): boolean {
|
||||
// Check exclusion first (exclusion takes priority)
|
||||
if (excludeActors.length > 0) {
|
||||
for (const pattern of excludeActors) {
|
||||
if (actorMatchesPattern(actor, pattern)) {
|
||||
return false; // Excluded
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check inclusion
|
||||
if (includeActors.length > 0) {
|
||||
for (const pattern of includeActors) {
|
||||
if (actorMatchesPattern(actor, pattern)) {
|
||||
return true; // Explicitly included
|
||||
}
|
||||
}
|
||||
return false; // Not in include list
|
||||
}
|
||||
|
||||
// No filters or passed all checks
|
||||
return true;
|
||||
}
|
||||
@@ -89,6 +89,8 @@ export const tagMode: Mode = {
|
||||
triggerUsername: context.actor,
|
||||
triggerTime,
|
||||
originalTitle,
|
||||
includeCommentsByActor: context.inputs.includeCommentsByActor,
|
||||
excludeCommentsByActor: context.inputs.excludeCommentsByActor,
|
||||
});
|
||||
|
||||
// Setup branch
|
||||
|
||||
172
test/actor-filter.test.ts
Normal file
172
test/actor-filter.test.ts
Normal file
@@ -0,0 +1,172 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import {
|
||||
parseActorFilter,
|
||||
actorMatchesPattern,
|
||||
shouldIncludeCommentByActor,
|
||||
} from "../src/github/utils/actor-filter";
|
||||
|
||||
describe("parseActorFilter", () => {
|
||||
test("parses comma-separated actors", () => {
|
||||
expect(parseActorFilter("user1,user2,bot[bot]")).toEqual([
|
||||
"user1",
|
||||
"user2",
|
||||
"bot[bot]",
|
||||
]);
|
||||
});
|
||||
|
||||
test("handles empty string", () => {
|
||||
expect(parseActorFilter("")).toEqual([]);
|
||||
});
|
||||
|
||||
test("handles whitespace-only string", () => {
|
||||
expect(parseActorFilter(" ")).toEqual([]);
|
||||
});
|
||||
|
||||
test("trims whitespace", () => {
|
||||
expect(parseActorFilter(" user1 , user2 ")).toEqual(["user1", "user2"]);
|
||||
});
|
||||
|
||||
test("filters out empty entries", () => {
|
||||
expect(parseActorFilter("user1,,user2")).toEqual(["user1", "user2"]);
|
||||
});
|
||||
|
||||
test("handles single actor", () => {
|
||||
expect(parseActorFilter("user1")).toEqual(["user1"]);
|
||||
});
|
||||
|
||||
test("handles wildcard bot pattern", () => {
|
||||
expect(parseActorFilter("*[bot]")).toEqual(["*[bot]"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("actorMatchesPattern", () => {
|
||||
test("matches exact username", () => {
|
||||
expect(actorMatchesPattern("john-doe", "john-doe")).toBe(true);
|
||||
});
|
||||
|
||||
test("does not match different username", () => {
|
||||
expect(actorMatchesPattern("john-doe", "jane-doe")).toBe(false);
|
||||
});
|
||||
|
||||
test("matches wildcard bot pattern", () => {
|
||||
expect(actorMatchesPattern("dependabot[bot]", "*[bot]")).toBe(true);
|
||||
expect(actorMatchesPattern("renovate[bot]", "*[bot]")).toBe(true);
|
||||
expect(actorMatchesPattern("github-actions[bot]", "*[bot]")).toBe(true);
|
||||
});
|
||||
|
||||
test("does not match non-bot with wildcard", () => {
|
||||
expect(actorMatchesPattern("john-doe", "*[bot]")).toBe(false);
|
||||
expect(actorMatchesPattern("user-bot", "*[bot]")).toBe(false);
|
||||
});
|
||||
|
||||
test("matches specific bot", () => {
|
||||
expect(actorMatchesPattern("dependabot[bot]", "dependabot[bot]")).toBe(
|
||||
true,
|
||||
);
|
||||
expect(actorMatchesPattern("renovate[bot]", "renovate[bot]")).toBe(true);
|
||||
});
|
||||
|
||||
test("does not match different specific bot", () => {
|
||||
expect(actorMatchesPattern("dependabot[bot]", "renovate[bot]")).toBe(false);
|
||||
});
|
||||
|
||||
test("is case sensitive", () => {
|
||||
expect(actorMatchesPattern("User1", "user1")).toBe(false);
|
||||
expect(actorMatchesPattern("user1", "User1")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("shouldIncludeCommentByActor", () => {
|
||||
test("includes all when no filters", () => {
|
||||
expect(shouldIncludeCommentByActor("user1", [], [])).toBe(true);
|
||||
expect(shouldIncludeCommentByActor("bot[bot]", [], [])).toBe(true);
|
||||
});
|
||||
|
||||
test("excludes when in exclude list", () => {
|
||||
expect(shouldIncludeCommentByActor("bot[bot]", [], ["*[bot]"])).toBe(false);
|
||||
expect(shouldIncludeCommentByActor("user1", [], ["user1"])).toBe(false);
|
||||
});
|
||||
|
||||
test("includes when not in exclude list", () => {
|
||||
expect(shouldIncludeCommentByActor("user1", [], ["user2"])).toBe(true);
|
||||
expect(shouldIncludeCommentByActor("user1", [], ["*[bot]"])).toBe(true);
|
||||
});
|
||||
|
||||
test("includes when in include list", () => {
|
||||
expect(shouldIncludeCommentByActor("user1", ["user1", "user2"], [])).toBe(
|
||||
true,
|
||||
);
|
||||
expect(shouldIncludeCommentByActor("user2", ["user1", "user2"], [])).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
test("excludes when not in include list", () => {
|
||||
expect(shouldIncludeCommentByActor("user3", ["user1", "user2"], [])).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
test("exclusion takes priority over inclusion", () => {
|
||||
expect(shouldIncludeCommentByActor("user1", ["user1"], ["user1"])).toBe(
|
||||
false,
|
||||
);
|
||||
expect(
|
||||
shouldIncludeCommentByActor("bot[bot]", ["*[bot]"], ["*[bot]"]),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
test("handles wildcard in include list", () => {
|
||||
expect(shouldIncludeCommentByActor("dependabot[bot]", ["*[bot]"], [])).toBe(
|
||||
true,
|
||||
);
|
||||
expect(shouldIncludeCommentByActor("renovate[bot]", ["*[bot]"], [])).toBe(
|
||||
true,
|
||||
);
|
||||
expect(shouldIncludeCommentByActor("user1", ["*[bot]"], [])).toBe(false);
|
||||
});
|
||||
|
||||
test("handles wildcard in exclude list", () => {
|
||||
expect(shouldIncludeCommentByActor("dependabot[bot]", [], ["*[bot]"])).toBe(
|
||||
false,
|
||||
);
|
||||
expect(shouldIncludeCommentByActor("renovate[bot]", [], ["*[bot]"])).toBe(
|
||||
false,
|
||||
);
|
||||
expect(shouldIncludeCommentByActor("user1", [], ["*[bot]"])).toBe(true);
|
||||
});
|
||||
|
||||
test("handles mixed include and exclude lists", () => {
|
||||
// Include user1 and user2, but exclude user2
|
||||
expect(
|
||||
shouldIncludeCommentByActor("user1", ["user1", "user2"], ["user2"]),
|
||||
).toBe(true);
|
||||
expect(
|
||||
shouldIncludeCommentByActor("user2", ["user1", "user2"], ["user2"]),
|
||||
).toBe(false);
|
||||
expect(
|
||||
shouldIncludeCommentByActor("user3", ["user1", "user2"], ["user2"]),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
test("handles complex bot filtering", () => {
|
||||
// Include all bots but exclude dependabot
|
||||
expect(
|
||||
shouldIncludeCommentByActor(
|
||||
"renovate[bot]",
|
||||
["*[bot]"],
|
||||
["dependabot[bot]"],
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
shouldIncludeCommentByActor(
|
||||
"dependabot[bot]",
|
||||
["*[bot]"],
|
||||
["dependabot[bot]"],
|
||||
),
|
||||
).toBe(false);
|
||||
expect(
|
||||
shouldIncludeCommentByActor("user1", ["*[bot]"], ["dependabot[bot]"]),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, it, jest } from "bun:test";
|
||||
import { describe, expect, it, jest, test } from "bun:test";
|
||||
import {
|
||||
extractTriggerTimestamp,
|
||||
extractOriginalTitle,
|
||||
@@ -1100,3 +1100,101 @@ describe("fetchGitHubData integration with time filtering", () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("filterCommentsByActor", () => {
|
||||
test("filters out excluded actors", () => {
|
||||
const comments = [
|
||||
{ author: { login: "user1" }, body: "comment1" },
|
||||
{ author: { login: "bot[bot]" }, body: "comment2" },
|
||||
{ author: { login: "user2" }, body: "comment3" },
|
||||
];
|
||||
|
||||
const { filterCommentsByActor } = require("../src/github/data/fetcher");
|
||||
const filtered = filterCommentsByActor(comments, "", "*[bot]");
|
||||
expect(filtered).toHaveLength(2);
|
||||
expect(filtered.map((c: any) => c.author.login)).toEqual([
|
||||
"user1",
|
||||
"user2",
|
||||
]);
|
||||
});
|
||||
|
||||
test("includes only specified actors", () => {
|
||||
const comments = [
|
||||
{ author: { login: "user1" }, body: "comment1" },
|
||||
{ author: { login: "user2" }, body: "comment2" },
|
||||
{ author: { login: "user3" }, body: "comment3" },
|
||||
];
|
||||
|
||||
const { filterCommentsByActor } = require("../src/github/data/fetcher");
|
||||
const filtered = filterCommentsByActor(comments, "user1,user2", "");
|
||||
expect(filtered).toHaveLength(2);
|
||||
expect(filtered.map((c: any) => c.author.login)).toEqual([
|
||||
"user1",
|
||||
"user2",
|
||||
]);
|
||||
});
|
||||
|
||||
test("returns all when no filters", () => {
|
||||
const comments = [
|
||||
{ author: { login: "user1" }, body: "comment1" },
|
||||
{ author: { login: "user2" }, body: "comment2" },
|
||||
];
|
||||
|
||||
const { filterCommentsByActor } = require("../src/github/data/fetcher");
|
||||
const filtered = filterCommentsByActor(comments, "", "");
|
||||
expect(filtered).toHaveLength(2);
|
||||
});
|
||||
|
||||
test("exclusion takes priority", () => {
|
||||
const comments = [
|
||||
{ author: { login: "user1" }, body: "comment1" },
|
||||
{ author: { login: "user2" }, body: "comment2" },
|
||||
];
|
||||
|
||||
const { filterCommentsByActor } = require("../src/github/data/fetcher");
|
||||
const filtered = filterCommentsByActor(comments, "user1,user2", "user1");
|
||||
expect(filtered).toHaveLength(1);
|
||||
expect(filtered[0].author.login).toBe("user2");
|
||||
});
|
||||
|
||||
test("filters multiple bot types", () => {
|
||||
const comments = [
|
||||
{ author: { login: "user1" }, body: "comment1" },
|
||||
{ author: { login: "dependabot[bot]" }, body: "comment2" },
|
||||
{ author: { login: "renovate[bot]" }, body: "comment3" },
|
||||
{ author: { login: "user2" }, body: "comment4" },
|
||||
];
|
||||
|
||||
const { filterCommentsByActor } = require("../src/github/data/fetcher");
|
||||
const filtered = filterCommentsByActor(comments, "", "*[bot]");
|
||||
expect(filtered).toHaveLength(2);
|
||||
expect(filtered.map((c: any) => c.author.login)).toEqual([
|
||||
"user1",
|
||||
"user2",
|
||||
]);
|
||||
});
|
||||
|
||||
test("filters specific bot only", () => {
|
||||
const comments = [
|
||||
{ author: { login: "dependabot[bot]" }, body: "comment1" },
|
||||
{ author: { login: "renovate[bot]" }, body: "comment2" },
|
||||
{ author: { login: "user1" }, body: "comment3" },
|
||||
];
|
||||
|
||||
const { filterCommentsByActor } = require("../src/github/data/fetcher");
|
||||
const filtered = filterCommentsByActor(comments, "", "dependabot[bot]");
|
||||
expect(filtered).toHaveLength(2);
|
||||
expect(filtered.map((c: any) => c.author.login)).toEqual([
|
||||
"renovate[bot]",
|
||||
"user1",
|
||||
]);
|
||||
});
|
||||
|
||||
test("handles empty comment array", () => {
|
||||
const comments: any[] = [];
|
||||
|
||||
const { filterCommentsByActor } = require("../src/github/data/fetcher");
|
||||
const filtered = filterCommentsByActor(comments, "user1", "");
|
||||
expect(filtered).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -39,6 +39,8 @@ describe("prepareMcpConfig", () => {
|
||||
allowedNonWriteUsers: "",
|
||||
trackProgress: false,
|
||||
includeFixLinks: true,
|
||||
includeCommentsByActor: "",
|
||||
excludeCommentsByActor: "",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ const defaultInputs = {
|
||||
allowedNonWriteUsers: "",
|
||||
trackProgress: false,
|
||||
includeFixLinks: true,
|
||||
includeCommentsByActor: "",
|
||||
excludeCommentsByActor: "",
|
||||
};
|
||||
|
||||
const defaultRepository = {
|
||||
@@ -55,7 +57,12 @@ export const createMockContext = (
|
||||
};
|
||||
|
||||
const mergedInputs = overrides.inputs
|
||||
? { ...defaultInputs, ...overrides.inputs }
|
||||
? {
|
||||
...defaultInputs,
|
||||
...overrides.inputs,
|
||||
includeCommentsByActor: overrides.inputs.includeCommentsByActor ?? "",
|
||||
excludeCommentsByActor: overrides.inputs.excludeCommentsByActor ?? "",
|
||||
}
|
||||
: defaultInputs;
|
||||
|
||||
return { ...baseContext, ...overrides, inputs: mergedInputs };
|
||||
@@ -79,7 +86,12 @@ export const createMockAutomationContext = (
|
||||
};
|
||||
|
||||
const mergedInputs = overrides.inputs
|
||||
? { ...defaultInputs, ...overrides.inputs }
|
||||
? {
|
||||
...defaultInputs,
|
||||
...overrides.inputs,
|
||||
includeCommentsByActor: overrides.inputs.includeCommentsByActor ?? "",
|
||||
excludeCommentsByActor: overrides.inputs.excludeCommentsByActor ?? "",
|
||||
}
|
||||
: { ...defaultInputs };
|
||||
|
||||
return { ...baseContext, ...overrides, inputs: mergedInputs };
|
||||
|
||||
@@ -27,6 +27,8 @@ describe("detectMode with enhanced routing", () => {
|
||||
allowedNonWriteUsers: "",
|
||||
trackProgress: false,
|
||||
includeFixLinks: true,
|
||||
includeCommentsByActor: "",
|
||||
excludeCommentsByActor: "",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -75,6 +75,8 @@ describe("checkWritePermissions", () => {
|
||||
allowedNonWriteUsers: "",
|
||||
trackProgress: false,
|
||||
includeFixLinks: true,
|
||||
includeCommentsByActor: "",
|
||||
excludeCommentsByActor: "",
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user