From b0a79ab2d0c3462ef4729af96984fa2ec9e173da Mon Sep 17 00:00:00 2001 From: vineyardbovines Date: Thu, 3 Sep 2026 10:37:24 -0400 Subject: [PATCH] Refine release model --- docs/release-model.md | 7 +- package.json | 1 - scripts/release/model.mjs | 6 +- scripts/release/model.test.mjs | 119 --------------------------------- 4 files changed, 7 insertions(+), 126 deletions(-) delete mode 100644 scripts/release/model.test.mjs diff --git a/docs/release-model.md b/docs/release-model.md index 5c38384e3b..4b7207733d 100644 --- a/docs/release-model.md +++ b/docs/release-model.md @@ -1,8 +1,9 @@ # Release model -The cactus release workflows use one canonical release document per native -version. This contract is intentionally independent of the existing production -workflows while the new system is being developed and tested. +Each app release gets one document that keeps its version, build information, +and public changelog together in one place. We are building this new release +model alongside the existing production workflows so we can try it safely +before using it for a real release. ## Identity diff --git a/package.json b/package.json index 80d6329f40..45fc1102cc 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,6 @@ "start": "expo start --dev-client", "start:prod": "expo start --dev-client --no-dev --minify", "test": "NODE_ENV=test jest --forceExit --testTimeout=20000 --bail", - "test:release-model": "node --test scripts/release/model.test.mjs", "test-watch": "NODE_ENV=test jest --watchAll", "test-ci": "NODE_ENV=test jest --ci --forceExit --reporters=default --reporters=jest-junit", "test-coverage": "NODE_ENV=test jest --coverage", diff --git a/scripts/release/model.mjs b/scripts/release/model.mjs index 96bf0af599..7ec176da06 100644 --- a/scripts/release/model.mjs +++ b/scripts/release/model.mjs @@ -19,15 +19,15 @@ const FRONTMATTER_KEYS = [ const PUBLIC_CHANGELOG_START = '' const PUBLIC_CHANGELOG_END = '' -export class ReleaseModelError extends Error { +export class ReleaseError extends Error { constructor(message) { super(message) - this.name = 'ReleaseModelError' + this.name = 'ReleaseError' } } function fail(message) { - throw new ReleaseModelError(message) + throw new ReleaseError(message) } export function assertReleaseVersion(version) { diff --git a/scripts/release/model.test.mjs b/scripts/release/model.test.mjs deleted file mode 100644 index 6a83d30f37..0000000000 --- a/scripts/release/model.test.mjs +++ /dev/null @@ -1,119 +0,0 @@ -import assert from 'node:assert/strict' -import test from 'node:test' - -import { - ReleaseModelError, - appendOtaChangelog, - createReleaseDocument, - deriveReleaseIdentity, - extractPublicChangelog, - finalizeReleaseDocument, - parseReleaseDocument, -} from './model.mjs' - -const SHA = '0123456789abcdef0123456789abcdef01234567' - -test('derives every release identifier from one version', () => { - assert.deepEqual(deriveReleaseIdentity('1.131.1'), { - version: '1.131.1', - branch: 'release-1.131.1', - tag: '1.131.1', - filename: 'RELEASE-1.131.1.md', - githubReleaseName: 'Release 1.131.1', - }) -}) - -test('rejects non-strict release versions', () => { - for (const version of [ - 'v1.131.1', - '1.131', - '1.131.1-beta', - ' 1.131.1', - '1.0131.1', - ]) { - assert.throws(() => deriveReleaseIdentity(version), ReleaseModelError) - } -}) - -test('creates and parses a prepared release document', () => { - const document = createReleaseDocument('1.131.1', '- Added something') - const parsed = parseReleaseDocument(document, { - filename: 'RELEASE-1.131.1.md', - }) - - assert.deepEqual(parsed.metadata, {releaseVersion: '1.131.1'}) - assert.equal(parsed.sections.length, 1) - assert.equal(parsed.sections[0].type, 'initial') - assert.equal( - extractPublicChangelog(document), - '## Initial release\n\n- Added something', - ) -}) - -test('finalizes a release using artifact-derived metadata', () => { - const prepared = createReleaseDocument('1.131.1', '- Added something') - const finalized = finalizeReleaseDocument(prepared, { - sourceTag: '1.131.1', - sourceSha: SHA, - iosBuildNumber: 1662, - androidVersionCode: 1110, - }) - const parsed = parseReleaseDocument(finalized, {stage: 'final'}) - - assert.equal(parsed.metadata.sourceSha, SHA) - assert.equal(parsed.metadata.iosBuildNumber, '1662') - assert.equal(parsed.metadata.androidVersionCode, '1110') -}) - -test('requires all operational metadata in the final state', () => { - const prepared = createReleaseDocument('1.131.1', '- Added something') - assert.throws( - () => parseReleaseDocument(prepared, {stage: 'final'}), - /missing 'sourceTag'/, - ) -}) - -test('appends contiguous OTA changelog sections', () => { - let document = createReleaseDocument('1.131.1', '- Initial change') - document = appendOtaChangelog(document, 1, '- First fix') - document = appendOtaChangelog(document, 2, '- Second fix') - - const parsed = parseReleaseDocument(document) - assert.deepEqual( - parsed.sections.map(section => section.sequence), - [null, 1, 2], - ) - assert.match(parsed.publicChangelog, /## OTA 2\n\n- Second fix$/) -}) - -test('rejects skipped OTA sequence numbers', () => { - const document = createReleaseDocument('1.131.1', '- Initial change') - assert.throws(() => appendOtaChangelog(document, 2, '- A fix'), /must be 1/) -}) - -test('rejects filename, metadata, and changelog inconsistencies', () => { - const document = createReleaseDocument('1.131.1', '- Initial change') - assert.throws( - () => parseReleaseDocument(document, {filename: 'RELEASE-1.132.0.md'}), - /Filename must be/, - ) - assert.throws( - () => - parseReleaseDocument(document.replace('releaseVersion:', 'surprise:')), - /Unknown release frontmatter field/, - ) - assert.throws( - () => parseReleaseDocument(document.replace('Initial release', 'OTA 1')), - /must begin with an '## Initial release'/, - ) - assert.throws( - () => - parseReleaseDocument( - document.replace( - '- Initial change', - '- Initial change\n\n## Notes\n\nNope', - ), - ), - /Unsupported public changelog section/, - ) -})