2 Commits
Author SHA1 Message Date
tmu 85fd37737a 🐛 Refresh origin/HEAD before pubv preflight
pubv resolves the default branch from the local refs/remotes/origin/HEAD,
which git fetch never updates, so a clone or default-branch change left it
stale and pubv warned that main was not the default. Refresh it from the
remote before pubv runs, and assert releases are cut from main explicitly.
2026-09-14 10:59:39 +00:00
tmu bd0145642c ✨ Add create:finish merge front door
The merge half of the branching model was still prose, so it drifted per
session. create:finish mirrors create:branch: it asserts the merge-side
preconditions, fast-forwards a stale main (divergence is refused), merges
--no-ff, runs npm run verify, and deletes the branch only when green. The
push stays with create:release so the merge is reviewable first.
2026-09-14 10:59:34 +00:00
4 changed files with 8 additions and 39 deletions

No files matched your search

+2 -2
View File
@@ -95,6 +95,6 @@ This is why every test in the suite pairs an `expectTypeOf(...)` with an `assert
Publishing is CI-only by policy. Local `npm publish` is not supported. The maintainer triggers releases from `main`:
1. All intended changes are merged to `main` and passing CI.
2. The maintainer runs `npm run create:release`. VS Code opens `CHANGELOG.md` to finalize the `[Unreleased]` notes; because pubv refuses a dirty tree, any edit is committed first (then folded into the release commit), and pubv's interactive prompt suggests a version from those notes — the maintainer confirms or edits it.
3. `scripts/release.sh` creates a single release commit (graduated changelog + package.json bump, amended into one commit), tags it, and pushes everything to Gitea.
2. The maintainer runs `npm run create:release` — an interactive prompt suggests a version (based on the latest CHANGELOG entry); the maintainer confirms or edits it.
3. `scripts/release.sh` creates a single release commit (changelog + package.json bump, amended into one commit), tags it, and pushes everything to Gitea.
4. CI runs on the push (the `build` and `maintain` jobs); the `publish` job then fires on the tag, consuming the `dist/` artifact the `build` job produced. The job graph lives in [.gitea/workflows/ci.yml](./.gitea/workflows/ci.yml) — keep that file, not this list, as the source of truth. The publish-tier checks must pass before the artifact is published. The `publish` job also creates the Gitea release page from the matching Keep-a-Changelog section (`scripts/release-notes.sh`); it runs _before_ `npm publish` so a broken page fails CI without consuming a version, and `npm publish` stays the last step.
+1 -4
View File
@@ -106,10 +106,7 @@ git show-ref --verify --quiet "refs/heads/${BASE}" || {
# Derive the remote rather than hardcoding it: this repo has `origin` (ssh) and
# `origin_https`, and `main` tracks the latter — `git fetch origin main` would
# check currency against a ref that is never updated here.
# `--quiet` echoes the unresolved `main@{upstream}` literal to stdout on
# failure, so it cannot be paired with a `$(...) || fallback`; the non-quiet
# form prints nothing on failure and the fallback runs.
UPSTREAM=$(git rev-parse --abbrev-ref --symbolic-full-name "${BASE}@{upstream}" 2>/dev/null) || UPSTREAM=""
UPSTREAM=$(git rev-parse --quiet --abbrev-ref --symbolic-full-name "${BASE}@{upstream}" 2>/dev/null || true)
if [ -n "${UPSTREAM}" ]; then
git fetch --quiet "${UPSTREAM%/*}" "${UPSTREAM#*/}" || {
echo "error: '${UPSTREAM}' check failed: could not reach '${UPSTREAM%/*}'." >&2
+2 -5
View File
@@ -85,10 +85,7 @@ git show-ref --verify --quiet "refs/heads/${BASE}" || {
# Derive the remote rather than hardcoding it: this repo has `origin` (ssh) and
# `origin_https`, and `main` tracks the latter — `git fetch origin main` would
# check currency against a ref that is never updated here.
# `--quiet` echoes the unresolved `main@{upstream}` literal to stdout on
# failure, so it cannot be paired with a `$(...) || fallback`; the non-quiet
# form prints nothing on failure and the fallback runs.
UPSTREAM=$(git rev-parse --abbrev-ref --symbolic-full-name "${BASE}@{upstream}" 2>/dev/null) || UPSTREAM=""
UPSTREAM=$(git rev-parse --quiet --abbrev-ref --symbolic-full-name "${BASE}@{upstream}" 2>/dev/null || true)
BEHIND=0
if [ -n "${UPSTREAM}" ]; then
git fetch --quiet "${UPSTREAM%/*}" "${UPSTREAM#*/}" || {
@@ -116,7 +113,7 @@ if [ "${BEHIND}" -ne 0 ]; then
git merge --quiet --ff-only "${UPSTREAM}"
fi
if ! git merge --quiet --no-ff -m ":twisted_rightwards_arrows: Merge ${START_REF} into ${BASE}" "${START_REF}"; then
if ! git merge --quiet --no-ff --no-edit "${START_REF}"; then
echo "error: merge of '${START_REF}' failed; aborting and returning to it." >&2
git merge --abort 2>/dev/null || true
git switch --quiet "${START_REF}"
+3 -28
View File
@@ -13,12 +13,6 @@ set -eu
# package.json + the lockfile; `--amend` folds them into pubv's single commit;
# tag AFTER the amend (so the tag is never orphaned) and push.
#
# The notes are finalized in VS Code *before* pubv: the [Unreleased] body is
# what pubv's bump heuristic reads, so editing afterwards would inform the
# changelog only, not the version choice. pubv refuses a dirty tree, so that
# edit is committed as a staging commit and folded back into the single release
# commit below.
#
# Rejected: the conventional-commits family (our history is gitmoji, not
# Conventional; and we want hand-written notes); changesets/rtk (config + a
# heavier version/publish flow that fights our CI-only publish); knope/kacl/
@@ -58,23 +52,12 @@ if ! git remote set-head origin --auto >/dev/null 2>&1; then
exit 1
fi
# The [Unreleased] body drives pubv's bump heuristic, so finalize it first.
echo "Opening ${CHANGELOG} in VS Code to finalize the release notes..."
code --wait "${CHANGELOG}"
# pubv refuses a dirty tree (its "continue with a dirty tree?" prompt defaults
# to No), so a changed changelog must be committed before it runs. That commit
# is staging only — the fold below rewrites it into the single release commit.
NOTES_MSG=":memo: Finalize release notes"
if [ -n "$(git status --porcelain -- "${CHANGELOG}")" ]; then
echo "Committing finalized release notes..."
git add "${CHANGELOG}"
git commit -m "${NOTES_MSG}"
fi
echo "Running pubv..."
pubv --no-tag --no-push --tag-prefix=none
echo "Opening ${CHANGELOG} in VS Code..."
code --wait "${CHANGELOG}"
echo "Reading version from ${CHANGELOG}..."
VERSION=$(
@@ -92,14 +75,6 @@ echo "Release version: ${VERSION}"
echo "Updating package.json and package-lock.json..."
npm version "${VERSION}" --no-git-tag-version
# If pubv's graduation commit sits on top of our staging notes commit, drop it
# back into the index so the amend below rewrites the notes commit into the one
# release commit. A message check, not a flag, so a re-run after pubv aborted
# still folds a notes commit left behind by the earlier attempt.
if [ "$(git log -1 --format=%s HEAD~1 2>/dev/null || true)" = "${NOTES_MSG}" ]; then
git reset --soft HEAD~1
fi
echo "Amending release commit..."
git add package.json package-lock.json "${CHANGELOG}"
git commit --amend -m ":bookmark: Release ${VERSION}"