From 7f961237f915d7095df8a02ff88d47ed75339e48 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 27 Dec 2025 19:35:39 +0100 Subject: [PATCH] chore: harden release checks --- docs/RELEASING.md | 1 + package.json | 3 +++ scripts/release-check.ts | 48 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 scripts/release-check.ts diff --git a/docs/RELEASING.md b/docs/RELEASING.md index 7562c167f..ebab1f444 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -29,6 +29,7 @@ Use `pnpm` (Node 22+) from the repo root. Keep the working tree clean before tag - [ ] `pnpm lint` - [ ] `pnpm test` (or `pnpm test:coverage` if you need coverage output) - [ ] `pnpm run build` (last sanity check after tests) +- [ ] `pnpm release:check` (verifies npm pack contents) - [ ] (Optional) Spot-check the web gateway if your changes affect send/receive paths. 5) **macOS app (Sparkle)** diff --git a/package.json b/package.json index d30819ce8..9d2d3e6eb 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,9 @@ "dist/commands/**", "dist/config/**", "dist/cron/**", + "dist/discord/**", "dist/gateway/**", + "dist/hooks/**", "dist/infra/**", "dist/macos/**", "dist/media/**", @@ -37,6 +39,7 @@ "dev": "tsx src/index.ts", "docs:list": "tsx scripts/docs-list.ts", "build": "tsc -p tsconfig.json && tsx scripts/canvas-a2ui-copy.ts", + "release:check": "tsx scripts/release-check.ts", "ui:install": "pnpm -C ui install", "ui:dev": "pnpm -C ui dev", "ui:build": "pnpm -C ui build", diff --git a/scripts/release-check.ts b/scripts/release-check.ts new file mode 100644 index 000000000..7c8f447a7 --- /dev/null +++ b/scripts/release-check.ts @@ -0,0 +1,48 @@ +#!/usr/bin/env tsx + +import { execSync } from "node:child_process"; + +type PackFile = { path: string }; +type PackResult = { files?: PackFile[] }; + +const requiredPaths = ["dist/discord/send.js", "dist/hooks/gmail.js"]; +const forbiddenPrefixes = ["dist/Clawdis.app/"]; + +function runPackDry(): PackResult[] { + const raw = execSync("npm pack --dry-run --json", { + encoding: "utf8", + stdio: ["ignore", "pipe", "pipe"], + }); + return JSON.parse(raw) as PackResult[]; +} + +function main() { + const results = runPackDry(); + const files = results.flatMap((entry) => entry.files ?? []); + const paths = new Set(files.map((file) => file.path)); + + const missing = requiredPaths.filter((path) => !paths.has(path)); + const forbidden = [...paths].filter((path) => + forbiddenPrefixes.some((prefix) => path.startsWith(prefix)), + ); + + if (missing.length > 0 || forbidden.length > 0) { + if (missing.length > 0) { + console.error("release-check: missing files in npm pack:"); + for (const path of missing) { + console.error(` - ${path}`); + } + } + if (forbidden.length > 0) { + console.error("release-check: forbidden files in npm pack:"); + for (const path of forbidden) { + console.error(` - ${path}`); + } + } + process.exit(1); + } + + console.log("release-check: npm pack contents look OK."); +} + +main();