fimo 0.3.4 → 0.3.5-staging.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/bundle.json
CHANGED
package/package.json
CHANGED
package/release.json
CHANGED
|
@@ -100,15 +100,44 @@ export function stripTemplateLockfile(cliRoot) {
|
|
|
100
100
|
return () => writeFileSync(file, original);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Next per-version prerelease counter: one past the highest already-published
|
|
105
|
+
* `<base>-<distTag>.<n>` on npm. Counting from what's actually published
|
|
106
|
+
* (instead of resetting blindly to 1) keeps the counter collision-proof even
|
|
107
|
+
* when the projected base flaps back to a value that already has prereleases —
|
|
108
|
+
* npm versions are immutable, so a blind reset would make the publish fail.
|
|
109
|
+
*
|
|
110
|
+
* @param {readonly string[]} existingVersions - all published versions of the package
|
|
111
|
+
* @param {string} base - X.Y.Z base (no prerelease suffix)
|
|
112
|
+
* @param {string} distTag
|
|
113
|
+
* @returns {number}
|
|
114
|
+
*/
|
|
115
|
+
export function nextPrereleaseCounter(existingVersions, base, distTag) {
|
|
116
|
+
const prefix = `${base}-${distTag}.`;
|
|
117
|
+
let max = 0;
|
|
118
|
+
for (const version of existingVersions) {
|
|
119
|
+
if (!version.startsWith(prefix)) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const n = Number(version.slice(prefix.length));
|
|
123
|
+
if (Number.isInteger(n) && n > max) {
|
|
124
|
+
max = n;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return max + 1;
|
|
128
|
+
}
|
|
129
|
+
|
|
103
130
|
/**
|
|
104
131
|
* Compute the version to publish for a channel.
|
|
105
132
|
* - Stable (`latest`) publishes the exact package.json version.
|
|
106
|
-
* - Prerelease channels synthesize a disposable `X.Y.Z-<distTag>.<n
|
|
107
|
-
*
|
|
133
|
+
* - Prerelease channels synthesize a disposable `X.Y.Z-<distTag>.<n>`.
|
|
134
|
+
* `n` counts per base version (`0.3.5-staging.1`, `.2`, …) when the
|
|
135
|
+
* published versions could be fetched from npm; otherwise it falls back
|
|
136
|
+
* to the CI run number, then a timestamp.
|
|
108
137
|
*
|
|
109
138
|
* @param {string} baseVersion - package.json version
|
|
110
139
|
* @param {import('./channels.mjs').Channel} channel
|
|
111
|
-
* @param {{ runId?: string }} [opts]
|
|
140
|
+
* @param {{ runId?: string, existingVersions?: readonly string[] }} [opts]
|
|
112
141
|
* @returns {string}
|
|
113
142
|
*/
|
|
114
143
|
export function computePublishVersion(baseVersion, channel, opts = {}) {
|
|
@@ -117,7 +146,9 @@ export function computePublishVersion(baseVersion, channel, opts = {}) {
|
|
|
117
146
|
}
|
|
118
147
|
// Strip any existing prerelease suffix from the base so we don't stack them.
|
|
119
148
|
const base = baseVersion.split('-')[0];
|
|
120
|
-
const n = opts.
|
|
149
|
+
const n = opts.existingVersions
|
|
150
|
+
? String(nextPrereleaseCounter(opts.existingVersions, base, channel.distTag))
|
|
151
|
+
: (opts.runId ?? String(Date.now()));
|
|
121
152
|
return `${base}-${channel.distTag}.${n}`;
|
|
122
153
|
}
|
|
123
154
|
|
|
@@ -5,7 +5,7 @@ import { join } from 'node:path';
|
|
|
5
5
|
import { afterEach, describe, expect, it } from 'vitest';
|
|
6
6
|
|
|
7
7
|
// @ts-expect-error plain mjs module without types
|
|
8
|
-
import { computePublishVersion, nextVersionFromChangesets } from './release-core.mjs';
|
|
8
|
+
import { computePublishVersion, nextPrereleaseCounter, nextVersionFromChangesets } from './release-core.mjs';
|
|
9
9
|
|
|
10
10
|
const stagingChannel = { prerelease: true, distTag: 'staging' };
|
|
11
11
|
const latestChannel = { prerelease: false, distTag: 'latest' };
|
|
@@ -22,6 +22,37 @@ describe('computePublishVersion', () => {
|
|
|
22
22
|
it('strips an existing prerelease suffix before synthesizing', () => {
|
|
23
23
|
expect(computePublishVersion('0.3.3-staging.9', stagingChannel, { runId: '26' })).toBe('0.3.3-staging.26');
|
|
24
24
|
});
|
|
25
|
+
|
|
26
|
+
it('counts per base version when published versions are provided', () => {
|
|
27
|
+
const existingVersions = ['0.3.4', '0.3.5-staging.1', '0.3.5-staging.2'];
|
|
28
|
+
expect(computePublishVersion('0.3.5', stagingChannel, { runId: '30', existingVersions })).toBe('0.3.5-staging.3');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('starts at 1 for a base with no published prereleases', () => {
|
|
32
|
+
const existingVersions = ['0.3.4', '0.3.4-staging.26', '0.3.4-staging.27'];
|
|
33
|
+
expect(computePublishVersion('0.3.5', stagingChannel, { runId: '30', existingVersions })).toBe('0.3.5-staging.1');
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe('nextPrereleaseCounter', () => {
|
|
38
|
+
it('returns 1 when nothing matches the base + tag', () => {
|
|
39
|
+
expect(nextPrereleaseCounter([], '0.3.5', 'staging')).toBe(1);
|
|
40
|
+
expect(nextPrereleaseCounter(['0.3.5', '0.3.5-experimental.4'], '0.3.5', 'staging')).toBe(1);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('continues past the highest published counter for the base', () => {
|
|
44
|
+
const versions = ['0.3.4-staging.26', '0.3.4-staging.27', '0.3.3-staging.25'];
|
|
45
|
+
expect(nextPrereleaseCounter(versions, '0.3.4', 'staging')).toBe(28);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('does not confuse prefix-sharing bases (0.3.4 vs 0.3.40)', () => {
|
|
49
|
+
expect(nextPrereleaseCounter(['0.3.40-staging.9'], '0.3.4', 'staging')).toBe(1);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('ignores non-integer counters (timestamps still count, garbage does not)', () => {
|
|
53
|
+
expect(nextPrereleaseCounter(['0.3.4-staging.abc', '0.3.4-staging.2.5'], '0.3.4', 'staging')).toBe(1);
|
|
54
|
+
expect(nextPrereleaseCounter(['0.3.3-experimental.1783410168478'], '0.3.3', 'experimental')).toBe(1783410168479);
|
|
55
|
+
});
|
|
25
56
|
});
|
|
26
57
|
|
|
27
58
|
describe('nextVersionFromChangesets', () => {
|
package/scripts/publish-npm.mjs
CHANGED
|
@@ -71,6 +71,23 @@ function run(cmd, args, cwd) {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
// All published versions of the package, or null when the registry can't be
|
|
75
|
+
// reached (offline, first-ever publish) — callers fall back to the
|
|
76
|
+
// run-number/timestamp counter.
|
|
77
|
+
function fetchPublishedVersions(name) {
|
|
78
|
+
const result = spawnSync('npm', ['view', name, 'versions', '--json'], { encoding: 'utf8' });
|
|
79
|
+
if (result.status !== 0) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const parsed = JSON.parse(result.stdout);
|
|
84
|
+
// npm view returns a bare string when exactly one version is published.
|
|
85
|
+
return Array.isArray(parsed) ? parsed : [parsed];
|
|
86
|
+
} catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
74
91
|
const { channel: channelName, dryRun, bootstrap, plan } = parseArgs(process.argv.slice(2));
|
|
75
92
|
|
|
76
93
|
if (!channelName) {
|
|
@@ -98,7 +115,14 @@ const baseVersion = channel.prerelease
|
|
|
98
115
|
? nextVersionFromChangesets(pkg.version, resolve(CLI_ROOT, '../../.changeset'))
|
|
99
116
|
: pkg.version;
|
|
100
117
|
const runId = process.env.GITHUB_RUN_NUMBER;
|
|
101
|
-
|
|
118
|
+
let existingVersions;
|
|
119
|
+
if (channel.prerelease) {
|
|
120
|
+
existingVersions = fetchPublishedVersions(pkg.name) ?? undefined;
|
|
121
|
+
if (!existingVersions) {
|
|
122
|
+
console.warn('[publish-npm] could not fetch published versions from npm — using run/timestamp counter.');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const publishVersion = computePublishVersion(baseVersion, channel, { runId, existingVersions });
|
|
102
126
|
|
|
103
127
|
console.log(`[publish-npm] channel: ${channelName} (dist-tag: ${channel.distTag})`);
|
|
104
128
|
console.log(
|