A self-hosted household ledger.
1// Create (and optionally push) the ChronVer git tag for the current release.
2// The version is read from package.json; the tag is an annotated tag on the
3// commit that set it. Run this AFTER committing the release bump — pushing the
4// tag is what triggers the CI image build (.tangled/workflows/build-image.yml).
5//
6// deno task tag # create the annotated tag locally
7// deno task tag --push # also push it to origin (triggers CI)
8import { isChronVer, pkgVersion } from "./version.ts";
9import { lastReleaseCommit } from "./changelog.ts";
10
11async function git(args: string[]) {
12 const { code, stdout, stderr } = await new Deno.Command("git", {
13 args,
14 stdout: "piped",
15 stderr: "piped",
16 }).output();
17 return {
18 code,
19 out: new TextDecoder().decode(stdout).trim(),
20 err: new TextDecoder().decode(stderr).trim(),
21 };
22}
23
24const version = await pkgVersion();
25if (!isChronVer(version)) {
26 console.error(
27 `package.json version "${version}" is not a ChronVer release — run \`deno task release\` first.`,
28 );
29 Deno.exit(1);
30}
31
32const commit = await lastReleaseCommit();
33if (!commit) {
34 console.error(
35 "No commit has set the version yet — commit the release bump first.",
36 );
37 Deno.exit(1);
38}
39
40// Guard: make sure the release bump is actually committed (not just in the
41// working copy), so the tag lands on the right commit.
42const shown = await git(["show", `${commit}:package.json`]);
43let committedVersion = "";
44try {
45 committedVersion = JSON.parse(shown.out).version;
46} catch { /* ignore */ }
47if (committedVersion !== version) {
48 console.error(
49 `The bump to ${version} isn't committed yet (that commit's package.json is ${
50 committedVersion || "?"
51 }). Commit the release, then re-run.`,
52 );
53 Deno.exit(1);
54}
55
56if ((await git(["tag", "--list", version])).out === version) {
57 console.error(`Tag ${version} already exists.`);
58 Deno.exit(1);
59}
60
61const created = await git([
62 "tag",
63 "-a",
64 version,
65 "-m",
66 `release ${version}`,
67 commit,
68]);
69if (created.code !== 0) {
70 console.error(created.err);
71 Deno.exit(1);
72}
73console.log(`Created tag ${version} at ${commit.slice(0, 12)}.`);
74
75if (Deno.args.includes("--push")) {
76 console.log("Pushing tag to origin (may prompt 1Password for SSH auth)...");
77 const pushed = await git(["push", "origin", version]);
78 if (pushed.code !== 0) {
79 console.error(pushed.err);
80 Deno.exit(1);
81 }
82 console.log(pushed.err || pushed.out || "Pushed.");
83 console.log("CI will build and publish the image for this tag.");
84} else {
85 console.log(
86 `Next: \`deno task tag --push\` (or \`git push origin ${version}\`) to trigger CI.`,
87 );
88}