Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/rules/advisory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,8 @@ export function buildPullRequestAdvisory(
/** Duplicate-winner adjudication (#dup-winner). When true AND this PR is the cluster winner (the lowest
* open sibling number), the `duplicate_pr_risk` finding is suppressed so the winner is not gate-blocked /
* closed as a duplicate. Default/false ⇒ every duplicate sibling keeps the finding (byte-identical). The
* caller sets this to `env.LOOPOVER_DUPLICATE_WINNER === "true"`. */
* caller resolves this via `isDuplicateWinnerEnabledGlobally` (settings/duplicate-winner-mode.ts), which
* applies the codebase truthy convention rather than a raw string comparison. */
duplicateWinnerEnabled?: boolean;
/** Author logins of the linked issues (one entry per resolved issue, may be null when unknown). Used to
* surface a `self_authored_linked_issue` finding when the PR author also opened the linked issue. Absent
Expand Down
12 changes: 7 additions & 5 deletions src/settings/duplicate-winner-mode.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
export type DuplicateWinnerMode = "inherit" | "off" | "enabled";

/** Truthy convention matches the rest of this codebase's `LOOPOVER_*` flags (exact `"true"` string, e.g. the
* raw checks this replaces) -- unlike `isSkipAutomationBotPullRequestsEnabledGlobally` (default ON, inverted
* truthy match), this flag is opt-in and default OFF: sparing a duplicate cluster's earliest claimant is a
* real behavior change to the close disposition, not a low-risk waste-elimination default. */
/** Truthy convention matches the rest of this codebase's `LOOPOVER_*` flags (`/^(1|true|yes|on)$/i`,
* trimmed + case-insensitive, e.g. `selfTuneFlagOn`/`isReputationEnabled`) -- so `1`, `on`, `TRUE`, and a
* `.env` value carrying trailing whitespace all read as truthy, not silently as OFF. Unlike
* `isSkipAutomationBotPullRequestsEnabledGlobally` (default ON, inverted truthy match), this flag is opt-in
* and default OFF: sparing a duplicate cluster's earliest claimant is a real behavior change to the close
* disposition, not a low-risk waste-elimination default. */
export function isDuplicateWinnerEnabledGlobally(env: { LOOPOVER_DUPLICATE_WINNER?: string | undefined }): boolean {
return env.LOOPOVER_DUPLICATE_WINNER === "true";
return /^(1|true|yes|on)$/i.test((env.LOOPOVER_DUPLICATE_WINNER ?? "").trim());
}

/** Per-repo override resolved against the global default. Mirrors `resolveSkipAutomationBotPullRequests`'s
Expand Down
8 changes: 5 additions & 3 deletions src/settings/open-pr-file-collision-mode.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
export type OpenPrFileCollisionMode = "inherit" | "off" | "enabled";

/** Truthy convention matches the rest of this codebase's `LOOPOVER_*` flags (exact `"true"` string) -- opt-in
* and default OFF: the enrichment call this gates costs an extra GitHub API round-trip per open PR
/** Truthy convention matches the rest of this codebase's `LOOPOVER_*` flags (`/^(1|true|yes|on)$/i`, trimmed
* + case-insensitive, e.g. `selfTuneFlagOn`/`isReputationEnabled`) -- so `1`, `on`, `TRUE`, and a `.env`
* value carrying trailing whitespace all read as truthy, not silently as OFF. Opt-in and default OFF: the
* enrichment call this gates costs an extra GitHub API round-trip per open PR
* (enrichOpenPullRequestsWithChangedFiles), so an operator should deliberately turn it on rather than pay
* that cost by default. */
export function isOpenPrFileCollisionEnabledGlobally(env: { LOOPOVER_OPEN_PR_FILE_COLLISION?: string | undefined }): boolean {
return env.LOOPOVER_OPEN_PR_FILE_COLLISION === "true";
return /^(1|true|yes|on)$/i.test((env.LOOPOVER_OPEN_PR_FILE_COLLISION ?? "").trim());
}

/** Per-repo override resolved against the global default. Mirrors `resolveDuplicateWinnerEnabled`'s
Expand Down
21 changes: 16 additions & 5 deletions test/unit/duplicate-winner-mode.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,26 @@ describe("isDuplicateWinnerEnabledGlobally", () => {
expect(isDuplicateWinnerEnabledGlobally({ LOOPOVER_DUPLICATE_WINNER: "" })).toBe(false);
});

it("is ON only for the exact string \"true\"", () => {
expect(isDuplicateWinnerEnabledGlobally({ LOOPOVER_DUPLICATE_WINNER: "true" })).toBe(true);
it("is ON for every value the codebase truthy convention accepts (#10054)", () => {
// Was `=== "true"` only, which silently read `1` / `on` / `TRUE` / a whitespace-padded `.env` value as
// OFF. It now mirrors selfTuneFlagOn's `/^(1|true|yes|on)$/i.test((X ?? "").trim())`, trimmed + i-flag.
for (const value of ["1", "true", "TRUE", "yes", "on", " true "]) {
expect(isDuplicateWinnerEnabledGlobally({ LOOPOVER_DUPLICATE_WINNER: value }), value).toBe(true);
}
});

it("stays OFF for any other value, including truthy-looking ones", () => {
for (const value of ["1", "yes", "on", "True", "TRUE", " true "]) {
expect(isDuplicateWinnerEnabledGlobally({ LOOPOVER_DUPLICATE_WINNER: value })).toBe(false);
it("stays OFF for a falsy or unrecognised value", () => {
for (const value of ["0", "false", "off", "no", "maybe"]) {
expect(isDuplicateWinnerEnabledGlobally({ LOOPOVER_DUPLICATE_WINNER: value }), value).toBe(false);
}
});

it("the =1 form an operator naturally writes actually enables the feature through the resolver (#10054)", () => {
// The end-to-end regression: `1` is the value the convention regex accepts first and env.d.ts publishes
// for a sibling flag, but under `=== "true"` it read OFF -- so a repo on `inherit` stayed off even after
// the operator set it. The fix must carry all the way through resolveDuplicateWinnerEnabled.
expect(resolveDuplicateWinnerEnabled(isDuplicateWinnerEnabledGlobally({ LOOPOVER_DUPLICATE_WINNER: "1" }), "inherit")).toBe(true);
});
});

describe("resolveDuplicateWinnerEnabled", () => {
Expand Down
14 changes: 9 additions & 5 deletions test/unit/open-pr-file-collision-mode.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ describe("isOpenPrFileCollisionEnabledGlobally", () => {
expect(isOpenPrFileCollisionEnabledGlobally({ LOOPOVER_OPEN_PR_FILE_COLLISION: "" })).toBe(false);
});

it("is ON only for the exact string \"true\"", () => {
expect(isOpenPrFileCollisionEnabledGlobally({ LOOPOVER_OPEN_PR_FILE_COLLISION: "true" })).toBe(true);
it("is ON for every value the codebase truthy convention accepts (#10054)", () => {
// Was `=== "true"` only, which silently read `1` / `on` / `TRUE` / a whitespace-padded `.env` value as
// OFF. It now mirrors selfTuneFlagOn's `/^(1|true|yes|on)$/i.test((X ?? "").trim())`, trimmed + i-flag.
for (const value of ["1", "true", "TRUE", "yes", "on", " true "]) {
expect(isOpenPrFileCollisionEnabledGlobally({ LOOPOVER_OPEN_PR_FILE_COLLISION: value }), value).toBe(true);
}
});

it("stays OFF for any other value, including truthy-looking ones", () => {
for (const value of ["1", "yes", "on", "True", "TRUE", " true "]) {
expect(isOpenPrFileCollisionEnabledGlobally({ LOOPOVER_OPEN_PR_FILE_COLLISION: value })).toBe(false);
it("stays OFF for a falsy or unrecognised value", () => {
for (const value of ["0", "false", "off", "no", "maybe"]) {
expect(isOpenPrFileCollisionEnabledGlobally({ LOOPOVER_OPEN_PR_FILE_COLLISION: value }), value).toBe(false);
}
});
});
Expand Down
Loading