release-kit 0.2.9

A canonical release workflow: a technology-agnostic method, per-technology bindings, and the rk CLI that lands and serves them.
Documentation
#!/usr/bin/env sh
# Prove the bot credential is stored on the project, and overwrite it when a
# replacement is supplied: a rotated credential must be able to replace an
# old one. install-bot stores the token at creation, because the create
# response is the only time the forge shows its value; this step is the
# rotation path and the assertion. The value travels on standard input, and
# printf is a shell builtin, so no process argument list ever holds it.
set -eu
: "${RK_REPO:?rk sets this; run this script through rk setup}"

project="$(printf '%s' "$RK_REPO" | sed 's|/|%2F|g')"

# The forge CLI may pretty-print JSON; stripping whitespace makes every
# pattern below hold for the compact and the pretty form alike, and no
# value a pattern touches can carry whitespace of its own.
compact() { tr -d ' \t\r\n'; }

if [ -n "${RK_BOT_TOKEN:-}" ]; then
  if glab api "projects/$project/variables/RELEASE_BOT_TOKEN" >/dev/null 2>&1; then
    printf '%s' "$RK_BOT_TOKEN" | glab variable update RELEASE_BOT_TOKEN --masked --repo "$RK_REPO"
  else
    printf '%s' "$RK_BOT_TOKEN" | glab variable set RELEASE_BOT_TOKEN --masked --repo "$RK_REPO"
  fi
  echo 'ok RELEASE_BOT_TOKEN overwritten from RK_BOT_TOKEN'
elif ! glab api "projects/$project/variables/RELEASE_BOT_TOKEN" >/dev/null 2>&1; then
  echo 'FAIL RELEASE_BOT_TOKEN is not stored on the project' >&2
  echo 'remediation: rk setup step install-bot --apply creates and stores it' >&2
  exit 1
fi

echo 'check: prints the variable key'
glab api "projects/$project/variables/RELEASE_BOT_TOKEN" | compact | grep -o '"key":"RELEASE_BOT_TOKEN"'