diff --git a/action/contribution.mts b/action/contribution.mts index 7656e26..22dfd08 100644 --- a/action/contribution.mts +++ b/action/contribution.mts @@ -155,11 +155,16 @@ export async function validateContributionAuthors( }; } +const GITHUB_SERVICE_LOGINS = new Set(["web-flow"]); + function isBot(user: GHUserLike | null): boolean { if (!user) return false; return user.type === "Bot" || isBotLogin(user.login); } function isBotLogin(login: string): boolean { - return typeof login === "string" && login.endsWith("[bot]"); + if (typeof login !== "string") return false; + if (login.endsWith("[bot]")) return true; + if (GITHUB_SERVICE_LOGINS.has(login)) return true; + return false; } diff --git a/action/test/dispatch_test.mts b/action/test/dispatch_test.mts index 3ff3e78..163d418 100644 --- a/action/test/dispatch_test.mts +++ b/action/test/dispatch_test.mts @@ -258,6 +258,33 @@ Deno.test("contribution ignores Co-authored-by trailers in commit messages", asy assertEquals(result.contribution.ok, true); }); +Deno.test("contribution filters web-flow (GitHub UI commits) from the author set", async () => { + mockFetch({ + "/repos/y/s/pulls/1/commits?per_page=100": { + body: [ + { + sha: "abc1234", + author: { login: "benjick", type: "User" }, + committer: { login: "web-flow", type: "User" }, + commit: { + author: { email: "b@e.com" }, + committer: { email: "noreply@github.com" }, + }, + }, + ], + }, + "/repos/y/s/contents/CLA.md?ref=h": contentsResp(claText("1.0")), + "/repos/y/s/contents/.signatures/cla/benjick.md?ref=h": contentsResp( + sigText("1.0"), + ), + }); + + const files: PRFile[] = [{ filename: "README.md" }]; + const result = await dispatch(makeCtx(), files); + + assertEquals(result.contribution.ok, true); +}); + Deno.test("contribution filters bot logins from the author set", async () => { mockFetch({ "/repos/y/s/pulls/1/commits?per_page=100": {