From 0ca212dd4c454a1c31ad83f5b21617e7e2169e08 Mon Sep 17 00:00:00 2001 From: sylyx Date: Wed, 3 Jun 2026 15:14:15 +0200 Subject: [PATCH] Release-Skript: ATN-Signierung (unlisted) + Gitea-Release + Auto-Update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit scripts/release.sh signiert die Extension via web-ext gegen addons.thunderbird.net (Kanal unlisted, also signiert aber nicht öffentlich gelistet), lädt das XPI als Gitea-Release hoch und trägt es in updates.json ein. web-ext wird global genutzt oder per npx (kein globales Install nötig). Secrets kommen aus scripts/.env (gitignored); .env.example als Vorlage. Co-Authored-By: Claude Opus 4.8 --- .gitignore | 5 ++ scripts/.env.example | 15 +++++ scripts/release.sh | 149 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 scripts/.env.example create mode 100755 scripts/release.sh diff --git a/.gitignore b/.gitignore index bd4a537..6dd1024 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,11 @@ settings*.json # Build-Artefakte (das signierte XPI wird als Gitea-Release verteilt, nicht im Repo) *.xpi +web-ext-artifacts/ + +# Release-Secrets (ATN-/Gitea-Token) – NIE committen! +scripts/.env +.env # No docs files docs/ diff --git a/scripts/.env.example b/scripts/.env.example new file mode 100644 index 0000000..836885c --- /dev/null +++ b/scripts/.env.example @@ -0,0 +1,15 @@ +# Vorlage für scripts/.env – Kopieren nach scripts/.env und ausfüllen. +# scripts/.env ist gitignored und darf NIE committet werden. + +# addons.thunderbird.net → Entwicklerbereich → "Manage API Keys" +ATN_API_KEY="user:000000:000" +ATN_API_SECRET="dein-atn-secret" + +# Gitea → Settings → Applications → Generate New Token (Scope: write:repository) +GITEA_TOKEN="dein-gitea-token" + +# Optional – sonst aus dem git-Remote "origin" abgeleitet: +# GITEA_BASE="https://sylyx.xyz" +# GITEA_OWNER="sylyx" +# GITEA_REPO="thunderbird2docuware" +# REPO_DIR="/pfad/zum/repo" # nur nötig, wenn release.sh außerhalb des Repos liegt diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 0000000..cbcf3cf --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env bash +# +# release.sh – signiert die Extension bei addons.thunderbird.net (Kanal "unlisted", +# also signiert ABER nicht öffentlich gelistet), lädt das signierte XPI als +# Gitea-Release hoch und trägt es in updates.json fürs Auto-Update ein. +# +# Benötigt: bash, node, npx, curl, git. web-ext wird genutzt, wenn global +# installiert; sonst automatisch via "npx web-ext" (kein globales Install nötig). +# +# Secrets kommen aus der Umgebung bzw. aus scripts/.env (gitignored, NIE committen): +# ATN_API_KEY – API-Schlüssel von addons.thunderbird.net (Entwicklerbereich) +# ATN_API_SECRET – zugehöriges Secret +# 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 # nutzt die Version aus manifest.json +# scripts/release.sh 0.9.0 # setzt zuerst diese Version in manifest.json +# +set -euo pipefail + +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 +# web-ext: global installiert bevorzugen, sonst per npx (kein globales Install nötig). +if command -v web-ext >/dev/null 2>&1; then + WEBEXT="web-ext" +else + need npx + WEBEXT="npx --yes web-ext" +fi +[ -f "$MANIFEST" ] || die "manifest.json nicht gefunden ($MANIFEST). Ggf. REPO_DIR setzen." +[ -f "$UPDATES" ] || die "updates.json nicht gefunden ($UPDATES)." +: "${ATN_API_KEY:?ATN_API_KEY fehlt (scripts/.env oder Umgebung)}" +: "${ATN_API_SECRET:?ATN_API_SECRET fehlt}" +: "${GITEA_TOKEN:?GITEA_TOKEN fehlt}" + +# --- 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) Signieren (zuerst – schlägt hier fehl, bevor irgendwas gepusht wird) --- +echo "→ Signiere bei addons.thunderbird.net (unlisted) …" +rm -f "$ARTIFACTS"/*.xpi 2>/dev/null || true +$WEBEXT sign \ + --channel=unlisted \ + --api-url-prefix="https://addons.thunderbird.net/api/v4" \ + --api-key="$ATN_API_KEY" \ + --api-secret="$ATN_API_SECRET" \ + --source-dir="$REPO_DIR" \ + --artifacts-dir="$ARTIFACTS" \ + --ignore-files "web-ext-artifacts/**" "scripts/**" "docs/**" "*.md" "*.xpi" \ + ".git/**" ".gitignore" "*.env" ".env" + +SIGNED="$(ls -t "$ARTIFACTS"/*.xpi 2>/dev/null | head -1)" +[ -n "${SIGNED:-}" ] && [ -f "$SIGNED" ] || die "Kein signiertes XPI in $ARTIFACTS gefunden." +cp -f "$SIGNED" "$ARTIFACTS/$XPI_NAME" +echo "✓ Signiert: $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."