Public: anyone can read this; the crew can change it.
A shipped tell finds its change by asking for the event, not scanning 200 #219
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/107-a-shipped-tell-finds-its-change-by-askin → main 1 commit fork
3 files
changed +49
−5
src/core/events.ts +6
| @@ -78,6 +78,8 @@ export class EventBus { | ||
| 78 | 78 | |
| 79 | 79 | export interface ListEventsOptions { |
| 80 | 80 | repoId?: string; |
| 81 | /** Restrict to events of this kind. */ | |
| 82 | kind?: string; | |
| 81 | 83 | /** Return events with id greater than this (exclusive). */ |
| 82 | 84 | afterId?: string; |
| 83 | 85 | /** @default 100 */ |
| @@ -148,6 +150,10 @@ export function listEvents( | ||
| 148 | 150 | params.push(options.repoId); |
| 149 | 151 | clauses.push(`repo_id = ?${params.length}`); |
| 150 | 152 | } |
| 153 | if (options.kind !== undefined) { | |
| 154 | params.push(options.kind); | |
| 155 | clauses.push(`kind = ?${params.length}`); | |
| 156 | } | |
| 151 | 157 | if (options.afterId !== undefined) { |
| 152 | 158 | params.push(options.afterId); |
| 153 | 159 | clauses.push(`id > ?${params.length}`); |
src/web/studio/tell.ts +6 −5
| @@ -52,11 +52,12 @@ import { | ||
| 52 | 52 | * shows. Undefined for an issue closed by hand, or still open. */ |
| 53 | 53 | function shippedBy(db: Database, repo: Repo, issue: Issue): Pull | undefined { |
| 54 | 54 | if (issue.state !== "closed") return undefined; |
| 55 | const closed = listEvents(db, { repoId: repo.id, limit: 200 }).find( | |
| 56 | (e) => | |
| 57 | e.kind === "issue.closed" && | |
| 58 | Number(e.payload.number) === issue.number && | |
| 59 | e.payload.by === "merge", | |
| 55 | const closed = listEvents(db, { | |
| 56 | repoId: repo.id, | |
| 57 | kind: "issue.closed", | |
| 58 | limit: 200, | |
| 59 | }).find( | |
| 60 | (e) => Number(e.payload.number) === issue.number && e.payload.by === "merge", | |
| 60 | 61 | ); |
| 61 | 62 | if (closed === undefined) return undefined; |
| 62 | 63 | const number = Number(closed.payload.pull); |
test/studio.test.ts +37
| @@ -362,6 +362,43 @@ describe("the studio", () => { | ||
| 362 | 362 | expect(getUserByName(app.db, "scout")).toBeDefined(); |
| 363 | 363 | }); |
| 364 | 364 | |
| 365 | test("a tell shipped long ago still reads shipped once it is buried under 250 later events", async () => { | |
| 366 | const told = openIssue(app, alice, repo, { | |
| 367 | title: "Buried tell", | |
| 368 | body: "", | |
| 369 | }); | |
| 370 | if (!told.ok) throw new Error(String(told.error)); | |
| 371 | const branch = await commitToBranch(app, alice, repo, { | |
| 372 | branch: "feature/buried", | |
| 373 | base: "main", | |
| 374 | message: "Buried", | |
| 375 | files: [{ path: "BURIED.md", content: "buried\n" }], | |
| 376 | }); | |
| 377 | if (!branch.ok) throw new Error(JSON.stringify(branch.error)); | |
| 378 | const opened = await openPull(app, alice, repo, { | |
| 379 | title: "Buried", | |
| 380 | body: `Closes #${told.value.number}`, | |
| 381 | baseBranch: "main", | |
| 382 | headBranch: "feature/buried", | |
| 383 | }); | |
| 384 | if (!opened.ok) throw new Error(String(opened.error)); | |
| 385 | const merged = await mergePull(app, alice, repo, opened.value, "squash"); | |
| 386 | if (!merged.ok) throw new Error(String(merged.error)); | |
| 387 | expect(getIssue(app.db, repo.id, told.value.number)?.state).toBe("closed"); | |
| 388 | ||
| 389 | // 250 events of other kinds, appended after the merge, so a scan of the | |
| 390 | // most recent 200 events of any kind would never reach the one that | |
| 391 | // actually closed this issue. | |
| 392 | for (let i = 0; i < 250; i++) | |
| 393 | app.bus.append({ kind: "push", repoId: repo.id, payload: { n: i } }); | |
| 394 | ||
| 395 | const page = await ( | |
| 396 | await get(`/alice/notes/issues/${told.value.number}`) | |
| 397 | ).text(); | |
| 398 | expect(page).toContain('data-word="shipped"'); | |
| 399 | expect(page).not.toContain('data-state="closed"'); | |
| 400 | }); | |
| 401 | ||
| 365 | 402 | test("a pull on an app renders as a studio page — the preview, the look and the decision, no diff; ?mode=dev still renders the diff", async () => { |
| 366 | 403 | const scout = getUserByName(app.db, "scout")!; |
| 367 | 404 | const branch = await commitToBranch(app, alice, repo, { |
new above
offline