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 @@
1import { execFileSync } from "node:child_process";
2import { cpSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3import { tmpdir } from "node:os";
4import { dirname, join, resolve } from "node:path";
5import { fileURLToPath } from "node:url";
6
7const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
8
9const 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
21function 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
30function 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
40files:
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
47path: T3-Code-9.9.9-smoke.0-arm64.zip
48sha512: arm64zip
49releaseDate: '2026-03-08T10:32:14.587Z'
50`,
51 );
52
53 writeFileSync(
54 x64Path,
55 `version: 9.9.9-smoke.0
56files:
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
63path: T3-Code-9.9.9-smoke.0-x64.zip
64sha512: x64zip
65releaseDate: '2026-03-08T10:36:07.540Z'
66`,
67 );
68
69 return { arm64Path, x64Path };
70}
71
72function assertContains(haystack: string, needle: string, message: string): void {
73 if (!haystack.includes(needle)) {
74 throw new Error(message);
75 }
76}
77
78const tempRoot = mkdtempSync(join(tmpdir(), "t3-release-smoke-"));
79
80try {
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 @@
1import { appendFileSync, readFileSync, writeFileSync } from "node:fs";
2import { resolve } from "node:path";
3import { fileURLToPath } from "node:url";
4
5export 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
12interface UpdateReleasePackageVersionsOptions {
13 readonly rootDir?: string;
14}
15
16interface MutablePackageJson {
17 version?: string;
18 [key: string]: unknown;
19}
20
21export 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
43function 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
91const isMain = process.argv[1] !== undefined && resolve(process.argv[1]) === fileURLToPath(import.meta.url);
92
93if (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}