diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2ca46d7..f9ecf2a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,6 +12,9 @@ jobs: contents: write steps: - uses: actions/checkout@v4 + with: + # The build names itself after the newest tag, which a shallow clone doesn't have. + fetch-depth: 0 - uses: actions/setup-java@v4 with: diff --git a/gearslip/build.gradle.kts b/gearslip/build.gradle.kts index 9a50ab0..00db85e 100644 --- a/gearslip/build.gradle.kts +++ b/gearslip/build.gradle.kts @@ -24,6 +24,36 @@ val keystoreProperties = Properties().apply { ).firstOrNull { it.exists() }?.inputStream()?.use { load(it) } } +// The version comes from the newest v* git tag, so a build can never disagree with its tag. A +// build of the tagged commit is named after it ("0.4.0-beta"); anything later adds the commits +// since and the commit ("0.4.0-beta+3.ba4374e"), so a test build can't pass for a release. +// The version code is worked out from the numbers, ((major*100 + minor)*100 + patch)*10 + stage, +// where stage is 1 for alpha, 2 for beta and 9 for a finished release. It only ever goes up as +// long as minor and patch stay under 100. Changelog entries use the same number. +class GitVersion(val name: String, val code: Int) + +val gitVersion: GitVersion = run { + val described = runCatching { + providers.exec { + commandLine("git", "describe", "--tags", "--match", "v*", "--abbrev=7") + isIgnoreExitValue = true + }.standardOutput.asText.get().trim() + }.getOrNull().orEmpty() + val match = Regex("""^v((\d+)\.(\d+)\.(\d+)(?:-([A-Za-z]+))?)(?:-(\d+)-g([0-9a-f]+))?$""").find(described) + ?: return@run GitVersion("0.0.0-dev", 1) // no git or no tags, e.g. a source download + val (base, major, minor, patch, suffix, since, commit) = match.destructured + val stage = when (suffix.lowercase()) { + "" -> 9 + "beta" -> 2 + "alpha" -> 1 + else -> 0 + } + GitVersion( + name = if (since.isEmpty()) base else "$base+$since.$commit", + code = ((major.toInt() * 100 + minor.toInt()) * 100 + patch.toInt()) * 10 + stage, + ) +} + // Keeps build output out of the module folder: /build/gearslip/... instead of // /gearslip/build/..., so everything this project produces lands under one // root-level build/ directory. Set before android {}, which works out the path to R8's default @@ -38,9 +68,9 @@ android { applicationId = "app.seb3thehacker.gearslip" minSdk = 31 targetSdk = 37 - versionCode = 15 + versionCode = gitVersion.code // -PgearslipVersionName=0.1.99-test makes a build that thinks it's older, to try the updater. - versionName = project.findProperty("gearslipVersionName")?.toString() ?: "0.3.40-alpha" + versionName = project.findProperty("gearslipVersionName")?.toString() ?: gitVersion.name manifestPlaceholders["appLabel"] = "Gearslip" // Where opted-in phones send their daily usage note: the stats-worker/ Worker's address, // set as gearslipStatsUrl in gradle.properties. Left empty, nothing is ever sent. diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/Changelog.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/Changelog.kt index 7b90971..7be9775 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/Changelog.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/Changelog.kt @@ -4,6 +4,10 @@ package app.seb3thehacker.gearslip * What changed in each release, newest first, shown on the car screen after an update (and on * the phone). Only the changes a driver would notice. Plain words, short lines: this is read in * a parked car. + * + * After 0.3.40, the version code is the one the build works out from the tag (see gitVersion in + * build.gradle.kts): ((major*100 + minor)*100 + patch)*10 + stage, so 0.4.0-beta is 4002. Older + * entries keep the hand-set codes they shipped with, which are all lower. */ object Changelog { diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/update/UpdateChecker.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/update/UpdateChecker.kt index cc2a1fa..9dbd5e6 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/update/UpdateChecker.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/update/UpdateChecker.kt @@ -578,12 +578,14 @@ object UpdateChecker { /** * "0.2.00-alpha" beats "0.1.10-alpha": the numbers before the dash compare one by one. With the * same numbers, a plain release beats a beta, and a beta beats an alpha, so "0.3.0" reaches - * someone on "0.3.0-beta". + * someone on "0.3.0-beta". Anything after a "+" only says which commit a test build came from, + * so "0.3.0-beta+4.ba4374e" counts the same as "0.3.0-beta". */ internal fun isNewer(candidate: String, installed: String): Boolean { - fun parts(v: String) = v.removePrefix("v").substringBefore('-').split('.').map { it.toIntOrNull() ?: 0 } + fun core(v: String) = v.removePrefix("v").substringBefore('+') + fun parts(v: String) = core(v).substringBefore('-').split('.').map { it.toIntOrNull() ?: 0 } fun stage(v: String): Int { - val tag = v.substringAfter('-', "").lowercase() + val tag = core(v).substringAfter('-', "").lowercase() return when { tag.isEmpty() -> 3 "beta" in tag -> 2