Release version management: single VERSION file as source of truth
- VERSION at repo root (0.1.2); bump it to cut a release - App: generated AppVersion.kt (config-cache-safe Gradle task with VERSION as declared input) shown in Settings; sent to the gateway via X-Iris-App-Version header on the SSE open - Gateway: reports its own version in hello.ack server_caps.app_version (read from the repo-root VERSION via the plugin symlink); stores the app's version in the device registry caps (merge, not overwrite, so an old app reconnecting without the header doesn't wipe it) - Settings: app + gateway version rows, mismatch hint, and a best-effort Gitea latest-release check (ReleaseCheck) with an 'update available' hint - Release workflow: reads VERSION from the repo (no manual input), with a guard against an empty file - Docs: frames.schema.json + 04-wire-protocol.md updated for app_version
This commit is contained in:
1 parent
f3f1b37221
commit
fb980d12b4
17 files changed
+422
-37
No files matched your search
@@ -33,6 +33,48 @@ val sqldelightVersion = "2.3.2"
|
||||
val cameraxVersion = "1.5.1"
|
||||
val mlKitVersion = "16.1.1"
|
||||
|
||||
// ── App version (generated) ─────────────────────────────────────────────
|
||||
// The repo-root VERSION file is the single source of truth (bump it to cut
|
||||
// a release; CI can still override with -PappVersion). Generate AppVersion.kt
|
||||
// into commonMain so both targets can display it in Settings and send it to
|
||||
// the gateway (X-Iris-App-Version header).
|
||||
//
|
||||
// A real task with the VERSION file as a DECLARED input: on a
|
||||
// configuration-cache hit the script body does not re-run, so only the task
|
||||
// (keyed on the file's content) can regenerate AppVersion.kt after a bump.
|
||||
// The doLast reads everything from the task's own inputs/outputs (which are
|
||||
// configuration-cache serializable) — it must not reference script-scope
|
||||
// vals, because a .kts script lambda captures the script object and the
|
||||
// configuration cache rejects that.
|
||||
val generatedVersionDir = layout.buildDirectory.dir("generated/app-version")
|
||||
val generateAppVersion by tasks.registering {
|
||||
inputs.file(project.file("../../VERSION"))
|
||||
inputs.property("appVersionOverride", (project.findProperty("appVersion") as? String).orEmpty())
|
||||
val outFile = generatedVersionDir.map { it.file("AppVersion.kt") }
|
||||
outputs.file(outFile)
|
||||
doLast {
|
||||
val override = inputs.properties["appVersionOverride"] as? String ?: ""
|
||||
val versionFile = inputs.files.singleFile
|
||||
val version =
|
||||
override.ifBlank {
|
||||
versionFile.takeIf { it.exists() }?.readText()?.trim() ?: "0.1.0"
|
||||
}
|
||||
val f = outFile.get().asFile
|
||||
f.parentFile?.mkdirs()
|
||||
f.writeText(
|
||||
"""
|
||||
|package iris
|
||||
|
|
||||
|/** Generated from the repo-root VERSION file - do not edit. */
|
||||
|object AppVersion {
|
||||
| const val VERSION = "$version"
|
||||
|}
|
||||
|
|
||||
""".trimMargin(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
android {
|
||||
namespace = "iris.shared"
|
||||
@@ -53,6 +95,11 @@ kotlin {
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
// AppVersion.kt is generated from the repo-root VERSION file (see
|
||||
// generateAppVersion above) into commonMain so both targets can read it.
|
||||
commonMain {
|
||||
kotlin.srcDir(generatedVersionDir)
|
||||
}
|
||||
// Both targets are JVM-based (androidTarget + jvm("desktop")), so
|
||||
// shared JVM code (File I/O, SHA-256, media cache) lives in jvmMain.
|
||||
val jvmMain by creating { dependsOn(commonMain.get()) }
|
||||
@@ -138,3 +185,8 @@ sqldelight {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Every Kotlin compile depends on the generated AppVersion.kt being current.
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
|
||||
dependsOn(generateAppVersion)
|
||||
}
|
||||
Reference in new issue
Block a user