release candidates: every push to main runs the full CI, the acceptance matrix and the Linux / Windows installer builds in parallel (ci.yml) and records the green result per commit as the draft rc-<sha> (green.json last); a version-only bump commit (proven file by file with the version writers) reuses its parent's CI and matrix and rebuilds only the installers; a v* tag only promotes the candidate (release.yml), fails fast on a red or missing commit; acceptance runs carry a CLI key; tools/release.ts does the whole release on the Mac (bump, CHANGELOG cut, fast gate, push, tag, Mac build + notarize in parallel with Forgejo, cached macOS acceptance, add, verify, publish with one upload of the Mac files, /Applications update, npm commands) and --rehearsal; DMG notarization runs while the app and updater bundle are checked; rehearsal channel on the VDS; docs
This commit is contained in:
parent
89d94d6993
commit
c3b1e8c370
14 changed files with 1438 additions and 526 deletions
48
tools/cli-key.ts
Normal file
48
tools/cli-key.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/env bun
|
||||
// The CLI key: one hash of everything that decides how the packed npm CLI behaves in the acceptance matrix
|
||||
// (tools/acceptance.ts), with the version copies normalized. Two commits with the same key run the same CLI code; a
|
||||
// version bump (tools/desktop-version.ts --set) does not change it. Acceptance results carry the key, so the results
|
||||
// of a commit count for a version-only child (tools/release-candidate.ts) and the Mac reuses its cached macOS results
|
||||
// (tools/release.ts) until the CLI code really changes.
|
||||
// bun tools/cli-key.ts print the key of the working tree (tracked files only)
|
||||
// In the key: the npm package's files (package.json "files") without the prose that ships with it (CHANGELOG.md,
|
||||
// README.md, docs/*.md: the CLI never reads storebound's own docs), package.json, bun.lock and what the acceptance
|
||||
// run itself uses (tools/acceptance.ts, tools/build-node.ts, tests/helpers, tests/build-fixtures.ts, tests/fixtures).
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { createHash } from 'node:crypto';
|
||||
import { existsSync, readFileSync } from 'node:fs';
|
||||
import { join, resolve } from 'node:path';
|
||||
import { COPIES } from './desktop-version';
|
||||
|
||||
const ROOT = resolve(import.meta.dir, '..');
|
||||
const PROSE = /^(CHANGELOG\.md|README\.md|docs\/[^/]+\.md)$/;
|
||||
const EXTRA = ['package.json', 'bun.lock', 'tools/acceptance.ts', 'tools/build-node.ts', 'tools/cli-key.ts', 'tools/desktop-version.ts', 'tests/helpers', 'tests/build-fixtures.ts', 'tests/fixtures'];
|
||||
const NORMAL = '0.0.0-cli-key';
|
||||
|
||||
/** The paths of the key (git pathspecs). Pure. */
|
||||
export function keyPaths(pkgFiles: string[]): string[] {
|
||||
return [...new Set([...pkgFiles.filter(f => f !== 'dist/storebound.mjs'), ...EXTRA])].sort();
|
||||
}
|
||||
|
||||
/** One file's content in the key: the version copies with the version normalized. Pure. */
|
||||
export function keyContent(file: string, text: Buffer): Buffer {
|
||||
const copy = COPIES.find(c => c.file === file);
|
||||
return copy ? Buffer.from(copy.write(text.toString('utf8'), NORMAL)) : text;
|
||||
}
|
||||
|
||||
/** sha256 over (path, content) of every tracked file of the key, sorted. Pure given the reader. */
|
||||
export function cliKeyOf(files: string[], read: (f: string) => Buffer): string {
|
||||
const h = createHash('sha256');
|
||||
for (const f of [...files].filter(f => !PROSE.test(f)).sort()) { h.update(`${f}\0`); h.update(keyContent(f, read(f))); h.update('\0'); }
|
||||
return h.digest('hex').slice(0, 32);
|
||||
}
|
||||
|
||||
export function cliKey(root = ROOT): string {
|
||||
const pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')) as { files: string[] };
|
||||
const ls = spawnSync('git', ['ls-files', '-z', '--', ...keyPaths(pkg.files)], { cwd: root, encoding: 'utf8', maxBuffer: 64 << 20 });
|
||||
if (ls.status !== 0) throw new Error(`git ls-files: ${ls.stderr}`);
|
||||
const files = ls.stdout.split('\0').filter(f => f && existsSync(join(root, f)));
|
||||
return cliKeyOf(files, f => readFileSync(join(root, f)));
|
||||
}
|
||||
|
||||
if (import.meta.main) console.log(cliKey());
|
||||
Loading…
Add table
Add a link
Reference in a new issue