diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b39589..4c4ab2f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,9 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true - name: Set up JDK 17 uses: actions/setup-java@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b449871..2e2cc03 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,6 +18,9 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true - name: Set up JDK 17 uses: actions/setup-java@v4 diff --git a/AGENTS.md b/AGENTS.md index 0004bd4..87b125f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,7 +12,7 @@ Toolchain: JDK 17, Android SDK platform 36 (`compileSdk`/`targetSdk`), `minSdk = - `./gradlew testDebugUnitTest` — unit tests (currently no test sources exist; CI runs the task anyway to catch new ones) - Single-module variants: `./gradlew :feature:timer:lintDebug`, `./gradlew :core:service:testDebugUnitTest`, etc. -`versionCode` in `app/build.gradle.kts` follows the schema `major*100_000 + minor*1_000 + patch*10`; the last digit is reserved for hotfixes. Bump both `versionCode` and `versionName` together. Release tags named `v*` trigger `.github/workflows/release.yml`, which builds a signed APK and publishes a GitHub Release. +Versioning is dynamic via the [axion-release](https://github.com/allegro/axion-release-plugin) plugin (applied at the root). `versionName` is derived from the latest `v*` git tag (`project.version`); `versionCode` is computed from that same tag version with the schema `major*100_000 + minor*1_000 + patch*10` (tag `v1.0.1` → `100010`), keeping it monotonic with releases published before dynamic versioning. Tags must be plain SemVer after the `v` prefix — axion-release fails the build on anything else (e.g. `v1.0.1.1`), so a hotfix is just the next patch tag. Don't hand-edit either field in `app/build.gradle.kts`. To cut a release, push a new `v` tag — `.github/workflows/release.yml` builds a signed APK and publishes the GitHub Release. CI checkouts must use `fetch-depth: 0` so tags and full history are visible. ## Module architecture diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b585c85..31abde5 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -6,6 +6,17 @@ plugins { alias(libs.plugins.ksp) } +// Schema: major * 100000 + minor * 1000 + patch * 10, derived from the axion-release tag +// version so versionCode stays monotonic with already-published releases (v1.0.1 = 100010). +// Axion only accepts SemVer tags (v..); a hotfix is the next patch tag. +fun versionCodeFrom(version: String): Int { + val parts = version.substringBefore("-").split(".").map { it.toInt() } + require(parts.size == 3 && parts[1] <= 99 && parts[2] <= 99) { + "Cannot derive versionCode from version '$version'" + } + return parts[0] * 100_000 + parts[1] * 1_000 + parts[2] * 10 +} + android { namespace = "dev.xitee.sleeptimer" compileSdk = 36 @@ -14,9 +25,8 @@ android { applicationId = "dev.xitee.sleeptimer" minSdk = 26 targetSdk = 36 - // Schema: major * 100000 + minor * 1000 + patch * 10 (last digit reserved for hotfixes) - versionCode = 1 * 100000 + 0 * 1000 + 1 * 10 - versionName = "1.0.1" + versionCode = versionCodeFrom(project.version.toString()) + versionName = project.version.toString() } signingConfigs { diff --git a/build.gradle.kts b/build.gradle.kts index a73cca7..43d18d2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,4 +5,15 @@ plugins { alias(libs.plugins.kotlin.serialization) apply false alias(libs.plugins.hilt.android) apply false alias(libs.plugins.ksp) apply false + alias(libs.plugins.axion.release) +} + +scmVersion { + tag { + prefix.set("v") + } +} + +allprojects { + version = rootProject.scmVersion.version } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6eee6f9..b6a2402 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,6 +12,7 @@ androidxCoreKtx = "1.18.0" androidxActivityCompose = "1.13.0" kotlinxSerializationJson = "1.11.0" shizuku = "13.1.5" +axionRelease = "1.18.16" [libraries] androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } @@ -49,3 +50,4 @@ kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "ko kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } +axion-release = { id = "pl.allegro.tech.build.axion-release", version.ref = "axionRelease" }