History

Fix release finalize lockfile refresh (#608)

* Add checkout and Node setup to release updater publish job - Ensure the updater publish job checks out the target ref - Initialize Node using the repository's package.json version file before downloading artifacts * Fix release finalize lockfile refresh

Theo Browne committed 8 months agov0.0.8

Commit 9b9006f1 parent 42234b85 files · +247 −28Browse files

Showing the changes to scripts (2 of 5 files). Show all

Unified · Split

2 files
  1. scripts/release-smoke.ts +113 −0
  2. scripts/update-release-package-versions.ts +111 −0
scripts/release-smoke.ts+113−0
@@ -0,0 +1,113 @@
1+import { execFileSync } from "node:child_process";
2+import { cpSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3+import { tmpdir } from "node:os";
4+import { dirname, join, resolve } from "node:path";
5+import { fileURLToPath } from "node:url";
6+
7+const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
8+
9+const workspaceFiles = [
10+ "package.json",
11+ "bun.lock",
12+ "apps/server/package.json",
13+ "apps/desktop/package.json",
14+ "apps/web/package.json",
15+ "apps/marketing/package.json",
16+ "packages/contracts/package.json",
17+ "packages/shared/package.json",
18+ "scripts/package.json",
19+] as const;
20+
21+function copyWorkspaceManifestFixture(targetRoot: string): void {
22+ for (const relativePath of workspaceFiles) {
23+ const sourcePath = resolve(repoRoot, relativePath);
24+ const destinationPath = resolve(targetRoot, relativePath);
25+ mkdirSync(dirname(destinationPath), { recursive: true });
26+ cpSync(sourcePath, destinationPath);
27+ }
28+}
29+
30+function writeMacManifestFixtures(targetRoot: string): { arm64Path: string; x64Path: string } {
31+ const assetDirectory = resolve(targetRoot, "release-assets");
32+ mkdirSync(assetDirectory, { recursive: true });
33+
34+ const arm64Path = resolve(assetDirectory, "latest-mac.yml");
35+ const x64Path = resolve(assetDirectory, "latest-mac-x64.yml");
36+
37+ writeFileSync(
38+ arm64Path,
39+ `version: 9.9.9-smoke.0
40+files:
41+ - url: T3-Code-9.9.9-smoke.0-arm64.zip
42+ sha512: arm64zip
43+ size: 125621344
44+ - url: T3-Code-9.9.9-smoke.0-arm64.dmg
45+ sha512: arm64dmg
46+ size: 131754935
47+path: T3-Code-9.9.9-smoke.0-arm64.zip
48+sha512: arm64zip
49+releaseDate: '2026-03-08T10:32:14.587Z'
50+`,
51+ );
52+
53+ writeFileSync(
54+ x64Path,
55+ `version: 9.9.9-smoke.0
56+files:
57+ - url: T3-Code-9.9.9-smoke.0-x64.zip
58+ sha512: x64zip
59+ size: 132000112
60+ - url: T3-Code-9.9.9-smoke.0-x64.dmg
61+ sha512: x64dmg
62+ size: 138148807
63+path: T3-Code-9.9.9-smoke.0-x64.zip
64+sha512: x64zip
65+releaseDate: '2026-03-08T10:36:07.540Z'
66+`,
67+ );
68+
69+ return { arm64Path, x64Path };
70+}
71+
72+function assertContains(haystack: string, needle: string, message: string): void {
73+ if (!haystack.includes(needle)) {
74+ throw new Error(message);
75+ }
76+}
77+
78+const tempRoot = mkdtempSync(join(tmpdir(), "t3-release-smoke-"));
79+
80+try {
81+ copyWorkspaceManifestFixture(tempRoot);
82+
83+ execFileSync(
84+ process.execPath,
85+ [resolve(repoRoot, "scripts/update-release-package-versions.ts"), "9.9.9-smoke.0", "--root", tempRoot],
86+ {
87+ cwd: repoRoot,
88+ stdio: "inherit",
89+ },
90+ );
91+
92+ execFileSync("bun", ["install", "--lockfile-only", "--ignore-scripts"], {
93+ cwd: tempRoot,
94+ stdio: "inherit",
95+ });
96+
97+ const lockfile = readFileSync(resolve(tempRoot, "bun.lock"), "utf8");
98+ assertContains(lockfile, `"version": "9.9.9-smoke.0"`, "Expected bun.lock to contain the smoke version.");
99+
100+ const { arm64Path, x64Path } = writeMacManifestFixtures(tempRoot);
101+ execFileSync(process.execPath, [resolve(repoRoot, "scripts/merge-mac-update-manifests.ts"), arm64Path, x64Path], {
102+ cwd: repoRoot,
103+ stdio: "inherit",
104+ });
105+
106+ const mergedManifest = readFileSync(arm64Path, "utf8");
107+ assertContains(mergedManifest, "T3-Code-9.9.9-smoke.0-arm64.zip", "Merged manifest is missing the arm64 asset.");
108+ assertContains(mergedManifest, "T3-Code-9.9.9-smoke.0-x64.zip", "Merged manifest is missing the x64 asset.");
109+
110+ console.log("Release smoke checks passed.");
111+} finally {
112+ rmSync(tempRoot, { recursive: true, force: true });
113+}
scripts/update-release-package-versions.ts+111−0
@@ -0,0 +1,111 @@
1+import { appendFileSync, readFileSync, writeFileSync } from "node:fs";
2+import { resolve } from "node:path";
3+import { fileURLToPath } from "node:url";
4+
5+export const releasePackageFiles = [
6+ "apps/server/package.json",
7+ "apps/desktop/package.json",
8+ "apps/web/package.json",
9+ "packages/contracts/package.json",
10+] as const;
11+
12+interface UpdateReleasePackageVersionsOptions {
13+ readonly rootDir?: string;
14+}
15+
16+interface MutablePackageJson {
17+ version?: string;
18+ [key: string]: unknown;
19+}
20+
21+export function updateReleasePackageVersions(
22+ version: string,
23+ options: UpdateReleasePackageVersionsOptions = {},
24+): { changed: boolean } {
25+ const rootDir = resolve(options.rootDir ?? process.cwd());
26+ let changed = false;
27+
28+ for (const relativePath of releasePackageFiles) {
29+ const filePath = resolve(rootDir, relativePath);
30+ const packageJson = JSON.parse(readFileSync(filePath, "utf8")) as MutablePackageJson;
31+ if (packageJson.version === version) {
32+ continue;
33+ }
34+
35+ packageJson.version = version;
36+ writeFileSync(filePath, `${JSON.stringify(packageJson, null, 2)}\n`);
37+ changed = true;
38+ }
39+
40+ return { changed };
41+}
42+
43+function parseArgs(argv: ReadonlyArray<string>): {
44+ version: string;
45+ rootDir: string | undefined;
46+ writeGithubOutput: boolean;
47+} {
48+ let version: string | undefined;
49+ let rootDir: string | undefined;
50+ let writeGithubOutput = false;
51+
52+ for (let index = 0; index < argv.length; index += 1) {
53+ const argument = argv[index];
54+ if (argument === undefined) {
55+ continue;
56+ }
57+
58+ if (argument === "--github-output") {
59+ writeGithubOutput = true;
60+ continue;
61+ }
62+
63+ if (argument === "--root") {
64+ rootDir = argv[index + 1];
65+ if (!rootDir) {
66+ throw new Error("Missing value for --root.");
67+ }
68+ index += 1;
69+ continue;
70+ }
71+
72+ if (argument.startsWith("--")) {
73+ throw new Error(`Unknown argument: ${argument}`);
74+ }
75+
76+ if (version !== undefined) {
77+ throw new Error("Only one release version can be provided.");
78+ }
79+ version = argument;
80+ }
81+
82+ if (!version) {
83+ throw new Error(
84+ "Usage: node scripts/update-release-package-versions.ts <version> [--root <path>] [--github-output]",
85+ );
86+ }
87+
88+ return { version, rootDir, writeGithubOutput };
89+}
90+
91+const isMain = process.argv[1] !== undefined && resolve(process.argv[1]) === fileURLToPath(import.meta.url);
92+
93+if (isMain) {
94+ const { version, rootDir, writeGithubOutput } = parseArgs(process.argv.slice(2));
95+ const { changed } = updateReleasePackageVersions(
96+ version,
97+ rootDir === undefined ? {} : { rootDir },
98+ );
99+
100+ if (!changed) {
101+ console.log("All package.json versions already match release version.");
102+ }
103+
104+ if (writeGithubOutput) {
105+ const githubOutputPath = process.env.GITHUB_OUTPUT;
106+ if (!githubOutputPath) {
107+ throw new Error("GITHUB_OUTPUT is required when --github-output is set.");
108+ }
109+ appendFileSync(githubOutputPath, `changed=${changed}\n`);
110+ }
111+}