1234import { describe, expect, test } from "bun:test";5import { writeFile } from "node:fs/promises";6import { join } from "node:path";7import { openBucket } from "../src/bucket/reader.ts";8import { syncAll } from "../src/bucket/sync.ts";9import { declaredVersion } from "../src/describe/version.ts";10import { instance } from "./browser.ts";11import { makeRepos, writeRelease } from "./fixture.ts";1213const from = (files: Record<string, string>) => declaredVersion((path) => files[path] ?? null);1415describe("the declared version", () => {16 test("is the first source that answers, VERSION first", () => {17 expect(from({ VERSION: " 2.0.1\n", "package.json": '{ "version": "1.0.0" }' })).toBe("2.0.1");18 expect(from({ "package.json": '{\n "name": "x",\n "version": "3.0.199",\n}' })).toBe(19 "3.0.199",20 );21 expect(22 from({ "build.zig.zon": '.{\n .version = "0.14.1",\n}', "Cargo.toml": 'version = "9"' }),23 ).toBe("0.14.1");24 expect(from({ "v.mod": "Module {\n\tname: 'koh'\n\tversion: '3.2.27'\n}" })).toBe("3.2.27");25 expect(from({ "Cargo.toml": '[package]\nversion = "0.5.0"' })).toBe("0.5.0");26 expect(27 from({28 "Info.plist": "<key>CFBundleShortVersionString</key>\n\t<string> 1.4 </string>",29 }),30 ).toBe("1.4");31 });3233 test("reads Gradle's versionName literally, never a suffix, comment or variable", () => {34 const gradle = (text: string) => from({ "app/build.gradle.kts": text });35 expect(gradle('versionNameSuffix = "-dev"\nversionName = "2.17.43"')).toBe("2.17.43");36 expect(gradle('// versionName = "1.0"\nversionName "5.2.62"')).toBe("5.2.62");37 expect(gradle("versionName = libs.versions.app.get()")).toBeNull();38 });3940 test("skips a source with no literal, and is none when the answer is not a version", () => {41 expect(42 from({ "package.json": '"version": pkg.version', "Cargo.toml": 'version = "1.1"' }),43 ).toBe("1.1");44 expect(from({ VERSION: "not a version!", "package.json": '"version": "1.0.0"' })).toBeNull();45 expect(from({})).toBeNull();46 });47});4849test("a repo's header shows its declared version, and a build's over it", async () => {50 const repos = await makeRepos(["app"]);51 await writeFile(52 join(repos.bucketDir, "..", "work", "app", "package.json"),53 '{\n "name": "app",\n "version": "1.2.3"\n}\n',54 );55 repos.koh("app", "save", "declare a version");56 repos.koh("app", "offer");57 const inst = await instance(repos.bucketDir);58 inst.kepr.run("UPDATE repos SET public = 1");59 const meta = async () =>60 /<p class="repo-meta">([^<]*)<\/p>/.exec(await (await inst.app.request("/app")).text())?.[1];61 expect(await meta()).toStartWith("v1.2.3 · ");62 const head = JSON.parse(repos.koh("app", "view", "--json")).head_id as string;63 await writeRelease(repos.bucketDir, "app", {64 version: "2.0.0",65 save: head,66 files: [{ platform: "linux-x86_64", name: "app", bytes: new Uint8Array([1]) }],67 });68 await syncAll({69 bucket: openBucket({ kind: "folder", path: repos.bucketDir }),70 kepr: inst.kepr,71 mirrorDir: join(inst.dataDir, "mirror"),72 });73 expect(await meta()).toStartWith("v2.0.0 · ");74});