Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 28 additions & 20 deletions bin/release
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#!/usr/bin/env sh
# Publishes the version in package.json and tags it. Run on a clean `main`. When npm already has that
# version, or a higher one, it commits the next free version to `main`, with the CHANGELOG heading
# renamed to match, and publishes that. An Unreleased section left above the dated, unpublished version is
# folded into it first.
# version, or a higher one, it lands the next free version on `main` through a pull request, with the
# CHANGELOG heading renamed to match, and publishes that. An Unreleased section left above the dated,
# unpublished version is folded into it first, through a pull request too.
#
# bin/release # publishes from GitHub Actions (.github/workflows/release.yml)
# bin/release --local # publishes from this machine with the npm token from the keyring
Expand Down Expand Up @@ -38,18 +38,10 @@ published() {
npm view "@wirecat/cli-base@$version" version --prefer-online >/dev/null 2>&1
}
# A session that merges after the version was dated, but before it was published, adds Unreleased above it.
# --land folds on a fresh main through its own pull request, and folds again once if main moves under it.
if ! published; then
folded=$(pnpm build >/dev/null && node dist/dev/bin.js changelog fold --version "$version")
if [ -n "$folded" ]; then
echo "$folded"
git commit -q -am "chore(release): $folded" \
-m "bin/release: $version is dated but not on npm. Only CHANGELOG.md changes."
git push -q origin main || {
git reset -q --hard HEAD~1
echo "main moved on origin while folding the changelog — run bin/release again" >&2
exit 1
}
fi
folded=$(pnpm build >/dev/null && node dist/dev/bin.js changelog fold --land --version "$version")
[ -z "$folded" ] || echo "$folded"
fi
# Only the top section: the rename below must never touch one that is already published.
top=$(grep -m1 '^## ' CHANGELOG.md || true)
Expand All @@ -58,6 +50,27 @@ case "$top" in
*) echo "CHANGELOG.md's top section is \"$top\" — date it as $version first" >&2; exit 1 ;;
esac

# main takes changes only through a pull request (the repository's ruleset).
land() {
branch=$1 title=$2 body=$3
git switch -q -c "$branch"
git commit -q -am "$title" -m "$body"
git push -q -u origin "$branch" || { echo "could not push $branch — nothing is published" >&2; exit 1; }
git switch -q main
pr=$(gh pr create --base main --head "$branch" --title "$title" --body "$body")
# Checks register a few seconds after the pull request; --watch with none exits at once.
for _ in $(seq 30); do
[ "$(gh pr checks "$pr" --json name --jq length 2>/dev/null || echo 0)" -gt 0 ] && break
sleep 2
done
gh pr checks "$pr" --watch --fail-fast >/dev/null ||
{ echo "checks failed on $pr — nothing is published" >&2; exit 1; }
gh pr merge "$pr" --squash --delete-branch --subject "$title (#${pr##*/})" ||
{ echo "$pr did not merge (main moved under it?) — close it and run bin/release again" >&2; exit 1; }
git fetch -q origin
git merge -q --ff-only origin/main
}

# Two sessions preparing the same number is normal; the second takes the next free one (2026-09-29).
latest=$(npm view @wirecat/cli-base version --prefer-online 2>/dev/null || true)
versions=$(npm view @wirecat/cli-base versions --json --prefer-online 2>/dev/null || true)
Expand All @@ -73,12 +86,7 @@ if [ "$next" != "$version" ]; then
return text
})
swaps.forEach(([file, from, to], i) => fs.writeFileSync(file, texts[i].replace(from, to)))' "$version" "$next"
git commit -q -am "chore: release $next" -m "bin/release: $why."
git push -q origin main || {
git reset -q --hard HEAD~1
echo "main moved on origin while raising the version — run bin/release again" >&2
exit 1
}
land "release/$next" "chore(release): $next" "bin/release: $why. Only package.json and the CHANGELOG heading change."
version=$next
fi
if published; then
Expand Down
Loading