From c2a78e1a73ad1d568ce04c32bbd7772c3ec9dd78 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 29 Aug 2026 13:30:22 -0500 Subject: [PATCH] ci: align MindMachine Android workflow with e-Sun setup --- .gitea/workflows/android-build.yml | 138 +++++++++++++++++++++++++++++ app/build.gradle.kts | 37 +++++--- 2 files changed, 162 insertions(+), 13 deletions(-) create mode 100644 .gitea/workflows/android-build.yml diff --git a/.gitea/workflows/android-build.yml b/.gitea/workflows/android-build.yml new file mode 100644 index 0000000..455804a --- /dev/null +++ b/.gitea/workflows/android-build.yml @@ -0,0 +1,138 @@ +name: Android build + +permissions: + contents: read + releases: write + +on: + push: + branches: + - '**' + pull_request: + release: + types: + - published + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 60 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Java 17 + uses: actions/setup-java@v5 + with: + distribution: temurin + java-version: '17' + + - name: Install Android SDK command-line tools and packages + shell: bash + run: | + set -euxo pipefail + export ANDROID_SDK_ROOT="$HOME/.android/sdk" + export ANDROID_HOME="$ANDROID_SDK_ROOT" + mkdir -p "$ANDROID_SDK_ROOT/cmdline-tools" + if [ ! -x "$ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager" ]; then + tools_url="$(curl -fsSL https://developer.android.com/studio | grep -o 'https://dl.google.com/android/repository/commandlinetools-linux-[0-9][0-9]*_latest.zip' | head -n 1)" + test -n "$tools_url" + curl -fsSL -o /tmp/commandlinetools.zip "$tools_url" + rm -rf "$ANDROID_SDK_ROOT/cmdline-tools/latest" "$ANDROID_SDK_ROOT/cmdline-tools/cmdline-tools" + unzip -q /tmp/commandlinetools.zip -d "$ANDROID_SDK_ROOT/cmdline-tools" + mv "$ANDROID_SDK_ROOT/cmdline-tools/cmdline-tools" "$ANDROID_SDK_ROOT/cmdline-tools/latest" + fi + export PATH="$ANDROID_SDK_ROOT/cmdline-tools/latest/bin:$ANDROID_SDK_ROOT/platform-tools:$PATH" + set +o pipefail + yes | sdkmanager --licenses >/dev/null + set -o pipefail + sdkmanager \ + "platform-tools" \ + "platforms;android-35" \ + "build-tools;35.0.0" + + - name: Prepare optional release signing + if: github.event_name == 'release' + continue-on-error: true + env: + ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} + ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} + ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} + ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} + shell: bash + run: | + set -euo pipefail + missing=() + for key in ANDROID_KEYSTORE_BASE64 ANDROID_KEYSTORE_PASSWORD ANDROID_KEY_ALIAS ANDROID_KEY_PASSWORD; do + if [ -z "${!key:-}" ]; then + missing+=("$key") + fi + done + + if [ ${#missing[@]} -gt 0 ]; then + printf -v missing_csv '%s, ' "${missing[@]}" + missing_csv="${missing_csv%, }" + echo "::error::Release signing secrets missing: ${missing_csv}. Continuing with unsigned/default-signed release AAB." + exit 1 + fi + + mkdir -p .ci-secrets + printf '%s' "$ANDROID_KEYSTORE_BASE64" | base64 -d > .ci-secrets/release-keystore.jks + cat > keystore.properties < local.properties + + - name: Build debug APK + if: github.event_name != 'release' + shell: bash + run: | + set -euxo pipefail + export ANDROID_SDK_ROOT="$HOME/.android/sdk" + export ANDROID_HOME="$ANDROID_SDK_ROOT" + ./gradlew --no-daemon clean assembleDebug + + - name: Build release AAB + if: github.event_name == 'release' + shell: bash + run: | + set -euxo pipefail + export ANDROID_SDK_ROOT="$HOME/.android/sdk" + export ANDROID_HOME="$ANDROID_SDK_ROOT" + ./gradlew --no-daemon bundleRelease + + - name: Upload debug APK + if: github.event_name != 'release' + uses: actions/upload-artifact@v3 + with: + name: debug-apk + path: app/build/outputs/apk/debug/*.apk + if-no-files-found: error + + - name: Attach release AAB to Gitea release + if: github.event_name == 'release' + env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + shell: bash + run: | + set -euxo pipefail + release_id="$(python3 -c 'import json, os; print(json.load(open(os.environ["GITHUB_EVENT_PATH"], encoding="utf-8"))["release"]["id"])')" + aab="$(find app/build/outputs/bundle/release -name '*.aab' | head -n 1)" + curl --fail-with-body \ + --request POST \ + --header "Authorization: token ${GITEA_TOKEN}" \ + --form "attachment=@${aab}" \ + "${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}/releases/${release_id}/assets?name=$(basename "$aab")" diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 906c7f4..144fca3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,3 +1,5 @@ +import java.util.Properties + plugins { id("com.android.application") id("org.jetbrains.kotlin.android") @@ -5,7 +7,17 @@ plugins { id("org.jetbrains.kotlin.plugin.compose") } -import java.util.Properties +val keystorePropertiesFile = rootProject.file("keystore.properties") +val keystoreProperties = Properties() +if (keystorePropertiesFile.exists()) { + keystorePropertiesFile.inputStream().use { keystoreProperties.load(it) } +} +val hasReleaseSigning = listOf( + "storeFile", + "storePassword", + "keyAlias", + "keyPassword", +).all { !keystoreProperties.getProperty(it).isNullOrBlank() } android { namespace = "solutions.tretter.mindmachine" @@ -21,25 +33,25 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } - buildTypes { - signingConfigs { + signingConfigs { + if (hasReleaseSigning) { create("release") { - val propsFile = rootProject.file("keystore/upload-keystore.properties") - if (propsFile.exists()) { - val props = Properties().apply { propsFile.inputStream().use { this.load(it) } } - storeFile = rootProject.file(props.getProperty("storeFile")) - storePassword = props.getProperty("storePassword") - keyAlias = props.getProperty("keyAlias") - keyPassword = props.getProperty("keyPassword") - } + storeFile = file(keystoreProperties.getProperty("storeFile")) + storePassword = keystoreProperties.getProperty("storePassword") + keyAlias = keystoreProperties.getProperty("keyAlias") + keyPassword = keystoreProperties.getProperty("keyPassword") } } + } + buildTypes { debug { buildConfigField("boolean", "DEBUG_AD_FREE", "true") } release { - signingConfig = signingConfigs.getByName("release") + if (hasReleaseSigning) { + signingConfig = signingConfigs.getByName("release") + } isMinifyEnabled = false proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), @@ -88,7 +100,6 @@ dependencies { implementation("androidx.compose.material:material-icons-extended") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1") - // Monetization implementation("com.google.android.gms:play-services-ads:23.1.0") implementation("com.android.billingclient:billing-ktx:8.0.0")