From bc0e72eb07df045bdbe1232a5c870e8eca41f765 Mon Sep 17 00:00:00 2001 From: Day Dreamer <87640074+HugoXK@users.noreply.github.com> Date: Thu, 5 Nov 2026 22:37:44 +0800 Subject: [PATCH] changelog: record the pass-label writer-case fix (#2544) --- .github/scripts/pass-label.mjs | 11 ++++++++--- .github/scripts/pass-label.test.mjs | 16 ++++++++++++++++ changelog.d/2544-pass-label-writer-case.fixed.md | 1 + 3 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 changelog.d/2544-pass-label-writer-case.fixed.md diff --git a/.github/scripts/pass-label.mjs b/.github/scripts/pass-label.mjs index 5341c6e48..b327e9bb9 100644 --- a/.github/scripts/pass-label.mjs +++ b/.github/scripts/pass-label.mjs @@ -36,13 +36,19 @@ const SHORT = 12 const firstLine = (body) => String(body ?? '').split('\n').map((line) => line.trim()).find((line) => line !== '') ?? '' +// The gates compare a `Written-by:` name with the policy's roster case-insensitively (#1131: +// `review-gate` lowercases both sides before `writers.has(...)`), so every reader of a conclusion here +// does the same — one rule, one place, and a label cannot go missing where the gate accepted the PASS. +const isListedWriter = (writers, name) => + new Set(writers.map((w) => String(w).toLowerCase())).has(String(name).toLowerCase()) + // Does this body decide that the tip was PASSed? `Correction from …` never does, whatever it quotes. export function verdictOf(body, { writers = [], association } = {}) { if (!ASSOCIATIONS.has(String(association ?? '').toUpperCase())) return null if (/^Correction\b/i.test(firstLine(body))) return null const report = parseReport(body) if (report.verdict !== 'PASS') return null - if (!report.writer || !writers.includes(report.writer)) return null + if (!report.writer || !isListedWriter(writers, report.writer)) return null return report } @@ -71,8 +77,7 @@ export function strangerPassOf(body, { writers = [], association } = {}) { if (/^Correction\b/i.test(firstLine(body))) return null const report = parseReport(body) if (report.verdict !== 'PASS' || !report.tip || !report.writer) return null - const listed = new Set(writers.map((w) => String(w).toLowerCase())) - if (listed.has(String(report.writer).toLowerCase())) return null + if (isListedWriter(writers, report.writer)) return null return { writer: report.writer, tip: report.tip } } diff --git a/.github/scripts/pass-label.test.mjs b/.github/scripts/pass-label.test.mjs index 1673d1398..ef0c68c7e 100644 --- a/.github/scripts/pass-label.test.mjs +++ b/.github/scripts/pass-label.test.mjs @@ -38,6 +38,22 @@ Written-by: Reviewer` assert.equal(verdictOf(conclusion('PASS', head, 'Stranger'), { writers, association: 'MEMBER' }), null, 'the name must be in writers') }) +// The gates compare `Written-by:` with the policy's names case-insensitively: `review-gate` lowercases +// both sides before `writers.has(...)`, and `strangerPassOf` here does the same. `verdictOf` compared with +// `writers.includes(report.writer)`, so a PASS written as `reviewer` or `dev4` counted for the gate and was +// silently neither labelled nor noted — the record #739 exists for went missing exactly where the gate +// had accepted it, and the `pass` job reported nothing at all. +test('#739: a writer matches the way the gates match it, whatever its case', () => { + for (const writer of ['reviewer', 'REVIEWER', 'dev4']) { + const body = conclusion('PASS', head, writer) + assert.ok(verdictOf(body, { writers, association: 'MEMBER' }), `${writer} is a listed name in another case`) + assert.equal(planComment({ pr: 7, body, association: 'MEMBER', writers }).add, true, `${writer} labels the pull request`) + } + // Not a widening: a name the policy does not list is not a conclusion in any case. + assert.equal(verdictOf(conclusion('PASS', head, 'reviewer3'), { writers, association: 'MEMBER' }), null) + assert.equal(verdictOf(conclusion('PASS', head, 'Reviewer Extra'), { writers, association: 'MEMBER' }), null) +}) + test('#739: a replacement PASS labels like a normal PASS, and a second run adds nothing', () => { const replacement = `Verdict: PASS at ${head} Written-by: Reviewer diff --git a/changelog.d/2544-pass-label-writer-case.fixed.md b/changelog.d/2544-pass-label-writer-case.fixed.md new file mode 100644 index 000000000..abdd085df --- /dev/null +++ b/changelog.d/2544-pass-label-writer-case.fixed.md @@ -0,0 +1 @@ +A pull request whose PASS verdict names its writer in a different letter case than the review policy roster no longer loses that record: the `pass` label job compares names the way `review-gate` and `merge-gate` already do, so a PASS the gates accept now labels the pull request instead of being silently dropped ([#2544](https://github.com/ThinkFlowLab/FlyBot/issues/2544)).