1 // Top-level build file where you can add configuration options common to all sub-projects/modules.
3 import io.gitlab.arturbosch.detekt.Detekt
4 import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask
5 import org.gradle.internal.logging.text.StyledTextOutput.Style
6 import org.gradle.internal.logging.text.StyledTextOutputFactory
7 import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
8 import static org.gradle.api.tasks.testing.TestResult.ResultType
12 gradle.mozconfig.substs.GRADLE_MAVEN_REPOSITORIES.each { repository ->
15 if (gradle.mozconfig.substs.ALLOW_INSECURE_GRADLE_REPOSITORIES) {
16 allowInsecureProtocol = true
23 classpath ComponentsDependencies.tools_androidgradle
24 classpath ComponentsDependencies.tools_kotlingradle
27 // Variables in plugins {} aren't directly supported. Hack around it by setting an
28 // intermediate variable which can pull from FenixDependencies.kt and be used later.
30 detekt_plugin = Versions.detekt
31 python_envs_plugin = Versions.python_envs_plugin
32 ksp_plugin = Versions.ksp_plugin
37 id("io.gitlab.arturbosch.detekt").version("$detekt_plugin")
38 id("com.google.devtools.ksp").version("$ksp_plugin")
43 gradle.mozconfig.substs.GRADLE_MAVEN_REPOSITORIES.each { repository ->
46 if (gradle.mozconfig.substs.ALLOW_INSECURE_GRADLE_REPOSITORIES) {
47 allowInsecureProtocol = true
53 url "${gradle.mozconfig.topobjdir}/gradle/maven"
59 apply plugin: 'jacoco'
61 // Enable Kotlin warnings as errors for all modules
62 tasks.withType(KotlinCompile).configureEach {
63 kotlinOptions.allWarningsAsErrors = true
66 project.configurations.configureEach {
67 // Dependencies can't depend on a different major version of Glean than A-C itself.
68 resolutionStrategy.eachDependency { details ->
69 if (details.requested.group == 'org.mozilla.telemetry'
70 && details.requested.name.contains('glean') ) {
71 def requested = details.requested.version.tokenize(".")
72 def defined = Versions.mozilla_glean.tokenize(".")
73 // Check the major version
74 if (requested[0] != defined[0]) {
75 throw new AssertionError("Cannot resolve to a single Glean version. Requested: ${details.requested.version}, A-C uses: ${Versions.mozilla_glean}")
77 // Enforce that all (transitive) dependencies are using the defined Glean version
78 details.useVersion Versions.mozilla_glean
83 resolutionStrategy.capabilitiesResolution.withCapability("org.mozilla.telemetry:glean-native") {
84 def toBeSelected = candidates.find { it.id instanceof ModuleComponentIdentifier && it.id.module.contains('geckoview') }
85 if (toBeSelected != null) {
88 because 'use GeckoView Glean instead of standalone Glean'
93 // Allow local appservices substitution in each subproject.
94 def appServicesSrcDir = null
95 if (gradle.hasProperty('localProperties.autoPublish.application-services.dir')) {
96 appServicesSrcDir = gradle.getProperty('localProperties.autoPublish.application-services.dir')
97 } else if (gradle.hasProperty('localProperties.branchBuild.application-services.dir')) {
98 appServicesSrcDir = gradle.getProperty('localProperties.branchBuild.application-services.dir')
100 if (appServicesSrcDir) {
101 if (appServicesSrcDir.startsWith("/")) {
102 apply from: "${appServicesSrcDir}/build-scripts/substitute-local-appservices.gradle"
104 apply from: "${rootProject.projectDir}/${appServicesSrcDir}/build-scripts/substitute-local-appservices.gradle"
108 // Allow local Glean substitution in each subproject.
109 if (gradle.hasProperty('localProperties.autoPublish.glean.dir')) {
110 ext.gleanSrcDir = gradle."localProperties.autoPublish.glean.dir"
111 apply from: "${rootProject.projectDir}/${gleanSrcDir}/build-scripts/substitute-local-glean.gradle"
114 if (gradle.hasProperty('localProperties.dependencySubstitutions.geckoviewTopsrcdir')) {
115 if (gradle.hasProperty('localProperties.dependencySubstitutions.geckoviewTopobjdir')) {
116 ext.topobjdir = gradle."localProperties.dependencySubstitutions.geckoviewTopobjdir"
118 ext.topsrcdir = gradle."localProperties.dependencySubstitutions.geckoviewTopsrcdir"
119 apply from: "${topsrcdir}/substitute-local-geckoview.gradle"
123 if (it.hasProperty('android')) {
125 toolVersion = Versions.jacoco
128 // Format test output
129 tasks.matching {it instanceof Test}.configureEach() {
130 systemProperty "robolectric.logging", "stdout"
131 systemProperty "logging.test-mode", "true"
132 systemProperty "javax.net.ssl.trustStoreType", "JKS"
134 testLogging.events = []
136 def out = services.get(StyledTextOutputFactory).create("an-ouput")
138 beforeSuite { descriptor ->
139 if (descriptor.getClassName() != null) {
140 out.style(Style.Header).println("\nSUITE: " + descriptor.getClassName())
144 beforeTest { descriptor ->
145 out.style(Style.Description).println(" TEST: " + descriptor.getName())
148 onOutput { descriptor, event ->
149 logger.lifecycle(" " + event.message.trim())
152 afterTest { descriptor, result ->
153 switch (result.getResultType()) {
154 case ResultType.SUCCESS:
155 out.style(Style.Success).println(" SUCCESS")
158 case ResultType.FAILURE:
159 def testId = descriptor.getClassName() + "." + descriptor.getName()
160 out.style(Style.Failure).println(" TEST-UNEXPECTED-FAIL | " + testId + " | " + result.getException())
163 case ResultType.SKIPPED:
164 out.style(Style.Info).println(" SKIPPED")
172 lintChecks project(':tooling-lint')
176 jvmToolchain(config.jvmTargetCompatibility)
182 includeAndroidResources = true
188 excludes += ['META-INF/atomicfu.kotlin_module', 'META-INF/AL2.0', 'META-INF/LGPL2.1']
189 // Required dependencies using byte-buddy; remove after this is
190 // fixed by: https://issuetracker.google.com/issues/170131605
191 excludes.add("META-INF/licenses/ASM")
193 pickFirsts += ['win32-x86-64/attach_hotspot_windows.dll', 'win32-x86/attach_hotspot_windows.dll']
198 ignoreAssetsPattern "manifest.template.json"
201 tasks.withType(KotlinCompile).configureEach {
202 kotlinOptions.freeCompilerArgs += ["-opt-in=kotlin.RequiresOptIn"]
206 if (project.hasProperty("coverage") && project.name != "support-test") {
207 android.buildTypes.all { buildType ->
208 tasks.withType(Test).configureEach() {
210 includeNoLocationClasses = true
211 excludes = ['jdk.internal.*']
214 finalizedBy { "jacoco${buildType.name.capitalize()}TestReport" }
217 tasks.register("jacoco${buildType.name.capitalize()}TestReport", JacocoReport) {
223 def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*',
224 '**/*Test*.*', 'android/**/*.*', '**/*$[0-9].*']
225 def kotlinDebugTree = fileTree(dir: "$project.layout.buildDirectory/tmp/kotlin-classes/${buildType.name}", excludes: fileFilter)
226 def javaDebugTree = fileTree(dir: "$project.layout.buildDirectory/intermediates/classes/${buildType.name}", excludes: fileFilter)
227 def mainSrc = "$project.projectDir/src/main/java"
229 sourceDirectories.setFrom(files([mainSrc]))
230 classDirectories.setFrom(files([kotlinDebugTree, javaDebugTree]))
231 getExecutionData().setFrom(fileTree(project.layout.buildDirectory).include([
232 "jacoco/test${buildType.name.capitalize()}UnitTest.exec"
240 testCoverageEnabled true
248 tasks.withType(KotlinCompile).configureEach {
249 // Translate Kotlin messages like "w: ..." and "e: ..." into
250 // "...: warning: ..." and "...: error: ...", to make Treeherder understand.
252 if (it.startsWith("e: warnings found")) {
256 if (it.startsWith('w: ') || it.startsWith('e: ')) {
257 def matches = (it =~ /([ew]): (.+):(\d+):(\d+) (.*)/)
259 logger.quiet "kotlinc message format has changed!"
260 if (it.startsWith('w: ')) {
261 // For warnings, don't continue because we don't want to throw an
262 // exception. For errors, we want the exception so that the new error
263 // message format gets translated properly.
267 def (_, type, file, line, column, message) = matches[0]
268 type = (type == 'w') ? 'warning' : 'error'
269 // Use logger.lifecycle, which does not go through stderr again.
270 logger.lifecycle "$file:$line:$column: $type: $message"
272 } as StandardOutputListener
275 logging.addStandardErrorListener(listener)
278 logging.removeStandardErrorListener(listener)
283 if (findProject(":geckoview") == null) {
284 // Avoid adding this task if it already exists in a different root project.
285 tasks.register("clean", Delete) {
286 delete rootProject.layout.buildDirectory
291 input = files("$projectDir/components", "$projectDir/buildSrc", "$projectDir/samples")
292 config = files("$projectDir/config/detekt.yml")
293 baseline = file("$projectDir/config/detekt-baseline.xml")
298 destination = file("$projectDir/build/reports/detekt.html")
309 tasks.withType(Detekt).configureEach() {
310 // Custom detekt rules should be build before
311 // See https://arturbosch.github.io/detekt/extensions.html#pitfalls
312 dependsOn(":tooling-detekt:assemble")
316 exclude "**/build.gradle.kts"
317 exclude "**/src/androidTest/**"
318 exclude "**/src/iosTest/**"
319 exclude "**/src/test/**"
320 exclude "**/test/src/**"
321 exclude "**/build/**"
322 exclude "**/resources/**"
324 exclude "**/tooling/fetch/tests/**"
325 exclude "**/tooling/fetch-tests/**"
326 exclude "**/src/main/assets/extensions/**"
330 // Apply same path exclusions as for the main task
331 tasks.withType(DetektCreateBaselineTask).configureEach() {
332 exclude "**/src/androidTest/**"
333 exclude "**/src/test/**"
334 exclude "**/test/src/**"
335 exclude "**/build/**"
336 exclude "**/resources/**"
338 exclude "**/tooling/fetch/tests/**"
339 exclude "**/tooling/fetch-tests/**"
347 ktlint("com.pinterest:ktlint:${Versions.ktlint}") {
349 attribute(Bundling.BUNDLING_ATTRIBUTE, getObjects().named(Bundling, Bundling.EXTERNAL))
352 detektPlugins project(":tooling-detekt")
355 tasks.register("ktlint", JavaExec) {
356 group = "verification"
357 description = "Check Kotlin code style."
358 classpath = configurations.ktlint
359 mainClass.set("com.pinterest.ktlint.Main")
360 args "components/**/*.kt" , "samples/**/*.kt", "!**/build/**/*.kt", "buildSrc/**/*.kt", "--baseline=ktlint-baseline.xml"
363 tasks.register("ktlintFormat", JavaExec) {
365 description = "Fix Kotlin code style deviations."
366 classpath = configurations.ktlint
367 mainClass.set("com.pinterest.ktlint.Main")
368 args "-F", "components/**/*.kt" , "samples/**/*.kt", "!**/build/**/*.kt", "buildSrc/**/*.kt", "--baseline=ktlint-baseline.xml"
369 jvmArgs("--add-opens", "java.base/java.lang=ALL-UNNAMED")
372 tasks.register("listRepositories") {
374 println "Repositories:"
375 project.repositories.each { println "Name: " + it.name + "; url: " + it.url }
379 tasks.register("testToolsDir", Exec) {
380 group = "verification"
381 description = "Run tests in the tools/ directory."
383 commandLine = ["python3", "test_list_compatible_dependency_versions.py"]