diff --git a/plugins/stewards/server.test.ts b/plugins/stewards/server.test.ts index b2f44494..b636ec53 100644 --- a/plugins/stewards/server.test.ts +++ b/plugins/stewards/server.test.ts @@ -8781,6 +8781,31 @@ describe("bb stewards needs lists the needsYou set (BB-69)", () => { expect(Array.isArray(all)).toBe(true); }); + it("shows a done need's resolution and no actionability reason in --all (BB-283)", async () => { + const t = await adopted(); + const b = t.binding(); + // A merged, observed pull request: `needView` on this closed approve-pr row + // would fall through to "the pull request has not been observed yet". + const merged = pull({ id: "acme/web#7", key: "acme/web#7", url: "https://github.com/acme/web/pull/7", state: "merged" }, { merged: true, mergeCommit: "b".repeat(40), checks: { state: "success", failing: [] } }); + t.entities.set("acme/web#7", merged); + t.hooks.store.patch(b.id, { lastSnapshot: { entity: t.entities.get("uuid-12")!, pulls: [merged] } }); + const need = t.hooks.store.fileNeed({ bindingId: b.id, kind: "approve-pr", url: "https://github.com/acme/web/pull/7", what: "Approve acme/web#7 on GitHub", how: null, filedBy: "plugin" }); + t.hooks.store.closeNeed(need.id, "Approved on the Stewards page."); + const out = (await t.harness.behavior.runCli(["needs", "--all", "--project", "p1"])).stdout; + const line = out.split("\n").find((l) => l.startsWith(need.id))!; + expect(line).toBe(`${need.id} — approve-pr, ENG-12: Approve acme/web#7 on GitHub (https://github.com/acme/web/pull/7) → Approved on the Stewards page.`); + expect(line).not.toContain("[not actionable"); + }); + + it("keeps an open need's --all line byte-for-byte, with its actionability reason (BB-283)", async () => { + const t = await adopted(); + const b = t.binding(); + const need = t.hooks.store.fileNeed({ bindingId: b.id, kind: "approve-pr", url: "https://github.com/acme/web/pull/999", what: "Approve an unobserved pull request", how: null }); + const out = (await t.harness.behavior.runCli(["needs", "--all", "--project", "p1"])).stdout; + const line = out.split("\n").find((l) => l.startsWith(need.id))!; + expect(line).toBe(`${need.id} — approve-pr, ENG-12: Approve an unobserved pull request (https://github.com/acme/web/pull/999) [not actionable: the pull request has not been observed yet]`); + }); + it("the printed done command closes the question and the escalation it names", async () => { const t = await adopted(); const b = t.binding(); diff --git a/plugins/stewards/server.ts b/plugins/stewards/server.ts index 15bb1c67..31882b1e 100644 --- a/plugins/stewards/server.ts +++ b/plugins/stewards/server.ts @@ -11647,8 +11647,13 @@ export function createStewardsPlugin(deps: StewardsDeps): (bb: BbPluginApi) => P stdout: rows .map((n) => { const b = store.binding(n.bindingId); + const head = `${n.id} — ${n.kind}, ${b?.entityKey ?? n.bindingId}: ${n.what}${choicesNote(needChoices(n))}${n.url === "" ? "" : ` (${n.url})`}`; + // A closed row is a record of what happened, not an open + // item: show its resolution rather than needView's reason + // it cannot be acted on now (BB-283). + if (n.status === "done") return `${head}${n.resolution === null ? "" : ` → ${n.resolution}`}`; const view = b === null ? null : needView(n, b); - return `${n.id} — ${n.kind}, ${b?.entityKey ?? n.bindingId}: ${n.what}${choicesNote(needChoices(n))}${n.url === "" ? "" : ` (${n.url})`}${view !== null && !view.actionable ? ` [not actionable: ${view.why}]` : ""}`; + return `${head}${view !== null && !view.actionable ? ` [not actionable: ${view.why}]` : ""}`; }) .join("\n"), };