Skip to content

Commit 2c445d3

Browse files
committed
test(engine): behaviour-test the author-association vocabulary in the ENGINE's own suite
Same cause as the sibling fix on #9847. packages/loopover-engine/src/** is credited by two Codecov uploads, and the "engine" flag is fed by the package's own node:test suite -- so a module that only the root vitest suite exercises reads as uncovered there. author-association.ts moved INTO the engine in this PR, which makes every one of its lines new to that flag. The predicate is now behaviour-tested in the engine suite, including through buildPullRequestAdvisory, since the gate-advisory twin is one of its callers and is where the fifth duplicate copy lived.
1 parent 9f08626 commit 2c445d3

2 files changed

Lines changed: 74 additions & 0 deletions

File tree

packages/loopover-engine/src/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -957,3 +957,12 @@ export { isDone as isPlanStepDone, nextReadySteps } from "./plan-step-readiness.
957957
// #9743: the priority label's single resolution, exported so the engine's OWN behaviour suite can test
958958
// it -- the `engine` Codecov flag credits engine source from that suite, not from the root vitest run.
959959
export { DEFAULT_PRIORITY_LABEL, resolvePriorityTypeLabel } from "./settings/pr-type-label.js";
960+
// #9743: the author-association vocabulary, exported so the engine's OWN behaviour suite can reach it --
961+
// the "engine" Codecov flag credits engine source from that suite, and gate-advisory (an engine twin)
962+
// is one of its callers.
963+
export {
964+
MAINTAINER_AUTHOR_ASSOCIATIONS,
965+
classifyAuthorAssociation,
966+
isMaintainerAuthorAssociation,
967+
type AuthorClass,
968+
} from "./settings/author-association.js";
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { test } from "node:test";
2+
import assert from "node:assert/strict";
3+
import { MAINTAINER_AUTHOR_ASSOCIATIONS, classifyAuthorAssociation, isMaintainerAuthorAssociation } from "../dist/index.js";
4+
5+
// The engine's own behaviour suite for the author-association vocabulary (#9743). gate-advisory -- an
6+
// engine twin -- is one of its callers, and the per-author-class parity rollups publish this split, so
7+
// these are engine semantics rather than app glue.
8+
9+
test("every maintainer association classifies as maintainer, case-insensitively", () => {
10+
for (const association of MAINTAINER_AUTHOR_ASSOCIATIONS) {
11+
assert.equal(classifyAuthorAssociation(association), "maintainer", association);
12+
assert.equal(classifyAuthorAssociation(association.toLowerCase()), "maintainer", association);
13+
assert.equal(isMaintainerAuthorAssociation(association), true, association);
14+
}
15+
});
16+
17+
test("CONTRIBUTOR is a contributor -- a merged PR in the past is not authority over the repo", () => {
18+
assert.equal(isMaintainerAuthorAssociation("CONTRIBUTOR"), false);
19+
assert.equal(classifyAuthorAssociation("CONTRIBUTOR"), "contributor");
20+
assert.equal(classifyAuthorAssociation("FIRST_TIME_CONTRIBUTOR"), "contributor");
21+
assert.equal(classifyAuthorAssociation("NONE"), "contributor");
22+
});
23+
24+
test("an unrecorded association is UNKNOWN, never folded into either side", () => {
25+
// Folding unknowns into `contributor` would bias the exact comparison the rollups publish.
26+
for (const value of [null, undefined, "", " "]) {
27+
assert.equal(classifyAuthorAssociation(value as never), "unknown", JSON.stringify(value));
28+
assert.equal(isMaintainerAuthorAssociation(value as never), false, JSON.stringify(value));
29+
}
30+
});
31+
32+
test("a non-string is not treated as an association", () => {
33+
assert.equal(isMaintainerAuthorAssociation(42 as never), false);
34+
assert.equal(classifyAuthorAssociation(42 as never), "unknown");
35+
});
36+
37+
// The gate-advisory TWIN is one of this predicate's callers (#9743 consolidated a fifth copy out of it),
38+
// so the branch it feeds is exercised here too rather than only through the app's own suite.
39+
test("buildPullRequestAdvisory raises maintainer_authored_pr for a maintainer association", async () => {
40+
const { buildPullRequestAdvisory } = await import("../dist/advisory/gate-advisory.js");
41+
const repo = { fullName: "o/r", defaultBranch: "main" } as never;
42+
const basePr = {
43+
repoFullName: "o/r",
44+
number: 1,
45+
title: "fix: a thing",
46+
state: "open",
47+
authorLogin: "someone",
48+
labels: [],
49+
linkedIssues: [],
50+
bodyObservedAt: null,
51+
};
52+
53+
const maintainer = buildPullRequestAdvisory(repo, { ...basePr, authorAssociation: "MEMBER" } as never, {});
54+
assert.ok(
55+
maintainer.findings.some((f) => f.code === "maintainer_authored_pr"),
56+
"a MEMBER-authored PR is flagged as maintainer-authored",
57+
);
58+
59+
const contributor = buildPullRequestAdvisory(repo, { ...basePr, authorAssociation: "CONTRIBUTOR" } as never, {});
60+
assert.equal(
61+
contributor.findings.some((f) => f.code === "maintainer_authored_pr"),
62+
false,
63+
"a CONTRIBUTOR-authored PR is not",
64+
);
65+
});

0 commit comments

Comments
 (0)