8 Commits

Author SHA1 Message Date
Hermes
0ae7ac86d9 ci: prefer github token for release asset upload
All checks were successful
Android build / build (push) Successful in 7m8s
Android build / build (release) Successful in 8m28s
2026-08-31 18:22:00 -05:00
Hermes
61b8c3d18f ci: broaden release asset upload token fallback
All checks were successful
Android build / build (push) Successful in 8m8s
2026-08-31 16:12:12 -05:00
Hermes
87c77dc1fa ci: bump APK versionCode and timestamp AAB names
Some checks failed
Android build / build (push) Successful in 11m31s
Android build / build (release) Failing after 8m2s
2026-08-31 15:05:45 -05:00
Hermes
e53a33c7b5 fix: repair AGP upgrade file corruption
All checks were successful
Android build / build (push) Successful in 9m9s
2026-08-31 13:49:22 -05:00
Hermes
4bbcead398 build: upgrade AGP for Android 16 support
Some checks failed
Android build / build (push) Has been cancelled
2026-08-31 13:30:46 -05:00
Hermes
dcdf69d02a build: target Android 16 / API 36
All checks were successful
Android build / build (push) Successful in 12m16s
2026-08-31 12:17:46 -05:00
Hermes Agent
aae81c202e ci: mark missing signing secrets as non-blocking error
All checks were successful
Android build / build (push) Successful in 10m49s
Android build / build (release) Successful in 10m22s
2026-08-29 12:22:56 -05:00
Hermes Agent
a2c34d5e3b ci: add optional release signing from repository secrets
All checks were successful
Android build / build (push) Successful in 9m43s
Android build / build (release) Successful in 10m35s
2026-08-29 12:04:19 -05:00
5 changed files with 114 additions and 11 deletions

View File

@@ -1,7 +1,7 @@
name: Android build name: Android build
permissions: permissions:
contents: read contents: write
releases: write releases: write
on: on:
@@ -50,8 +50,42 @@ jobs:
set -o pipefail set -o pipefail
sdkmanager \ sdkmanager \
"platform-tools" \ "platform-tools" \
"platforms;android-35" \ "platforms;android-36" \
"build-tools;35.0.0" "build-tools;36.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 <<EOF
storeFile=.ci-secrets/release-keystore.jks
storePassword=$ANDROID_KEYSTORE_PASSWORD
keyAlias=$ANDROID_KEY_ALIAS
keyPassword=$ANDROID_KEY_PASSWORD
EOF
- name: Make Gradle wrapper executable - name: Make Gradle wrapper executable
run: chmod +x gradlew run: chmod +x gradlew
@@ -62,6 +96,29 @@ jobs:
set -euxo pipefail set -euxo pipefail
printf 'sdk.dir=%s/.android/sdk\n' "$HOME" > local.properties printf 'sdk.dir=%s/.android/sdk\n' "$HOME" > 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 - name: Build debug APK
if: github.event_name != 'release' if: github.event_name != 'release'
shell: bash shell: bash
@@ -80,6 +137,18 @@ jobs:
export ANDROID_HOME="$ANDROID_SDK_ROOT" export ANDROID_HOME="$ANDROID_SDK_ROOT"
./gradlew --no-daemon bundleRelease ./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"
- name: Upload debug APK - name: Upload debug APK
if: github.event_name != 'release' if: github.event_name != 'release'
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
@@ -92,13 +161,19 @@ jobs:
if: github.event_name == 'release' if: github.event_name == 'release'
env: env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITHUB_TOKEN: ${{ github.token }}
shell: bash shell: bash
run: | run: |
set -euxo pipefail set -euxo pipefail
token="${GITHUB_TOKEN:-${GITEA_TOKEN:-}}"
if [ -z "$token" ]; then
echo "::error::No release upload token is available from secrets.GITEA_TOKEN or github.token"
exit 1
fi
release_id="$(python3 -c 'import json, os; print(json.load(open(os.environ["GITHUB_EVENT_PATH"], encoding="utf-8"))["release"]["id"])')" 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)" aab="${{ steps.release_aab.outputs.path }}"
curl --fail-with-body \ curl --fail-with-body \
--request POST \ --request POST \
--header "Authorization: token ${GITEA_TOKEN}" \ --header "Authorization: token ${token}" \
--form "attachment=@${aab}" \ --form "attachment=@${aab}" \
"${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}/releases/${release_id}/assets?name=$(basename "$aab")" "${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}/releases/${release_id}/assets?name=$(basename "$aab")"

View File

@@ -3,8 +3,8 @@ set -Eeuo pipefail
APP_NAME="e-SUN" APP_NAME="e-SUN"
MODULE="app" MODULE="app"
API_LEVEL="35" API_LEVEL="36"
BUILD_TOOLS_VERSION="35.0.0" BUILD_TOOLS_VERSION="36.0.0"
DIST_DIR="dist" DIST_DIR="dist"
COMMIT_MSG_FILE="commit-message.txt" COMMIT_MSG_FILE="commit-message.txt"

View File

@@ -1,17 +1,31 @@
import java.util.Properties
plugins { plugins {
id("com.android.application") id("com.android.application")
id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.android")
id("org.jetbrains.kotlin.plugin.compose") id("org.jetbrains.kotlin.plugin.compose")
} }
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 { android {
namespace = "solutions.tretter.esunandroid" namespace = "solutions.tretter.esunandroid"
compileSdk = 35 compileSdk = 36
defaultConfig { defaultConfig {
applicationId = "solutions.tretter.esunandroid" applicationId = "solutions.tretter.esunandroid"
minSdk = 26 minSdk = 26
targetSdk = 35 targetSdk = 36
versionCode = 19 versionCode = 19
versionName = "19" versionName = "19"
@@ -19,6 +33,17 @@ android {
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
} }
signingConfigs {
if (hasReleaseSigning) {
create("release") {
storeFile = file(keystoreProperties.getProperty("storeFile"))
storePassword = keystoreProperties.getProperty("storePassword")
keyAlias = keystoreProperties.getProperty("keyAlias")
keyPassword = keystoreProperties.getProperty("keyPassword")
}
}
}
buildTypes { buildTypes {
release { release {
isMinifyEnabled = false isMinifyEnabled = false
@@ -26,6 +51,9 @@ android {
getDefaultProguardFile("proguard-android-optimize.txt"), getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro" "proguard-rules.pro"
) )
if (hasReleaseSigning) {
signingConfig = signingConfigs.getByName("release")
}
} }
} }

View File

@@ -1,5 +1,5 @@
plugins { plugins {
id("com.android.application") version "8.7.2" apply false id("com.android.application") version "8.10.0" apply false
id("org.jetbrains.kotlin.android") version "2.0.21" apply false id("org.jetbrains.kotlin.android") version "2.0.21" apply false
// Required for Kotlin 2.0+ when Compose is enabled // Required for Kotlin 2.0+ when Compose is enabled
id("org.jetbrains.kotlin.plugin.compose") version "2.0.21" apply false id("org.jetbrains.kotlin.plugin.compose") version "2.0.21" apply false

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists