From e94093ac174159d2b8d948c0cb501726c9abe5af Mon Sep 17 00:00:00 2001 From: Kirill Date: Fri, 2 Oct 2026 00:07:34 +0300 Subject: [PATCH] Add Android production release and testing builds workflows --- .gitea/workflows/android-release.yml | 107 +++++++++++++++++++++++++++ .gitea/workflows/android.yml | 94 ----------------------- .gitea/workflows/testing-builds.yml | 62 ++++++++++++++++ 3 files changed, 169 insertions(+), 94 deletions(-) create mode 100644 .gitea/workflows/android-release.yml delete mode 100644 .gitea/workflows/android.yml create mode 100644 .gitea/workflows/testing-builds.yml diff --git a/.gitea/workflows/android-release.yml b/.gitea/workflows/android-release.yml new file mode 100644 index 0000000..7af3808 --- /dev/null +++ b/.gitea/workflows/android-release.yml @@ -0,0 +1,107 @@ +name: Android production release + +on: + push: + tags: + - "v*" + +jobs: + test-build-publish: + runs-on: godot + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + lfs: true + + - name: Verify tag belongs to main + run: | + git fetch origin main + git merge-base --is-ancestor "${GITHUB_SHA}" origin/main + + - name: Show Godot version + run: godot --version + + - name: Import project + run: | + rm -rf .godot + godot --headless --path . --editor --import --quit --verbose + + - name: Run all tests + shell: bash + run: | + set -euo pipefail + mapfile -t tests < <(find tests -maxdepth 1 -type f -name 'test_*.gd' | sort) + test "${#tests[@]}" -gt 0 + + for test_file in "${tests[@]}"; do + echo "::group::${test_file}" + godot --headless --path . --script "res://${test_file}" + echo "::endgroup::" + done + + - name: Prepare Android signing + env: + ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} + run: | + test -n "${ANDROID_KEYSTORE_BASE64}" + printf '%s' "${ANDROID_KEYSTORE_BASE64}" | base64 --decode > "${RUNNER_TEMP}/release.keystore" + test -s "${RUNNER_TEMP}/release.keystore" + + - name: Configure release AAB + env: + RELEASE_VERSION: ${{ github.ref_name }} + RELEASE_VERSION_CODE: ${{ github.run_number }} + run: | + python3 - <<'PY' + import os + import re + from pathlib import Path + + path = Path("export_presets.cfg") + text = path.read_text() + start = text.index('[preset.1.options]') + head, android = text[:start], text[start:] + replacements = ( + (r'gradle_build/use_gradle_build=false', 'gradle_build/use_gradle_build=true'), + (r'gradle_build/export_format=0', 'gradle_build/export_format=1'), + (r'package/signed=false', 'package/signed=true'), + (r'version/code=\d+', f'version/code={100000 + int(os.environ["RELEASE_VERSION_CODE"])}'), + (r'version/name="[^"]*"', f'version/name="{os.environ["RELEASE_VERSION"].removeprefix("v")}"'), + ) + for pattern, replacement in replacements: + android, count = re.subn(pattern, replacement, android, count=1) + if count != 1: + raise RuntimeError(f'Expected one Android preset match for {pattern!r}, got {count}') + path.write_text(head + android) + PY + + - name: Build signed Android App Bundle + env: + GODOT_ANDROID_KEYSTORE_RELEASE_USER: ${{ secrets.ANDROID_KEYSTORE_ALIAS }} + GODOT_ANDROID_KEYSTORE_RELEASE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} + run: | + export GODOT_ANDROID_KEYSTORE_RELEASE_PATH="${RUNNER_TEMP}/release.keystore" + mkdir -p build + godot --headless --path . --export-release "Android" build/owniverse-${GITHUB_REF_NAME}.aab + test -s "build/owniverse-${GITHUB_REF_NAME}.aab" + ls -lh "build/owniverse-${GITHUB_REF_NAME}.aab" + + - name: Publish to Google Play production + uses: r0adkll/upload-google-play@v1 + with: + serviceAccountJsonPlainText: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON }} + packageName: com.KIDGameProduction.Owniverse + releaseFiles: build/owniverse-${{ github.ref_name }}.aab + tracks: production + status: completed + + - name: Upload release bundle + uses: actions/upload-artifact@v3 + with: + name: owniverse-${{ github.ref_name }}-aab + path: build/owniverse-${{ github.ref_name }}.aab + if-no-files-found: error + retention-days: 90 diff --git a/.gitea/workflows/android.yml b/.gitea/workflows/android.yml deleted file mode 100644 index 0208e64..0000000 --- a/.gitea/workflows/android.yml +++ /dev/null @@ -1,94 +0,0 @@ -name: Android - -on: - push: - tags: - - "v*" - -jobs: - android: - runs-on: godot - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - lfs: true - - name: Godot version - run: godot --version - - - name: Prepare Godot - run: | - rm -rf .godot - - godot \ - --headless \ - --path . \ - --editor \ - --import \ - --quit \ - --verbose - - - - name: Build APK - run: | - mkdir -p build - - godot \ - --headless \ - --path . \ - --editor \ - --import \ - --quit - - godot \ - --headless \ - --path . \ - --export-release "Android" \ - build/app.apk - - - - name: Check imported resources - run: | - echo "=== PNG imports ===" - find .godot/imported -iname '*habitable*' -o -iname '*civ2*' - - echo "=== PNG files ===" - ls -lh ui/4-life/habitable_planet.png - ls -lh ui/4-life/civ2.png - - - - name: Verify APK - run: | - test -f build/app.apk - ls -lh build/app.apk - - - name: Create Release - env: - GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }} - run: | - curl -f \ - -X POST \ - -H "Authorization: token ${GITEA_TOKEN}" \ - -H "Content-Type: application/json" \ - "https://gt.owad.ru/api/v1/repos/K/owniverse/releases" \ - -d "{ - \"tag_name\": \"${GITHUB_REF_NAME}\", - \"name\": \"${GITHUB_REF_NAME}\", - \"body\": \"Android build ${GITHUB_REF_NAME}\" - }" - - - name: Upload APK to Release - env: - GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }} - run: | - RELEASE_ID=$(curl -fsS \ - -H "Authorization: token ${GITEA_TOKEN}" \ - "https://gt.owad.ru/api/v1/repos/K/owniverse/releases/tags/${GITHUB_REF_NAME}" \ - | python3 -c 'import sys,json; print(json.load(sys.stdin)["id"])') - - curl -f \ - -X POST \ - -H "Authorization: token ${GITEA_TOKEN}" \ - -F "attachment=@build/app.apk" \ - "https://gt.owad.ru/api/v1/repos/K/owniverse/releases/${RELEASE_ID}/assets?name=owniverse-${GITHUB_REF_NAME}.apk" diff --git a/.gitea/workflows/testing-builds.yml b/.gitea/workflows/testing-builds.yml new file mode 100644 index 0000000..946df44 --- /dev/null +++ b/.gitea/workflows/testing-builds.yml @@ -0,0 +1,62 @@ +name: Testing builds + +on: + push: + branches: + - testing + +jobs: + test-and-build: + runs-on: godot + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + lfs: true + + - name: Show Godot version + run: godot --version + + - name: Import project + run: | + rm -rf .godot + godot --headless --path . --editor --import --quit --verbose + + - name: Run all tests + shell: bash + run: | + set -euo pipefail + mapfile -t tests < <(find tests -maxdepth 1 -type f -name 'test_*.gd' | sort) + test "${#tests[@]}" -gt 0 + + for test_file in "${tests[@]}"; do + echo "::group::${test_file}" + godot --headless --path . --script "res://${test_file}" + echo "::endgroup::" + done + + - name: Build Android APK + run: | + mkdir -p build + godot --headless --path . --export-release "Android" build/owniverse-testing.apk + + - name: Build Windows EXE + run: | + godot --headless --path . --export-release "Windows Desktop" build/owniverse-testing.exe + + - name: Verify builds + run: | + test -s build/owniverse-testing.apk + test -s build/owniverse-testing.exe + ls -lh build/owniverse-testing.apk build/owniverse-testing.exe + + - name: Upload testing builds + uses: actions/upload-artifact@v3 + with: + name: owniverse-testing-${{ github.sha }} + path: | + build/owniverse-testing.apk + build/owniverse-testing.exe + if-no-files-found: error + retention-days: 14