Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
uses: actions/checkout@v4

- name: Set up Temurin JDK 21
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '21'
Expand Down
69 changes: 53 additions & 16 deletions .github/workflows/release-apk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@ on:
tags:
- 'v*'
workflow_dispatch:
inputs:
version:
description: 'Release tag name, e.g. v3.2.0'
required: true
type: string

jobs:
build-release:
name: Build and publish unsigned APK
name: Build and publish signed APK
runs-on: ubuntu-24.04
env:
TAG: ${{ github.ref_name }}
TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.version || github.ref_name }}
REPO: ${{ github.repository }}
steps:
- name: Checkout
Expand All @@ -20,23 +25,45 @@ jobs:
fetch-depth: 0

- name: Set up Temurin JDK 21
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '21'
cache: 'gradle'

- name: Set up Android SDK (platform + build-tools)
uses: r0adkll/setup-android@v2
with:
api-level: 36
build-tools: '36.0.0'
- name: Set up Android SDK
uses: android-actions/setup-android@v3

- name: Install Android platform and build-tools
run: |
yes | "$ANDROID_HOME"/cmdline-tools/latest/bin/sdkmanager --licenses
"$ANDROID_HOME"/cmdline-tools/latest/bin/sdkmanager --install "platforms;android-36" "build-tools;36.0.0"

- name: Prepare release signing config
env:
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
run: |
if [ -n "$KEYSTORE_BASE64" ] && [ -n "$KEYSTORE_PASSWORD" ] && [ -n "$KEY_ALIAS" ] && [ -n "$KEY_PASSWORD" ]; then
echo "$KEYSTORE_BASE64" | base64 --decode > "$GITHUB_WORKSPACE/release-keystore.jks"
echo "KEYSTORE_PATH=$GITHUB_WORKSPACE/release-keystore.jks" >> "$GITHUB_ENV"
echo "KEYSTORE_PASSWORD=$KEYSTORE_PASSWORD" >> "$GITHUB_ENV"
echo "KEY_ALIAS=$KEY_ALIAS" >> "$GITHUB_ENV"
echo "KEY_PASSWORD=$KEY_PASSWORD" >> "$GITHUB_ENV"
fi

- name: Grant execute permission for gradlew
run: chmod +x ./gradlew

- name: Assemble release APK (unsigned)
run: ./gradlew :app:assembleRelease --no-daemon -x validateSigningRelease
- name: Assemble signed release APK
env:
KEYSTORE_PATH: ${{ env.KEYSTORE_PATH }}
KEYSTORE_PASSWORD: ${{ env.KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ env.KEY_ALIAS }}
KEY_PASSWORD: ${{ env.KEY_PASSWORD }}
run: ./gradlew :app:assembleRelease --no-daemon

