Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions scripts/check-version-coherence.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -225,10 +225,14 @@ function gitLines(args) {
// exists — is skipped by the same rule that catches a merged one.
const branch =
process.env.GITHUB_REF_NAME ?? (gitLines(['rev-parse', '--abbrev-ref', 'HEAD']) ?? [null])[0];
// Set only by `finish-release.mjs` around its own internal `qa:pre-release`
// spawn — the one caller genuinely seconds from creating this exact tag, not
// CI, not a PR check, not a plain manual run. See published-version.mjs.
const publishedTag = checkMainDeclaresPublishedVersion({
branch,
pkgVersion,
tags: gitLines(['tag', '--list', 'v*']) ?? [],
aboutToTagThisVersion: process.env.MEMESH_FINISH_RELEASE_TAGGING === '1',
});
findings.push(`main-declares-published-version: ${publishedTag.status} — ${publishedTag.message}`);
if (publishedTag.status === 'error') {
Expand Down
7 changes: 7 additions & 0 deletions scripts/finish-release.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,17 @@ const repoSlug = capture('gh', ['repo', 'view', '--json', 'nameWithOwner', '-q',
// — a receipt can go stale the moment the next commit lands, and re-running a
// few minutes of build+test is cheaper than trusting a stale one.
console.log(`\n--- npm run qa:pre-release (build + verify:artifact + audit:memory; several minutes)`);
// MEMESH_FINISH_RELEASE_TAGGING=1 tells check-version-coherence.mjs's
// main-declares-published-version check that THIS run is the one about to
// create v<pkgVersion> seconds from now — the one caller for whom "main
// declares a version with no tag yet" is expected, not the five-day gap the
// check exists to catch. Set only here, at this one spawn; unset for CI, PR
// checks, and every other way qa:pre-release runs. See published-version.mjs.
const qaPreReleaseResult = spawnSync('npm', ['run', 'qa:pre-release'], {
cwd: repoRoot,
stdio: 'inherit',
shell: process.platform === 'win32',
env: { ...process.env, MEMESH_FINISH_RELEASE_TAGGING: '1' },
});
const qaPreReleaseStatus = qaPreReleaseResult.status;

Expand Down
27 changes: 26 additions & 1 deletion scripts/lib/published-version.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,28 @@
// nobody break-tested is the defect class this repository keeps finding.

/**
* `finish-release.mjs` runs `npm run qa:pre-release` as its own precondition,
* and that spawns this exact check, on `main`, before the tag it is about to
* create exists — the one moment this check cannot help but call an error.
* `aboutToTagThisVersion` is how the caller who is actually about to create
* `v<pkgVersion>` says so. It narrows to exactly the branch that condition
* can affect: tags ARE visible and simply do not include this one yet. It
* does nothing to the "no tags visible at all" branch above — a shallow
* checkout with no tag data is still a real failure, about-to-tag or not —
* and it does nothing to any of `check-version-coherence.mjs`'s other nine
* anchors, which this function never sees.
*
* @param {object} input
* @param {string|null} input.branch Current branch, or null if undiscoverable.
* @param {string} input.pkgVersion `package.json` version.
* @param {string[]} input.tags Every `v*` tag visible to the checkout.
* @param {boolean} [input.aboutToTagThisVersion] Set only by the caller that is
* itself seconds away from creating `v<pkgVersion>` (`finish-release.mjs`,
* via `MEMESH_FINISH_RELEASE_TAGGING=1`) — never by CI, a PR check, or a
* plain manual run.
* @returns {{status: 'ok'|'skipped'|'error', message: string}}
*/
export function checkMainDeclaresPublishedVersion({ branch, pkgVersion, tags }) {
export function checkMainDeclaresPublishedVersion({ branch, pkgVersion, tags, aboutToTagThisVersion = false }) {
if (branch !== 'main') {
return {
status: 'skipped',
Expand Down Expand Up @@ -59,6 +74,16 @@ export function checkMainDeclaresPublishedVersion({ branch, pkgVersion, tags })
return { status: 'ok', message: `v${pkgVersion} is tagged` };
}

if (aboutToTagThisVersion) {
return {
status: 'skipped',
message:
`main declares ${pkgVersion} with no \`v${pkgVersion}\` tag yet, but the ` +
'caller running this check is finish-release.mjs itself, seconds from ' +
'creating that exact tag — not a stale bump.',
};
}

return {
status: 'error',
message:
Expand Down
45 changes: 45 additions & 0 deletions tests/main-declares-published-version.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,49 @@ describe('main must declare a published version', () => {
});
expect(r.status).toBe('skipped');
});

/**
* `finish-release.mjs` runs `qa:pre-release` as its own precondition, on
* `main`, before the tag it is about to create exists — the one moment
* this check cannot help but call an error against its own caller.
* `aboutToTagThisVersion` is how that one caller says so.
*/
describe('aboutToTagThisVersion (set only by finish-release.mjs)', () => {
it('skips instead of erroring when other tags are visible but not this one', () => {
const r = checkMainDeclaresPublishedVersion({
branch: 'main',
pkgVersion: '4.2.12',
tags: ['v4.2.10', 'v4.2.11'],
aboutToTagThisVersion: true,
});
expect(r.status).toBe('skipped');
expect(r.message).toContain('4.2.12');
});

it('still passes outright when the tag already exists', () => {
const r = checkMainDeclaresPublishedVersion({
branch: 'main',
pkgVersion: '4.2.11',
tags: ['v4.2.10', 'v4.2.11'],
aboutToTagThisVersion: true,
});
expect(r.status).toBe('ok');
});

// Break-test: a shallow checkout with no tag data at all is still a real
// failure whether or not the caller is about to tag — the flag narrows to
// "this one tag is missing", not "trust me". If this ever went green, the
// flag would also paper over the exact defect `actions/checkout` fetching
// no tags reintroduces.
it('does NOT rescue a checkout where no tags are visible at all', () => {
const r = checkMainDeclaresPublishedVersion({
branch: 'main',
pkgVersion: '4.2.11',
tags: [],
aboutToTagThisVersion: true,
});
expect(r.status).toBe('error');
expect(r.message).toContain('fetch-tags');
});
});
});
Loading