fix(cicd): sync .versions.json + harden release pipeline against silent failures#154
Merged
Merged
Conversation
…nt failures
Two issues bundled because they were exposed by the same release attempt:
1. `.versions.json` was missing entries for `utils`, `cli`, and
`native-test` (added to the workspace after the last release).
`tailwind` was also stale (0.2.5 vs current 0.2.6). When the releaser
walks commits since the last tag and accumulates per-package bump
types, it then calls `bumpVersion(versions[pkgName], type, true)` —
for missing entries that's `bumpVersion(undefined, ...)`, which
crashes inside `VERSION_MATCHER.exec(undefined)` with a confusing
TypeError. The crash happened before the `-release` marker logic, so
the resulting workflow path was wrong, no .tgz was produced, and the
artifact upload failed with "Input required and not supplied: path".
2. The workflow's bash glue masked the crash. The previous step was:
echo "TAG_NAME=$(npm run release | grep v)" >> $GITHUB_OUTPUT
When `npm run release` crashed and `grep v` matched nothing, the
pipeline failed but the outer `echo` succeeded, so the step exited 0
with an empty TAG_NAME. Subsequent steps silently produced broken
artifacts. This is exactly the "happy-path-only" CI bug class that
makes release pipelines untrustworthy.
Changes:
- `.versions.json`: add `utils`, `cli`, `native-test` entries with
their current package.json versions; correct `tailwind` to 0.2.6.
- `prepare-release.yml`:
* New "Validate .versions.json is in sync with workspaces" step
runs before the releaser and fails fast with a clear actionable
message if any workspace is missing from .versions.json.
* Rewrote "Prepare tag or release" to use `set -euo pipefail`,
capture releaser output to a file, extract the tag with a strict
regex (`^v[0-9]+\.[0-9]+\.[0-9]+(-[a-z0-9]+)*`), and explicitly
fail the step if no tag was produced. Also annotates a clear
`::error::` message instead of swallowing the crash.
* Same hardening on "Get generated package name" so an empty
*.tgz directory produces a clear error instead of the cryptic
"Input required and not supplied: path" from upload-artifact.
* Fixed long-standing typo "genereated" -> "generated".
After this lands, a future workspace addition that forgets
.versions.json will fail in the validation step with a one-line
actionable message, and any future releaser crash will surface
immediately at its origin instead of corrupting downstream artifacts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Third (and hopefully final) fix to unblock the v0.5.0 release pipeline. After getting past the Node 18→22 issue, the next run still failed — but now in a deeper way that exposed both a stale state file and a long-standing class of silent-failure CI bugs.
What broke
Tests passed on Node 22 ✓, but the release pipeline failed at the artifact upload step with the cryptic
Input required and not supplied: path. Tracing back:bumpVersion(versions[pkgName], type, true)was being called withversions[pkgName] === undefined. Reason:.versions.jsonwas missingutils,cli, andnative-test— workspaces added since the last release that nobody synced into the state file.The crash happened before the
-releasemarker / icons-tarball-pack logic. So the releaser exited mid-flight, no.tgzwas produced, no tag name was emitted, and the workflow merrily marched into upload steps with empty inputs.Why we didn't notice the crash
This step:
When
npm run releasecrashed andgrep vmatched nothing, the inner pipeline failed but the outerechosucceeded, so the step exited 0 withTAG_NAME="". The release process then ran along a happy path that didn't exist. This is the "make CI step succeed even when it shouldn't" anti-pattern, and the workflow had it in two places.Fix (two parts in one PR)
1. Sync
.versions.jsonAdded the missing workspace entries:
utils: "0.2.7"cli: "0.2.5"native-test: "0.1.0"tailwind: "0.2.5"→"0.2.6"(was stale by one patch)All 8 current workspaces now covered.
2. Harden
prepare-release.ymlagainst silent failuresNew pre-flight step
Validate .versions.json is in sync with workspaces. Runs before the releaser, walkspackage.json#workspaces, fails fast with a clear::error::message listing missing entries. Future workspace additions that forget.versions.jsonget caught immediately with a one-line actionable error instead of a TypeError 60 seconds in.Rewrote
Prepare tag or releasewithset -euo pipefail, captures releaser output torelease-output.log, extracts the tag with a strict regex (^v[0-9]+\.[0-9]+\.[0-9]+(-[a-z0-9]+)*rather thangrep v), and explicitly fails with a useful annotation if no tag was produced.Same hardening on
Get generated package name— empty*.tgzdirectory now produces a clear error instead ofInput required and not supplied: pathtwo steps later.Fixed the long-standing typo
genereated→generated.Verification
YAML still parses with 2 jobs. Workflow committed via the husky commit hook (lint-staged formatted both files).
After merge
PR #151 (develop → main) auto-resyncs and
prepare-releaseruns again. With Node 22 + a complete.versions.json+ hardened error-surfacing, the releaser should:v0.4.1-releaseutils,cli,native-test)packages/iconsintorocketicons-0.x.0.tgz-releaseto the tag name (the icons package has substantive changes)ci(releaser): bump packages versions...commit onto developnpm publishon merge to main