Files
DeepSeek-Reasonix/scripts/resolve-cli-release.sh
T
SivanCola b6da01dbdc feat(release): separate Stable and Preview histories
Context: Stable and Preview need independent reviewed identities while CLI, Desktop, npm, and changelog publication remain one protected release event.

Changes:
- Add a protected Preview orchestrator with a shared ordinal and SignPath preflight.
- Bind reviewed release notes to immutable all-surface publication markers.
- Route downloads and changelog archives by channel with accessible theme-aware navigation.
- Harden release authorization, manifests, tests, and operator documentation.

Compatibility:
- Legacy catalog entries without managed status remain readable and public.
- Existing Stable pointers remain unchanged, and Preview continues mirroring the legacy canary pointer for older Desktop clients.
- No persisted user state or Wails JSON contract changes.

Verification:
- bash scripts/release-workflows.test.sh
- node --test scripts/release-notes.test.mjs
- cd desktop && go test ./cmd/sign ./internal/update
- cd site && npm test
- cd site && npm run build
- actionlint for all release workflows
2026-07-31 01:12:23 +08:00

76 lines
2.2 KiB
Bash

#!/usr/bin/env bash
# Resolve and validate one native CLI release tag. Stable releases and internal
# RCs stay on the stable control plane; public Preview archives use the explicit
# vX.Y.Z-preview.N contract and the Preview deployment gate.
set -euo pipefail
stable_semver_re='(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)'
release_semver_re="^v${stable_semver_re}(-([0-9A-Za-z-]+)(\.[0-9A-Za-z-]+)*)?)?$"
preview_semver_re="^v${stable_semver_re}-preview\.(0|[1-9][0-9]*)$"
if [ "${IN_ORCHESTRATED:-false}" = "true" ]; then
tag="${IN_TAG:?orchestrated CLI release requires tag}"
else
if [ "${EVENT_NAME:-}" = "workflow_dispatch" ]; then
if [ "${CALLER_REF:-}" != "refs/heads/main-v2" ] || [ "${CALLER_REF_PROTECTED:-}" != "true" ]; then
echo "::error::manual CLI releases must run from protected main-v2" >&2
exit 1
fi
tag="${IN_TAG:?manual CLI release requires an existing protected tag}"
else
tag="${REF_NAME:?CLI tag push requires ref name}"
fi
fi
if [[ ! "$tag" =~ $release_semver_re ]]; then
echo "::error::CLI release tag must be vMAJOR.MINOR.PATCH[-PRERELEASE], got: $tag" >&2
exit 1
fi
base_version="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.${BASH_REMATCH[3]}"
version="${tag#v}"
case "$version" in
*-*) prerelease="true" ;;
*) prerelease="false" ;;
esac
if [[ "$tag" =~ $preview_semver_re ]]; then
channel="preview"
notes_version="$tag"
else
case "$tag" in
v*-preview*)
echo "::error::CLI Preview tag must be vMAJOR.MINOR.PATCH-preview.N, got: $tag" >&2
exit 1
;;
esac
channel="stable"
notes_version="$tag"
fi
requested_channel="${IN_CHANNEL:-}"
if [ -n "$requested_channel" ]; then
case "$requested_channel" in
stable | preview) ;;
*)
echo "::error::CLI release channel must be stable or preview, got: $requested_channel" >&2
exit 1
;;
esac
if [ "$requested_channel" != "$channel" ]; then
echo "::error::CLI tag $tag belongs to $channel, not requested channel $requested_channel" >&2
exit 1
fi
fi
{
echo "tag=$tag"
echo "version=$version"
echo "base_version=$base_version"
echo "notes_version=$notes_version"
echo "channel=$channel"
echo "prerelease=$prerelease"
} >>"${GITHUB_OUTPUT:-/dev/stdout}"
echo "CLI release resolved: tag=$tag channel=$channel prerelease=$prerelease"