Repository navigation
Conversation
The release workflow published without running checks or tests, from any branch when skip_git_check was set, and pushed the release tag before publishing, so a failed publish left a tag with no npm release. - Run the job only on main unless skip_git_check is set. - Run `pnpm run check` and `pnpm test` before bumping. - Bump with `--no-push`, then pack every package, install the tarballs outside the workspace, import every exports entry and typecheck a consumer of each (`pnpm run test:pack`). - Dry-run the push, publish, then push the commit and tag atomically. - Draft the changelog last, since changelogithub needs the tag on GitHub. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CU1qN3CiSyADEfwPinsqCx
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
This is the initial pullfrog review of the release-hardening PR (base cda4e92, head b0d098b).
release.yamljob gate and step reorder — publishes only frommain(or the explicitskip_git_checkopt-out), runscheck/test/test:packbefore publishing, bumps and tags locally withbumpp --no-push, dry-run pushes before publish and pushes atomically after, and moveschangelogithubto the end so it runs once the tag is on GitHub.scripts/smoke-pack.ts— packs the workspace tarballs (prepack: unbuild), installs them into a scratch consumer outside the workspace, imports everyexportsentry point at runtime, and type-checks the built.d.mtsas a consumer would see it.package.json— adds thetest:packscript.
I verified the load-bearing claims locally: pnpm run test:pack passes against all 6 entry points and pnpm run check passes, both leaving a clean tree; bumpp emits an annotated tag so --follow-tags carries it; and pnpm's recursive publish skips versions already on the registry, so the partial-publish recovery story holds. The credential-sharing and PR-time smoke-test gaps are already scoped as follow-ups in the PR description.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

Why
release.yamlcould publish code that was never checked or tested:pnpm run checkorpnpm test.skip_git_check: trueit published from any branch, and there was no branch guard otherwise either.pnpm publish. A publish that failed left a pushedvX.Y.Ztag with no npm release, and re-running then failed because the tag already existed.src(the devexports), so nothing ever checked thedisttarball that actually ships.This matters because
@orpc/openapi2.x depends on@openapi-spec/downgraderand@openapi-spec/typeswith~0.3.0, so every 0.3.x patch reaches every oRPC install automatically.New step order
The job now runs only when
github.ref == 'refs/heads/main' || inputs.skip_git_check.skip_git_checkwas already the explicit "publish from elsewhere" switch (--no-git-checks), so it doubles as the opt-out.version/taginputspnpm ipnpm run checkpnpm testbumpp -r "$VERSION" --yes --no-push--no-push: commit and tag exist only on the runnerpnpm run test:packgit push --dry-run --atomic --follow-tagspnpm publish -r --provenance …git push --atomic --follow-tagschangelogithub --draftNotes on the ordering:
pnpm publish -rskips versions already on npm, so a partly failed publish (saytypeswent out butdowngraderdidn't) finishes on the re-run.--atomic, so the commit and tag land together or not at all. bumpp's tag is annotated, so--follow-tagscarries it.mainduring check/test fails the run before publishing, instead of leaving an npm release whose tag can't be pushed. It doesn't run server-side hooks, so a branch-protection rejection would still only show up at step 10.hasTagOnGitHub), so it has to run after the push. It's also the least critical step: before, a GitHub API hiccup there aborted the run after the tag was pushed but before publishing.skip_bumpnow also skips both push steps, since there's nothing to push.pnpm run test:pack(scripts/smoke-pack.ts)No CI pack job exists yet, so this is a standalone script that a future CI job can call too:
pnpm --filter=./packages/* packinto a temp dir. This runsprepack(unbuild), appliespublishConfig.exportsand resolvesworkspace:^, the same as publish does.npm installall the tarballs into a scratch project outside the workspace. They're installed together sodowngrader's^X.Y.Zdependency ontypesresolves to the local tarball, with no registry lookup for a version that isn't published yet.exportsentry point at runtime.tsc(nodenext,strict,skipLibCheck: false) on a consumer thatimport types every entry point, so the.d.mtsfiles are checked as a consumer like oRPC sees them.Validation
pnpm run checkandpnpm testpass locally (197 tests). The pre-commit hook passed on the commit.pnpm run test:packpasses: 6 entry points. Checked that it fails on:typessubpath removed frompublishConfig.exports.downgrader's.d.mtsbreaks with TS2307 while the unit tests still pass, which is exactly the gap this closes.exportstarget (unbuild already fails that one atprepack).bumpp --no-pushcommits and tags locally and pushes nothing.pnpm publish -r --dry-runaccepts a branch one commit ahead of upstream (the new post-bump state) and still rejects one that's behind.$NO_GIT_CHECKSword splitting is deliberate (an empty value must disappear), andmainreports the same finding.Possible follow-up (not in this PR)
Check, tests and the smoke test run in the same job that holds
contents: writeandid-token: write(npm trusted publishing). Splitting them into a read-onlyverifyjob thatreleaseneeds:would keep test-time dependencies away from publish credentials.Generated by Claude Code