Match updater versions by ordering and cover Wolfskin asset selection
All checks were successful
review/code-claude Approved: no blocking findings

This commit is contained in:
justinzeus 2026-10-22 16:06:09 +02:00
parent 0f7a23faa8
commit 1715041df3
4 changed files with 79 additions and 1 deletions

View file

@ -77,7 +77,8 @@ class UpdateChecker
): JsonObject? = ): JsonObject? =
releases releases
.firstOrNull { release -> .firstOrNull { release ->
Version.tryFromString(release.jsonObject["name"]?.jsonPrimitive?.contentOrNull) == version val candidate = Version.tryFromString(release.jsonObject["name"]?.jsonPrimitive?.contentOrNull)
candidate != null && !candidate.isGreaterThan(version) && !version.isGreaterThan(candidate)
}?.jsonObject }?.jsonObject
/** /**

View file

@ -7,6 +7,7 @@ import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive import kotlinx.serialization.json.jsonPrimitive
@ -26,6 +27,7 @@ class TestUpdateChecker {
private val forgejoLatest: JsonObject by lazy { read("forgejo_release_latest.json") } private val forgejoLatest: JsonObject by lazy { read("forgejo_release_latest.json") }
private val forgejoAssets: JsonArray by lazy { forgejoLatest["assets"]!!.jsonArray } private val forgejoAssets: JsonArray by lazy { forgejoLatest["assets"]!!.jsonArray }
private val forgejoReleases: JsonArray by lazy { readElement("forgejo_releases.json").jsonArray } private val forgejoReleases: JsonArray by lazy { readElement("forgejo_releases.json").jsonArray }
private val suffixedAssets: JsonArray by lazy { read("forgejo_release_suffixed.json")["assets"]!!.jsonArray }
private fun readElement(filename: String): JsonElement { private fun readElement(filename: String): JsonElement {
val resource = javaClass.classLoader?.getResource(filename) val resource = javaClass.classLoader?.getResource(filename)
@ -113,12 +115,58 @@ class TestUpdateChecker {
Assert.assertNull(getDownloadUrl(forgejoAssets, true, listOf("arm64-v8a"))) Assert.assertNull(getDownloadUrl(forgejoAssets, true, listOf("arm64-v8a")))
} }
@Test
fun `Choose debug ABI before universal and fall back for missing ABI`() {
for ((abis, name) in listOf(
listOf("arm64-v8a") to "Wolfskin-debug-arm64-v8a.apk",
listOf("unknown") to "Wolfskin-debug.apk",
emptyList<String>() to "Wolfskin-debug.apk",
)) {
Assert.assertEquals(forgejoDownload(name), getDownloadUrl(suffixedAssets, true, abis))
}
}
@Test
fun `Choose release suffixed ABI before universal and unsuffixed assets`() {
val assets = JsonArray(forgejoAssets + suffixedAssets)
for ((abis, name) in listOf(
listOf("arm64-v8a") to "Wolfskin-release-arm64-v8a.apk",
listOf("armeabi-v7a") to "Wolfskin-release.apk",
emptyList<String>() to "Wolfskin-release.apk",
)) {
Assert.assertEquals(forgejoDownload(name), getDownloadUrl(assets, false, abis))
}
}
@Test
fun `Release and debug assets do not cross build types`() {
val debugAssets = JsonArray(suffixedAssets.filter { it.jsonObject["name"]!!.jsonPrimitive.content.contains("-debug") })
val releaseAssets = JsonArray(suffixedAssets.filter { it.jsonObject["name"]!!.jsonPrimitive.content.contains("-release") })
Assert.assertNull(getDownloadUrl(debugAssets, false, listOf("arm64-v8a")))
Assert.assertNull(getDownloadUrl(releaseAssets, true, listOf("arm64-v8a")))
}
@Test @Test
fun `Find installed version in release list`() { fun `Find installed version in release list`() {
val release = UpdateChecker.findReleaseByVersion(forgejoReleases, Version.fromString("1.0.9-2-g3094fc8c")) val release = UpdateChecker.findReleaseByVersion(forgejoReleases, Version.fromString("1.0.9-2-g3094fc8c"))
Assert.assertEquals("v1.0.9-2-g3094fc8c", release?.get("name")?.jsonPrimitive?.content) Assert.assertEquals("v1.0.9-2-g3094fc8c", release?.get("name")?.jsonPrimitive?.content)
} }
@Test
fun `Find release with different hash abbreviation length`() {
val release = UpdateChecker.findReleaseByVersion(forgejoReleases, Version.fromString("1.0.9-2-g3094fc8"))
Assert.assertEquals("v1.0.9-2-g3094fc8c", release?.get("name")?.jsonPrimitive?.content)
}
@Test
fun `Find release with absent or zero commit count`() {
val release = UpdateChecker.findReleaseByVersion(forgejoReleases, Version.fromString("1.0.10"))
Assert.assertEquals("v1.0.10-0-gfeedbee", release?.get("name")?.jsonPrimitive?.content)
val plainRelease = JsonObject(forgejoReleases.first().jsonObject + ("name" to JsonPrimitive("v1.0.10")))
val plainReleases = JsonArray(listOf(plainRelease))
Assert.assertEquals(plainReleases.first(), UpdateChecker.findReleaseByVersion(plainReleases, Version.fromString("1.0.10-0-gfeedbee")))
}
@Test @Test
fun `Find no release for version missing from list`() { fun `Find no release for version missing from list`() {
Assert.assertNull(UpdateChecker.findReleaseByVersion(forgejoReleases, Version.fromString("1.0.9-3-gffffff"))) Assert.assertNull(UpdateChecker.findReleaseByVersion(forgejoReleases, Version.fromString("1.0.9-3-gffffff")))

View file

@ -0,0 +1,24 @@
{
"name": "v1.0.9-2-g3094fc8c",
"tag_name": "pwolfskin-v1.0.9-2-g3094fc8c",
"published_at": "2026-10-20T09:05:00Z",
"body": "Wolfskin release and debug builds",
"assets": [
{
"name": "Wolfskin-debug.apk",
"browser_download_url": "https://git.justinvisser.org/justinzeus/wolfskin/releases/download/pwolfskin-v1.0.9-2-g3094fc8c/Wolfskin-debug.apk"
},
{
"name": "Wolfskin-release.apk",
"browser_download_url": "https://git.justinvisser.org/justinzeus/wolfskin/releases/download/pwolfskin-v1.0.9-2-g3094fc8c/Wolfskin-release.apk"
},
{
"name": "Wolfskin-debug-arm64-v8a.apk",
"browser_download_url": "https://git.justinvisser.org/justinzeus/wolfskin/releases/download/pwolfskin-v1.0.9-2-g3094fc8c/Wolfskin-debug-arm64-v8a.apk"
},
{
"name": "Wolfskin-release-arm64-v8a.apk",
"browser_download_url": "https://git.justinvisser.org/justinzeus/wolfskin/releases/download/pwolfskin-v1.0.9-2-g3094fc8c/Wolfskin-release-arm64-v8a.apk"
}
]
}

View file

@ -17,6 +17,11 @@ use the catalog's exact Wholphin extension version (currently `0.2.4`). Do not
place local extension AARs in `app/libs`: upstream prefers them over the pinned place local extension AARs in `app/libs`: upstream prefers them over the pinned
GitHub Packages dependencies. GitHub Packages dependencies.
Upload release assets renamed to `Wolfskin.apk` / `Wolfskin-<abi>.apk` for the
in-app updater. Gradle outputs
`Wholphin-default-release-<versionName>-<versionCode>[-<abi>].apk`; strip the
flavor, version, and code as well as replacing the prefix.
Upstream enables JVM unit tests only for debug variants; there is no Upstream enables JVM unit tests only for debug variants; there is no
`testDefaultReleaseUnitTest` task. `make test` uses the closest default-flavor `testDefaultReleaseUnitTest` task. `make test` uses the closest default-flavor
task without changing upstream's test configuration. task without changing upstream's test configuration.