git status --porcelain ohne --untracked-files=no blockierte den Stable-Release wegen fremder, noch nicht committeter Arbeit in unversionierten Verzeichnissen (deploy/angie, internal/angie, internal/proxy, migrations) — die gehen ein Release nichts an, nur uncommittete Änderungen an bereits versionierten Dateien sollen blocken. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
185 lines
8.1 KiB
Bash
Executable File
185 lines
8.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# EdgeGuard — Release erstellen (Testing-Push oder Stable-Promotion)
|
|
#
|
|
# Verwendung:
|
|
# ./scripts/release.sh # Testing-Push: baut den aktuellen
|
|
# # Stand, Version = datumsbasiert
|
|
# # YYYY.MM.DD.NN, Upload → testing
|
|
# ./scripts/release.sh stable # Stable-Promotion: baut den
|
|
# # aktuellen Stand unter der
|
|
# # nächsten Patch-Version (VERSION-
|
|
# # Datei +1), Upload → stable,
|
|
# # VERSION-Commit + Git-Tag v<version>
|
|
# ./scripts/release.sh stable 1.4.0 # Stable mit expliziter Version
|
|
#
|
|
# Kanal-Modell 1:1 von enconf (netcell-webpanel) übernommen — Suite=trixie
|
|
# fest, Komponente=Kanal (stable/testing). An EdgeGuard angepasst:
|
|
# - Gates laufen über die bestehende Go-Quality-Baseline (`make deb` ruft
|
|
# `release-check` + `management-ui`-tsc automatisch auf) statt eigener
|
|
# Preflight-Schritte.
|
|
# - Kein Docs-/Changelog-/Checksum-/Marketing-Site-Deploy — dafür
|
|
# existiert bei EdgeGuard keine Infrastruktur (siehe CLAUDE.md).
|
|
# - Testing-Versionen sind datumsbasiert (wie enconf) DAMIT sie (a) bei
|
|
# apt immer über jeder Stable-Semver-Version sortieren und (b) nie mit
|
|
# einer Stable-Versionsnummer kollidieren — Gitea dedupliziert
|
|
# (Name,Version) global über alle Kanäle hinweg.
|
|
#
|
|
# Voraussetzung: GITEA_TOKEN (env oder ~/.gitea-token) mit Package-
|
|
# Upload/Delete/Query-Scope.
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
cd "$REPO_DIR"
|
|
|
|
OWNER="projekte"
|
|
GITEA_URL="https://git.netcell-it.de"
|
|
KEEP="${KEEP:-10}"
|
|
|
|
log() { echo "[release] $*"; }
|
|
warn() { echo " ⚠ $*" >&2; }
|
|
abort() { echo "🛑 ABBRUCH: $*" >&2; exit 1; }
|
|
|
|
if [ -z "${GITEA_TOKEN:-}" ]; then
|
|
if [ -r "$HOME/.gitea-token" ]; then
|
|
GITEA_TOKEN="$(tr -d '\n' < "$HOME/.gitea-token")"
|
|
else
|
|
abort "GITEA_TOKEN fehlt (env oder ~/.gitea-token)"
|
|
fi
|
|
fi
|
|
export GITEA_TOKEN
|
|
|
|
# ─── Testing-Version: datumsbasiert YYYY.MM.DD.NN ──────────────────────
|
|
# NN = laufende Nummer für den Tag, ermittelt aus den bereits im Registry
|
|
# vorhandenen Versionen des Meta-Pakets (edgeguard) mit dem heutigen
|
|
# Datumspräfix. Erster Release des Tages -> .01.
|
|
next_testing_version() {
|
|
local today
|
|
today="$(date -u +%Y.%m.%d)"
|
|
local raw
|
|
raw="$(curl -fsS -H "Authorization: token $GITEA_TOKEN" \
|
|
"$GITEA_URL/api/v1/packages/$OWNER?type=debian&q=edgeguard&limit=1000" 2>/dev/null || echo '[]')"
|
|
local last_n
|
|
last_n="$(printf '%s' "$raw" | jq -r --arg n "edgeguard" --arg pfx "${today}." \
|
|
'.[] | select(.name==$n) | .version | select(startswith($pfx))' \
|
|
| sed "s/^${today}\.//" | sort -n | tail -1)"
|
|
printf '%s.%02d' "$today" "$(( ${last_n:-0} + 1 ))"
|
|
}
|
|
|
|
# ─── Stable-Version: Patch-Bump der VERSION-Datei (Default) ────────────
|
|
bump_patch() {
|
|
local major minor patch
|
|
IFS='.' read -r major minor patch <<< "$1"
|
|
echo "${major}.${minor}.$((patch + 1))"
|
|
}
|
|
|
|
# ─── Alte Version im Ziel-Kanal ersetzen — Upload derselben Nummer würde
|
|
# sonst mit 409 den alten Inhalt behalten (Gitea dedupliziert (Name,
|
|
# Version,Arch,Kanal-Pool) — best-effort, 404 ist der Normalfall). ──────
|
|
delete_before_upload() {
|
|
local channel="$1" version="$2" name="$3" arch="$4"
|
|
local url="$GITEA_URL/api/packages/$OWNER/debian/pool/trixie/$channel/$name/$version/$arch"
|
|
curl -sS -o /dev/null -w '' -X DELETE -H "Authorization: token $GITEA_TOKEN" "$url" || true
|
|
}
|
|
|
|
replace_in_channel() {
|
|
local channel="$1" version="$2"
|
|
delete_before_upload "$channel" "$version" edgeguard-api amd64
|
|
delete_before_upload "$channel" "$version" edgeguard-api arm64
|
|
delete_before_upload "$channel" "$version" edgeguard-ui all
|
|
delete_before_upload "$channel" "$version" edgeguard all
|
|
}
|
|
|
|
# ─── verify_channel_debs — Health-Gate wie enconf verify_stable_debs ───
|
|
# Holt den Packages-Index eines Kanals und prüft für JEDE dort
|
|
# referenzierte .deb, ob sie unter ihrer Pool-URL wirklich mit HTTP 200
|
|
# abrufbar ist (nicht nur ob der Index existiert — Gitea regeneriert den
|
|
# Index nicht immer zuverlässig nach einem Delete).
|
|
verify_channel_debs() {
|
|
local channel="$1"
|
|
log "verify_channel_debs($channel): jede indexierte .deb muss abrufbar sein..."
|
|
local files f code bad=0 checked=0
|
|
files="$(curl -sk -H "Authorization: token $GITEA_TOKEN" \
|
|
"$GITEA_URL/api/packages/$OWNER/debian/dists/trixie/$channel/binary-amd64/Packages" 2>/dev/null \
|
|
| awk '/^Filename:/{print $2}')"
|
|
if [ -z "$files" ]; then
|
|
warn "$channel: Packages-Index leer/nicht erreichbar — übersprungen"
|
|
return 0
|
|
fi
|
|
while IFS= read -r f; do
|
|
[ -z "$f" ] && continue
|
|
checked=$((checked + 1))
|
|
code="$(curl -sk -o /dev/null -w '%{http_code}' \
|
|
-H "Authorization: token $GITEA_TOKEN" "$GITEA_URL/api/packages/$OWNER/debian/$f")"
|
|
if [ "$code" != "200" ]; then
|
|
warn "$channel: $f -> HTTP $code"
|
|
bad=$((bad + 1))
|
|
fi
|
|
done <<< "$files"
|
|
[ "$bad" -eq 0 ] || abort "$channel: $bad von $checked .deb(s) im Index nicht abrufbar — Registry inkonsistent."
|
|
log "$channel: $checked .deb(s) verifiziert, alle abrufbar."
|
|
}
|
|
|
|
# ─── Testing-Push ───────────────────────────────────────────────────────
|
|
testing_push() {
|
|
local new_version
|
|
new_version="$(next_testing_version)"
|
|
log "[testing 1/3] Gates + Build $new_version (make deb — release-check, amd64+arm64+ui)..."
|
|
make VERSION="$new_version" deb
|
|
|
|
log "[testing 2/3] Alte Version im testing-Kanal ersetzen + hochladen..."
|
|
replace_in_channel testing "$new_version"
|
|
./scripts/apt-repo/publish.sh "$new_version" amd64 testing
|
|
./scripts/apt-repo/publish.sh "$new_version" arm64 testing
|
|
|
|
log "[testing 3/3] Cleanup (keep last $KEEP) + Verify..."
|
|
KEEP="$KEEP" ./scripts/apt-repo/cleanup-old.sh testing
|
|
verify_channel_debs testing
|
|
|
|
log "✅ Testing-Release $new_version veröffentlicht."
|
|
}
|
|
|
|
# ─── Stable-Promotion ───────────────────────────────────────────────────
|
|
promote_stable() {
|
|
local explicit_version="${1:-}"
|
|
local current_version new_version
|
|
current_version="$(cat "$REPO_DIR/VERSION")"
|
|
new_version="${explicit_version:-$(bump_patch "$current_version")}"
|
|
|
|
git -C "$REPO_DIR" rev-parse "v$new_version" >/dev/null 2>&1 && \
|
|
abort "Git-Tag v$new_version existiert bereits."
|
|
# --untracked-files=no: nur versionierte Änderungen blocken. Das Repo
|
|
# kann fremde, noch nicht committete Arbeit in eigenen Verzeichnissen
|
|
# liegen haben (untracked) — die geht ein Stable-Release nichts an.
|
|
[ -n "$(git -C "$REPO_DIR" status --porcelain --untracked-files=no)" ] && \
|
|
abort "Uncommittete Änderungen an versionierten Dateien — commit/stash erst, dann Stable-Release."
|
|
|
|
log "[stable 1/4] Gates + Build $new_version (make deb — release-check, amd64+arm64+ui)..."
|
|
make VERSION="$new_version" deb
|
|
|
|
log "[stable 2/4] Alte Version im stable-Kanal ersetzen + hochladen..."
|
|
replace_in_channel stable "$new_version"
|
|
./scripts/apt-repo/publish.sh "$new_version" amd64 stable
|
|
./scripts/apt-repo/publish.sh "$new_version" arm64 stable
|
|
|
|
log "[stable 3/4] VERSION-Datei setzen + Commit + Git-Tag..."
|
|
printf '%s' "$new_version" > "$REPO_DIR/VERSION"
|
|
git -C "$REPO_DIR" add VERSION
|
|
git -C "$REPO_DIR" commit -m "chore(release): v$new_version stable"
|
|
git -C "$REPO_DIR" tag "v$new_version"
|
|
|
|
log "[stable 4/4] Cleanup (keep last $KEEP) + Verify..."
|
|
KEEP="$KEEP" ./scripts/apt-repo/cleanup-old.sh stable
|
|
verify_channel_debs stable
|
|
|
|
log "✅ Stable-Release v$new_version fertig."
|
|
log " Push nicht vergessen: git push origin main --tags"
|
|
}
|
|
|
|
case "${1:-}" in
|
|
stable) promote_stable "${2:-}" ;;
|
|
"") testing_push ;;
|
|
*) abort "unbekanntes Argument '$1' (erwartet: 'stable' oder kein Argument)" ;;
|
|
esac
|