#!/usr/bin/env bash # Release a new signed XPI, update dist/updates.json, and prepare a commit. # Requires: WEB_EXT_API_KEY, WEB_EXT_API_SECRET (AMO JWT credentials). # # Usage: # bin/release.sh patch # 0.1.0 -> 0.1.1 # bin/release.sh minor # 0.1.0 -> 0.2.0 # bin/release.sh major # 0.1.0 -> 1.0.0 # bin/release.sh 1.2.3 # explicit version set -euo pipefail BUMP="${1:-patch}" REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" cd "$REPO_ROOT" ADDON_ID="autotrader-marker@tony.codes" RAW_BASE="https://git.nocker.cloud/tony/autotrader-marker/raw/branch/main/dist" : "${WEB_EXT_API_KEY:?WEB_EXT_API_KEY is required (AMO JWT issuer)}" : "${WEB_EXT_API_SECRET:?WEB_EXT_API_SECRET is required (AMO JWT secret)}" # --- Compute next version --- CURRENT=$(node -p "require('./manifest.json').version") if [[ "$BUMP" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then NEXT="$BUMP" else NEXT=$(node -e " const [maj,min,pat] = require('./manifest.json').version.split('.').map(Number); const bump = process.argv[1]; let v; if (bump === 'major') v = [maj+1, 0, 0]; else if (bump === 'minor') v = [maj, min+1, 0]; else v = [maj, min, pat+1]; console.log(v.join('.')); " "$BUMP") fi echo "→ Bumping $CURRENT → $NEXT" # --- Write version to manifest.json and package.json --- node -e " const fs = require('fs'); for (const f of ['manifest.json','package.json']) { const j = JSON.parse(fs.readFileSync(f, 'utf8')); j.version = process.argv[1]; fs.writeFileSync(f, JSON.stringify(j, null, 2) + '\n'); } " "$NEXT" # --- Sign via AMO --- ARTIFACTS_DIR="$REPO_ROOT/.web-ext-artifacts" rm -rf "$ARTIFACTS_DIR" mkdir -p "$ARTIFACTS_DIR" echo "→ Signing via AMO (unlisted channel)" npx --yes web-ext sign \ --source-dir="$REPO_ROOT" \ --artifacts-dir="$ARTIFACTS_DIR" \ --channel=unlisted \ --api-key="$WEB_EXT_API_KEY" \ --api-secret="$WEB_EXT_API_SECRET" \ --ignore-files "node_modules/**" "dist/**" "bin/**" "package.json" "package-lock.json" "README.md" ".gitignore" # --- Move signed XPI to dist/ with a predictable name --- SIGNED_XPI=$(find "$ARTIFACTS_DIR" -name '*.xpi' -type f | head -1) if [[ -z "$SIGNED_XPI" ]]; then echo "ERROR: no signed XPI produced — check AMO output above" >&2 exit 1 fi TARGET="dist/autotrader-marker-$NEXT.xpi" mkdir -p dist cp "$SIGNED_XPI" "$TARGET" echo "→ Signed XPI: $TARGET" # --- Regenerate dist/updates.json (keep all historical versions) --- node -e " const fs = require('fs'); const path = 'dist/updates.json'; const j = fs.existsSync(path) ? JSON.parse(fs.readFileSync(path, 'utf8')) : { addons: {} }; const addonId = process.argv[1]; const version = process.argv[2]; const rawBase = process.argv[3]; j.addons = j.addons || {}; j.addons[addonId] = j.addons[addonId] || { updates: [] }; const updates = j.addons[addonId].updates.filter(u => u.version !== version); updates.push({ version, update_link: rawBase + '/autotrader-marker-' + version + '.xpi' }); // Sort ascending by semver (Firefox picks the highest applicable) updates.sort((a, b) => { const pa = a.version.split('.').map(Number); const pb = b.version.split('.').map(Number); for (let i = 0; i < 3; i++) if (pa[i] !== pb[i]) return pa[i] - pb[i]; return 0; }); j.addons[addonId].updates = updates; fs.writeFileSync(path, JSON.stringify(j, null, 2) + '\n'); " "$ADDON_ID" "$NEXT" "$RAW_BASE" echo "→ dist/updates.json updated" # --- Summarise for the developer --- cat <