feat(release-notes): terse bilingual notes as data files — new/fixed only, the dialog lists the latest ten (E28)
This commit is contained in:
@@ -2,20 +2,52 @@ import { readFileSync } from "node:fs";
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { RELEASE_NOTES } from "./releaseNotes";
|
||||
import en from "../content/release-notes/en.json";
|
||||
import hu from "../content/release-notes/hu.json";
|
||||
import { type ReleaseEntry } from "./releaseNotes";
|
||||
|
||||
const EN = en as ReleaseEntry[];
|
||||
const HU = hu as ReleaseEntry[];
|
||||
|
||||
// DX-6: the app version is hand-maintained in two places that MUST agree — the repo-root VERSION file
|
||||
// (the single source baked into the image + served at /api/version) and the newest RELEASE_NOTES entry
|
||||
// (the single source baked into the image + served at /api/version) and the newest release note
|
||||
// (what the in-app "What's new" shows). A release that bumps one but forgets the other ships a wrong
|
||||
// changelog or a mismatched banner. This locks them together so the gate catches the drift.
|
||||
describe("release version consistency", () => {
|
||||
it("RELEASE_NOTES[0].version matches the VERSION file", () => {
|
||||
it("the newest note's version matches the VERSION file", () => {
|
||||
const version = readFileSync(new URL("../../../VERSION", import.meta.url), "utf-8").trim();
|
||||
expect(RELEASE_NOTES[0]?.version).toBe(version);
|
||||
expect(EN[0]?.version).toBe(version);
|
||||
});
|
||||
|
||||
it("release notes are ordered newest-first with unique versions", () => {
|
||||
const versions = RELEASE_NOTES.map((r) => r.version);
|
||||
expect(new Set(versions).size).toBe(versions.length); // no duplicate version entries
|
||||
const versions = EN.map((r) => r.version);
|
||||
expect(new Set(versions).size).toBe(versions.length);
|
||||
const num = (v: string) => v.split(".").map(Number) as [number, number, number];
|
||||
for (let i = 1; i < versions.length; i++) {
|
||||
const [a, b] = [num(versions[i - 1]!), num(versions[i]!)];
|
||||
const newer = a[0] - b[0] || a[1] - b[1] || a[2] - b[2];
|
||||
expect(newer, `${versions[i - 1]} before ${versions[i]}`).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// E28 (owner): internal work never ships on its own — it waits for a release a user can see. So the
|
||||
// release being cut always says what changed for the user.
|
||||
it("the newest release has something a user notices", () => {
|
||||
expect(EN[0]!.new.length + EN[0]!.fixed.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
// A note is a sentence or two (owner, E28): the old paragraphs were what made the dialog slow and
|
||||
// unread. The ceiling is generous for Hungarian, whose words run longer.
|
||||
it("every item is short", () => {
|
||||
const long = [...EN, ...HU].flatMap((r) =>
|
||||
[...r.new, ...r.fixed].filter((s) => s.length > 260).map((s) => `${r.version}: ${s}`),
|
||||
);
|
||||
expect(long).toEqual([]);
|
||||
});
|
||||
|
||||
it("the Hungarian notes are the English ones, item for item", () => {
|
||||
const shape = (all: ReleaseEntry[]) =>
|
||||
all.map((r) => [r.version, r.date, r.sha ?? "", r.new.length, r.fixed.length].join(" "));
|
||||
expect(shape(HU)).toEqual(shape(EN));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user