also looking at this
fix: validate native SDK release prerequisites before tagging
#364
7 files
+153
-15
Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.
| @@ -1,5 +1,5 @@ | ||
| 1 | 1 | import { afterAll, expect, test } from 'bun:test' |
| 2 | import { mkdirSync, rmSync, writeFileSync } from 'node:fs' | |
| 2 | import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs' | |
| 3 | 3 | import { join } from 'node:path' |
| 4 | 4 | import { validateReleaseCheckout, checkReleaseVersion, validateReleaseVersion } from './release-version' |
| 5 | 5 | import { createTempDir, removeAllTempDirs } from '../packages/typescript/src/temp-dir' |
| @@ -60,3 +60,17 @@ test('refuses an incomplete sparse release checkout before a version bump', () = | ||
| 60 | 60 | rmSync(manifest) |
| 61 | 61 | expect(() => validateReleaseCheckout(root)).toThrow('packages/react/package.json') |
| 62 | 62 | }) |
| 63 | ||
| 64 | test('release preflight rejects missing tools before changing package versions or tags', () => { | |
| 65 | const root = createTempDir('craft-release-prerequisites-') | |
| 66 | mkdirSync(join(root, 'scripts')) | |
| 67 | const manifest = '{"version":"1.2.3"}\n' | |
| 68 | writeFileSync(join(root, 'package.json'), manifest) | |
| 69 | writeFileSync(join(root, 'scripts/release-version.ts'), readFileSync(join(import.meta.dir, 'release-version.ts'))) | |
| 70 | expect(Bun.spawnSync(['git', 'init', '-q'], { cwd: root }).exitCode).toBe(0) | |
| 71 | const result = Bun.spawnSync([process.execPath, 'scripts/release-version.ts', '--preflight'], { cwd: root, stdout: 'pipe', stderr: 'pipe' }) | |
| 72 | expect(result.exitCode).not.toBe(0) | |
| 73 | expect(result.stderr.toString()).toContain('bun install --frozen-lockfile') | |
| 74 | expect(readFileSync(join(root, 'package.json'), 'utf8')).toBe(manifest) | |
| 75 | expect(Bun.spawnSync(['git', 'tag', '--list'], { cwd: root, stdout: 'pipe' }).stdout.toString()).toBe('') | |
| 76 | }) | |
| @@ -10,6 +10,16 @@ export function validateReleaseCheckout(root: string): void { | ||
| 10 | 10 | throw new Error(`Release checkout omits package manifests: ${missing.join(', ')}. Expand the sparse checkout before releasing.`) |
| 11 | 11 | } |
| 12 | 12 | |
| 13 | /** Refuse missing release tools before a version or immutable tag can change. */ | |
| 14 | export function validateReleaseDependencies(root: string): void { | |
| 15 | for (const cli of ['@stacksjs/bumpx/bin/cli.js', '@stacksjs/logsmith/bin/cli.js']) { | |
| 16 | try { Bun.resolveSync(cli, root) } | |
| 17 | catch (cause) { | |
| 18 | throw new Error(`Cannot resolve release dependency ${cli}. Run bun install --frozen-lockfile before releasing.`, { cause }) | |
| 19 | } | |
| 20 | } | |
| 21 | } | |
| 22 | ||
| 13 | 23 | export function validateReleaseVersion(ref: string, version: string, manifests: Record<string, unknown>): void { |
| 14 | 24 | const errors: string[] = [] |
| 15 | 25 | const identifier = '(?:0|[1-9]\\d*|[\\da-z-]*[a-z-][\\da-z-]*)' |
| @@ -47,6 +57,7 @@ if (import.meta.main) { | ||
| 47 | 57 | const root = resolve(import.meta.dir, '..') |
| 48 | 58 | if (process.argv.includes('--preflight')) { |
| 49 | 59 | validateReleaseCheckout(root) |
| 60 | validateReleaseDependencies(root) | |
| 50 | 61 | console.log('Release checkout contains every tracked package manifest') |
| 51 | 62 | process.exit(0) |
| 52 | 63 | } |