thunderbird2docuware/scripts/release.sh

172 lines
7.8 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
#
# release.sh baut ein sauberes XPI, lädt es als Gitea-Release hoch und trägt es
# in updates.json fürs Auto-Update ein.
#
# KEIN Signieren: Thunderbird verlangt für self-distributed Add-ons keine
# Mozilla-Signatur, und addons.thunderbird.net (ATN) zeichnet Thunderbird-Add-ons
# ohnehin nicht gegen (jede Version bleibt `signed=false`; "web-ext sign" scheitert
# mit "no signed files were found"). Wir verteilen also das unsignierte XPI direkt
# über Gitea genau wie schon 0.8.0, das nie bei ATN war.
#
# WICHTIG fürs Auto-Update: update_url und Release-Asset müssen ANONYM (ohne Login)
# erreichbar sein. Bei Gitea heißt das: Repo öffentlich UND instanzweit
# REQUIRE_SIGNIN_VIEW=false (in app.ini). Sonst bekommt Thunderbird beim Update-Check
# nur die Login-Seite und aktualisiert nie.
#
# Benötigt: bash, node, curl, git. Zum Bauen zusätzlich npx (web-ext); im --xpi-Modus
# nicht nötig.
#
# Secrets kommen aus der Umgebung bzw. aus scripts/.env (gitignored, NIE committen):
# GITEA_TOKEN Gitea Personal Access Token (Scope: write:repository)
# Optionale Overrides (sonst aus dem git-Remote "origin" abgeleitet):
# GITEA_BASE, GITEA_OWNER, GITEA_REPO, REPO_DIR
#
# Aufruf:
# scripts/release.sh # baut sauberes XPI, Version aus manifest.json
# scripts/release.sh 0.9.0 # setzt zuerst diese Version, dann bauen
# scripts/release.sh --xpi <datei.xpi> # fertiges XPI/ZIP veröffentlichen (kein Build)
# scripts/release.sh --xpi <datei.xpi> 0.9.0
#
# Verifikation nach jedem Release (anonym, wie Thunderbird):
# curl -L .../raw/branch/main/updates.json → muss JSON liefern, nicht die Login-Seite
# curl -L .../releases/download/vX/...xpi → Content-Type application/octet-stream
#
set -euo pipefail
# --- Argumente: optional vorsigniertes XPI (--xpi) --------------------------
PRESIGNED=""
if [ "${1:-}" = "--xpi" ]; then
PRESIGNED="${2:-}"; shift 2
[ -n "$PRESIGNED" ] && [ -f "$PRESIGNED" ] || { echo "FEHLER: --xpi braucht eine existierende Datei." >&2; exit 1; }
fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# .env (falls vorhanden) laden liefert die Secrets, ohne sie ins Repo zu schreiben.
if [ -f "$SCRIPT_DIR/.env" ]; then
set -a; . "$SCRIPT_DIR/.env"; set +a
fi
# Projektwurzel: Standard = ein Ordner über diesem Skript. Bei abweichendem Ort
# REPO_DIR setzen. Es muss eine manifest.json enthalten.
REPO_DIR="${REPO_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
MANIFEST="$REPO_DIR/manifest.json"
UPDATES="$REPO_DIR/updates.json"
ARTIFACTS="$REPO_DIR/web-ext-artifacts"
die() { echo "FEHLER: $*" >&2; exit 1; }
need() { command -v "$1" >/dev/null 2>&1 || die "'$1' nicht gefunden. Bitte installieren."; }
# --- Vorbedingungen -----------------------------------------------------------
need node; need curl; need git
[ -f "$MANIFEST" ] || die "manifest.json nicht gefunden ($MANIFEST). Ggf. REPO_DIR setzen."
[ -f "$UPDATES" ] || die "updates.json nicht gefunden ($UPDATES)."
: "${GITEA_TOKEN:?GITEA_TOKEN fehlt (scripts/.env oder Umgebung)}"
if [ -z "$PRESIGNED" ]; then
# Sauberes Paket wird mit "web-ext build" erzeugt (kein Signieren, daher
# versionsunabhängig). Per WEBEXT_CMD überschreibbar.
need npx
WEBEXT="${WEBEXT_CMD:-npx --yes web-ext}"
fi
# --- Version setzen / lesen ---------------------------------------------------
if [ "${1:-}" ]; then
node -e 'const fs=require("fs"),p=process.argv[1],v=process.argv[2];
const m=JSON.parse(fs.readFileSync(p,"utf8"));m.version=v;
fs.writeFileSync(p,JSON.stringify(m,null,2)+"\n");' "$MANIFEST" "$1"
echo "manifest.json → Version $1"
fi
VERSION="$(node -p "require('$MANIFEST').version")"
ADDON_ID="$(node -p "require('$MANIFEST').applications.gecko.id")"
[ -n "$VERSION" ] && [ -n "$ADDON_ID" ] || die "Version/Add-on-ID konnten nicht gelesen werden."
TAG="v${VERSION}"
XPI_NAME="docuware-ablage-${VERSION}.xpi"
# --- Gitea-Koordinaten aus dem Remote ableiten (oder per Env überschreiben) ---
REMOTE_URL="$(git -C "$REPO_DIR" remote get-url origin)"
case "$REMOTE_URL" in
git@*) host="${REMOTE_URL#git@}"; host="${host%%:*}"; path="${REMOTE_URL#*:}";;
ssh://*) rest="${REMOTE_URL#ssh://}"; rest="${rest#*@}"; host="${rest%%/*}"; path="${rest#*/}";;
http://*|https://*) rest="${REMOTE_URL#*://}"; host="${rest%%/*}"; path="${rest#*/}";;
*) die "Remote-URL-Form nicht erkannt: $REMOTE_URL";;
esac
path="${path%.git}"
GITEA_BASE="${GITEA_BASE:-https://$host}"
GITEA_OWNER="${GITEA_OWNER:-${path%%/*}}"
GITEA_REPO="${GITEA_REPO:-${path#*/}}"
API="$GITEA_BASE/api/v1/repos/$GITEA_OWNER/$GITEA_REPO"
BRANCH="$(git -C "$REPO_DIR" rev-parse --abbrev-ref HEAD)"
UPDATE_LINK="$GITEA_BASE/$GITEA_OWNER/$GITEA_REPO/releases/download/$TAG/$XPI_NAME"
echo "Release $VERSION (Add-on $ADDON_ID)"
echo " Gitea : $GITEA_BASE/$GITEA_OWNER/$GITEA_REPO (Branch $BRANCH)"
echo " Asset : $UPDATE_LINK"
# --- 1) XPI besorgen: fertiges Paket (--xpi) oder sauber selbst bauen -----------
mkdir -p "$ARTIFACTS"
if [ -n "$PRESIGNED" ]; then
echo "→ Nutze fertiges Paket: $PRESIGNED"
cp -f "$PRESIGNED" "$ARTIFACTS/$XPI_NAME"
else
echo "→ Baue sauberes XPI (web-ext build) …"
rm -f "$ARTIFACTS"/*.zip "$ARTIFACTS"/*.xpi 2>/dev/null || true
# --ignore-files hält Secrets/Build-Kram raus: scripts/ (mit .env!), docs/,
# web-ext-artifacts/, *.md, *.xpi, git-Kram und updates.json (gehört NICHT ins XPI).
$WEBEXT build \
--source-dir="$REPO_DIR" \
--artifacts-dir="$ARTIFACTS" \
--overwrite-dest \
--ignore-files "web-ext-artifacts/**" "scripts/**" "docs/**" "*.md" "*.xpi" \
".git/**" ".gitignore" "*.env" ".env" "updates.json"
BUILT="$(ls -t "$ARTIFACTS"/*.zip 2>/dev/null | head -1)"
[ -n "${BUILT:-}" ] && [ -f "$BUILT" ] || die "Kein Paket in $ARTIFACTS gebaut."
cp -f "$BUILT" "$ARTIFACTS/$XPI_NAME"
fi
echo "✓ XPI bereit: $ARTIFACTS/$XPI_NAME"
# --- 2) updates.json patchen --------------------------------------------------
node -e 'const fs=require("fs");
const [p,id,ver,link]=process.argv.slice(1);
const j=JSON.parse(fs.readFileSync(p,"utf8"));
j.addons=j.addons||{}; j.addons[id]=j.addons[id]||{updates:[]};
const u=j.addons[id].updates=j.addons[id].updates||[];
const e={version:ver,update_link:link}, i=u.findIndex(x=>x.version===ver);
if(i>=0)u[i]=e; else u.push(e);
fs.writeFileSync(p, JSON.stringify(j,null,2)+"\n");' \
"$UPDATES" "$ADDON_ID" "$VERSION" "$UPDATE_LINK"
echo "✓ updates.json aktualisiert"
# --- 3) Version + updates.json committen und pushen ---------------------------
git -C "$REPO_DIR" add manifest.json updates.json
if ! git -C "$REPO_DIR" diff --cached --quiet; then
git -C "$REPO_DIR" commit -m "Release $VERSION"
fi
git -C "$REPO_DIR" push origin "$BRANCH"
echo "✓ committed & gepusht"
# --- 4) Gitea-Release anlegen (oder vorhandenes nehmen) + XPI hochladen -------
echo "→ Lege Gitea-Release $TAG an …"
gitea() { curl -fsS -H "Authorization: token $GITEA_TOKEN" "$@"; }
REL_JSON="$(gitea -X POST "$API/releases" -H "Content-Type: application/json" \
-d "{\"tag_name\":\"$TAG\",\"target_commitish\":\"$BRANCH\",\"name\":\"$TAG\",\"body\":\"DocuWare Ablage $VERSION\"}" \
2>/dev/null || true)"
if [ -z "$REL_JSON" ]; then
echo " (Release/Tag existiert evtl. schon hole vorhandenes)"
REL_JSON="$(gitea "$API/releases/tags/$TAG")"
fi
RELEASE_ID="$(printf '%s' "$REL_JSON" | node -p "JSON.parse(require('fs').readFileSync(0,'utf8')).id")"
[ -n "$RELEASE_ID" ] || die "Konnte Release-ID nicht ermitteln."
echo "→ Lade $XPI_NAME hoch …"
gitea -X POST "$API/releases/$RELEASE_ID/assets?name=$XPI_NAME" \
-F "attachment=@$ARTIFACTS/$XPI_NAME;type=application/x-xpinstall" >/dev/null \
|| die "Asset-Upload fehlgeschlagen (existiert der Asset-Name schon? Dann altes Asset löschen)."
echo
echo "✓ Release $VERSION fertig."
echo " Download : $UPDATE_LINK"
echo " Auto-Update zieht beim nächsten Thunderbird-Check."