Public: anyone can read this; the crew can change it.
A mirror's "do it there" sentence lives in one module, read by issue teams and the thread page #5638
Check · Review · Land · Live done — Landed and live in production.
mason/forge:mason/5591-a-mirror-s-do-it-there-sentence-lives-in → main 1 commit fork
4 files
changed +47
−4
src/actions/issue_teams.ts +2 −2
| @@ -11,13 +11,13 @@ import type { User } from "../core/users.ts"; | ||
| 11 | 11 | import { err, type Result } from "../kernel/result.ts"; |
| 12 | 12 | import { isMirror } from "../origins/write-through.ts"; |
| 13 | 13 | import { requireWriter, type AccessError } from "./access.ts"; |
| 14 | import { MIRRORED_DO_IT_THERE } from "./mirror_words.ts"; | |
| 14 | 15 | |
| 15 | 16 | /** One sentence per refusal, said the same by the page, API, MCP tool and terminal. */ |
| 16 | 17 | export const ISSUE_TEAMS_SAY: Record<string, string> = { |
| 17 | 18 | too_many: `An issue names at most ${TEAMS_MAX} teams.`, |
| 18 | 19 | no_such_team: "No such team.", |
| 19 | mirrored: | |
| 20 | "This repository mirrors an origin — do it there, and the next sync brings it back.", | |
| 20 | mirrored: MIRRORED_DO_IT_THERE, | |
| 21 | 21 | unauthorized: "Sign in to name teams.", |
| 22 | 22 | forbidden: "You need write access to name teams.", |
| 23 | 23 | not_found: "No such issue.", |
src/actions/mirror_words.ts added +8
| @@ -0,0 +1,8 @@ | ||
| 1 | /** | |
| 2 | * What a mirror says when a local write belongs on its origin (#5591): | |
| 3 | * one sentence, said the same by the issue teams action and the thread page. | |
| 4 | */ | |
| 5 | ||
| 6 | /** A mirror's issues and pulls are the origin's: the change is made there. */ | |
| 7 | export const MIRRORED_DO_IT_THERE = | |
| 8 | "This repository mirrors an origin — do it there, and the next sync brings it back."; |
src/web/pages/thread.ts +2 −2
| @@ -10,6 +10,7 @@ | ||
| 10 | 10 | |
| 11 | 11 | import { mayView } from "../../core/sealed.ts"; |
| 12 | 12 | import { ISSUE_TEAMS_SAY, nameTeams } from "../../actions/issue_teams.ts"; |
| 13 | import { MIRRORED_DO_IT_THERE } from "../../actions/mirror_words.ts"; | |
| 13 | 14 | import { teamsOfIssue, TEAMS_MAX } from "../../core/issue_teams.ts"; |
| 14 | 15 | import { listTeams } from "../../core/teams.ts"; |
| 15 | 16 | import { listCrew } from "../../actions/crew.ts"; |
| @@ -81,8 +82,7 @@ import { interruptionsOn } from "../../crew/interrupted.ts"; | ||
| 81 | 82 | */ |
| 82 | 83 | export function originError(error: string): string | undefined { |
| 83 | 84 | const words: Record<string, string> = { |
| 84 | mirrored: | |
| 85 | "This repository mirrors an origin — do it there, and the next sync brings it back.", | |
| 85 | mirrored: MIRRORED_DO_IT_THERE, | |
| 86 | 86 | origin_owner_only: |
| 87 | 87 | "Only the person who connected this origin can write through it. Your comment would otherwise appear upstream under their name.", |
| 88 | 88 | origin_refused: "The origin refused that. Nothing was changed here either.", |
test/mirror-words.test.ts added +35
| @@ -0,0 +1,35 @@ | ||
| 1 | /** | |
| 2 | * A mirror's "do it there" sentence is said from one module (#5591): the | |
| 3 | * issue teams action and the thread page import it, and neither types a | |
| 4 | * copy of it back. | |
| 5 | */ | |
| 6 | ||
| 7 | import { describe, expect, test } from "bun:test"; | |
| 8 | import { readFileSync } from "node:fs"; | |
| 9 | import { join } from "node:path"; | |
| 10 | import * as words from "../src/actions/mirror_words.ts"; | |
| 11 | ||
| 12 | const READERS = ["src/actions/issue_teams.ts", "src/web/pages/thread.ts"]; | |
| 13 | ||
| 14 | describe("a mirror's words live in one module", () => { | |
| 15 | const sentences = Object.entries(words); | |
| 16 | ||
| 17 | test("each exported sentence is a non-empty string", () => { | |
| 18 | expect(sentences.length).toBeGreaterThan(0); | |
| 19 | for (const [, sentence] of sentences) { | |
| 20 | expect(typeof sentence).toBe("string"); | |
| 21 | expect((sentence as string).trim()).not.toBe(""); | |
| 22 | } | |
| 23 | }); | |
| 24 | ||
| 25 | for (const file of READERS) { | |
| 26 | test(`${file} imports the sentences and types none of them`, () => { | |
| 27 | const source = readFileSync(join(import.meta.dir, "..", file), "utf8"); | |
| 28 | expect(source).toContain("mirror_words.ts"); | |
| 29 | for (const [name, sentence] of sentences) { | |
| 30 | expect(source).toContain(name); | |
| 31 | expect(source).not.toContain(sentence as string); | |
| 32 | } | |
| 33 | }); | |
| 34 | } | |
| 35 | }); |
new above
offline