Files
apex/scripts/release.sh
s0wlz (Matthias Puchstein) f4566fa638 fix: release meta.yaml newlines
2025-12-31 06:17:21 +01:00

220 lines
4.6 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
usage() {
cat <<'EOF'
Usage: scripts/release.sh <version> [options]
Options:
--repo <slug> Gitea repo slug (default: auto-detect)
--login <name> tea login name (default: tea default)
--notes <text> Release notes (single line)
--notes-file <file> Release notes file (applies to all apps)
--notes-dir <dir> Per-app notes dir; uses <app>.md or common.md
--no-push Skip git push
--dry-run Print actions without executing
-h, --help Show this help
EOF
}
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
usage
exit 0
fi
version="${1:-}"
shift || true
if [[ -z "$version" ]]; then
usage
exit 1
fi
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "error: version must be semver (e.g., 1.2.3)"
exit 1
fi
repo=""
login=""
notes=""
notes_file=""
notes_dir=""
no_push=0
dry_run=0
while [[ $# -gt 0 ]]; do
case "$1" in
--repo)
repo="$2"
shift 2
;;
--login)
login="$2"
shift 2
;;
--notes)
notes="$2"
shift 2
;;
--notes-file)
notes_file="$2"
shift 2
;;
--notes-dir)
notes_dir="$2"
shift 2
;;
--no-push)
no_push=1
shift
;;
--dry-run)
dry_run=1
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "error: unknown option: $1"
usage
exit 1
;;
esac
done
run() {
if (( dry_run )); then
echo "+ $*"
else
"$@"
fi
}
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
echo "error: not inside a git repository"
exit 1
fi
if ! git diff --quiet || ! git diff --cached --quiet; then
echo "error: working tree not clean; commit or stash first"
exit 1
fi
if ! command -v tea >/dev/null 2>&1; then
echo "error: tea is not installed or not on PATH"
exit 1
fi
mapfile -t apps < <(python - <<'PY'
from pathlib import Path
apps = sorted({p.parent.name for p in Path("templates").rglob("meta.yaml")})
print("\n".join(apps))
PY
)
changed_apps=()
for app in "${apps[@]}"; do
last_tag="$(git tag --list "${app}-v*" --sort=-version:refname | head -n 1)"
if [[ -z "$last_tag" ]]; then
changed_apps+=("$app")
continue
fi
if git diff --name-only "${last_tag}..HEAD" | grep -Eq "^(src/|build.py$|templates/${app}/)"; then
changed_apps+=("$app")
fi
done
if (( ${#changed_apps[@]} == 0 )); then
echo "no app changes detected since last per-app tags; nothing to release"
exit 0
fi
if (( dry_run )); then
echo "+ update meta.yaml for: ${changed_apps[*]}"
else
APP_LIST="$(printf "%s\n" "${changed_apps[@]}")" APP_VERSION="${version}" python - <<'PY'
import os
from pathlib import Path
new_version = os.environ["APP_VERSION"]
targets = set(filter(None, os.environ["APP_LIST"].splitlines()))
for path in Path("templates").rglob("meta.yaml"):
if path.parent.name not in targets:
continue
text = path.read_text()
lines = text.splitlines()
out = []
changed = False
for line in lines:
if line.startswith("version:"):
out.append(f"version: {new_version}")
changed = True
else:
out.append(line)
if changed:
path.write_text("\n".join(out) + "\n")
PY
fi
if ! git diff --quiet; then
run git add templates/*/meta.yaml
run git commit -m "chore: release apps v${version}"
fi
run uv run build.py
run mkdir -p dist/releases
for app in "${changed_apps[@]}"; do
run tar -czf "dist/releases/apex-${app}-v${version}.tar.gz" -C dist "$app"
done
if (( no_push == 0 )); then
run git push origin HEAD
fi
commit="$(git rev-parse HEAD)"
note_args=()
pick_note_args() {
local app="$1"
note_args=()
if [[ -n "$notes_file" ]]; then
note_args=(--note-file "$notes_file")
return
fi
if [[ -n "$notes" ]]; then
note_args=(--note "$notes")
return
fi
if [[ -n "$notes_dir" ]]; then
if [[ -f "$notes_dir/$app.md" ]]; then
note_args=(--note-file "$notes_dir/$app.md")
return
fi
if [[ -f "$notes_dir/common.md" ]]; then
note_args=(--note-file "$notes_dir/common.md")
return
fi
fi
note_args=(--note "Release v${version}")
}
for app in "${changed_apps[@]}"; do
tag="${app}-v${version}"
title="Apex ${app} v${version}"
asset="dist/releases/apex-${app}-v${version}.tar.gz"
args=(tea releases create)
[[ -n "$repo" ]] && args+=(--repo "$repo")
[[ -n "$login" ]] && args+=(--login "$login")
args+=(--tag "$tag" --target "$commit" --title "$title")
pick_note_args "$app"
args+=("${note_args[@]}" --asset "$asset")
run "${args[@]}"
done