261 lines
7.6 KiB
Bash
261 lines
7.6 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
usage() {
|
|
cat <<'USAGE'
|
|
Usage:
|
|
tools/release/publish-release-catalog.sh --version <x.y.z> --catalog-signing-key <key-id=/path/private.pem> [options]
|
|
|
|
Generates a signed module package catalog for a GovOPlaN release, writes it into
|
|
addideas-govoplan-website/public/catalogs/v1, validates it, optionally builds the website,
|
|
and optionally commits/tags/pushes addideas-govoplan-website.
|
|
|
|
Options:
|
|
--version <x.y.z> Release version without leading v.
|
|
--channel <name> Catalog channel. Defaults to stable.
|
|
--sequence <number> Monotonic channel sequence. Defaults to UTC timestamp.
|
|
--expires-days <days> Catalog expiry window. Defaults to 90.
|
|
--catalog-signing-key <key-id=/path/private.pem>
|
|
Ed25519 private key. May be repeated for rotation.
|
|
--core-root <path> govoplan-core checkout. Defaults to ../govoplan-core.
|
|
--web-root <path> addideas-govoplan-website checkout. Defaults to ../addideas-govoplan-website.
|
|
--public-base-url <url> Public website URL. Defaults to https://govoplan.add-ideas.de.
|
|
--npm <path> npm executable used for optional web build.
|
|
--build-web Run npm run build in addideas-govoplan-website after generating files.
|
|
--commit Commit generated catalog files in addideas-govoplan-website.
|
|
--tag Tag addideas-govoplan-website with catalog-v<x.y.z>. Implies --commit.
|
|
--push Push addideas-govoplan-website branch and tag. Implies --commit.
|
|
--remote <name> Git remote for push. Defaults to origin.
|
|
--branch <name> Branch to push. Defaults to current addideas-govoplan-website branch.
|
|
-n, --dry-run Print commands and validate inputs without writing git changes.
|
|
-h, --help Show this help.
|
|
USAGE
|
|
}
|
|
|
|
fail() {
|
|
echo "error: $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
META_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
PARENT="$(dirname "$META_ROOT")"
|
|
CORE_ROOT="${GOVOPLAN_CORE_ROOT:-$PARENT/govoplan-core}"
|
|
CORE_ROOT="$(cd "$CORE_ROOT" && pwd)"
|
|
WEB_ROOT="$PARENT/addideas-govoplan-website"
|
|
VERSION=""
|
|
CHANNEL="stable"
|
|
SEQUENCE=""
|
|
EXPIRES_DAYS="90"
|
|
PUBLIC_BASE_URL="https://govoplan.add-ideas.de"
|
|
REMOTE="origin"
|
|
BRANCH=""
|
|
BUILD_WEB=0
|
|
COMMIT=0
|
|
TAG_WEB=0
|
|
PUSH=0
|
|
DRY_RUN=0
|
|
SIGNING_KEYS=()
|
|
NPM_BIN="${NPM:-}"
|
|
|
|
if [[ -z "${PYTHON:-}" ]]; then
|
|
if [[ -x "$META_ROOT/.venv/bin/python" ]]; then
|
|
PYTHON="$META_ROOT/.venv/bin/python"
|
|
else
|
|
PYTHON="python3"
|
|
fi
|
|
fi
|
|
|
|
if [[ -z "$NPM_BIN" ]]; then
|
|
if [[ -x "/home/zemion/.nvm/versions/node/v22.22.3/bin/npm" ]]; then
|
|
NPM_BIN="/home/zemion/.nvm/versions/node/v22.22.3/bin/npm"
|
|
else
|
|
NPM_BIN="npm"
|
|
fi
|
|
fi
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--version)
|
|
[[ $# -ge 2 ]] || fail "missing value for $1"
|
|
VERSION="${2#v}"
|
|
shift 2
|
|
;;
|
|
--channel)
|
|
[[ $# -ge 2 ]] || fail "missing value for $1"
|
|
CHANNEL="$2"
|
|
shift 2
|
|
;;
|
|
--sequence)
|
|
[[ $# -ge 2 ]] || fail "missing value for $1"
|
|
SEQUENCE="$2"
|
|
shift 2
|
|
;;
|
|
--expires-days)
|
|
[[ $# -ge 2 ]] || fail "missing value for $1"
|
|
EXPIRES_DAYS="$2"
|
|
shift 2
|
|
;;
|
|
--catalog-signing-key)
|
|
[[ $# -ge 2 ]] || fail "missing value for $1"
|
|
SIGNING_KEYS+=("$2")
|
|
shift 2
|
|
;;
|
|
--core-root)
|
|
[[ $# -ge 2 ]] || fail "missing value for $1"
|
|
CORE_ROOT="$(cd "$2" && pwd)"
|
|
shift 2
|
|
;;
|
|
--web-root)
|
|
[[ $# -ge 2 ]] || fail "missing value for $1"
|
|
WEB_ROOT="$(cd "$2" && pwd)"
|
|
shift 2
|
|
;;
|
|
--public-base-url)
|
|
[[ $# -ge 2 ]] || fail "missing value for $1"
|
|
PUBLIC_BASE_URL="$2"
|
|
shift 2
|
|
;;
|
|
--npm)
|
|
[[ $# -ge 2 ]] || fail "missing value for $1"
|
|
NPM_BIN="$2"
|
|
shift 2
|
|
;;
|
|
--build-web)
|
|
BUILD_WEB=1
|
|
shift
|
|
;;
|
|
--commit)
|
|
COMMIT=1
|
|
shift
|
|
;;
|
|
--tag)
|
|
TAG_WEB=1
|
|
COMMIT=1
|
|
shift
|
|
;;
|
|
--push)
|
|
PUSH=1
|
|
COMMIT=1
|
|
shift
|
|
;;
|
|
--remote)
|
|
[[ $# -ge 2 ]] || fail "missing value for $1"
|
|
REMOTE="$2"
|
|
shift 2
|
|
;;
|
|
--branch)
|
|
[[ $# -ge 2 ]] || fail "missing value for $1"
|
|
BRANCH="$2"
|
|
shift 2
|
|
;;
|
|
-n|--dry-run)
|
|
DRY_RUN=1
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown argument: $1" >&2
|
|
usage >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|
|
|
|
[[ -n "$VERSION" ]] || fail "--version is required"
|
|
[[ "$VERSION" =~ ^[0-9]+[.][0-9]+[.][0-9]+$ ]] || fail "version must be x.y.z: $VERSION"
|
|
[[ ${#SIGNING_KEYS[@]} -gt 0 ]] || fail "at least one --catalog-signing-key is required"
|
|
[[ -d "$CORE_ROOT/.git" ]] || fail "not a govoplan-core git repo: $CORE_ROOT"
|
|
[[ -d "$WEB_ROOT/.git" ]] || fail "not an addideas-govoplan-website git repo: $WEB_ROOT"
|
|
command -v "$PYTHON" >/dev/null 2>&1 || fail "Python not found: $PYTHON"
|
|
|
|
if [[ "$BUILD_WEB" -eq 1 ]]; then
|
|
command -v "$NPM_BIN" >/dev/null 2>&1 || fail "npm not found: $NPM_BIN"
|
|
fi
|
|
|
|
if [[ -z "$BRANCH" ]]; then
|
|
BRANCH="$(git -C "$WEB_ROOT" symbolic-ref --quiet --short HEAD || true)"
|
|
fi
|
|
[[ -n "$BRANCH" ]] || fail "cannot infer addideas-govoplan-website branch; pass --branch"
|
|
|
|
CATALOG_PATH="$WEB_ROOT/public/catalogs/v1/channels/$CHANNEL.json"
|
|
KEYRING_PATH="$WEB_ROOT/public/catalogs/v1/keyring.json"
|
|
TAG_NAME="catalog-v$VERSION"
|
|
|
|
run() {
|
|
printf '+'
|
|
printf ' %q' "$@"
|
|
printf '\n'
|
|
if [[ "$DRY_RUN" -eq 0 ]]; then
|
|
"$@"
|
|
fi
|
|
}
|
|
|
|
GEN_ARGS=(
|
|
"$PYTHON" "$META_ROOT/tools/release/generate-release-catalog.py"
|
|
--version "$VERSION"
|
|
--channel "$CHANNEL"
|
|
--expires-days "$EXPIRES_DAYS"
|
|
--catalog-output "$CATALOG_PATH"
|
|
--keyring-output "$KEYRING_PATH"
|
|
--public-base-url "$PUBLIC_BASE_URL"
|
|
)
|
|
if [[ -n "$SEQUENCE" ]]; then
|
|
GEN_ARGS+=(--sequence "$SEQUENCE")
|
|
fi
|
|
for signing_key in "${SIGNING_KEYS[@]}"; do
|
|
GEN_ARGS+=(--catalog-signing-key "$signing_key")
|
|
done
|
|
|
|
run "${GEN_ARGS[@]}"
|
|
|
|
if [[ "$DRY_RUN" -eq 0 ]]; then
|
|
GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_FILE="$KEYRING_PATH" \
|
|
"$PYTHON" -m govoplan_core.commands.module_installer \
|
|
--validate-package-catalog "$CATALOG_PATH" \
|
|
--require-signed-catalog \
|
|
--approved-catalog-channel "$CHANNEL" \
|
|
--format json >/dev/null
|
|
else
|
|
echo "+ GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_FILE=$KEYRING_PATH $PYTHON -m govoplan_core.commands.module_installer --validate-package-catalog $CATALOG_PATH --require-signed-catalog --approved-catalog-channel $CHANNEL --format json"
|
|
fi
|
|
|
|
if [[ "$BUILD_WEB" -eq 1 ]]; then
|
|
run env PATH="$(dirname "$NPM_BIN"):$PATH" "$NPM_BIN" --prefix "$WEB_ROOT" run build
|
|
fi
|
|
|
|
if [[ "$COMMIT" -eq 1 ]]; then
|
|
run git -C "$WEB_ROOT" add "$CATALOG_PATH" "$KEYRING_PATH"
|
|
if [[ "$DRY_RUN" -eq 0 ]]; then
|
|
if git -C "$WEB_ROOT" diff --cached --quiet; then
|
|
echo "No addideas-govoplan-website catalog changes to commit."
|
|
else
|
|
run git -C "$WEB_ROOT" commit -m "Publish GovOPlaN v$VERSION $CHANNEL catalog"
|
|
fi
|
|
else
|
|
run git -C "$WEB_ROOT" commit -m "Publish GovOPlaN v$VERSION $CHANNEL catalog"
|
|
fi
|
|
fi
|
|
|
|
if [[ "$TAG_WEB" -eq 1 ]]; then
|
|
if git -C "$WEB_ROOT" rev-parse --quiet --verify "refs/tags/$TAG_NAME" >/dev/null; then
|
|
fail "addideas-govoplan-website tag already exists: $TAG_NAME"
|
|
fi
|
|
run git -C "$WEB_ROOT" tag -a "$TAG_NAME" -m "Publish GovOPlaN v$VERSION $CHANNEL catalog"
|
|
fi
|
|
|
|
if [[ "$PUSH" -eq 1 ]]; then
|
|
if [[ "$TAG_WEB" -eq 1 ]]; then
|
|
run git -C "$WEB_ROOT" push --atomic "$REMOTE" "HEAD:refs/heads/$BRANCH" "refs/tags/$TAG_NAME"
|
|
else
|
|
run git -C "$WEB_ROOT" push "$REMOTE" "HEAD:refs/heads/$BRANCH"
|
|
fi
|
|
fi
|
|
|
|
echo "Catalog ready:"
|
|
echo " $CATALOG_PATH"
|
|
echo " $KEYRING_PATH"
|
|
echo " URL: $PUBLIC_BASE_URL/catalogs/v1/channels/$CHANNEL.json"
|