From 0543f057160293e092eefbe46ffeb8cd013ef05e Mon Sep 17 00:00:00 2001 From: alexander-sei Date: Sun, 23 Aug 2026 19:17:11 +0200 Subject: [PATCH] ci: keep the create-sei smoke green on Version Packages branches `changeset status` refuses to report on a branch that changes packages without adding a changeset, which is exactly what a Version Packages branch looks like after Changesets consumes every changeset and writes the bumped manifests. It exits before writing `--output`, so the release smoke failed while computing pending release metadata and never reached the versions it exists to validate. Only require the status report while changesets are still waiting to be released, and otherwise treat the consumed state as an empty release plan so the smoke validates the already-bumped manifests. Co-authored-by: Cursor --- .../create-sei/scripts/pending-changesets.ts | 7 +++++ .../create-sei/scripts/smoke-generated-app.ts | 26 ++++++++++++++++--- packages/create-sei/src/main.test.ts | 11 ++++++++ 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 packages/create-sei/scripts/pending-changesets.ts 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);