- name: Find release APK
id: find_apk
Expand All @@ -61,19 +88,29 @@ jobs:
git fetch --tags
TAG=${{ env.TAG }}
REPO=${{ env.REPO }}
PREV_TAG=$(git tag --sort=-v:refname | sed -n '2p' || true)
CHANGELOG_FILE=$(ls -t fastlane/metadata/android/en-US/changelogs/*.txt 2>/dev/null | head -n1 || true)
PREV_TAG=$(git tag --sort=-v:refname | grep -v "^${TAG}$" | head -n 1 || true)
CHANGELOG_FILE=$(find fastlane/metadata/android/en-US/changelogs -maxdepth 1 -type f -name '*.txt' 2>/dev/null | sort -V | tail -n 1 || true)
CHANGELOG=""
if [ -n "$CHANGELOG_FILE" ]; then CHANGELOG=$(cat "$CHANGELOG_FILE"); fi
if [ -n "$PREV_TAG" ]; then
COMP="[${PREV_TAG}...${TAG}](https://github.com/${REPO}/compare/${PREV_TAG}...${TAG})"
else
COMP=""
fi
BODY="[${TAG}](https://github.com/${REPO}/releases/tag/${TAG}) [Latest](https://github.com/${REPO}/releases/latest)\n\n## What's Changed\n\n${CHANGELOG}\n\n**Full Changelog**: ${COMP}"
echo "release_body<<EOF" >> $GITHUB_OUTPUT
echo "$BODY" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
BODY=$(printf '%s\n' \
"[${TAG}](https://github.com/${REPO}/releases/tag/${TAG}) [Latest](https://github.com/${REPO}/releases/latest)" \
"" \
"## What's Changed" \
"" \
"${CHANGELOG}" \
"" \
"**Full Changelog**: ${COMP}")
echo "release_body<<EOF" >> "$GITHUB_OUTPUT"
printf '%s\n' "$BODY" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
echo "--- GENERATED RELEASE BODY ---"
printf '%s\n' "$BODY"
echo "--- END RELEASE BODY ---"

- name: Create GitHub Release
id: create_release
Expand Down
46 changes: 38 additions & 8 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@ android {

signingConfigs {
create("release") {
val envStorePath = System.getenv("KEYSTORE_PATH")
val envStorePassword = System.getenv("KEYSTORE_PASSWORD")
val envKeyAlias = System.getenv("KEY_ALIAS")
val envKeyPassword = System.getenv("KEY_PASSWORD")

if (!envStorePath.isNullOrBlank()) {
storeFile = file(envStorePath)
storePassword = envStorePassword ?: ""
keyAlias = envKeyAlias ?: ""
keyPassword = envKeyPassword ?: ""
return@create
}

val propFile = rootProject.file("keystore.properties")
if (!propFile.exists()) {
propFile.createNewFile()
Expand All @@ -44,19 +57,36 @@ android {
load(propFile.inputStream())
}

keyAlias = keystoreProps["keyAlias"] as? String ?: ""
keyPassword = keystoreProps["keyPassword"] as? String ?: ""
storeFile = file(keystoreProps["storeFile"] as? String ?: "/")
storePassword = keystoreProps["storePassword"] as? String ?: ""
val storeFilePath = keystoreProps["storeFile"] as? String
val keyAliasValue = keystoreProps["keyAlias"] as? String
val keyPasswordValue = keystoreProps["keyPassword"] as? String
val storePasswordValue = keystoreProps["storePassword"] as? String

keyAlias = keyAliasValue ?: ""
keyPassword = keyPasswordValue ?: ""
storeFile = if (!storeFilePath.isNullOrBlank()) file(storeFilePath) else file("/dev/null")
storePassword = storePasswordValue ?: ""
}
}

buildTypes {
getByName("release") {
isMinifyEnabled = !AppConfig.devCycle
isShrinkResources = !AppConfig.devCycle
isDebuggable = AppConfig.devCycle
signingConfig = signingConfigs.getByName("release")
isMinifyEnabled = true
isShrinkResources = true
isDebuggable = false
val envEnabled = !System.getenv("KEYSTORE_PATH").isNullOrBlank() &&
!System.getenv("KEYSTORE_PASSWORD").isNullOrBlank() &&
!System.getenv("KEY_ALIAS").isNullOrBlank() &&
!System.getenv("KEY_PASSWORD").isNullOrBlank()
val propFile = rootProject.file("keystore.properties")
val keyStoreExists = propFile.exists() && propFile.readText().contains("storeFile")
val hasSigningValues = keyStoreExists && propFile.readText().contains("keyAlias") &&
propFile.readText().contains("storePassword")
signingConfig = if (envEnabled || hasSigningValues) {
signingConfigs.getByName("release")
} else {
signingConfigs.getByName("debug")
}
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
Expand Down
11 changes: 3 additions & 8 deletions common/design/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ android {

buildTypes {
release {
isMinifyEnabled = !AppConfig.devCycle
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
Expand Down Expand Up @@ -58,11 +58,6 @@ dependencies {

androidTestImplementation(platform(libs.androidx.compose.bom))

if (AppConfig.devCycle) {
api(libs.androidx.compose.ui.tooling)
api(libs.androidx.ui.test.manifest)
} else {
debugApi(libs.androidx.compose.ui.tooling)
debugApi(libs.androidx.ui.test.manifest)
}
debugApi(libs.androidx.compose.ui.tooling)
debugApi(libs.androidx.ui.test.manifest)
}
2 changes: 1 addition & 1 deletion common/utils/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ android {

buildTypes {
getByName("release") {
isMinifyEnabled = !AppConfig.devCycle
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
Expand Down
Loading