140 lines
6.8 KiB
Kotlin
140 lines
6.8 KiB
Kotlin
import groovy.json.JsonOutput
|
|
import java.io.File
|
|
import java.security.MessageDigest
|
|
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
|
|
import org.gradle.api.artifacts.ExternalModuleDependency
|
|
import org.gradle.api.artifacts.ProjectDependency
|
|
|
|
plugins {
|
|
alias(libs.plugins.android.application) apply false
|
|
alias(libs.plugins.android.library) apply false
|
|
alias(libs.plugins.kotlin.jvm) apply false
|
|
alias(libs.plugins.compose) apply false
|
|
alias(libs.plugins.hilt) apply false
|
|
alias(libs.plugins.ksp) apply false
|
|
alias(libs.plugins.ktlint) apply false
|
|
}
|
|
|
|
val allowed = mapOf(
|
|
":app" to setOf(":features", ":core", ":platform"),
|
|
":features" to setOf(":core"),
|
|
":core" to setOf(":rust-bridge"),
|
|
":platform" to setOf(":core"),
|
|
":rust-bridge" to emptySet(),
|
|
)
|
|
subprojects {
|
|
apply(plugin = "org.jlleitschuh.gradle.ktlint")
|
|
extensions.configure<org.jlleitschuh.gradle.ktlint.KtlintExtension> {
|
|
version.set(rootProject.libs.versions.ktlint.get())
|
|
filter { exclude("**/build/**") }
|
|
}
|
|
dependencyLocking { lockAllConfigurations() }
|
|
val ownerPath = project.path
|
|
configurations.configureEach {
|
|
dependencies.withType<ProjectDependency>().configureEach {
|
|
val destination = this.path
|
|
require(destination == ownerPath || destination in allowed.getValue(ownerPath)) {
|
|
"$ownerPath cannot depend on $destination"
|
|
}
|
|
}
|
|
dependencies.withType<ExternalModuleDependency>().configureEach {
|
|
require(group.orEmpty().let { group ->
|
|
listOf("org.eclipse.jgit", "org.bouncycastle", "androidx.room", "com.squareup.retrofit2", "com.squareup.okhttp3").none { group.startsWith(it) }
|
|
}) { "Domain libraries must stay in crates/storage: $group:$name" }
|
|
}
|
|
val enforceDomain = name.endsWith("RuntimeClasspath") || name.endsWith("CompileClasspath")
|
|
resolutionStrategy.eachDependency {
|
|
require(requested.version.orEmpty().let { version ->
|
|
!version.contains('+') && !version.contains("SNAPSHOT") &&
|
|
!version.startsWith("latest.") && version.none { it in "[]()," }
|
|
}) { "Dynamic versions are forbidden" }
|
|
require(!enforceDomain || listOf("org.eclipse.jgit", "org.bouncycastle", "androidx.room", "com.squareup.retrofit2", "com.squareup.okhttp3", "org.pgpainless", "com.google.mlkit").none {
|
|
requested.group == it || requested.group.startsWith("$it.")
|
|
}) { "Transitive domain libraries must stay in crates/storage" }
|
|
}
|
|
}
|
|
}
|
|
|
|
val cargoExecutable = providers.environmentVariable("CARGO")
|
|
.orElse(providers.environmentVariable("PATH").map { path ->
|
|
path.split(File.pathSeparatorChar)
|
|
.map { File(it, "cargo") }
|
|
.firstOrNull { it.isFile && it.canExecute() }?.absolutePath
|
|
?: error("Cargo is required: put it in PATH or set CARGO to its absolute path")
|
|
})
|
|
val workspace = layout.projectDirectory.dir("..").asFile
|
|
val checkArchitecture = tasks.register<Exec>("checkArchitecture") {
|
|
workingDir = workspace
|
|
inputs.files(fileTree(".") { include("**/src/**/*.kt", "**/build.gradle.kts"); exclude("**/build/**", ".gradle/**") })
|
|
inputs.files(workspace.resolve("Cargo.lock"), workspace.resolve("tools/android-build/src/main.rs"))
|
|
commandLine(cargoExecutable.get(), "run", "--locked", "--package", "ironstorage-android-build", "--", "check", layout.projectDirectory.asFile.absolutePath)
|
|
}
|
|
subprojects {
|
|
tasks.matching { it.name == "preBuild" || it.name == "check" }.configureEach { dependsOn(rootProject.tasks.named("checkArchitecture")) }
|
|
}
|
|
|
|
tasks.register<Exec>("auditNativePackages") {
|
|
dependsOn(":app:assembleDebug", ":app:assembleRelease", ":app:bundleRelease")
|
|
workingDir = workspace
|
|
val packages = listOf(
|
|
layout.projectDirectory.file("app/build/outputs/apk/debug/app-debug.apk"),
|
|
layout.projectDirectory.file("app/build/outputs/apk/release/app-release-unsigned.apk"),
|
|
layout.projectDirectory.file("app/build/outputs/bundle/release/app-release.aab")
|
|
)
|
|
inputs.files(packages)
|
|
commandLine(
|
|
listOf(
|
|
cargoExecutable.get(), "+${libs.versions.rust.get()}", "run", "--locked",
|
|
"--package", "ironstorage-android-build", "--", "audit-package"
|
|
) + packages.map { it.asFile.absolutePath }
|
|
)
|
|
}
|
|
|
|
|
|
// Each project resolves its own configurations under Gradle's project lock.
|
|
subprojects {
|
|
val owner = project
|
|
tasks.register("dependencyInventory") {
|
|
val output = layout.buildDirectory.file("reports/android-dependencies.json")
|
|
outputs.file(output)
|
|
outputs.upToDateWhen { false }
|
|
doLast {
|
|
val rows = listOf("debugRuntimeClasspath", "releaseRuntimeClasspath", "debugAndroidTestRuntimeClasspath", "debugUnitTestRuntimeClasspath").flatMap { name ->
|
|
val configuration = owner.configurations.findByName(name)
|
|
if (configuration == null || !configuration.isCanBeResolved) emptyList() else {
|
|
configuration.incoming.artifactView {
|
|
componentFilter { it is ModuleComponentIdentifier }
|
|
}.artifacts.artifacts.mapNotNull { artifact ->
|
|
val id = artifact.id.componentIdentifier as? ModuleComponentIdentifier
|
|
id?.let {
|
|
mapOf(
|
|
"group" to it.group, "name" to it.module, "version" to it.version,
|
|
"sha256" to MessageDigest.getInstance("SHA-256").digest(artifact.file.readBytes())
|
|
.joinToString("") { byte -> "%02x".format(byte) },
|
|
"scope" to "${owner.path}:$name"
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}.sortedWith(compareBy({ it.getValue("scope") }, { it.getValue("group") }, { it.getValue("name") }, { it.getValue("version") }, { it.getValue("sha256") }))
|
|
output.get().asFile.apply {
|
|
parentFile.mkdirs()
|
|
writeText(JsonOutput.prettyPrint(JsonOutput.toJson(rows)) + "\n")
|
|
}
|
|
}
|
|
notCompatibleWithConfigurationCache("Resolves reviewed artifact graphs")
|
|
}
|
|
}
|
|
|
|
tasks.register("dependencyInventory") {
|
|
dependsOn(subprojects.map { "${it.path}:dependencyInventory" })
|
|
}
|
|
|
|
tasks.register("androidVerification") {
|
|
dependsOn("checkArchitecture", "dependencyInventory", "auditNativePackages")
|
|
dependsOn(subprojects.map { "${it.path}:ktlintCheck" })
|
|
dependsOn(subprojects.map { "${it.path}:lintDebug" })
|
|
dependsOn(subprojects.map { "${it.path}:testDebugUnitTest" })
|
|
dependsOn(":app:assembleDebugAndroidTest", ":rust-bridge:assembleDebugAndroidTest", ":platform:assembleDebugAndroidTest")
|
|
}
|