// Top-level build file where you can add configuration options common to all sub-projects/modules. import io.gitlab.arturbosch.detekt.Detekt import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import java.nio.file.Files import java.nio.file.Paths import java.nio.file.StandardCopyOption buildscript { // This logic is duplicated in the allprojects block: I don't know how to fix that. repositories { gradle.mozconfig.substs.GRADLE_MAVEN_REPOSITORIES.each { repository -> maven { url repository if (gradle.mozconfig.substs.ALLOW_INSECURE_GRADLE_REPOSITORIES) { allowInsecureProtocol = true } } } } dependencies { classpath ComponentsDependencies.tools_androidgradle classpath ComponentsDependencies.tools_kotlingradle classpath FenixDependencies.tools_benchmarkgradle classpath ComponentsDependencies.androidx_safeargs classpath FenixDependencies.osslicenses_plugin classpath "org.mozilla.telemetry:glean-gradle-plugin:${Versions.mozilla_glean}" classpath "${ApplicationServicesConfig.groupId}:tooling-nimbus-gradle:${ApplicationServicesConfig.version}" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } // Variables in plugins {} aren't directly supported. Hack around it by setting an // intermediate variable which can pull from FenixDependenciesPlugin.kt and be used later. ext { detekt_plugin = Versions.detekt ksp_plugin = Versions.ksp_plugin protobuf_plugin = FenixVersions.protobuf_plugin python_envs_plugin = Versions.python_envs_plugin } } plugins { id("io.gitlab.arturbosch.detekt").version("$detekt_plugin") id("com.google.devtools.ksp").version("$ksp_plugin") } allprojects { // This logic is duplicated in the buildscript block: I don't know how to fix that. repositories { gradle.mozconfig.substs.GRADLE_MAVEN_REPOSITORIES.each { repository -> maven { url repository if (gradle.mozconfig.substs.ALLOW_INSECURE_GRADLE_REPOSITORIES) { allowInsecureProtocol = true } } } } tasks.withType(KotlinCompile).configureEach { kotlinOptions.allWarningsAsErrors = true kotlinOptions.freeCompilerArgs += [ "-opt-in=kotlin.RequiresOptIn", "-Xjvm-default=all-compatibility" ] } ext { gleanParserOverride = "14.4.0" } } subprojects { afterEvaluate { kotlin { jvmToolchain(config.jvmTargetCompatibility) } } tasks.withType(KotlinCompile).configureEach { task -> // Translate Kotlin messages like "w: ..." and "e: ..." into // "...: warning: ..." and "...: error: ...", to make Treeherder understand. def listener = { if (it.startsWith("e: warnings found")) { return } if (it.startsWith('w: ') || it.startsWith('e: ')) { def matches = (it =~ /([ew]): (.+):(\d+):(\d+) (.*)/) if (!matches) { logger.quiet "kotlinc message format has changed!" if (it.startsWith('w: ')) { // For warnings, don't continue because we don't want to throw an // exception. For errors, we want the exception so that the new error // message format gets translated properly. return } } def (_, type, file, line, column, message) = matches[0] type = (type == 'w') ? 'warning' : 'error' // Use logger.lifecycle, which does not go through stderr again. logger.lifecycle "$file:$line:$column: $type: $message" } } as StandardOutputListener doFirst { logging.addStandardErrorListener(listener) } doLast { logging.removeStandardErrorListener(listener) } } } tasks.register('clean', Delete) { delete rootProject.layout.buildDirectory } detekt { input = files("$projectDir/app/src") config = files("$projectDir/config/detekt.yml") reports { html { enabled = true destination = file("$projectDir/build/reports/detekt.html") } xml { enabled = false } txt { enabled = false } } } tasks.withType(Detekt).configureEach() { autoCorrect = true exclude "**/test/**" exclude "**/androidTest/**" exclude "**/build/**" exclude "**/resources/**" exclude "**/tmp/**" } // Apply same path exclusions as for the main task tasks.withType(DetektCreateBaselineTask).configureEach() { exclude "**/test/**" exclude "**/androidTest/**" exclude "**/build/**" exclude "**/resources/**" exclude "**/tmp/**" } configurations { ktlint } dependencies { ktlint("com.pinterest:ktlint:${Versions.ktlint}") { attributes { attribute(Bundling.BUNDLING_ATTRIBUTE, getObjects().named(Bundling, Bundling.EXTERNAL)) } } detekt project(":mozilla-detekt-rules") detekt "io.gitlab.arturbosch.detekt:detekt-cli:${Versions.detekt}" } tasks.register('ktlint', JavaExec) { group = "verification" description = "Check Kotlin code style." classpath = configurations.ktlint mainClass.set("com.pinterest.ktlint.Main") args "app/src/**/*.kt", "!**/build/**/*.kt", "--baseline=ktlint-baseline.xml" } tasks.register('ktlintFormat', JavaExec) { description = "Fix Kotlin code style deviations." classpath = configurations.ktlint mainClass.set("com.pinterest.ktlint.Main") args "-F", "app/src/**/*.kt", "!**/build/**/*.kt", "--baseline=ktlint-baseline.xml" jvmArgs("--add-opens", "java.base/java.lang=ALL-UNNAMED") } tasks.withType(Detekt.class).configureEach { exclude("**/resources/**") exclude("**/tmp/**") } tasks.register("listRepositories") { doLast { println "Repositories:" project.repositories.each { println "Name: " + it.name + "; url: " + it.url } } } // Task to copy generated baseline profile to the app module nightly variant. tasks.register("copyBaselineProfile", DefaultTask) { doLast { File profileFile = fileTree('benchmark/build/outputs') { include '**/*baseline-prof.txt' }.getSingleFile() def destinationPath = Paths.get("app", "src", "nightly", "baselineProfiles", "baseline-prof.txt") File destinationDir = destinationPath.toFile().parentFile if (!destinationDir.exists()) { destinationDir.mkdirs() } Files.copy(profileFile.toPath(), destinationPath, StandardCopyOption.REPLACE_EXISTING) } }