OXYGENHUB
# 40ab4df121e0 oxygenhub-android / scripts / release.sh
3.0 KiB · Bourne Again Shell (bash) · executable · last changed Alerts from the hub: the phone registers its Cloud Messaging token and an X25519 key kept by the Keystore, and opens and shows what the hub seals to it with the Rust core; Firebase from google-services.json (the release job's firebase-config secret); pins OxygenFlow main (refs #16) 8 days ago source blame history raw
1
#!/usr/bin/env bash
2
# The app's release job (#7), in OxygenFlow's Android image with no network:
3
# a signed release APK of the version in gradle.properties, checked with
4
# apksigner, in dist/ beside its SHA256SUMS, for a release on oxygenhub.io.
5
#
6
# The key comes from the job's secrets, mounted as files and never in the
7
# environment: android-keystore (the PKCS12 keystore, base64) and
8
# android-keystore-password; and firebase-config (google-services.json, for
9
# alerts). Locally, give the same files:
10
#   KEYSTORE_B64=path PASSWORD_FILE=path [FIREBASE_CONFIG=path] scripts/release.sh
11
set -euo pipefail
12
cd "$(dirname "$0")/.."
13
b64=${KEYSTORE_B64:-/run/secrets/android-keystore}
14
password=${PASSWORD_FILE:-/run/secrets/android-keystore-password}
15
# Firebase's client settings for alerts (#16): google-services.json, the
16
# repository's firebase-config secret; without it the release takes no alerts.
17
firebase=${FIREBASE_CONFIG:-/run/secrets/firebase-config}
18
for f in "$b64" "$password"; do
19
    [ -s "$f" ] || { echo "release: no $f: the job needs the android-keystore secrets" >&2; exit 1; }
20
done
21
version=$(sed -n 's/^oxygenhub\.version=//p' gradle.properties)
22
[ -n "$version" ] || { echo "release: no oxygenhub.version in gradle.properties" >&2; exit 1; }
23
24
# As ci.sh: the image's JDKs for Gradle's daemon, never a download.
25
jdks=$( (ls -d /opt/gradle-home/jdks/*/ 2>/dev/null || true) | sed 's:/$::' | paste -sd, -)
26
if [ -n "$jdks" ] && [ -n "${GRADLE_USER_HOME:-}" ]; then
27
    mkdir -p "$GRADLE_USER_HOME"
28
    {
29
        echo "org.gradle.java.installations.paths=$jdks"
30
        echo "org.gradle.java.installations.auto-download=false"
31
    } >> "$GRADLE_USER_HOME/gradle.properties"
32
fi
33
34
# The keystore, decoded where only this job can read it, and gone after.
35
keys=$(mktemp -d)
36
trap 'rm -rf "$keys"' EXIT
37
chmod 700 "$keys"
38
base64 -d "$b64" > "$keys/release.p12"
39
export OXYGENHUB_KEYSTORE="$keys/release.p12" OXYGENHUB_KEYSTORE_PASSWORD_FILE="$password"
40
if [ -s "$firebase" ]; then
41
    cp "$firebase" app/google-services.json
42
    trap 'rm -rf "$keys" app/google-services.json' EXIT
43
else
44
    echo "release: no $firebase: this release takes no alerts" >&2
45
fi
46
gradle=$(command -v gradle || echo ./gradlew)
47
"$gradle" --offline --no-daemon :app:assembleRelease
48
49
apk=app/build/outputs/apk/release/app-release.apk
50
[ -f "$apk" ] || { echo "release: no $apk (was it signed? an unsigned build is app-release-unsigned.apk)" >&2; exit 1; }
51
sdk=${ANDROID_HOME:-${ANDROID_SDK_ROOT:-}}
52
apksigner=$(ls -d "$sdk"/build-tools/*/apksigner 2>/dev/null | sort -V | tail -1)
53
"$apksigner" verify --print-certs "$apk" | grep -E '^Signer #1 certificate (DN|SHA-256)'
54
55
# Kept as an artifact by a fixed name; SHA256SUMS gives the name it takes
56
# in a release, with the version (as OxygenHub's and OxygenFlow's dist do).
57
rm -rf dist
58
mkdir -p dist
59
cp "$apk" dist/oxygenhub-android-universal.apk
60
echo "$(sha256sum < dist/oxygenhub-android-universal.apk | cut -d' ' -f1)  oxygenhub-android-$version-universal.apk" > dist/SHA256SUMS
61
echo "release: oxygenhub-android-$version-universal.apk"