diff --git a/distribution/README.md b/distribution/README.md index d91d314..84618ae 100644 --- a/distribution/README.md +++ b/distribution/README.md @@ -66,18 +66,33 @@ The Android project is generated by Capacitor and intentionally not committed, so the prebuild steps must be verified in the F-Droid build environment before submitting to F-Droid main. +IzzyOnDroid submission details, when you want to send it: + +- App ID: `org.skatespots.app` +- Source: `https://git.skate-spots.org/skatespots/SkateSpots` +- APK: the signed asset on the latest Forgejo release +- License: `AGPL-3.0-only` +- Category: Sports +- Summary: `Local-first skate map, crews, events and marketplace` +- Keep the developer signature; do not ask users to replace an existing install + with an F-Droid-main-signed build. + +No GitHub account is used anywhere in this path. + ## Release checklist 1. `npm test` 2. `scripts/release.sh patch --yes --deploy` (Zapstore + web) 3. Push the release tag and `main` to Forgejo. -4. Attach `android/app/build/outputs/apk/release/app-release.apk` and its - `.sha256` to the Forgejo release. -5. Copy the signed APK into the F-Droid repo on the relay host, update the - metadata changelog and run `fdroid update`; sync `repo/` to - `/var/www/fdroid/repo/`. +4. Upload the APK through the helper: + `FORGEJO_TOKEN=... scripts/publish-forgejo.sh ` + (or set `FORGEJO_TOKEN` before `release.sh`; the APK upload is then automatic) +5. Copy the signed APK into the F-Droid repo on the relay host, add a + `metadata/org.skatespots.app.yml` changelog entry, run `fdroid update`, and + sync `repo/` to `/var/www/fdroid/repo/`. 6. Verify the public latest-release page contains the new `.apk`, and that - `https://fdroid.skate-spots.org/repo/index-v2.json` still lists the app. + `https://fdroid.skate-spots.org/repo/index-v2.json` lists the new + `versionCode`. 7. Update the static download page if the displayed version/checksum changes: `public/download/index.html`. diff --git a/scripts/publish-forgejo.sh b/scripts/publish-forgejo.sh new file mode 100755 index 0000000..9ecf873 --- /dev/null +++ b/scripts/publish-forgejo.sh @@ -0,0 +1,108 @@ +#!/usr/bin/env bash +# +# Publish a built APK to the self-hosted Forgejo release page. +# +# Usage: +# FORGEJO_TOKEN=... scripts/publish-forgejo.sh 1.7.62 [path/to.apk] +# FORGEJO_PASSWORD=... FORGEJO_USER=skatespots scripts/publish-forgejo.sh 1.7.62 +# +# This uploads the APK and its .sha256 file. It does not push the git tag or +# source; do that separately (the Forgejo repo is a mirror, not an auto-push +# remote). Keep credentials in your shell/environment, never in this repo. +set -euo pipefail + +VERSION="${1:?usage: publish-forgejo.sh [apk]}" +APK="${2:-android/app/build/outputs/apk/release/app-release.apk}" +TAG="${FORGEJO_TAG:-v$VERSION}" +BASE="${FORGEJO_URL:-https://git.skate-spots.org}" +OWNER="${FORGEJO_OWNER:-skatespots}" +REPO="${FORGEJO_REPO:-SkateSpots}" +API="$BASE/api/v1/repos/$OWNER/$REPO" + +command -v curl >/dev/null || { echo "curl is required" >&2; exit 1; } +command -v python3 >/dev/null || { echo "python3 is required" >&2; exit 1; } +[ -f "$APK" ] || { echo "APK not found: $APK" >&2; exit 1; } + +AUTH=() +if [ -n "${FORGEJO_TOKEN:-}" ]; then + AUTH=(-H "Authorization: token $FORGEJO_TOKEN") +elif [ -n "${FORGEJO_PASSWORD:-}" ]; then + AUTH=(-u "${FORGEJO_USER:-skatespots}:$FORGEJO_PASSWORD") +else + echo "set FORGEJO_TOKEN (preferred) or FORGEJO_PASSWORD" >&2 + exit 1 +fi + +tmpdir="$(mktemp -d)" +trap 'rm -rf "$tmpdir"' EXIT + +sha="$(sha256sum "$APK" | awk '{print $1}')" +body="$tmpdir/release.md" +cat >"$body" <"$tmpdir/payload.json" <<'PY' +import json +import sys +from pathlib import Path + +tag, version, body_path = sys.argv[1:] +print(json.dumps({ + "tag_name": tag, + "name": version, + "body": Path(body_path).read_text(), + "draft": False, + "prerelease": False, +})) +PY + +create_code="$(curl -sS -o "$tmpdir/release.json" -w '%{http_code}' \ + "${AUTH[@]}" -H 'Content-Type: application/json' \ + -X POST "$API/releases" --data-binary @"$tmpdir/payload.json" || true)" + +if [ "$create_code" = "201" ]; then + release_id="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["id"])' "$tmpdir/release.json")" +elif [ "$create_code" = "409" ] || [ "$create_code" = "422" ]; then + curl -fsS "${AUTH[@]}" "$API/releases/tags/$TAG" -o "$tmpdir/release.json" + release_id="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["id"])' "$tmpdir/release.json")" +else + echo "Forgejo release creation failed (HTTP $create_code)" >&2 + cat "$tmpdir/release.json" >&2 + exit 1 +fi + +sha_file="$tmpdir/SkateSpots-$VERSION.apk.sha256" +printf '%s SkateSpots-%s.apk\n' "$sha" "$VERSION" >"$sha_file" + +existing_assets="$(python3 - "$tmpdir/release.json" <<'PY' +import json +import sys + +data = json.load(open(sys.argv[1])) +print("\n".join(asset["name"] for asset in data.get("assets", []))) +PY +)" + +for file in "$APK" "$sha_file"; do + name="$(basename "$file")" + if printf '%s\n' "$existing_assets" | grep -Fqx "$name"; then + echo "already present: $name" + continue + fi + code="$(curl -sS -o "$tmpdir/asset.json" -w '%{http_code}' \ + "${AUTH[@]}" -X POST "$API/releases/$release_id/assets?name=$name" \ + -F "attachment=@$file" || true)" + case "$code" in + 201|202) echo "uploaded $name" ;; + *) echo "warning: upload of $name returned HTTP $code" >&2 ;; + esac +done + +echo "release: $BASE/$OWNER/$REPO/releases/tag/$TAG" +echo "latest: $BASE/$OWNER/$REPO/releases/latest" diff --git a/scripts/release.sh b/scripts/release.sh index 286d542..e455bc8 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -126,6 +126,14 @@ for _ in 1 2 3 4 5 6; do done [ "$FOUND" -eq 1 ] || log "warning: the release event did not appear on the relay yet (it usually propagates shortly)" +if [ -n "${FORGEJO_TOKEN:-}" ] || [ -n "${FORGEJO_PASSWORD:-}" ]; then + log "publishing the APK to the self-hosted Forgejo release page…" + scripts/publish-forgejo.sh "$VERSION" "$APK" || \ + log "warning: Forgejo upload failed — the Zapstore release is still valid" +else + log "Forgejo: skipped (set FORGEJO_TOKEN or FORGEJO_PASSWORD to publish there)" +fi + log "committing the release…" git add package.json package-lock.json release-notes.txt git commit -m "release: $VERSION" >/dev/null