Replace the build-counter version scheme (every alpha push monotonically
bumps the patch number, producing immutable :0.0.X tags that look
indistinguishable from stable releases) with proper semver pre-release
suffixes. Stable owns clean vX.Y.Z; alpha and beta carry
vX.Y.Z-{alpha,beta}[.N] indicating the next-stable target.
The next-stable target is the patch-bump of the latest clean
<prefix>-vX.Y.Z tag. Counter N is per-channel (alpha and beta count
separately) and resets when a new stable advances next-patch. Used
only for zddc-server image tags, where every release is git-tagged;
HTML tools omit the counter since alpha/beta cuts there don't tag.
release-image.sh:
- New CLI: sh release-image.sh [alpha|beta|stable] [<version>].
- Default channel alpha. Version arg only valid (and only optional)
for stable.
- Auto-derives the version via next_prerelease for alpha/beta, and
patch-bump for unspecified stable.
- Now creates the git tag itself (the auto-derived version is no
longer something the operator can predict in advance), but does
not push — operator finishes with `git push --tags`.
shared/build-lib.sh:
- Add next_prerelease(channel, tag_prefix) helper.
- compute_build_label embeds v<next-stable>-{alpha,beta} in the
on-page label for plain and --release alpha|beta builds.
- Plain builds: v<next-stable>-alpha · <ts> · <sha>[-dirty]
--release alpha: v<next-stable>-alpha · <date> · <sha>
--release beta: v<next-stable>-beta · <date> · <sha>
--release [<version>]: v<X.Y.Z> (clean stable, unchanged shape).
Pre-release semver ordering (vX.Y.Z-alpha.1 < vX.Y.Z-alpha.2 <
vX.Y.Z-beta.1 < vX.Y.Z) is honored by registry tag sorting,
git tag --sort=-v:refname, sort -V, npm, cargo — so consumers can
pin or compare versions without surprises.
Existing zddc-server-v0.0.{3..7} git tags and registry tags are
audit history; not rewritten. Going forward, alpha/beta cuts produce
v0.0.8-{alpha,beta}.N format, and clean v0.0.8 is reserved for a
deliberate stable promotion.
freshen-channel needs no code change. It runs --release <channel>
inside a worktree at the latest stable tag, where the build-lib.sh
at that tag is still the old version producing old-format labels;
the first stable cut after this commit will propagate the new format
to subsequent freshens (per the existing "build pipeline at the tag"
reproducibility policy).
AGENTS.md and CLAUDE.md updated.
181 lines
6.4 KiB
Bash
Executable file
181 lines
6.4 KiB
Bash
Executable file
#!/bin/sh
|
|
# release-image.sh — build the zddc-server runtime image locally and push it
|
|
# to codeberg.org/varasys/zddc-server with cascading channel tags.
|
|
#
|
|
# Usage:
|
|
# sh release-image.sh # alpha cut, version auto-derived
|
|
# sh release-image.sh alpha # same
|
|
# sh release-image.sh beta # beta cut, version auto-derived
|
|
# sh release-image.sh stable # stable cut, patch++ from latest stable
|
|
# sh release-image.sh stable 0.1.0 # stable cut, explicit version
|
|
#
|
|
# Channel cascade rules (unchanged from earlier):
|
|
# alpha → :<version> :alpha
|
|
# beta → :<version> :beta :alpha
|
|
# stable → :<version> :stable :beta :alpha
|
|
#
|
|
# Versioning: pre-release semver. Stable releases own clean vX.Y.Z; alpha
|
|
# and beta carry vX.Y.Z-alpha.N / vX.Y.Z-beta.N suffixes, where X.Y.Z is
|
|
# the next patch of the latest clean stable tag and N is a per-channel
|
|
# counter that resets when stable advances.
|
|
#
|
|
# The script does ONE thing the old version did not: it `git tag`s the
|
|
# release before pushing the image, since auto-derivation means the
|
|
# operator can no longer predict the version up-front. The tag is pushed
|
|
# to origin only if the operator runs `git push --tags` afterwards
|
|
# (intentional — the script never pushes git history on its own).
|
|
#
|
|
# Prerequisites:
|
|
# - podman (or docker — commands are identical)
|
|
# - logged in to codeberg.org: `podman login codeberg.org`
|
|
# (Codeberg username + a token with `package:write` scope, generated at
|
|
# https://codeberg.org/user/settings/applications)
|
|
#
|
|
# What it does:
|
|
# 1. Compute the version (auto for alpha/beta, auto-or-explicit for stable).
|
|
# 2. Refresh dist/web by running sh build.sh — the Containerfile's
|
|
# server stage COPYs those files in.
|
|
# 3. Tag the current commit zddc-server-v<version>.
|
|
# 4. Build zddc/Containerfile's `server` stage as a single local image.
|
|
# 5. Tag and push each cascade tag.
|
|
|
|
set -eu
|
|
|
|
usage() {
|
|
cat >&2 <<'EOF'
|
|
usage: release-image.sh [alpha|beta|stable] [<version>]
|
|
|
|
alpha (default) cut alpha, version auto-derived from the latest
|
|
clean stable tag (vX.Y.Z + patch++ + -alpha.N).
|
|
beta cut beta, version auto-derived (vX.Y.Z + -beta.N).
|
|
stable cut stable. Without <version>, patch-bump from the
|
|
latest clean stable tag. With <version>, use it
|
|
verbatim (must be a clean X.Y.Z).
|
|
EOF
|
|
exit 1
|
|
}
|
|
|
|
CHANNEL="${1:-alpha}"
|
|
case "$CHANNEL" in
|
|
alpha | beta | stable) ;;
|
|
-h | --help) usage ;;
|
|
*) echo "error: unknown channel '$CHANNEL'" >&2; usage ;;
|
|
esac
|
|
|
|
EXPLICIT_VERSION="${2:-}"
|
|
if [ -n "$EXPLICIT_VERSION" ] && [ "$CHANNEL" != "stable" ]; then
|
|
echo "error: an explicit <version> is only valid with the 'stable' channel" >&2
|
|
echo " alpha and beta versions are auto-derived." >&2
|
|
exit 1
|
|
fi
|
|
|
|
REPO="codeberg.org/varasys/zddc-server"
|
|
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
|
|
TAG_PREFIX="zddc-server-v"
|
|
|
|
# Source build-lib.sh so we can call next_prerelease for alpha/beta and
|
|
# share the validation helpers used by the HTML tools.
|
|
root_dir="$SCRIPT_DIR"
|
|
. "$SCRIPT_DIR/shared/build-lib.sh"
|
|
|
|
# --- Determine the version --------------------------------------------------
|
|
case "$CHANNEL" in
|
|
alpha | beta)
|
|
VERSION=$(next_prerelease "$CHANNEL" "$TAG_PREFIX")
|
|
;;
|
|
stable)
|
|
if [ -n "$EXPLICIT_VERSION" ]; then
|
|
_validate_semver "$EXPLICIT_VERSION"
|
|
VERSION="$EXPLICIT_VERSION"
|
|
else
|
|
# Auto-bump patch from the latest clean stable tag.
|
|
_latest=$(git -C "$SCRIPT_DIR" tag --list "${TAG_PREFIX}*" 2>/dev/null \
|
|
| grep -E "^${TAG_PREFIX}[0-9]+\.[0-9]+\.[0-9]+\$" \
|
|
| sed "s|^${TAG_PREFIX}||" \
|
|
| sort -V \
|
|
| tail -1)
|
|
[ -n "$_latest" ] || _latest="0.0.0"
|
|
_major="${_latest%%.*}"
|
|
_rest="${_latest#*.}"
|
|
_minor="${_rest%%.*}"
|
|
_patch="${_rest#*.}"
|
|
VERSION="${_major}.${_minor}.$((_patch + 1))"
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
case "$CHANNEL" in
|
|
alpha) TAGS="$VERSION alpha" ;;
|
|
beta) TAGS="$VERSION beta alpha" ;;
|
|
stable) TAGS="$VERSION stable beta alpha" ;;
|
|
esac
|
|
|
|
# Pick podman or docker, whichever is on PATH.
|
|
if command -v podman >/dev/null 2>&1; then
|
|
OCI=podman
|
|
elif command -v docker >/dev/null 2>&1; then
|
|
OCI=docker
|
|
else
|
|
echo "error: neither podman nor docker found on PATH" >&2
|
|
exit 1
|
|
fi
|
|
|
|
GIT_TAG="${TAG_PREFIX}${VERSION}"
|
|
|
|
echo "=== Building $REPO ==="
|
|
echo "Channel: $CHANNEL"
|
|
echo "Version: $VERSION"
|
|
echo "Git tag: $GIT_TAG"
|
|
echo "Image tags: $TAGS"
|
|
echo "OCI CLI: $OCI"
|
|
echo
|
|
|
|
# --- Refresh HTML dist (Containerfile COPYs from dist/web) ------------------
|
|
sh "$SCRIPT_DIR/build.sh"
|
|
|
|
# --- Tag the commit (idempotent: skip if the tag already points here) -------
|
|
if git -C "$SCRIPT_DIR" rev-parse -q --verify "refs/tags/$GIT_TAG" >/dev/null; then
|
|
_existing=$(git -C "$SCRIPT_DIR" rev-list -n 1 "$GIT_TAG")
|
|
_head=$(git -C "$SCRIPT_DIR" rev-parse HEAD)
|
|
if [ "$_existing" != "$_head" ]; then
|
|
echo "error: tag $GIT_TAG already exists at $_existing, but HEAD is $_head" >&2
|
|
echo " refusing to overwrite. Resolve manually." >&2
|
|
exit 1
|
|
fi
|
|
echo "(tag $GIT_TAG already at HEAD)"
|
|
else
|
|
git -C "$SCRIPT_DIR" tag "$GIT_TAG"
|
|
echo "tagged $GIT_TAG (run 'git push --tags' to publish)"
|
|
fi
|
|
|
|
# --- Build + push -----------------------------------------------------------
|
|
"$OCI" build --target server -t zddc-server:build "$SCRIPT_DIR/zddc/"
|
|
|
|
echo
|
|
echo "=== Pushing tags ==="
|
|
for tag in $TAGS; do
|
|
"$OCI" tag zddc-server:build "$REPO:$tag"
|
|
"$OCI" push "$REPO:$tag"
|
|
echo "pushed $REPO:$tag"
|
|
done
|
|
|
|
echo
|
|
echo "=== Done ==="
|
|
echo "Image: $REPO:$VERSION"
|
|
echo "Cascading tags: $TAGS"
|
|
echo "Git tag: $GIT_TAG (publish with: git push origin $GIT_TAG)"
|
|
echo
|
|
case "$CHANNEL" in
|
|
stable)
|
|
echo "Reminder (channel discipline rule 4): freshen alpha + beta now"
|
|
echo "so users tracking those channels are not on stale code:"
|
|
echo " ./freshen-channel <tool> alpha"
|
|
echo " ./freshen-channel <tool> beta"
|
|
echo
|
|
echo "Bump tnd-zddc-chart's ZDDC_SERVER_TAG (push to develop) so the"
|
|
echo "chart's CI rebuilds the dev-shell image and helm-rolls."
|
|
;;
|
|
beta)
|
|
echo "Beta cut. Soak before promoting to stable."
|
|
;;
|
|
esac
|