ci: gitea actions for the suites, the image and the APK
Four workflows, none of which existed: * `tests.yml` — backend, desktop, `:core` and the web app's typecheck+build, in parallel. `:core` needs no Android SDK at all, because settings.gradle.kts leaves `:app` out when there is none; `:app`'s Robolectric suite therefore lives in the APK workflow, where the SDK is installed anyway. Nothing needs a running backend — the suites feed on committed fixtures, which is the whole reason they were written that way. * `lint.yml` — ruff, which the repo had been configured for and never run. * `docker.yml` — builds the image, *starts* it against SQLite and waits for /api/health before pushing, then publishes `:latest` and `:<short-sha>` to git.timka.su. A tag nobody can run is worse than no tag. * `android-release.yml` — the release APK on every push to master, signed from secrets, with `apksigner verify --print-certs` reporting which key was really used and failing if it was the debug one. Three things the repo needed before any of that could work: `versionCode` was pinned at 1, so every APK looked like the same version to the phone and would not install over its predecessor. It now comes from the run number, with `versionName` from a property, both via one `setting()` helper that reads a Gradle property or an environment variable. The release build fell back to the *debug* signing key whenever the keystore was missing — silently. That is a trap: the APK installs, looks fine, and can never be upgraded by a properly signed build. `KADENCE_REQUIRE_SIGNING=1` makes that case fail the build instead, and the release job sets it whenever a keystore secret is present. The compose files built an image with no name, so there was nothing to pull. `image:` now names the registry tag while `up --build` still builds locally. Also: `android/ci/install-sdk.sh` (idempotent, cacheable, and the one place that knows `platforms;android-37.0` is spelled with the minor version), the runner as a compose service with its config and a setup checklist, six make targets, and a README section. No runner is registered yet — `make ci-runner` is step two of that checklist. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
11 files changed
+547
-11
No files matched your search
@@ -19,6 +19,25 @@ plugins {
|
||||
val glyphAar = layout.projectDirectory.file("libs/glyph-matrix-sdk-2.0.aar").asFile
|
||||
val hasGlyphSdk = glyphAar.isFile
|
||||
|
||||
/**
|
||||
* One property or environment variable, whichever is set.
|
||||
*
|
||||
* CI passes these as environment variables and a developer puts them in
|
||||
* `~/.gradle/gradle.properties`; neither should have to care which the build reads.
|
||||
*/
|
||||
fun setting(name: String): String? =
|
||||
(project.findProperty(name) as String?) ?: System.getenv(name)
|
||||
|
||||
/**
|
||||
* Successive builds have to install over each other, so the code has to climb.
|
||||
*
|
||||
* It was pinned at 1, which meant every CI artifact looked like the same version to
|
||||
* the phone. In CI this is the run number; locally it stays 1, because a developer
|
||||
* installing over their own debug build does not care.
|
||||
*/
|
||||
val buildVersionCode = setting("KADENCE_VERSION_CODE")?.toIntOrNull() ?: 1
|
||||
val buildVersionName = setting("KADENCE_VERSION_NAME") ?: "0.1.0"
|
||||
|
||||
android {
|
||||
namespace = "tech.kadence.android"
|
||||
compileSdk = libs.versions.compileSdk.get().toInt()
|
||||
@@ -27,8 +46,8 @@ android {
|
||||
applicationId = "tech.kadence.android"
|
||||
minSdk = libs.versions.minSdk.get().toInt()
|
||||
targetSdk = libs.versions.targetSdk.get().toInt()
|
||||
versionCode = 1
|
||||
versionName = "1.0.0"
|
||||
versionCode = buildVersionCode
|
||||
versionName = buildVersionName
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
buildConfigField("boolean", "HAS_GLYPH_SDK", hasGlyphSdk.toString())
|
||||
@@ -53,16 +72,21 @@ android {
|
||||
// key: it still produces an installable APK for one's own phone, which is the
|
||||
// only distribution this app has.
|
||||
create("release") {
|
||||
val storePath = (project.findProperty("KADENCE_KEYSTORE") as String?)
|
||||
?: System.getenv("KADENCE_KEYSTORE")
|
||||
val storePath = setting("KADENCE_KEYSTORE")
|
||||
if (storePath != null && file(storePath).isFile) {
|
||||
storeFile = file(storePath)
|
||||
storePassword = (project.findProperty("KADENCE_KEYSTORE_PASSWORD") as String?)
|
||||
?: System.getenv("KADENCE_KEYSTORE_PASSWORD")
|
||||
keyAlias = (project.findProperty("KADENCE_KEY_ALIAS") as String?)
|
||||
?: System.getenv("KADENCE_KEY_ALIAS") ?: "kadence"
|
||||
keyPassword = (project.findProperty("KADENCE_KEY_PASSWORD") as String?)
|
||||
?: System.getenv("KADENCE_KEY_PASSWORD")
|
||||
storePassword = setting("KADENCE_KEYSTORE_PASSWORD")
|
||||
keyAlias = setting("KADENCE_KEY_ALIAS") ?: "kadence"
|
||||
keyPassword = setting("KADENCE_KEY_PASSWORD")
|
||||
} else if (setting("KADENCE_REQUIRE_SIGNING") == "1") {
|
||||
// Without this the fallback below quietly produces a *debug-signed*
|
||||
// "release" APK: installable, apparently fine, and impossible to ship
|
||||
// or to upgrade a real install with. A release job sets this so a
|
||||
// missing or misnamed secret fails the build instead of the release.
|
||||
throw GradleException(
|
||||
"KADENCE_REQUIRE_SIGNING is set but no keystore was found at " +
|
||||
"${storePath ?: "<KADENCE_KEYSTORE unset>"}",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user