diff --git a/README.md b/README.md index 31a3ce8..225b31f 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,8 @@ Rules: ## Release readiness docs - `pnpm run release:check` runs build, tests, smoke, and package smoke. -- `pnpm run package:smoke` runs `npm pack --dry-run` against the publish surface. +- `pnpm run package:smoke` runs `npm pack --dry-run` and verifies the packed + CLI, source, templates, release docs, README, and license are present. - [Release readiness guide](docs/release-readiness.md) - [Release checklist](docs/release-checklist.md) diff --git a/package.json b/package.json index 5d8c764..8cf75be 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "release:check": "pnpm run docs:check && pnpm run build && pnpm test && pnpm run smoke && pnpm run package:smoke", "test": "pnpm run build && node scripts/check-template-registry.mjs", "smoke": "pnpm run smoke:init", - "package:smoke": "npm pack --dry-run" + "package:smoke": "pnpm run build && node scripts/package-smoke.mjs" }, "dependencies": { "commander": "^12.1.0" @@ -36,6 +36,7 @@ "type": "git", "url": "git+https://github.com/rogerchappel/stackforge.git" }, + "license": "MIT", "files": [ "dist", "src", diff --git a/scripts/package-smoke.mjs b/scripts/package-smoke.mjs new file mode 100644 index 0000000..61c082d --- /dev/null +++ b/scripts/package-smoke.mjs @@ -0,0 +1,31 @@ +import { spawnSync } from 'node:child_process'; + +const requiredFiles = [ + 'dist/index.js', + 'src/index.ts', + 'templates/npm-package/package.json', + 'docs/release-readiness.md', + 'README.md', + 'LICENSE', +]; + +const result = spawnSync('npm', ['pack', '--dry-run', '--json'], { + encoding: 'utf8', + stdio: ['ignore', 'pipe', 'pipe'], +}); + +if (result.status !== 0) { + process.stderr.write(result.stderr); + process.exit(result.status ?? 1); +} + +const [pack] = JSON.parse(result.stdout); +const packedFiles = new Set(pack.files.map((file) => file.path)); +const missingFiles = requiredFiles.filter((file) => !packedFiles.has(file)); + +if (missingFiles.length > 0) { + console.error(`Package smoke failed; missing files: ${missingFiles.join(', ')}`); + process.exit(1); +} + +console.log(`Package smoke passed for ${pack.filename} (${pack.files.length} files).`);