# Builds the signed release APK and F-Droid v2 artifacts as soon as a new # release is created, and attaches everything to that release. # # Written for Gitea Actions (GitHub-Actions-compatible) — the repo lives on # https://git.obahan.xyz/frank/wirevpn. If release-attachment storage is # unavailable on the server, outputs are also published to the `artifacts` # branch (tag-name addressed via commit message). # # Required repository secrets: # KEYSTORE_FILE base64-encoded release signing keystore (.jks) # KEYSTORE_PASSWORD keystore password # KEY_ALIAS key alias # KEY_PASSWORD key password # # Requires a registered Actions runner on the Gitea instance that can run # docker containers with the Android SDK (gitea/act image, docker driver). name: release on: release: types: [published, created] concurrency: group: release-${{ github.ref }} cancel-in-progress: false env: ANDROID_NDK_VERSION: "28.2.13676358" ANDROID_API_LEVEL: "36" GRADLE_USER_HOME: ${{ github.workspace }}/.gradle jobs: build: runs-on: self-hosted timeout-minutes: 90 steps: - name: Checkout uses: actions/checkout@v4 with: submodules: recursive fetch-depth: 0 - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: temurin java-version: "21" - name: Ensure Android SDK (platform, build-tools, NDK) run: | set -e if [ -z "${ANDROID_HOME:-}" ] && [ -d /usr/lib/android-sdk ]; then export ANDROID_HOME=/usr/lib/android-sdk fi if [ -z "${ANDROID_HOME:-}" ]; then echo "ANDROID_HOME not set; installing SDK" export ANDROID_HOME=$HOME/android-sdk mkdir -p "$ANDROID_HOME/cmdline-tools" curl -fsSL https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -o ct.zip (cd "$ANDROID_HOME/cmdline-tools" && unzip -q ../../ct.zip && mv cmdline-tools latest && rm -rf latest/latest) yes | "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" --sdk_root="$ANDROID_HOME" --licenses >/dev/null fi "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" --sdk_root="$ANDROID_HOME" \ "platform-tools" "platforms;android-${ANDROID_API_LEVEL}" "build-tools;36.0.0" "ndk;${ANDROID_NDK_VERSION}" echo "sdk.dir=$ANDROID_HOME" > local.properties - name: Ensure build prerequisites (patch) run: | set -e if ! command -v patch >/dev/null 2>&1; then echo "patch not found; using vendored shim" mkdir -p "$HOME/bin" cp scripts/patch-shim.py "$HOME/bin/patch" chmod +x "$HOME/bin/patch" echo "$HOME/bin" >> "$GITHUB_PATH" echo "patch shim ready (vendored)" else echo "patch present on runner" fi - name: Decode signing keystore run: | mkdir -p "$HOME/keystore" echo "$KEYSTORE_FILE" | base64 -d > "$HOME/keystore/wirevpn-release.jks" env: KEYSTORE_FILE: ${{ secrets.KEYSTORE_FILE }} - name: Build signed release APK uses: gradle/actions/setup-gradle@v4 env: KEYSTORE_FILE: ${{ env.HOME }}/keystore/wirevpn-release.jks KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }} KEY_ALIAS: ${{ secrets.KEY_ALIAS }} KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }} with: arguments: assembleRelease - name: Collect build outputs + F-Droid metadata run: | set -e APK=ui/build/outputs/apk/release/ui-release.apk test -f "$APK" mkdir -p dist cp "$APK" dist/page.onram.wirevpn.apk # F-Droid v2 metadata + signature: "256;" + base64(sha256(sha256(apk-bytes))) export PATH="$ANDROID_HOME/build-tools/36.0.0:$PATH" python3 scripts/fdroid_metadata.py dist/page.onram.wirevpn.apk > dist/page.onram.wirevpn.metadata python3 -c " import hashlib, base64 d = open('dist/page.onram.wirevpn.apk', 'rb').read() sig = base64.b64encode(hashlib.sha256(hashlib.sha256(d).digest()).digest()).decode() open('dist/page.onram.wirevpn.signature', 'w').write(f'256;{sig}\n') " echo "--- metadata ---" cat dist/page.onram.wirevpn.metadata echo "--- signature ---" cat dist/page.onram.wirevpn.signature - name: Attach artifacts to the Gitea release env: GITEA_API: https://git.obahan.xyz/api/v1 GITEA_TOKEN: ${{ secrets.GITEA_TOKEN || github.token }} REPO: frank/wirevpn run: | set -e tag="${GITHUB_REF#refs/tags/}" [ -n "$tag" ] || tag="latest" # Find or create the release rid=$(curl -fsSL -H "Authorization: token $GITEA_TOKEN" "$GITEA_API/repos/$REPO/releases/tags/$tag" | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])' 2>/dev/null || true) if [ -z "$rid" ]; then rid=$(curl -fsSL -H "Authorization: token $GITEA_TOKEN" -H "Content-Type: application/json" \ -d "{\"name\":\"$tag\",\"tag_name\":\"$tag\",\"target\":\"master\"}" \ "$GITEA_API/repos/$REPO/releases" | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])') fi ok=0 for f in dist/page.onram.wirevpn.apk dist/page.onram.wirevpn.metadata dist/page.onram.wirevpn.signature; do if curl -fsSL -H "Authorization: token $GITEA_TOKEN" \ -F "file=@$f" \ "$GITEA_API/repos/$REPO/releases/$rid/assets" >/dev/null; then echo "uploaded $f" ok=1 else echo "attachment upload failed for $f (Gitea attachment storage broken?)" fi done if [ "$ok" != "1" ]; then echo "::warning::Could not attach release assets; falling back to artifacts branch" fi - name: Publish build outputs to artifacts branch (fallback + archive) if: always() env: GITEA_TOKEN: ${{ secrets.GITEA_TOKEN || github.token }} run: | set -e tag="${GITHUB_REF#refs/tags/}" [ -n "$tag" ] || tag="latest" mkdir -p dist-artifacts && cd dist-artifacts cp ../dist/page.onram.wirevpn.apk ../dist/page.onram.wirevpn.metadata ../dist/page.onram.wirevpn.signature . 2>/dev/null || exit 0 git config user.name "wirevpn-ci" git config user.email "ci@localhost" git init -q . git add -A git commit -qm "build outputs for $tag" git push -q --force "https://frank:${GITEA_TOKEN}@git.obahan.xyz/frank/wirevpn.git" HEAD:artifacts echo "artifacts published to branch 'artifacts'" - name: Upload build artifacts uses: actions/upload-artifact@v4 with: name: fdroid-bundle path: dist/