| 1 | #!/usr/bin/env bash |
| 2 | # Resolve and validate one native CLI release tag. Manual recovery exposes only |
| 3 | # official versions; prerelease parsing remains for historical workflow calls. |
| 4 | set -euo pipefail |
| 5 | |
| 6 | stable_semver_re='(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)' |
| 7 | release_semver_re="^v${stable_semver_re}(-([0-9A-Za-z-]+)(\.[0-9A-Za-z-]+)*)?)?$" |
| 8 | preview_semver_re="^v${stable_semver_re}-preview\.(0|[1-9][0-9]*)$" |
| 9 | |
| 10 | if [ "${IN_ORCHESTRATED:-false}" = "true" ]; then |
| 11 | tag="${IN_TAG:?orchestrated CLI release requires tag}" |
| 12 | else |
| 13 | if [ "${EVENT_NAME:-}" = "workflow_dispatch" ]; then |
| 14 | if [ "${CALLER_REF:-}" != "refs/heads/main-v2" ] || [ "${CALLER_REF_PROTECTED:-}" != "true" ]; then |
| 15 | echo "::error::manual CLI releases must run from protected main-v2" >&2 |
| 16 | exit 1 |
| 17 | fi |
| 18 | tag="${IN_TAG:?manual CLI release requires an existing protected tag}" |
| 19 | else |
| 20 | tag="${REF_NAME:?CLI tag push requires ref name}" |
| 21 | fi |
| 22 | fi |
| 23 | |
| 24 | if [[ ! "$tag" =~ $release_semver_re ]]; then |
| 25 | echo "::error::CLI release tag must be vMAJOR.MINOR.PATCH[-PRERELEASE], got: $tag" >&2 |
| 26 | exit 1 |
| 27 | fi |
| 28 | |
| 29 | base_version="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.${BASH_REMATCH[3]}" |
| 30 | version="${tag#v}" |
| 31 | case "$version" in |
| 32 | *-*) prerelease="true" ;; |
| 33 | *) prerelease="false" ;; |
| 34 | esac |
| 35 | |
| 36 | if [ "${EVENT_NAME:-}" = "workflow_dispatch" ] && \ |
| 37 | [ "${IN_ORCHESTRATED:-false}" != "true" ] && [ "$prerelease" = "true" ]; then |
| 38 | echo "::error::manual CLI recovery accepts only vMAJOR.MINOR.PATCH" >&2 |
| 39 | exit 1 |
| 40 | fi |
| 41 | |
| 42 | if [[ "$tag" =~ $preview_semver_re ]]; then |
| 43 | channel="preview" |
| 44 | notes_version="$tag" |
| 45 | else |
| 46 | case "$tag" in |
| 47 | v*-preview*) |
| 48 | echo "::error::CLI Preview tag must be vMAJOR.MINOR.PATCH-preview.N, got: $tag" >&2 |
| 49 | exit 1 |
| 50 | ;; |
| 51 | esac |
| 52 | channel="stable" |
| 53 | case "$version" in |
| 54 | *-*) notes_version="v${base_version}" ;; |
| 55 | *) notes_version="$tag" ;; |
| 56 | esac |
| 57 | fi |
| 58 | |
| 59 | requested_channel="${IN_CHANNEL:-}" |
| 60 | if [ -n "$requested_channel" ]; then |
| 61 | case "$requested_channel" in |
| 62 | stable | preview) ;; |
| 63 | *) |
| 64 | echo "::error::CLI release channel must be stable or preview, got: $requested_channel" >&2 |
| 65 | exit 1 |
| 66 | ;; |
| 67 | esac |
| 68 | if [ "$requested_channel" != "$channel" ]; then |
| 69 | echo "::error::CLI tag $tag belongs to $channel, not requested channel $requested_channel" >&2 |
| 70 | exit 1 |
| 71 | fi |
| 72 | fi |
| 73 | |
| 74 | if [ "$channel" = "preview" ] && [ "${IN_ORCHESTRATED:-false}" != "true" ]; then |
| 75 | echo "::error::public CLI Preview releases must be dispatched by release-preview.yml" >&2 |
| 76 | exit 1 |
| 77 | fi |
| 78 | |
| 79 | { |
| 80 | echo "tag=$tag" |
| 81 | echo "version=$version" |
| 82 | echo "base_version=$base_version" |
| 83 | echo "notes_version=$notes_version" |
| 84 | echo "channel=$channel" |
| 85 | echo "prerelease=$prerelease" |
| 86 | } >>"${GITHUB_OUTPUT:-/dev/stdout}" |
| 87 | |
| 88 | echo "CLI release resolved: tag=$tag channel=$channel prerelease=$prerelease" |
| 89 |