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 if (project.hasProperty("googleRepo")) {
15 url project.property("googleRepo")
16 allowInsecureProtocol true // Local Nexus in CI uses HTTP
22 if (project.hasProperty("centralRepo")) {
25 url project.property("centralRepo")
26 allowInsecureProtocol true // Local Nexus in CI uses HTTP
34 classpath ComponentsDependencies.tools_androidgradle
35 classpath ComponentsDependencies.tools_kotlingradle
38 // Variables in plugins {} aren't directly supported. Hack around it by setting an
39 // intermediate variable which can pull from FenixDependencies.kt and be used later.
41 detekt_plugin = Versions.detekt
42 python_envs_plugin = Versions.python_envs_plugin
43 ksp_plugin = Versions.ksp_plugin
48 id("io.gitlab.arturbosch.detekt").version("$detekt_plugin")
49 id("com.google.devtools.ksp").version("$ksp_plugin")
54 if (project.hasProperty("googleRepo")) {
57 url project.property("googleRepo")
58 allowInsecureProtocol true // Local Nexus in CI uses HTTP
64 if (project.hasProperty("centralRepo")) {
67 url project.property("centralRepo")
68 allowInsecureProtocol true // Local Nexus in CI uses HTTP
76 url "https://maven.mozilla.org/maven2"
79 if (ExtraRepositories.mozillaStaging) {
81 name "Mozilla Staging"
82 url "https://maven-default.stage.mozaws.net/maven2"
89 apply plugin: 'jacoco'
91 // Enable Kotlin warnings as errors for all modules
92 tasks.withType(KotlinCompile).configureEach {
93 kotlinOptions.allWarningsAsErrors = true
96 project.configurations.configureEach {
97 // Dependencies can't depend on a different major version of Glean than A-C itself.
98 resolutionStrategy.eachDependency { details ->
99 if (details.requested.group == 'org.mozilla.telemetry'
100 && details.requested.name.contains('glean') ) {
101 def requested = details.requested.version.tokenize(".")
102 def defined = Versions.mozilla_glean.tokenize(".")
103 // Check the major version
104 if (requested[0] != defined[0]) {
105 throw new AssertionError("Cannot resolve to a single Glean version. Requested: ${details.requested.version}, A-C uses: ${Versions.mozilla_glean}")
107 // Enforce that all (transitive) dependencies are using the defined Glean version
108 details.useVersion Versions.mozilla_glean
113 resolutionStrategy.capabilitiesResolution.withCapability("org.mozilla.telemetry:glean-native") {
114 def toBeSelected = candidates.find { it.id instanceof ModuleComponentIdentifier && it.id.module.contains('geckoview') }
115 if (toBeSelected != null) {
118 because 'use GeckoView Glean instead of standalone Glean'
123 // Allow local appservices substitution in each subproject.
124 def appServicesSrcDir = null
125 if (gradle.hasProperty('localProperties.autoPublish.application-services.dir')) {
126 appServicesSrcDir = gradle.getProperty('localProperties.autoPublish.application-services.dir')
127 } else if (gradle.hasProperty('localProperties.branchBuild.application-services.dir')) {
128 appServicesSrcDir = gradle.getProperty('localProperties.branchBuild.application-services.dir')
130 if (appServicesSrcDir) {
131 if (appServicesSrcDir.startsWith("/")) {
132 apply from: "${appServicesSrcDir}/build-scripts/substitute-local-appservices.gradle"
134 apply from: "${rootProject.projectDir}/${appServicesSrcDir}/build-scripts/substitute-local-appservices.gradle"
138 // Allow local Glean substitution in each subproject.
139 if (gradle.hasProperty('localProperties.autoPublish.glean.dir')) {
140 ext.gleanSrcDir = gradle."localProperties.autoPublish.glean.dir"
141 apply from: "${rootProject.projectDir}/${gleanSrcDir}/build-scripts/substitute-local-glean.gradle"
144 if (gradle.hasProperty('localProperties.dependencySubstitutions.geckoviewTopsrcdir')) {
145 if (gradle.hasProperty('localProperties.dependencySubstitutions.geckoviewTopobjdir')) {
146 ext.topobjdir = gradle."localProperties.dependencySubstitutions.geckoviewTopobjdir"
148 ext.topsrcdir = gradle."localProperties.dependencySubstitutions.geckoviewTopsrcdir"
149 apply from: "${topsrcdir}/substitute-local-geckoview.gradle"
153 if (it.hasProperty('android')) {
155 toolVersion = Versions.jacoco
158 // Format test output
159 tasks.matching {it instanceof Test}.configureEach() {
160 systemProperty "robolectric.logging", "stdout"
161 systemProperty "logging.test-mode", "true"
162 systemProperty "javax.net.ssl.trustStoreType", "JKS"
164 testLogging.events = []
166 def out = services.get(StyledTextOutputFactory).create("an-ouput")
168 beforeSuite { descriptor ->
169 if (descriptor.getClassName() != null) {
170 out.style(Style.Header).println("\nSUITE: " + descriptor.getClassName())
174 beforeTest { descriptor ->
175 out.style(Style.Description).println(" TEST: " + descriptor.getName())
178 onOutput { descriptor, event ->
179 logger.lifecycle(" " + event.message.trim())
182 afterTest { descriptor, result ->
183 switch (result.getResultType()) {
184 case ResultType.SUCCESS:
185 out.style(Style.Success).println(" SUCCESS")
188 case ResultType.FAILURE:
189 out.style(Style.Failure).println(" FAILURE")
190 logger.lifecycle("", result.getException())
193 case ResultType.SKIPPED:
194 out.style(Style.Info).println(" SKIPPED")
202 lintChecks project(':tooling-lint')
206 jvmToolchain(config.jvmTargetCompatibility)
212 includeAndroidResources = true
218 excludes += ['META-INF/atomicfu.kotlin_module', 'META-INF/AL2.0', 'META-INF/LGPL2.1']
219 // Required dependencies using byte-buddy; remove after this is
220 // fixed by: https://issuetracker.google.com/issues/170131605
221 excludes.add("META-INF/licenses/ASM")
223 pickFirsts += ['win32-x86-64/attach_hotspot_windows.dll', 'win32-x86/attach_hotspot_windows.dll']
228 ignoreAssetsPattern "manifest.template.json"
231 tasks.withType(KotlinCompile).configureEach {
232 kotlinOptions.freeCompilerArgs += ["-opt-in=kotlin.RequiresOptIn"]
236 if (project.hasProperty("coverage") && project.name != "support-test") {
237 android.buildTypes.all { buildType ->
238 tasks.withType(Test).configureEach() {
240 includeNoLocationClasses = true
241 excludes = ['jdk.internal.*']
244 finalizedBy { "jacoco${buildType.name.capitalize()}TestReport" }
247 tasks.register("jacoco${buildType.name.capitalize()}TestReport", JacocoReport) {
253 def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*',
254 '**/*Test*.*', 'android/**/*.*', '**/*$[0-9].*']
255 def kotlinDebugTree = fileTree(dir: "$project.layout.buildDirectory/tmp/kotlin-classes/${buildType.name}", excludes: fileFilter)
256 def javaDebugTree = fileTree(dir: "$project.layout.buildDirectory/intermediates/classes/${buildType.name}", excludes: fileFilter)
257 def mainSrc = "$project.projectDir/src/main/java"
259 sourceDirectories.setFrom(files([mainSrc]))
260 classDirectories.setFrom(files([kotlinDebugTree, javaDebugTree]))
261 getExecutionData().setFrom(fileTree(project.layout.buildDirectory).include([
262 "jacoco/test${buildType.name.capitalize()}UnitTest.exec"
270 testCoverageEnabled true
279 if (findProject(":geckoview") == null) {
280 // Avoid adding this task if it already exists in a different root project.
281 tasks.register("clean", Delete) {
282 delete rootProject.layout.buildDirectory
287 input = files("$projectDir/components", "$projectDir/buildSrc", "$projectDir/samples")
288 config = files("$projectDir/config/detekt.yml")
289 baseline = file("$projectDir/config/detekt-baseline.xml")
294 destination = file("$projectDir/build/reports/detekt.html")
305 tasks.withType(Detekt).configureEach() {
306 // Custom detekt rules should be build before
307 // See https://arturbosch.github.io/detekt/extensions.html#pitfalls
308 dependsOn(":tooling-detekt:assemble")
312 exclude "**/build.gradle.kts"
313 exclude "**/src/androidTest/**"
314 exclude "**/src/iosTest/**"
315 exclude "**/src/test/**"
316 exclude "**/test/src/**"
317 exclude "**/build/**"
318 exclude "**/resources/**"
320 exclude "**/tooling/fetch/tests/**"
321 exclude "**/tooling/fetch-tests/**"
322 exclude "**/src/main/assets/extensions/**"
326 // Apply same path exclusions as for the main task
327 tasks.withType(DetektCreateBaselineTask).configureEach() {
328 exclude "**/src/androidTest/**"
329 exclude "**/src/test/**"
330 exclude "**/test/src/**"
331 exclude "**/build/**"
332 exclude "**/resources/**"
334 exclude "**/tooling/fetch/tests/**"
335 exclude "**/tooling/fetch-tests/**"
343 ktlint("com.pinterest:ktlint:${Versions.ktlint}") {
345 attribute(Bundling.BUNDLING_ATTRIBUTE, getObjects().named(Bundling, Bundling.EXTERNAL))
348 detektPlugins project(":tooling-detekt")
351 tasks.register("ktlint", JavaExec) {
352 group = "verification"
353 description = "Check Kotlin code style."
354 classpath = configurations.ktlint
355 mainClass.set("com.pinterest.ktlint.Main")
356 args "components/**/*.kt" , "samples/**/*.kt", "!**/build/**/*.kt", "buildSrc/**/*.kt", "--baseline=ktlint-baseline.xml"
359 tasks.register("ktlintFormat", JavaExec) {
361 description = "Fix Kotlin code style deviations."
362 classpath = configurations.ktlint
363 mainClass.set("com.pinterest.ktlint.Main")
364 args "-F", "components/**/*.kt" , "samples/**/*.kt", "!**/build/**/*.kt", "buildSrc/**/*.kt", "--baseline=ktlint-baseline.xml"
365 jvmArgs("--add-opens", "java.base/java.lang=ALL-UNNAMED")
368 tasks.register("listRepositories") {
370 println "Repositories:"
371 project.repositories.each { println "Name: " + it.name + "; url: " + it.url }
375 tasks.register("githubBuildDetails", GithubDetailsTask) {
376 text = """### Test result files
378 - [Test Coverage]({reportsUrl}/jacoco/jacocoReleaseTestReport/html/index.html)
379 - [Unit Tests]({reportsUrl}/tests/testReleaseUnitTest/index.html)
380 - [Android Lint]({reportsUrl}/lint-results-release.html)"""
383 tasks.register("githubLintDetektDetails", GithubDetailsTask) {
384 text = "### [Detekt Results Android-Components]({reportsUrl}/detekt.html)"
387 tasks.register("githubLintAndroidDetails", GithubDetailsTask) {
388 text = "### [Android Lint Results Android-Components]({reportsUrl}/lint-results-debug.html)"
391 tasks.register("testToolsDir", Exec) {
392 group = "verification"
393 description = "Run tests in the tools/ directory."
395 commandLine = ["python3", "test_list_compatible_dependency_versions.py"]