diff --git a/scripts/release/bump.ts b/scripts/release/bump.ts index e79b7a0e9c..885efb0de4 100644 --- a/scripts/release/bump.ts +++ b/scripts/release/bump.ts @@ -5,9 +5,10 @@ * * The dsh family shares one version across its members and the workspace root: * `major`, `minor`, `patch`, or an explicit `x.y.z` (including a prerelease such - * as `0.0.1-rc.1`). The vendored family has one version line per package and - * publishes only what changed since that package's own `vendor--v*` - * tag, which is the record of the commit it last published from. + * as `0.0.1-rc.1`). The vendored family has one version line per package, but + * every release advances and publishes the complete family so the next release + * never reuses an unchanged member's existing version from a different + * repository state. * * The version lands in the manifests, the lockfile follows, and a human creates * the tag after the commit merges. CI never writes to the repository. @@ -17,7 +18,7 @@ import { readFileSync, writeFileSync } from 'node:fs' import { join, matchesGlob } from 'node:path' import { parseArgs } from 'node:util' import { releaseFamily, type ReleaseFamily, type ReleaseMember } from './families.ts' -import { attempt, capture, isEntry } from './process.ts' +import { capture, isEntry } from './process.ts' /** Files npm publishes whether or not `files` lists them. */ const ALWAYS_PUBLISHED = ['package.json', 'README*', 'LICENSE*', 'LICENCE*'] as const @@ -144,30 +145,33 @@ function nextSharedVersion(current: string, request: string): string { /** * The version a vendored package publishes next. * - * The baseline is the higher of the manifest version and the last published + * The baseline is the higher of the manifest version and the last tagged * version: a vendor re-sync restores upstream's version, which is lower than - * what this repository already published, and incrementing that would name a - * version the registry already carries. + * the release version this repository already reserved, and incrementing that + * would reuse an existing version. * * A prerelease does not consume its own release numbers. Publishing * `4.0.1-rc.1` leaves `4.0.1` free, so the next stable version is `4.0.1` * rather than `4.0.2`, and a second prerelease keeps those numbers too. * @param current - the package's manifest version. - * @param published - the version its newest tag names, when it has one. + * @param tagged - the version its newest tag names, when it has one. * @param prerelease - prerelease identifier to append, for a rehearsal publication. * @returns The target version. */ export function nextVendorVersion( current: string, - published: string | undefined, + tagged: string | undefined, prerelease?: string, ): string { - const ahead = published !== undefined && compareReleaseNumbers(published, current) > 0 - const baseline = ahead ? published : current + const taggedOrder = tagged === undefined ? undefined : compareReleaseNumbers(tagged, current) + const ahead = taggedOrder !== undefined && taggedOrder > 0 + const baseline = ahead ? tagged : current const [major, minor, patch] = releaseNumbers(baseline) - // Reuse the numbers when the published version that set them is a prerelease + // Reuse the numbers when the tagged version that set them is a prerelease // of them; increment when a stable release already holds them. - const reuse = ahead && published.includes('-') + const taggedPrerelease = tagged !== undefined && prereleaseOf(tagged) !== undefined + const sameReleasePrereleases = taggedOrder === 0 && prereleaseOf(current) !== undefined + const reuse = taggedPrerelease && (ahead || sameReleasePrereleases) const numbers = reuse ? `${String(major)}.${String(minor)}.${String(patch)}` : `${String(major)}.${String(minor)}.${String(patch + 1)}` @@ -191,12 +195,12 @@ export function reachesPayload(member: ReleaseMember, path: string): boolean { } /** - * The newest version a member published, read from its tags. + * The newest version a member tagged. * @param family - the member's family. * @param member - the member. - * @returns The version, or undefined when the member never published. + * @returns The version, or undefined when the member has no release tag. */ -function lastPublishedVersion(family: ReleaseFamily, member: ReleaseMember): string | undefined { +function lastTaggedVersion(family: ReleaseFamily, member: ReleaseMember): string | undefined { const prefix = family.tagPrefixFor(member) const versions = capture('git', ['tag', '--list', `${prefix}*`]) .split('\n').filter(line => line !== '').map(tag => tag.slice(prefix.length)) @@ -204,33 +208,6 @@ function lastPublishedVersion(family: ReleaseFamily, member: ReleaseMember): str return versions.reduce((newest, candidate) => compareVersions(candidate, newest) > 0 ? candidate : newest) } -/** - * Confirm the registry carries the version a tag names. - * - * A tag is a commit pointer, not proof of publication: a tag pushed for a - * publication that then failed would otherwise read as "already published" and - * skip the package indefinitely. Querying a private package needs credentials, - * so an unauthenticated machine reports the gap instead of failing. - * @param name - package name. - * @param version - the version the tag names. - */ -function confirmPublished(name: string, version: string): void { - const result = attempt('npm', ['view', `${name}@${version}`, 'version']) - if (result.status === 0) return - const output = `${result.stdout}${result.stderr}` - if (output.includes('ENEEDAUTH') || output.includes('E401') || output.includes('E403')) { - console.log(`release bump: cannot reach the registry for ${name}@${version}; skipping the tag check`) - return - } - if (output.includes('E404') || output.includes('404 Not Found')) { - throw new Error( - `${name}@${version} is tagged but absent from the registry.` - + '\nThe tag was pushed for a publication that did not complete: re-run that publish, or delete the tag.', - ) - } - throw new Error(`npm view ${name}@${version} failed:\n${output}`) -} - /** * Write a version into a manifest, preserving formatting and key order. * @param root - repository root. @@ -293,8 +270,8 @@ function planShared( } /** - * Plan the vendored family's rewrite: every package whose payload changed since - * it last published. + * Plan the vendored family's rewrite: every package advances together while + * retaining its own version line and tag. * @param family - the vendored family. * @param members - the family's members. * @param prerelease - prerelease identifier to append, for a rehearsal publication. @@ -307,15 +284,8 @@ function planPerPackage( ): PlannedVersion[] { const planned: PlannedVersion[] = [] for (const member of members) { - const published = lastPublishedVersion(family, member) - if (published !== undefined) { - confirmPublished(member.name, published) - const since = `${family.tagPrefixFor(member)}${published}` - const changed = capture('git', ['diff', '--name-only', `${since}..HEAD`, '--', member.directory]) - .split('\n').filter(line => line !== '') - if (!changed.some(path => reachesPayload(member, path))) continue - } - const to = nextVendorVersion(member.version, published, prerelease) + const tagged = lastTaggedVersion(family, member) + const to = nextVendorVersion(member.version, tagged, prerelease) planned.push({ manifestPath: join(member.directory, 'package.json'), label: member.directory, diff --git a/vendor/cordis/package.json b/vendor/cordis/package.json index 66a5f1593d..b3ed7f0b78 100644 --- a/vendor/cordis/package.json +++ b/vendor/cordis/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/cordis", "description": "Meta-Framework for Modern JavaScript Applications", - "version": "4.0.1-rc.1", + "version": "4.0.1-rc.3", "publishConfig": { "access": "restricted" }, diff --git a/vendor/cosmokit/package.json b/vendor/cosmokit/package.json index 0016ec0bb4..eb5befa72c 100644 --- a/vendor/cosmokit/package.json +++ b/vendor/cosmokit/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/cosmokit", "description": "A collection of common utilities", - "version": "1.8.2-rc.1", + "version": "1.8.2-rc.3", "publishConfig": { "access": "restricted" }, diff --git a/vendor/group/package.json b/vendor/group/package.json index 03baae1394..08aa357572 100644 --- a/vendor/group/package.json +++ b/vendor/group/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/cordis-plugin-group", "description": "Nested plugin group for cordis", - "version": "1.0.1-rc.1", + "version": "1.0.1-rc.3", "publishConfig": { "access": "restricted" }, diff --git a/vendor/hmr/package.json b/vendor/hmr/package.json index e231701881..9b80498bb9 100644 --- a/vendor/hmr/package.json +++ b/vendor/hmr/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/cordis-plugin-hmr", "description": "Hot Module Replacement Plugin for Cordis", - "version": "1.0.16-rc.1", + "version": "1.0.16-rc.3", "publishConfig": { "access": "restricted" }, diff --git a/vendor/include/package.json b/vendor/include/package.json index 8df8cf2122..b0b80d8e87 100644 --- a/vendor/include/package.json +++ b/vendor/include/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/cordis-plugin-include", "description": "Include files in cordis configurations", - "version": "1.0.6-rc.2", + "version": "1.0.6-rc.3", "publishConfig": { "access": "restricted" }, diff --git a/vendor/loader/package.json b/vendor/loader/package.json index 55d884625d..8bb71e4329 100644 --- a/vendor/loader/package.json +++ b/vendor/loader/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/cordis-plugin-loader", "description": "Plugin loader for cordis", - "version": "1.0.2-rc.2", + "version": "1.0.2-rc.3", "publishConfig": { "access": "restricted" }, diff --git a/vendor/logger-console/package.json b/vendor/logger-console/package.json index ceb1c0bd75..0b96a53640 100644 --- a/vendor/logger-console/package.json +++ b/vendor/logger-console/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/cordis-plugin-logger-console", "description": "Console logger exporter for cordis", - "version": "1.0.1-rc.1", + "version": "1.0.1-rc.3", "publishConfig": { "access": "restricted" }, diff --git a/vendor/schemastery/package.json b/vendor/schemastery/package.json index 76f3748a5b..07cfea20b1 100644 --- a/vendor/schemastery/package.json +++ b/vendor/schemastery/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/schemastery", "description": "Type driven schema validator", - "version": "3.18.1-rc.1", + "version": "3.18.1-rc.3", "publishConfig": { "access": "restricted" }, diff --git a/vendor/timer/package.json b/vendor/timer/package.json index 211dba0036..cdfc6f89d6 100644 --- a/vendor/timer/package.json +++ b/vendor/timer/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/cordis-plugin-timer", "description": "Timer service for cordis", - "version": "1.1.3-rc.1", + "version": "1.1.3-rc.3", "publishConfig": { "access": "restricted" },