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.
| @@ -11,7 +11,9 @@ They also read addressed native state from the main, child, and adopted windows. | ||
| 11 | 11 | Each installed-app smoke also checks creator teardown and adoption of a |
| 12 | 12 | surviving, unparented grandchild. The PKG case explicitly destroys the retained |
| 13 | 13 | macOS creator after close; DEB and MSI close already releases it. |
| 14 | The release hook generates the next changelog section before that commit, | |
| 14 | The release command registers the workspace and Zig release manifests with | |
| 15 | Bumpx so their versions update and roll back together. The release hook | |
| 16 | generates the next changelog section before that commit, | |
| 15 | 17 | deduplicates repeated issue references, and links the previous and new tags. |
| 16 | 18 | Do not run the hook again after it has written the section. |
| 17 | 19 | |
| @@ -61,8 +61,8 @@ | ||
| 61 | 61 | "changelog:generate": "bun scripts/generate-release-changelog.ts", |
| 62 | 62 | "test:release": "bun test ./scripts/changelog-preview.test.ts ./scripts/release-workflow.test.ts ./scripts/release-manifest.test.ts ./scripts/verify-sbom.test.ts", |
| 63 | 63 | "release": "bun scripts/release-version.ts --preflight && bun x --bun @stacksjs/bumpx prompt --recursive", |
| 64 | "release:patch": "bun scripts/release-version.ts --preflight && bun x --bun @stacksjs/bumpx patch --recursive --commit --tag --push --yes --no-changelog --execute \"bun scripts/sync-release-version.ts && bun scripts/generate-release-changelog.ts && git add packages/zig/build.zig.zon packages/zig/pantry.json CHANGELOG.md\"", | |
| 65 | "release:version": "bun scripts/release-version.ts --preflight && bun x --bun @stacksjs/bumpx --recursive --commit --tag --push --yes --no-changelog --execute \"bun scripts/sync-release-version.ts && bun scripts/generate-release-changelog.ts && git add packages/zig/build.zig.zon packages/zig/pantry.json CHANGELOG.md\"" | |
| 64 | "release:patch": "bun scripts/release-version.ts --preflight && bun x --bun @stacksjs/bumpx patch --recursive --files package.json,packages/zig/build.zig.zon,packages/zig/pantry.json --commit --tag --push --yes --no-changelog --execute \"bun scripts/generate-release-changelog.ts && git add CHANGELOG.md\"", | |
| 65 | "release:version": "bun scripts/release-version.ts --preflight && bun x --bun @stacksjs/bumpx --recursive --files package.json,packages/zig/build.zig.zon,packages/zig/pantry.json --commit --tag --push --yes --no-changelog --execute \"bun scripts/generate-release-changelog.ts && git add CHANGELOG.md\"" | |
| 66 | 66 | }, |
| 67 | 67 | "devDependencies": { |
| 68 | 68 | "@stacksjs/buddy": "0.72.56", |
| @@ -1,5 +1,5 @@ | ||
| 1 | 1 | import { afterAll, expect, test } from 'bun:test' |
| 2 | import { readFileSync, rmSync, writeFileSync } from 'node:fs' | |
| 2 | import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs' | |
| 3 | 3 | import { join } from 'node:path' |
| 4 | 4 | import { dedupeChangelogReferences, previewChangelog } from './changelog-preview' |
| 5 | 5 | import { generateReleaseChangelog } from './generate-release-changelog' |
| @@ -9,6 +9,7 @@ import { createTempDir, removeAllTempDirs } from '../packages/typescript/src/tem | ||
| 9 | 9 | afterAll(removeAllTempDirs) |
| 10 | 10 | |
| 11 | 11 | const cli = join(import.meta.dir, 'changelog-preview.ts') |
| 12 | const shellQuote = (value: string): string => `'${value.replaceAll("'", "'\\''")}'` | |
| 12 | 13 | function fixture(run: (directory: string, git: (...args: string[]) => string) => void) { |
| 13 | 14 | const directory = createTempDir('craft-changelog-fixture-') |
| 14 | 15 | const git = (...args: string[]) => { |
| @@ -127,17 +128,22 @@ test('patch release uses the guarded changelog generator before committing', () | ||
| 127 | 128 | expect(project.scripts['changelog:generate']).toBe('bun scripts/generate-release-changelog.ts') |
| 128 | 129 | expect(command).toContain('--no-changelog') |
| 129 | 130 | expect(command).toContain('bun scripts/generate-release-changelog.ts') |
| 130 | expect(command).toContain('git add packages/zig/build.zig.zon packages/zig/pantry.json CHANGELOG.md') | |
| 131 | expect(command).toContain('--files package.json,packages/zig/build.zig.zon,packages/zig/pantry.json') | |
| 131 | 132 | }) |
| 132 | 133 | |
| 133 | 134 | test('an explicit version commits and tags the guarded changelog without its duplicate generator', () => { |
| 134 | 135 | fixture((directory, git) => { |
| 136 | mkdirSync(join(directory, 'packages/zig'), { recursive: true }) | |
| 137 | writeFileSync(join(directory, 'packages/zig/build.zig.zon'), '.{ .version = "1.0.1", }') | |
| 138 | writeFileSync(join(directory, 'packages/zig/pantry.json'), '{"version":"1.0.1"}') | |
| 139 | git('add', 'packages') | |
| 140 | git('commit', '-qm', 'chore: register native release metadata') | |
| 135 | 141 | git('commit', '--allow-empty', '-qm', 'Merge pull request #326 from example/feature') |
| 136 | 142 | const bumpx = Bun.resolveSync('@stacksjs/bumpx/bin/cli.js', import.meta.dir) |
| 137 | 143 | const generator = join(import.meta.dir, 'generate-release-changelog.ts') |
| 138 | 144 | const result = Bun.spawnSync([ |
| 139 | process.execPath, bumpx, '--recursive', '--commit', '--tag', '--no-push', '--yes', '--no-changelog', | |
| 140 | '--execute', `bun ${JSON.stringify(generator)} && git add CHANGELOG.md`, | |
| 145 | process.execPath, bumpx, '--recursive', '--files', 'package.json,packages/zig/build.zig.zon,packages/zig/pantry.json', '--commit', '--tag', '--no-push', '--yes', '--no-changelog', | |
| 146 | '--execute', `${shellQuote(process.execPath)} ${shellQuote(generator)} && git add CHANGELOG.md`, | |
| 141 | 147 | '1.0.2', |
| 142 | 148 | ], { cwd: directory, stdout: 'pipe', stderr: 'pipe', timeout: 30_000 }) |
| 143 | 149 | expect(result.exitCode, result.stderr.toString()).toBe(0) |
| @@ -145,6 +151,31 @@ test('an explicit version commits and tags the guarded changelog without its dup | ||
| 145 | 151 | const notes = git('show', 'HEAD:CHANGELOG.md') |
| 146 | 152 | expect(notes).toContain('[Compare changes](https://github.com/example/fixture/compare/v1.0.0...v1.0.2)') |
| 147 | 153 | expect(notes.match(/\[#326\]\(https:\/\/github\.com\/example\/fixture\/issues\/326\)/g)).toHaveLength(1) |
| 154 | expect(JSON.parse(git('show', 'HEAD:packages/zig/pantry.json')).version).toBe('1.0.2') | |
| 155 | expect(git('show', 'HEAD:packages/zig/build.zig.zon')).toContain('"1.0.2"') | |
| 156 | expect(git('status', '--porcelain')).toBe('') | |
| 157 | }) | |
| 158 | }) | |
| 159 | ||
| 160 | test('the published release tool restores workspace and native versions when a required command fails', () => { | |
| 161 | fixture((directory, git) => { | |
| 162 | mkdirSync(join(directory, 'packages/zig'), { recursive: true }) | |
| 163 | writeFileSync(join(directory, 'packages/zig/build.zig.zon'), '.{ .version = "1.0.1", }') | |
| 164 | writeFileSync(join(directory, 'packages/zig/pantry.json'), '{"version":"1.0.1"}') | |
| 165 | git('add', 'packages') | |
| 166 | git('commit', '-qm', 'chore: register native release metadata') | |
| 167 | const head = git('rev-parse', 'HEAD') | |
| 168 | const paths = ['package.json', 'packages/zig/build.zig.zon', 'packages/zig/pantry.json'] | |
| 169 | const before = paths.map(path => readFileSync(join(directory, path), 'utf8')) | |
| 170 | const bumpx = Bun.resolveSync('@stacksjs/bumpx/bin/cli.js', import.meta.dir) | |
| 171 | const result = Bun.spawnSync([ | |
| 172 | process.execPath, bumpx, 'patch', '--recursive', '--files', paths.join(','), '--commit', '--tag', '--no-push', '--yes', '--no-changelog', | |
| 173 | '--execute', 'bun -e "process.exit(23)"', | |
| 174 | ], { cwd: directory, stdout: 'pipe', stderr: 'pipe', timeout: 30_000 }) | |
| 175 | expect(result.exitCode).not.toBe(0) | |
| 176 | expect(paths.map(path => readFileSync(join(directory, path), 'utf8'))).toEqual(before) | |
| 177 | expect(git('rev-parse', 'HEAD')).toBe(head) | |
| 178 | expect(git('tag', '--list', 'v1.0.2')).toBe('') | |
| 148 | 179 | expect(git('status', '--porcelain')).toBe('') |
| 149 | 180 | }) |
| 150 | 181 | }) |