From c84181ea18924ae674d744cdab945dd441c71afc Mon Sep 17 00:00:00 2001 From: Hermes Date: Tue, 1 Sep 2026 17:16:44 -0500 Subject: [PATCH] ci: route Android builds through BuildTool --- .gitea/workflows/android-build.yml | 123 ++++------------------------- BuildTool.sh | 54 +++++++++++-- README.md | 22 +++--- 3 files changed, 75 insertions(+), 124 deletions(-) diff --git a/.gitea/workflows/android-build.yml b/.gitea/workflows/android-build.yml index 1539a1a..58546a6 100644 --- a/.gitea/workflows/android-build.yml +++ b/.gitea/workflows/android-build.yml @@ -29,132 +29,37 @@ jobs: distribution: temurin java-version: '17' - - name: Install Android SDK command-line tools and packages + - name: Run project build tooling for debug APK + if: github.event_name != 'release' shell: bash + env: + CI_VERSION_CODE: ${{ github.run_number }} 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-36" \ - "build-tools;36.0.0" + chmod +x ./BuildTool.sh + ./BuildTool.sh --no-commit --apk-only - - name: Prepare optional release signing + - name: Run project build tooling for release AAB if: github.event_name == 'release' - continue-on-error: true + shell: bash env: + CI_VERSION_CODE: ${{ github.run_number }} + CI_ARTIFACT_TIMESTAMP: ${{ github.run_id }} 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: Prepare CI build metadata - id: build_meta - shell: bash - run: | - set -euxo pipefail - timestamp_utc="$(date -u +%Y%m%d-%H%M%S)" - version_code="$(date -u +%s)" - project_name="$(basename "$GITHUB_REPOSITORY")" - python3 - "$version_code" <<'PY' - from pathlib import Path - import re, sys - path = Path('app/build.gradle.kts') - text = path.read_text(encoding='utf-8') - new_text, count = re.subn(r'(\bversionCode\s*=\s*)\d+', rf'\g<1>{sys.argv[1]}', text, count=1) - if count != 1: - raise SystemExit('versionCode not found in app/build.gradle.kts') - path.write_text(new_text, encoding='utf-8') - PY - echo "Using CI versionCode: $version_code" - echo "project_name=$project_name" >> "$GITHUB_OUTPUT" - echo "timestamp_utc=$timestamp_utc" >> "$GITHUB_OUTPUT" - echo "version_code=$version_code" >> "$GITHUB_OUTPUT" - - - 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: Rename release AAB for upload - if: github.event_name == 'release' - id: release_aab - shell: bash - run: | - set -euxo pipefail - aab="$(find app/build/outputs/bundle/release -name '*.aab' | head -n 1)" - renamed="app/build/outputs/bundle/release/${{ steps.build_meta.outputs.project_name }}-${{ steps.build_meta.outputs.timestamp_utc }}-release.aab" - mv -f "$aab" "$renamed" - echo "Renamed release AAB to $(basename "$renamed")" - echo "path=$renamed" >> "$GITHUB_OUTPUT" + chmod +x ./BuildTool.sh + ./BuildTool.sh --no-commit --with-aab - 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 + path: dist/*.apk if-no-files-found: error - name: Attach release AAB to Gitea release @@ -171,7 +76,7 @@ jobs: exit 1 fi release_id="$(python3 -c 'import json, os; print(json.load(open(os.environ["GITHUB_EVENT_PATH"], encoding="utf-8"))["release"]["id"])')" - aab="${{ steps.release_aab.outputs.path }}" + aab="$(find dist -name '*.aab' | head -n 1)" curl --fail-with-body \ --request POST \ --header "Authorization: token ${token}" \ diff --git a/BuildTool.sh b/BuildTool.sh index 1f372c0..d651a84 100755 --- a/BuildTool.sh +++ b/BuildTool.sh @@ -47,6 +47,9 @@ for arg in "$@"; do esac done +CI_VERSION_CODE="${CI_VERSION_CODE:-}" +CI_ARTIFACT_TIMESTAMP="${CI_ARTIFACT_TIMESTAMP:-}" + need_cmd() { command -v "$1" >/dev/null 2>&1 || { echo "Missing required command: $1" >&2 @@ -111,6 +114,35 @@ gradle_no_daemon() { ./gradlew --no-daemon -Dorg.gradle.daemon=false "$@" } +prepare_optional_release_signing() { + local required=(ANDROID_KEYSTORE_BASE64 ANDROID_KEYSTORE_PASSWORD ANDROID_KEY_ALIAS ANDROID_KEY_PASSWORD) + local missing=() + local key + for key in "${required[@]}"; do + if [[ -z "${!key:-}" ]]; then + missing+=("$key") + fi + done + + if [[ ${#missing[@]} -eq ${#required[@]} ]]; then + return + fi + + if [[ ${#missing[@]} -gt 0 ]]; then + printf 'Release signing secrets missing: %s\n' "${missing[*]}" >&2 + exit 1 + fi + + mkdir -p .ci-secrets + printf '%s' "$ANDROID_KEYSTORE_BASE64" | base64 -d > .ci-secrets/release-keystore.jks + cat > keystore.properties <%d' % new_code, text, count=1) -text = re.sub(r'(\bversionName\s*=\s*)"\d+(?:\.\d+)*"', r'\g<1>"%s"' % new_name, text, count=1) +if not ci_version_code: + text = re.sub(r'(\bversionName\s*=\s*)"\d+(?:\.\d+)*"', r'\g<1>"%s"' % new_name, text, count=1) path.write_text(text) print(new_code) @@ -193,8 +227,14 @@ copy_artifacts() { echo "Release AAB not found." >&2 exit 1 fi - cp "$release_aab" "$DIST_DIR/${APP_NAME}-v${version_code}-release.aab" - echo "Created: $DIST_DIR/${APP_NAME}-v${version_code}-release.aab" + local release_name + if [[ -n "$CI_ARTIFACT_TIMESTAMP" ]]; then + release_name="${APP_NAME}-${CI_ARTIFACT_TIMESTAMP}-release.aab" + else + release_name="${APP_NAME}-v${version_code}-release.aab" + fi + cp "$release_aab" "$DIST_DIR/$release_name" + echo "Created: $DIST_DIR/$release_name" fi } @@ -233,6 +273,10 @@ main() { exit 0 fi + if [[ "$WITH_AAB" == true ]]; then + prepare_optional_release_signing + fi + local version_code version_code="$(increment_versions)" diff --git a/README.md b/README.md index 8f50544..b0721e5 100644 --- a/README.md +++ b/README.md @@ -16,22 +16,24 @@ Native Kotlin + Jetpack Compose app (API 35) that provides a light-therapy style - Unit test coverage for Kelvin conversion output range ## BuildTool.sh -The project intentionally runs Gradle with daemon disabled (`--no-daemon` and `org.gradle.daemon=false`). +The project intentionally runs builds through `./BuildTool.sh` so local development and CI use the same build path. -### Options +### Common commands ```bash ./BuildTool.sh --setup-only -./BuildTool.sh --debug -./BuildTool.sh --release -./BuildTool.sh --all +./BuildTool.sh --no-commit --apk-only +./BuildTool.sh --no-commit --with-aab ``` ### Behavior -- `--setup-only`: prepares wrapper/dependencies without building release artifacts. -- `--debug`: increments version code/name, builds debug APK, renames output to include app name and version code. -- `--release`: increments version code/name, builds release AAB, renames output similarly. -- `--all`: runs debug + release flow in one run. -- After successful build tasks, script commits all changes with message from `commit-message.txt` (fallback: `No Details`) and then clears that file. +- `--setup-only`: prepares the local Android SDK/tooling and exits. +- `--apk-only`: builds the debug APK. +- `--with-aab`: also builds the release AAB. +- `--no-commit`: skips the post-build git commit step. +- Local builds increment `versionCode` and `versionName`. +- CI can provide `CI_VERSION_CODE` to force the build version code and `CI_ARTIFACT_TIMESTAMP` to control the release AAB filename. +- Artifacts are copied into `dist/`. +- Gitea Actions uses this same script instead of duplicating build logic in YAML. ## Upload Key (Release Signing) For this first increment, release uses default debug signing unless custom signing is added.