#!/usr/bin/env bash set -euo pipefail usage() { cat <<'EOF' Usage: GITEA_BASE_URL=git.example.com GITEA_TOKEN_FILE=local/gitea-token scripts/release-gitea.sh 0.1 Creates a Gitea release for the current HEAD and uploads: - the signed release APK - a SHA-256 checksum file for the APK Environment: GITEA_BASE_URL Base URL of the Gitea instance, for example git.example.com GITEA_TOKEN Gitea access token with repository write/release permissions GITEA_TOKEN_FILE Optional file containing the token, used when GITEA_TOKEN is unset GITEA_OWNER Optional repository owner override. Defaults to origin remote owner. GITEA_REPO Optional repository name override. Defaults to origin remote repo. VERSION_CODE Optional Android versionCode override. The script requires a clean working tree and pushes the current branch and tag. EOF } if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then usage exit 0 fi version="${1:-}" if [[ ! "$version" =~ ^[0-9]+\.[0-9]+$ ]]; then usage >&2 exit 2 fi : "${GITEA_BASE_URL:?Set GITEA_BASE_URL, for example git.example.com}" if [[ -z "${GITEA_TOKEN:-}" && -n "${GITEA_TOKEN_FILE:-}" ]]; then if [[ ! -f "$GITEA_TOKEN_FILE" ]]; then echo "GITEA_TOKEN_FILE does not exist: ${GITEA_TOKEN_FILE}" >&2 exit 1 fi GITEA_TOKEN="$(tr -d '\r\n' < "$GITEA_TOKEN_FILE")" fi : "${GITEA_TOKEN:?Set GITEA_TOKEN or GITEA_TOKEN_FILE to a Gitea access token}" require_clean_tree() { if [[ -n "$(git status --porcelain)" ]]; then echo "Working tree is not clean. Commit or stash changes before releasing." >&2 exit 1 fi } remote_repo_path() { local remote_url remote_url="$(git remote get-url origin)" remote_url="${remote_url%.git}" case "$remote_url" in ssh://*) remote_url="${remote_url#ssh://}" remote_url="${remote_url#*/}" ;; http://*|https://*) remote_url="${remote_url#http://}" remote_url="${remote_url#https://}" remote_url="${remote_url#*/}" ;; *@*:*) remote_url="${remote_url#*:}" ;; esac printf '%s\n' "$remote_url" } json_string() { python3 -c 'import json,sys; print(json.dumps(sys.argv[1]))' "$1" } extract_json_id() { python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])' } version_code_for() { local major minor IFS=. read -r major minor <<<"$1" printf '%d\n' "$((major * 10000 + minor * 100))" } urlencode() { python3 -c 'import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1], safe=""))' "$1" } normalize_base_url() { local base_url base_url="${1%/}" case "$base_url" in http://*|https://*) ;; *) base_url="https://${base_url}" ;; esac printf '%s\n' "$base_url" } require_clean_tree tag="v${version}" release_name="StatusBarTweak ${version}" version_code="${VERSION_CODE:-$(version_code_for "$version")}" repo_path="$(remote_repo_path)" owner="${GITEA_OWNER:-${repo_path%%/*}}" repo="${GITEA_REPO:-${repo_path##*/}}" gitea_base_url="$(normalize_base_url "$GITEA_BASE_URL")" api_base="${gitea_base_url}/api/v1" if [[ "$owner" == "$repo_path" || -z "$owner" || -z "$repo" ]]; then echo "Could not infer owner/repo from origin. Set GITEA_OWNER and GITEA_REPO." >&2 exit 1 fi git fetch origin --tags if git rev-parse -q --verify "refs/tags/${tag}" >/dev/null; then echo "Tag ${tag} already exists." >&2 exit 1 fi ./gradlew clean assembleRelease \ -PsbtVersionName="$version" \ -PsbtVersionCode="$version_code" apk_source="app/build/outputs/apk/release/app-release.apk" if [[ ! -f "$apk_source" ]]; then echo "Release APK not found at ${apk_source}." >&2 exit 1 fi release_dir="build/release/${tag}" apk_name="StatusBarTweak-${version}.apk" checksum_name="${apk_name}.sha256" mkdir -p "$release_dir" cp "$apk_source" "${release_dir}/${apk_name}" (cd "$release_dir" && sha256sum "$apk_name" > "$checksum_name") git tag -a "$tag" -m "$release_name" git push origin HEAD git push origin "$tag" body="Tested primarily on Samsung Galaxy Fold 5 running One UI 8.0 / Android 16." payload="$( cat </dev/null } upload_asset "${release_dir}/${apk_name}" upload_asset "${release_dir}/${checksum_name}" echo "Created release ${tag}: ${gitea_base_url}/${owner}/${repo}/releases/tag/${tag}"