Public: anyone can read this; the crew can change it.
A pull's re-check and conflict sentences live in one module, read by the pull page, conflicts and the terminal #5629
Check · Review · Land · Live done — Landed and live in production.
mason/forge:mason/5620-a-pull-s-re-check-and-conflict-sentences → main 2 commits fork
6 files
changed +52
−4
src/actions/pull_ask_words.ts added +11
| @@ -0,0 +1,11 @@ | ||
| 1 | /** | |
| 2 | * What a person is told after asking something of a pull (#5620): a check at | |
| 3 | * its head, or the crew's resolution of its conflicts. Said the same on the | |
| 4 | * pull page, the conflicts page and the terminal, from here. | |
| 5 | */ | |
| 6 | ||
| 7 | /** A check was asked for at the pull's head. */ | |
| 8 | export const CHECK_ASKED = "Check asked for at the current head."; | |
| 9 | ||
| 10 | /** The crew was asked to resolve the pull's conflicts. */ | |
| 11 | export const RESOLUTION_ASKED = "Asked: the crew is resolving it on the pull's own branch."; |
src/tui/screens/pull.ts +2 −1
| @@ -109,6 +109,7 @@ import { assignPicker, assignedText } from "./assign.ts"; | ||
| 109 | 109 | import { DiffView, type DiffAnchor, type DiffNote } from "./commits.ts"; |
| 110 | 110 | import { liveBindings, liveKey } from "./mirror.ts"; |
| 111 | 111 | import { pullConflicts } from "../../actions/conflicts.ts"; |
| 112 | import { RESOLUTION_ASKED } from "../../actions/pull_ask_words.ts"; | |
| 112 | 113 | import { FINISH_REFUSALS, finishConflicts } from "../../actions/finish-conflicts.ts"; |
| 113 | 114 | import { PROPOSE_WHY, proposalOf, proposeResolution } from "../../crew/proposal.ts"; |
| 114 | 115 | import { conflictScreen } from "./conflicts.ts"; |
| @@ -737,7 +738,7 @@ export function pullScreen( | ||
| 737 | 738 | const fresh = getPull(f.db, target.id, number) ?? row; |
| 738 | 739 | const made = await proposeResolution(f.app, f.user, target, fresh); |
| 739 | 740 | return made.ok |
| 740 | ? { ok: true, message: "Asked: the crew is resolving it on the pull's own branch." } | |
| 741 | ? { ok: true, message: RESOLUTION_ASKED } | |
| 741 | 742 | : { ok: false, message: PROPOSE_WHY[made.error] }; |
| 742 | 743 | }, |
| 743 | 744 | }), |
src/tui/screens/stalled.ts +2 −1
| @@ -6,6 +6,7 @@ | ||
| 6 | 6 | * step under the cursor; the list is live, and a step that moves on leaves it. |
| 7 | 7 | */ |
| 8 | 8 | |
| 9 | import { CHECK_ASKED } from "../../actions/pull_ask_words.ts"; | |
| 9 | 10 | import { readStalled, type StalledStep } from "../../flow/stalled.ts"; |
| 10 | 11 | import { unblock } from "../../flow/unblock.ts"; |
| 11 | 12 | import type { Ctx, Screen } from "../app/app.ts"; |
| @@ -37,7 +38,7 @@ export function stalledScreen(f: Session, ctx: Ctx): Screen { | ||
| 37 | 38 | if (step === undefined || user === undefined) return; |
| 38 | 39 | runAsync(ctx, async () => { |
| 39 | 40 | const done = await unblock(f.app, user, step); |
| 40 | ctx.toast(done.ok ? "Check asked for at the current head." : done.message, done.ok ? "default" : "danger"); | |
| 41 | ctx.toast(done.ok ? CHECK_ASKED : done.message, done.ok ? "default" : "danger"); | |
| 41 | 42 | reload(); |
| 42 | 43 | }); |
| 43 | 44 | }; |
src/web/pages/conflicts.ts +2 −1
| @@ -28,6 +28,7 @@ import { notePhase, takeSessionTime, timePhase, timePhaseAsync } from "../../cor | ||
| 28 | 28 | import type { Ctx } from "../../http/context.ts"; |
| 29 | 29 | import { crumbsFor, notFoundPage, repoBase, repoPalette, repoHeader } from "../chrome.ts"; |
| 30 | 30 | import { FINISH_REFUSALS, finishConflicts } from "../../actions/finish-conflicts.ts"; |
| 31 | import { RESOLUTION_ASKED } from "../../actions/pull_ask_words.ts"; | |
| 31 | 32 | import { field, readForm } from "../form.ts"; |
| 32 | 33 | import { html, type Html } from "../html.ts"; |
| 33 | 34 | import { flashTo, page } from "../layout.ts"; |
| @@ -78,7 +79,7 @@ export async function proposeSubmit(ctx: Ctx): Promise<Response> { | ||
| 78 | 79 | const made = await proposeResolution(ctx.app, ctx.auth.user, repo, pull); |
| 79 | 80 | if (!made.ok) return flashTo(ctx, dest, { tone: "danger", message: PROPOSE_WHY[made.error] }); |
| 80 | 81 | return flashTo(ctx, dest, { |
| 81 | message: "Asked: the crew is resolving it on the pull's own branch.", | |
| 82 | message: RESOLUTION_ASKED, | |
| 82 | 83 | }); |
| 83 | 84 | } |
| 84 | 85 |
src/web/pages/pull.ts +2 −1
| @@ -21,6 +21,7 @@ import { | ||
| 21 | 21 | submitReview, |
| 22 | 22 | approveToRun, |
| 23 | 23 | } from "../../actions/pulls.ts"; |
| 24 | import { CHECK_ASKED } from "../../actions/pull_ask_words.ts"; | |
| 24 | 25 | import { reviewWords } from "../../actions/review_words.ts"; |
| 25 | 26 | import { readFileAt } from "../../apps/checkout.ts"; |
| 26 | 27 | import { parseCheck } from "../../apps/manifest.ts"; |
| @@ -1291,7 +1292,7 @@ export async function pullChecksSubmit(ctx: Ctx): Promise<Response> { | ||
| 1291 | 1292 | ctx, |
| 1292 | 1293 | dest, |
| 1293 | 1294 | asked.ok |
| 1294 | ? { message: "Check asked for at the current head." } | |
| 1295 | ? { message: CHECK_ASKED } | |
| 1295 | 1296 | : { tone: "danger", message: `No check was asked for: ${asked.message}.` }, |
| 1296 | 1297 | ); |
| 1297 | 1298 | } |
test/pull-ask-words.test.ts added +33
| @@ -0,0 +1,33 @@ | ||
| 1 | /** | |
| 2 | * A pull's re-check and conflict sentences are said from one module | |
| 3 | * (#5620): the pull page, the conflicts page and the terminal import them, | |
| 4 | * and none of them types a copy back. | |
| 5 | */ | |
| 6 | ||
| 7 | import { expect, test } from "bun:test"; | |
| 8 | import { readFileSync } from "node:fs"; | |
| 9 | import { join } from "node:path"; | |
| 10 | import { CHECK_ASKED, RESOLUTION_ASKED } from "../src/actions/pull_ask_words.ts"; | |
| 11 | ||
| 12 | const ROOT = join(import.meta.dir, ".."); | |
| 13 | const READERS = [ | |
| 14 | "src/web/pages/pull.ts", | |
| 15 | "src/web/pages/conflicts.ts", | |
| 16 | "src/tui/screens/stalled.ts", | |
| 17 | "src/tui/screens/pull.ts", | |
| 18 | ]; | |
| 19 | ||
| 20 | test("the sentences read as they always have", () => { | |
| 21 | expect(CHECK_ASKED).toBe("Check asked for at the current head."); | |
| 22 | expect(RESOLUTION_ASKED).toBe("Asked: the crew is resolving it on the pull's own branch."); | |
| 23 | }); | |
| 24 | ||
| 25 | test("every reader imports the module and types no copy of a sentence", () => { | |
| 26 | for (const path of READERS) { | |
| 27 | const text = readFileSync(join(ROOT, path), "utf8"); | |
| 28 | expect(text).toContain("actions/pull_ask_words.ts"); | |
| 29 | for (const sentence of [CHECK_ASKED, RESOLUTION_ASKED]) { | |
| 30 | expect({ path, has: text.includes(sentence) }).toEqual({ path, has: false }); | |
| 31 | } | |
| 32 | } | |
| 33 | }); |
new above
offline