From 455c46420f0860b2c76bac5b5584721d62ff2fda Mon Sep 17 00:00:00 2001 From: okjodom Date: Tue, 21 Apr 2026 22:39:31 +0300 Subject: [PATCH] fix: verify publish manifests before release --- .github/workflows/changesets.yml | 3 +- .github/workflows/snapshot.yml | 1 + package.json | 1 + scripts/verify-publish-manifests.mjs | 62 ++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 scripts/verify-publish-manifests.mjs diff --git a/.github/workflows/changesets.yml b/.github/workflows/changesets.yml index 9288eb22..2a4795e2 100644 --- a/.github/workflows/changesets.yml +++ b/.github/workflows/changesets.yml @@ -62,7 +62,7 @@ jobs: uses: changesets/action@v1 timeout-minutes: 10 with: - publish: nix develop --accept-flake-config -c bash -c "export CI=true; pnpm changeset publish" + publish: nix develop --accept-flake-config -c bash -c "export CI=true; pnpm changeset:verify-publish-manifests; pnpm changeset publish" createGithubReleases: ${{ github.ref == 'refs/heads/main' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -107,6 +107,7 @@ jobs: patch -p0 --forward < patches/snapshot_version.patch || true cd ../.. + pnpm changeset:verify-publish-manifests pnpm build pnpm build:reactnative pnpm changeset publish --no-git-tag --snapshot canary --tag canary diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 37177063..81646b27 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -55,6 +55,7 @@ jobs: patch -p0 --forward < patches/snapshot_version.patch || true cd ../.. + pnpm changeset:verify-publish-manifests pnpm build pnpm build:reactnative pnpm changeset publish --no-git-tag --snapshot \$snapshot --tag snapshot diff --git a/package.json b/package.json index 9f5e7050..70ecf621 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "preview": "pnpm --filter vite-core preview", "reset": "pnpm clean && pnpm build && pnpm preview", "changeset": "changeset", + "changeset:verify-publish-manifests": "node scripts/verify-publish-manifests.mjs", "version": "changeset version", "typecheck": "pnpm run --r --parallel --filter \"!@fedimint/react-native\" --filter \"!@fedimint/react-native-bindings\" typecheck", "coverage": "vitest run --coverage", diff --git a/scripts/verify-publish-manifests.mjs b/scripts/verify-publish-manifests.mjs new file mode 100644 index 00000000..5463a45d --- /dev/null +++ b/scripts/verify-publish-manifests.mjs @@ -0,0 +1,62 @@ +import { readdirSync, readFileSync } from 'node:fs' +import { join } from 'node:path' + +const rootDir = process.cwd() +const packagesDir = join(rootDir, 'packages') +const dependencyFields = [ + 'dependencies', + 'optionalDependencies', + 'peerDependencies', +] + +const packageDirs = readdirSync(packagesDir, { withFileTypes: true }) + .filter((entry) => entry.isDirectory()) + .map((entry) => join(packagesDir, entry.name)) + +const failures = [] + +for (const packageDir of packageDirs) { + const packageJsonPath = join(packageDir, 'package.json') + const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf8')) + + if (pkg.private) { + continue + } + + const workspaceProtocolEntries = dependencyFields.flatMap((field) => { + const dependencies = pkg[field] ?? {} + return Object.entries(dependencies) + .filter( + ([, version]) => + typeof version === 'string' && version.startsWith('workspace:'), + ) + .map(([name, version]) => `${field}.${name}=${version}`) + }) + + if (workspaceProtocolEntries.length > 0) { + failures.push({ + name: pkg.name, + entries: workspaceProtocolEntries, + }) + } +} + +if (failures.length > 0) { + console.error( + [ + 'Refusing to publish: one or more publishable package manifests still contain workspace protocol references.', + 'This check must run after `changeset version` has rewritten internal dependency ranges.', + '', + ...failures.flatMap(({ name, entries }) => [ + `${name}:`, + ...entries.map((entry) => `- ${entry}`), + '', + ]), + ] + .join('\n') + .trim(), + ) + process.exit(1) +} + +console.log('Verified all publishable package manifests are publish-safe.')