# shellcheck shell=bash # Single source of truth for punktfunk release/canary version numbers (Linux + macOS runners). # # WHY THIS EXISTS: every release workflow used to hardcode a canary base version # (`0.5.0`, `0.3`, …). Those magic numbers had to be hand-bumped on every stable release # and nobody did — so canary channels silently fell *behind* stable (a canary showed up on # TestFlight as 0.5.0 while 0.6.0 was already published). This script computes the base # version DETERMINISTICALLY from the git tags instead, so there is nothing to hand-edit and # no future agent can get it wrong. # # THE RULE (chosen 2026-07-03): # * stable (a `vX.Y.Z` tag push) → PF_BASE = X.Y.Z (the tag, minus any -rc/+meta suffix). # * canary (a main push) → PF_BASE = . # i.e. latest release v0.6.0 → canary base 0.7.0. Cutting v0.7.0 auto-advances canary to # 0.8.0. Canary is therefore ALWAYS exactly one minor ahead of the newest stable release. # # USAGE (bash workflows) — eval it, then format your channel's suffix off $PF_BASE: # eval "$(bash scripts/ci/pf-version.sh)" # case "$GITHUB_REF" in # refs/tags/v*) V="${GITHUB_REF_NAME#v}" ;; # stable # *) V="${PF_BASE}-ci${GITHUB_RUN_NUMBER}" ;; # canary suffix is per-channel # esac # # It prints `KEY=VALUE` lines (eval-able) to stdout and — when $GITHUB_ENV is set — also # appends them there for later steps. Exports: # PF_CHANNEL stable | canary # PF_BASE the base semver X.Y.Z (see THE RULE) # PF_MAJOR/MINOR/PATCH the components of PF_BASE (numeric-version channels build # `..` from these — MSIX/decky need monotonic ints) # PF_STABLE_TAG the latest stable release version the canary base was derived from (for logs) # # The pwsh twin scripts/ci/pf-version.ps1 implements the identical rule for the Windows runners. set -euo pipefail _root="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")/../.." && pwd)" # actions/checkout is shallow and fetches NO tags by default — canary needs the full tag list # to find the latest stable. Best-effort fetch; the Cargo.toml fallback below covers a fresh # repo with no tags at all. git -C "$_root" fetch --tags --force --quiet 2>/dev/null || true # Latest stable release = highest strict vX.Y.Z tag (pre-releases like v0.7.0-rc1 are ignored). _stable="$( git -C "$_root" tag -l 'v*' \ | sed -n 's/^v\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)$/\1/p' \ | sort -V | tail -n1 )" if [ -z "${_stable:-}" ]; then # No tags yet — seed from the workspace Cargo.toml version so canary still has a base. _stable="$(sed -n 's/^version = "\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)".*/\1/p' "$_root/Cargo.toml" | head -n1)" fi _stable="${_stable:-0.0.0}" case "${GITHUB_REF:-}" in refs/tags/v*) _channel="stable" _base="${GITHUB_REF_NAME#v}" _base="${_base%%-*}" # drop -rc / pre-release for the numeric marketing/package version _base="${_base%%+*}" # drop +build metadata ;; *) _channel="canary" _maj="${_stable%%.*}"; _rest="${_stable#*.}"; _min="${_rest%%.*}" _base="${_maj}.$((_min + 1)).0" ;; esac _pf_major="${_base%%.*}"; _pf_rest="${_base#*.}"; _pf_minor="${_pf_rest%%.*}"; _pf_patch="${_pf_rest##*.}" _emit() { printf '%s=%s\n' "$1" "$2" if [ -n "${GITHUB_ENV:-}" ]; then printf '%s=%s\n' "$1" "$2" >> "$GITHUB_ENV"; fi } _emit PF_CHANNEL "$_channel" _emit PF_BASE "$_base" _emit PF_MAJOR "$_pf_major" _emit PF_MINOR "$_pf_minor" _emit PF_PATCH "$_pf_patch" _emit PF_STABLE_TAG "$_stable"