diff --git a/packages/create-sei/scripts/pending-changesets.ts b/packages/create-sei/scripts/pending-changesets.ts new file mode 100644 index 00000000..25703825 --- /dev/null +++ b/packages/create-sei/scripts/pending-changesets.ts @@ -0,0 +1,7 @@ +/** + * `.changeset` stores `config.json` and `README.md` next to the changesets themselves, so + * only the remaining markdown entries describe releases that Changesets has yet to consume. + */ +export function hasPendingChangesets(changesetDirectoryEntries: string[]): boolean { + return changesetDirectoryEntries.some((entry) => entry.endsWith('.md') && entry !== 'README.md'); +} diff --git a/packages/create-sei/scripts/smoke-generated-app.ts b/packages/create-sei/scripts/smoke-generated-app.ts index 8bf59c65..7589295a 100644 --- a/packages/create-sei/scripts/smoke-generated-app.ts +++ b/packages/create-sei/scripts/smoke-generated-app.ts @@ -3,10 +3,12 @@ import { promises as fs } from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { BRAND_ASSET_HASHES } from '../brand-assets'; +import { hasPendingChangesets } from './pending-changesets'; import { type PrecompilesSource, type PrecompilesSourceSelection, type RequestedPrecompilesSource, selectPrecompilesSource } from './select-precompiles-source'; const packageRoot = path.resolve(import.meta.dir, '..'); const repositoryRoot = path.resolve(packageRoot, '../..'); +const changesetRoot = path.join(repositoryRoot, '.changeset'); const precompilesRoot = path.join(repositoryRoot, 'packages/precompiles'); const cliPath = path.join(packageRoot, 'dist/main.js'); const templateManifestPath = path.join(packageRoot, 'templates/next-template/package.json'); @@ -88,6 +90,26 @@ async function pathExists(target: string): Promise { .catch(() => false); } +async function computePendingReleasePlan(tempRoot: string): Promise { + // A Version Packages branch consumes every changeset while it writes the bumped manifests + // this smoke test exists to validate, and `changeset status` rejects that state because the + // branch changes packages without a changeset. Only require a status report while changesets + // are still waiting to be released. + const changesetsPending = hasPendingChangesets(await fs.readdir(changesetRoot)); + const releasePlanPath = path.join(tempRoot, 'changeset-status.json'); + const exitCode = await run( + 'Compute pending release metadata', + [process.execPath, 'run', 'changeset', 'status', '--output', releasePlanPath], + repositoryRoot, + changesetsPending + ); + if (exitCode !== 0) { + console.log('Every changeset has already been consumed, so the error above is expected and no release is pending.'); + return { releases: [] }; + } + return JSON.parse(await fs.readFile(releasePlanPath, 'utf8')) as ReleasePlan; +} + async function resolvePrecompilesTarget(tempRoot: string): Promise { const templateManifest = JSON.parse(await fs.readFile(templateManifestPath, 'utf8')) as { dependencies?: Record; @@ -97,9 +119,7 @@ async function resolvePrecompilesTarget(tempRoot: string): Promise release.name === '@sei-js/precompiles'); const currentManifest = JSON.parse(await fs.readFile(path.join(precompilesRoot, 'package.json'), 'utf8')) as { version: string; diff --git a/packages/create-sei/src/main.test.ts b/packages/create-sei/src/main.test.ts index de5499d6..958eac21 100644 --- a/packages/create-sei/src/main.test.ts +++ b/packages/create-sei/src/main.test.ts @@ -4,6 +4,7 @@ import { promises as fs } from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { BRAND_ASSET_HASHES } from '../brand-assets'; +import { hasPendingChangesets } from '../scripts/pending-changesets'; import { selectPrecompilesSource } from '../scripts/select-precompiles-source'; import { SEI_NEUTRAL_RAMP } from '../templates/next-template/src/theme'; @@ -83,6 +84,16 @@ describe('precompiles source selection', () => { }); }); +describe('pending changeset detection', () => { + test('counts changeset markdown as pending', () => { + expect(hasPendingChangesets(['README.md', 'config.json', 'fix-create-sei-scaffold.md'])).toBe(true); + }); + + test('treats a versioned changeset folder as consumed', () => { + expect(hasPendingChangesets(['README.md', 'config.json'])).toBe(false); + }); +}); + describe('CLI', () => { beforeAll(async () => { const { stdout, stderr, exitCode } = await runProcess([process.execPath, 'run', 'build'], packageRoot);