Skip to content

feat(ci): fail hard if a publishable package lacks a build-linked prepublishOnly - #52

Draft
MaximusHaximus wants to merge 1 commit into
mainfrom
ci/verify-prepublish-hooks
Draft

feat(ci): fail hard if a publishable package lacks a build-linked prepublishOnly#52
MaximusHaximus wants to merge 1 commit into
mainfrom
ci/verify-prepublish-hooks

Conversation

@MaximusHaximus

Copy link
Copy Markdown
Contributor

Summary

Adds a fail-fast presence check to the shared ci composite action: if any package where private !== true declares a build script but its prepublishOnly doesn't run pnpm run build, CI fails before install.

Why a presence check, not a CI build step

prepublishOnly is the only hook that runs on every publish path — CI changeset publish, a maintainer's local pnpm publish, npm publish. Building in CI before publish would make CI publishes correct while leaving local publishes free to ship whatever stale dist/ is on disk — a new point/major release that's silently a byte-for-byte copy of an old build, with no error anywhere. That's worse than an empty publish, because nothing surfaces it. So this gate requires the hook (protecting all paths) rather than doing the hook's job in CI (which only fixes CI and hides the gap).

Concretely: a missing prepublishOnly shipped @polygonlabs/spol-api-client@1.0.0 and spol-api-schemas@1.0.0 to npm with no dist/ — empty, unimportable packages. This makes that class of failure impossible to merge.

Implementation

  • verify-prepublish-hooks.mjs — zero-dependency (Node built-ins only) script in the action dir, run via ${{ github.action_path }} (no ncc bundle needed). Recursively scans package.json, skipping node_modules/dist/out-tsc/dotdirs.
  • Rule: private !== true and has a build script → prepublishOnly must exist and run pnpm run build (flags absence, build:clean misuse, or a prepublishOnly that doesn't build). Private packages and no-compile packages are correctly skipped.
  • Placed before install so it fails fast; gated on !changeset-release/* like the other steps.

Verification

  • Passes against lst-api main (post-fix — every publishable package has the hook).
  • Flagged the pre-fix lst-api state and a synthetic {build, no prepublishOnly} package (exit 1); correctly skipped private: true and no-build packages.

Companion: the assess-repo skill now flags the same gap for manual audits (apps-team-workspace#103); this is the automated, every-PR enforcement.

…publishOnly

Add a fail-fast presence check to the shared `ci` composite action: for every
package where `private !== true` and a `build` script exists, `prepublishOnly`
must run `pnpm run build`. Runs before install; zero-dependency Node script in
the action dir (no ncc bundle needed).

This is deliberately a *presence* check, not a build-in-CI step. `prepublishOnly`
is the only hook that runs on every publish path — CI `changeset publish`, a
maintainer's local `pnpm publish`, `npm publish`. Building in CI would fix CI
while leaving local publishes free to ship stale `dist/` (a new release that is
silently a byte-for-byte copy of an old build), which is worse because nothing
surfaces it. Requiring the hook protects every path; building in CI hides the gap.

A missing hook shipped @polygonlabs/spol-api-client@1.0.0 to npm with no dist/
(empty, unimportable). This gate makes that class of failure impossible to merge.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant