#!/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"