* 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
Showing the changes to scripts (2 of 5 files). Show all
Unified · Split
| @@ -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 | +} | |
| @@ -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 | +} | |