diff --git a/.forgejo/workflows/android.yml b/.forgejo/workflows/android.yml index ae97cbf..0e8e0b9 100644 --- a/.forgejo/workflows/android.yml +++ b/.forgejo/workflows/android.yml @@ -79,11 +79,18 @@ jobs: - name: Build the native library and bindings run: ./gradlew generateUniffiBindings + # The image's PINNED CLIs, not Gradle plugins. ci-rust-android carries both + # (M12 step 3) precisely so this lane needs no second image, and going + # through Gradle plugins would mean a second version of each tool resolved + # at build time and kept in lockstep with the image's by hand. + # + # Scoped to src/main: the generated uniffi bindings live under build/ and + # are not ours to style. - name: ktlint - run: ./gradlew ktlintCheck + run: ktlint "app/src/main/**/*.kt" - name: detekt - run: ./gradlew detekt + run: detekt --build-upon-default-config --config config/detekt.yml --input app/src/main/java - name: Unit tests # Host-JVM tests only. Anything touching the core needs an Android diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 95bf552..656f307 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -3,8 +3,6 @@ import javax.inject.Inject plugins { alias(libs.plugins.android.application) alias(libs.plugins.compose.compiler) - alias(libs.plugins.ktlint) - alias(libs.plugins.detekt) } // The Cargo workspace root — two levels up from android/app. @@ -192,8 +190,14 @@ android { sourceSets { getByName("main") { // The .so and the bindings are build outputs, not checked-in sources. - jniLibs.srcDir(jniLibsOut) - java.srcDir(bindingsOut) + // Passing the TASK PROVIDERS, not plain paths: Gradle reads each + // task's @OutputDirectory and infers the build ordering itself. A + // bare path would compile Kotlin before the bindings exist, and the + // usual fix — depending on KotlinCompile by type — cannot be written + // here, because AGP 9's built-in Kotlin means that class is not on + // the buildscript classpath. + jniLibs.srcDir(cargoNdkDebug) + java.srcDir(generateBindings) } } @@ -202,25 +206,6 @@ android { } } -// Kotlin compilation needs the generated bindings to exist first. -tasks.withType().configureEach { - dependsOn(generateBindings) -} -tasks.named("preBuild") { dependsOn(generateBindings) } - -// ktlint must not police generated code — it is uniffi's output, not ours, and -// there is no edit that would fix a complaint about it. -ktlint { - filter { - exclude { it.file.path.contains("generated") } - } -} - -detekt { - buildUponDefaultConfig = true - config.setFrom(files("$rootDir/config/detekt.yml")) -} - dependencies { implementation(libs.androidx.core.ktx) implementation(libs.androidx.activity.compose) diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 558f6d5..9866537 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -4,6 +4,6 @@ plugins { // older plugin can't cast AGP 9's ApplicationExtension to the removed // BaseExtension. Same conclusion Minstrel reached on this toolchain pair. alias(libs.plugins.compose.compiler) apply false - alias(libs.plugins.ktlint) apply false - alias(libs.plugins.detekt) apply false + // ktlint/detekt are run from the CI image's pinned CLIs, not as Gradle + // plugins — see the note in gradle/libs.versions.toml. } diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml index 9456b01..fa16ef5 100644 --- a/android/gradle/libs.versions.toml +++ b/android/gradle/libs.versions.toml @@ -12,10 +12,12 @@ lifecycle = "2.8.7" activity-compose = "1.9.3" coroutines = "1.9.0" -# LOCKSTEP with ci-rust-android's versions.env. Bumping either side alone makes -# local and CI analysis disagree; Renovate cannot see the coupling. -ktlint-gradle = "12.1.1" -detekt = "2.0.0-alpha.3" +# ktlint and detekt are NOT Gradle plugins here. ci-rust-android already ships +# both as pinned CLIs (M12 step 3), and the CI lane invokes those directly. Adding +# the Gradle plugins would mean a SECOND pinned version of each tool, resolved at +# build time, that has to be kept in lockstep with the image's by hand — and the +# first attempt at it failed outright, because the detekt version Minstrel pins +# (2.0.0-alpha.3) is not published to Maven Central or the plugin portal at all. # JNA is not optional: uniffi's Kotlin bindings call into the .so through it. # The @aar classifier matters — the plain jar has no Android native payload and @@ -42,5 +44,3 @@ junit = { module = "junit:junit", version.ref = "junit" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } -ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint-gradle" } -detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }