Single-source the version from package.json #95

Merged
clawbot merged 1 commits from issue-5-single-version into next2 2026-09-23 05:07:47 +02:00
5 changed files with 66 additions and 7 deletions
+6
View File
@@ -18,6 +18,12 @@ Tag v1.0.0.
# Completed Steps
- 2026-09-23: Single-sourced the version string (issue 5). `package.json` is the
only place it is written: `src/index.ts` imports it for `VERSION` and
`bin/quak.ts` passes `VERSION` to commander. tsc copies `package.json` to
`dist/package.json`, so the import resolves from the built output too, and
`script/build` runs the built CLI with `--version` to prove it. A test checks
that `VERSION` and `quak --version` both equal the `package.json` version.
- 2026-09-23: Tested that `Library.close()` waits for the originals precache
(issue 93). The test that holds a precache fetch open while `close()` runs now
runs once with only the thumbnail fill and once with only the originals fill,
+2 -1
View File
@@ -19,6 +19,7 @@ import {
fixMissingThumbnailsCommand,
} from "../src/cli-commands.js";
import { loadSession } from "../src/cli-session.js";
import { VERSION } from "../src/index.js";
const paths = envPaths("quak", { suffix: "" });
@@ -27,7 +28,7 @@ const program = new Command();
program
.name("quak")
.description("CLI for the Ente end-to-end encrypted photo service")
.version("0.0.0")
.version(VERSION)
.option(
"--cache-dir <path>",
"Directory for the local metadata/content cache " +
+14
View File
@@ -45,10 +45,24 @@ for (const bin of bins) {
'
}
# src/index.ts imports ../package.json for the version, which tsc copies to
# dist/package.json. Running the built CLI proves that import resolves from
# dist/ and reports the version package.json declares.
verify_version() {
built="$(node dist/bin/quak.js --version)"
declared="$(node -p 'require("./package.json").version')"
if [ "$built" != "$declared" ]; then
echo "build: dist/bin/quak.js reports $built, package.json declares $declared" >&2
exit 1
fi
echo "build: dist/bin/quak.js reports version $built"
}
main() {
cd "$ROOT"
yarn run tsc
verify_entrypoints
verify_version
}
main "$@"
+5 -1
View File
@@ -1,4 +1,8 @@
export const VERSION = "0.0.0";
// package.json is the one place the version is written. tsc copies it to
// dist/package.json, so this path resolves from source and from dist/src/.
import pkg from "../package.json" with { type: "json" };
export const VERSION: string = pkg.version;
export {
Client,
+39 -5
View File
@@ -1,9 +1,43 @@
import { describe, expect, it } from "vitest";
import { afterEach, describe, expect, it, vi } from "vitest";
import { readFileSync } from "node:fs";
import { VERSION } from "../src/index.js";
describe("quak", () => {
it("exports a version string", () => {
expect(typeof VERSION).toBe("string");
expect(VERSION.length).toBeGreaterThan(0);
const packageVersion = (
JSON.parse(
readFileSync(new URL("../package.json", import.meta.url), "utf-8"),
) as { version: string }
).version;
class ExitCalled extends Error {}
describe("version", () => {
const argv = process.argv;
afterEach(() => {
process.argv = argv;
vi.restoreAllMocks();
});
it("exports the version from package.json", () => {
expect(VERSION).toBe(packageVersion);
});
// Runs bin/quak.ts with --version. commander prints the version and then
// calls process.exit, which is stubbed to throw so the test survives.
it("reports the version from package.json in quak --version", async () => {
const printed: string[] = [];
vi.spyOn(process.stdout, "write").mockImplementation((chunk) => {
printed.push(String(chunk));
return true;
});
vi.spyOn(process, "exit").mockImplementation(() => {
throw new ExitCalled();
});
process.argv = ["node", "quak", "--version"];
await expect(import("../bin/quak.js")).rejects.toBeInstanceOf(
ExitCalled,
);
expect(printed.join("").trim()).toBe(packageVersion);
});
});