Bug 1881238 - Add logs to SettingsSubMenuHttpsOnlyModeRobot
[gecko.git] / mobile / android / android-components / build.gradle
blob60ddf96706de838af6de50edf6d8587f88897dfa
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
10 buildscript {
11     repositories {
12         if (project.hasProperty("googleRepo")) {
13             maven {
14                 name "Google"
15                 url project.property("googleRepo")
16                 allowInsecureProtocol true // Local Nexus in CI uses HTTP
17             }
18         } else {
19             google()
20         }
22         if (project.hasProperty("centralRepo")) {
23             maven {
24                 name "MavenCentral"
25                 url project.property("centralRepo")
26                 allowInsecureProtocol true // Local Nexus in CI uses HTTP
27             }
28         } else {
29             mavenCentral()
30         }
31     }
33     dependencies {
34         classpath ComponentsDependencies.tools_androidgradle
35         classpath ComponentsDependencies.tools_kotlingradle
36     }
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.
40     ext {
41         detekt_plugin = Versions.detekt
42         python_envs_plugin = Versions.python_envs_plugin
43         ksp_plugin = Versions.ksp_plugin
44     }
47 plugins {
48     id("io.gitlab.arturbosch.detekt").version("$detekt_plugin")
49     id("com.google.devtools.ksp").version("$ksp_plugin")
52 allprojects {
53     repositories {
54         if (project.hasProperty("googleRepo")) {
55             maven {
56                 name "Google"
57                 url project.property("googleRepo")
58                 allowInsecureProtocol true // Local Nexus in CI uses HTTP
59             }
60         } else {
61             google()
62         }
64         if (project.hasProperty("centralRepo")) {
65             maven {
66                 name "MavenCentral"
67                 url project.property("centralRepo")
68                 allowInsecureProtocol true // Local Nexus in CI uses HTTP
69             }
70         } else {
71             mavenCentral()
72         }
74         maven {
75             name "Mozilla"
76             url "https://maven.mozilla.org/maven2"
77         }
79         if (ExtraRepositories.mozillaStaging) {
80             maven {
81                 name "Mozilla Staging"
82                 url "https://maven-default.stage.mozaws.net/maven2"
83             }
84         }
85     }
88 subprojects {
89     apply plugin: 'jacoco'
91     // Enable Kotlin warnings as errors for all modules
92     tasks.withType(KotlinCompile).configureEach {
93         kotlinOptions.allWarningsAsErrors = true
94     }
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}")
106                 } else {
107                     // Enforce that all (transitive) dependencies are using the defined Glean version
108                     details.useVersion Versions.mozilla_glean
109                 }
110             }
111         }
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) {
116                 select(toBeSelected)
117             }
118             because 'use GeckoView Glean instead of standalone Glean'
119         }
120     }
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')
129     }
130     if (appServicesSrcDir) {
131         if (appServicesSrcDir.startsWith("/")) {
132             apply from: "${appServicesSrcDir}/build-scripts/substitute-local-appservices.gradle"
133         } else {
134             apply from: "${rootProject.projectDir}/${appServicesSrcDir}/build-scripts/substitute-local-appservices.gradle"
135         }
136     }
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"
142     }
144     if (gradle.hasProperty('localProperties.dependencySubstitutions.geckoviewTopsrcdir')) {
145         if (gradle.hasProperty('localProperties.dependencySubstitutions.geckoviewTopobjdir')) {
146             ext.topobjdir = gradle."localProperties.dependencySubstitutions.geckoviewTopobjdir"
147         }
148         ext.topsrcdir = gradle."localProperties.dependencySubstitutions.geckoviewTopsrcdir"
149         apply from: "${topsrcdir}/substitute-local-geckoview.gradle"
150     }
152     afterEvaluate {
153         if (it.hasProperty('android')) {
154             jacoco {
155                 toolVersion = Versions.jacoco
156             }
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())
171                     }
172                 }
174                 beforeTest { descriptor ->
175                     out.style(Style.Description).println("  TEST: " + descriptor.getName())
176                 }
178                 onOutput { descriptor, event ->
179                     logger.lifecycle("    " + event.message.trim())
180                 }
182                 afterTest { descriptor, result ->
183                     switch (result.getResultType()) {
184                         case ResultType.SUCCESS:
185                             out.style(Style.Success).println("  SUCCESS")
186                             break
188                         case ResultType.FAILURE:
189                             out.style(Style.Failure).println("  FAILURE")
190                             logger.lifecycle("", result.getException())
191                             break
193                         case ResultType.SKIPPED:
194                             out.style(Style.Info).println("  SKIPPED")
195                             break
196                     }
197                     logger.lifecycle("")
198                 }
199             }
201             dependencies {
202                 lintChecks project(':tooling-lint')
203             }
205             android {
206                 testOptions {
207                     unitTests {
208                         includeAndroidResources = true
209                     }
210                 }
212                 packagingOptions {
213                     resources {
214                         excludes += ['META-INF/atomicfu.kotlin_module', 'META-INF/AL2.0', 'META-INF/LGPL2.1']
215                         // Required dependencies using byte-buddy; remove after this is
216                         // fixed by: https://issuetracker.google.com/issues/170131605
217                         excludes.add("META-INF/licenses/ASM")
219                         pickFirsts += ['win32-x86-64/attach_hotspot_windows.dll', 'win32-x86/attach_hotspot_windows.dll']
220                     }
221                 }
223                 androidResources {
224                     ignoreAssetsPattern "manifest.template.json"
225                 }
227                 compileOptions {
228                     sourceCompatibility JavaVersion.VERSION_17
229                     targetCompatibility JavaVersion.VERSION_17
230                 }
232                 tasks.withType(KotlinCompile).configureEach {
233                     kotlinOptions.jvmTarget = "17"
234                     kotlinOptions.freeCompilerArgs += ["-opt-in=kotlin.RequiresOptIn"]
235                 }
236             }
238             if (project.hasProperty("coverage") && project.name != "support-test") {
239                 android.buildTypes.all { buildType ->
240                     tasks.withType(Test).configureEach() {
241                         jacoco {
242                             includeNoLocationClasses = true
243                             excludes = ['jdk.internal.*']
244                         }
246                         finalizedBy { "jacoco${buildType.name.capitalize()}TestReport" }
247                     }
249                     tasks.register("jacoco${buildType.name.capitalize()}TestReport", JacocoReport) {
250                         reports {
251                             xml.required = true
252                             html.required = true
253                         }
255                         def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*',
256                                           '**/*Test*.*', 'android/**/*.*', '**/*$[0-9].*']
257                         def kotlinDebugTree = fileTree(dir: "$project.layout.buildDirectory/tmp/kotlin-classes/${buildType.name}", excludes: fileFilter)
258                         def javaDebugTree = fileTree(dir: "$project.layout.buildDirectory/intermediates/classes/${buildType.name}", excludes: fileFilter)
259                         def mainSrc = "$project.projectDir/src/main/java"
261                         sourceDirectories.setFrom(files([mainSrc]))
262                         classDirectories.setFrom(files([kotlinDebugTree, javaDebugTree]))
263                         getExecutionData().setFrom(fileTree(project.layout.buildDirectory).include([
264                                 "jacoco/test${buildType.name.capitalize()}UnitTest.exec"
265                         ]))
266                     }
267                 }
269                 android {
270                     buildTypes {
271                         debug {
272                             testCoverageEnabled true
273                         }
274                     }
275                 }
276             }
277         }
278     }
281 tasks.register("clean", Delete) {
282     delete rootProject.layout.buildDirectory
285 detekt {
286     input = files("$projectDir/components", "$projectDir/buildSrc", "$projectDir/samples")
287     config = files("$projectDir/config/detekt.yml")
288     baseline = file("$projectDir/config/detekt-baseline.xml")
290     reports {
291         html {
292             enabled = true
293             destination = file("$projectDir/build/reports/detekt.html")
294         }
295         xml {
296             enabled = false
297         }
298         txt {
299             enabled = false
300         }
301     }
304 tasks.withType(Detekt).configureEach() {
305     // Custom detekt rules should be build before
306     // See https://arturbosch.github.io/detekt/extensions.html#pitfalls
307     dependsOn(":tooling-detekt:assemble")
309     autoCorrect = true
311     exclude "**/build.gradle.kts"
312     exclude "**/src/androidTest/**"
313     exclude "**/src/iosTest/**"
314     exclude "**/src/test/**"
315     exclude "**/test/src/**"
316     exclude "**/build/**"
317     exclude "**/resources/**"
318     exclude "**/tmp/**"
319     exclude "**/tooling/fetch/tests/**"
320     exclude "**/tooling/fetch-tests/**"
321     exclude "**/src/main/assets/extensions/**"
322     exclude "**/docs/**"
325 // Apply same path exclusions as for the main task
326 tasks.withType(DetektCreateBaselineTask).configureEach() {
327     exclude "**/src/androidTest/**"
328     exclude "**/src/test/**"
329     exclude "**/test/src/**"
330     exclude "**/build/**"
331     exclude "**/resources/**"
332     exclude "**/tmp/**"
333     exclude "**/tooling/fetch/tests/**"
334     exclude "**/tooling/fetch-tests/**"
337 configurations {
338     ktlint
341 dependencies {
342     ktlint("com.pinterest:ktlint:${Versions.ktlint}") {
343         attributes {
344             attribute(Bundling.BUNDLING_ATTRIBUTE, getObjects().named(Bundling, Bundling.EXTERNAL))
345         }
346     }
347     detektPlugins project(":tooling-detekt")
350 tasks.register("ktlint", JavaExec) {
351     group = "verification"
352     description = "Check Kotlin code style."
353     classpath = configurations.ktlint
354     mainClass.set("com.pinterest.ktlint.Main")
355     args "components/**/*.kt" , "samples/**/*.kt", "!**/build/**/*.kt", "buildSrc/**/*.kt", "--baseline=ktlint-baseline.xml"
358 tasks.register("ktlintFormat", JavaExec) {
359     group = "formatting"
360     description = "Fix Kotlin code style deviations."
361     classpath = configurations.ktlint
362     mainClass.set("com.pinterest.ktlint.Main")
363     args "-F", "components/**/*.kt" , "samples/**/*.kt", "!**/build/**/*.kt", "buildSrc/**/*.kt", "--baseline=ktlint-baseline.xml"
364     jvmArgs("--add-opens", "java.base/java.lang=ALL-UNNAMED")
367 tasks.register("listRepositories") {
368     doLast {
369         println "Repositories:"
370         project.repositories.each { println "Name: " + it.name + "; url: " + it.url }
371    }
374 tasks.register("githubBuildDetails", GithubDetailsTask) {
375     text = """### Test result files
377 - [Test Coverage]({reportsUrl}/jacoco/jacocoReleaseTestReport/html/index.html)
378 - [Unit Tests]({reportsUrl}/tests/testReleaseUnitTest/index.html)
379 - [Android Lint]({reportsUrl}/lint-results-release.html)"""
382 tasks.register("githubLintDetektDetails", GithubDetailsTask) {
383     text = "### [Detekt Results Android-Components]({reportsUrl}/detekt.html)"
386 tasks.register("githubLintAndroidDetails", GithubDetailsTask) {
387     text = "### [Android Lint Results Android-Components]({reportsUrl}/lint-results-debug.html)"
390 tasks.register("testToolsDir", Exec) {
391     group = "verification"
392     description = "Run tests in the tools/ directory."
393     workingDir = "tools"
394     commandLine = ["python3", "test_list_compatible_dependency_versions.py"]