build.gradle (7218B)
1 import io.gitlab.arturbosch.detekt.Detekt 2 import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask 3 import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 4 5 6 // Top-level build file where you can add configuration options common to all sub-projects/modules. 7 8 buildscript { 9 repositories { 10 gradle.mozconfig.substs.GRADLE_MAVEN_REPOSITORIES.each { repository -> 11 maven { 12 url = repository 13 if (gradle.mozconfig.substs.ALLOW_INSECURE_GRADLE_REPOSITORIES) { 14 allowInsecureProtocol = true 15 } 16 } 17 } 18 } 19 20 dependencies { 21 classpath libs.android.gradle.plugin 22 classpath libs.mozilla.glean.gradle.plugin 23 classpath libs.osslicenses.plugin 24 25 // NOTE: Do not place your application dependencies here; they belong 26 // in the individual module build.gradle files 27 } 28 } 29 30 plugins { 31 id "mozac.ConfigPlugin" 32 alias(libs.plugins.detekt) 33 alias(libs.plugins.kotlin.android) apply false 34 alias(libs.plugins.kotlin.compose) apply false 35 alias(libs.plugins.ksp) 36 } 37 38 detekt { 39 input = files("$projectDir/app") 40 config = files("$projectDir/quality/detekt.yml") 41 baseline = file("$projectDir/quality/detekt-baseline.xml") 42 43 reports { 44 html { 45 enabled = true 46 destination = file("$projectDir/build/reports/detekt.html") 47 } 48 xml { 49 enabled = false 50 } 51 txt { 52 enabled = false 53 } 54 } 55 } 56 57 tasks.withType(Detekt).configureEach() { 58 autoCorrect = true 59 60 exclude "**/test/**" 61 exclude "**/androidTest/**" 62 exclude "**/build/**" 63 exclude "**/resources/**" 64 exclude "**/tmp/**" 65 } 66 67 // Apply same path exclusions as for the main task 68 tasks.withType(DetektCreateBaselineTask).configureEach() { 69 exclude "**/test/**" 70 exclude "**/androidTest/**" 71 exclude "**/build/**" 72 exclude "**/resources/**" 73 exclude "**/tmp/**" 74 } 75 76 allprojects { 77 repositories { 78 gradle.mozconfig.substs.GRADLE_MAVEN_REPOSITORIES.each { repository -> 79 maven { 80 url = repository 81 if (gradle.mozconfig.substs.ALLOW_INSECURE_GRADLE_REPOSITORIES) { 82 allowInsecureProtocol = true 83 } 84 } 85 } 86 87 maven { 88 url = "${gradle.mozconfig.topobjdir}/gradle/maven" 89 } 90 } 91 92 ext { 93 gleanVersion = libs.versions.glean.get() 94 } 95 96 tasks.withType(KotlinCompile).configureEach { 97 compilerOptions.allWarningsAsErrors = true 98 } 99 } 100 101 subprojects { 102 afterEvaluate { 103 if (it.hasProperty('kotlin')) { 104 kotlin { 105 jvmToolchain(config.jvmTargetCompatibility) 106 } 107 } 108 109 if (it.hasProperty('android')) { 110 android { 111 buildToolsVersion gradle.mozconfig.substs.ANDROID_BUILD_TOOLS_VERSION 112 } 113 } 114 } 115 116 project.configurations.configureEach { 117 // Dependencies can't depend on a different major version of Glean than A-C itself. 118 resolutionStrategy.eachDependency { details -> 119 if (details.requested.group == 'org.mozilla.telemetry' 120 && details.requested.name.contains('glean') ) { 121 def requested = details.requested.version.tokenize(".") 122 def defined = project.ext.gleanVersion.tokenize(".") 123 // Check the major version 124 if (requested[0] != defined[0]) { 125 throw new AssertionError("Cannot resolve to a single Glean version. Requested: ${details.requested.version}, A-C uses: ${project.ext.gleanVersion}") 126 } else { 127 // Enforce that all (transitive) dependencies are using the defined Glean version 128 details.useVersion project.ext.gleanVersion 129 } 130 } 131 } 132 133 resolutionStrategy.capabilitiesResolution.withCapability("org.mozilla.telemetry:glean-native") { 134 def toBeSelected = candidates.find { it.id instanceof ModuleComponentIdentifier && it.id.module.contains('geckoview') } 135 if (toBeSelected != null) { 136 select(toBeSelected) 137 } 138 because 'use GeckoView Glean instead of standalone Glean' 139 } 140 } 141 142 tasks.withType(KotlinCompile).configureEach { task -> 143 // Translate Kotlin messages like "w: ..." and "e: ..." into 144 // "...: warning: ..." and "...: error: ...", to make Treeherder understand. 145 def listener = { 146 147 if (it.startsWith("e: warnings found")) { 148 return 149 } 150 151 if (it.startsWith('w: ') || it.startsWith('e: ')) { 152 def matches = (it =~ /([ew]): (.+):(\d+):(\d+) (.*)/) 153 if (!matches) { 154 logger.quiet "kotlinc message format has changed!" 155 if (it.startsWith('w: ')) { 156 // For warnings, don't continue because we don't want to throw an 157 // exception. For errors, we want the exception so that the new error 158 // message format gets translated properly. 159 return 160 } 161 } 162 def (_, type, file, line, column, message) = matches[0] 163 type = (type == 'w') ? 'warning' : 'error' 164 // Use logger.lifecycle, which does not go through stderr again. 165 logger.lifecycle "$file:$line:$column: $type: $message" 166 } 167 } as StandardOutputListener 168 169 doFirst { 170 logging.addStandardErrorListener(listener) 171 } 172 doLast { 173 logging.removeStandardErrorListener(listener) 174 } 175 } 176 } 177 178 tasks.register('clean', Delete) { 179 delete rootProject.layout.buildDirectory 180 } 181 182 183 configurations { 184 ktlint 185 } 186 187 dependencies { 188 ktlint(libs.ktlint) { 189 attributes { 190 attribute(Bundling.BUNDLING_ATTRIBUTE, getObjects().named(Bundling, Bundling.EXTERNAL)) 191 } 192 } 193 } 194 195 tasks.register('ktlint', JavaExec) { 196 description = "Check Kotlin code style." 197 classpath = configurations.ktlint 198 mainClass.set("com.pinterest.ktlint.Main") 199 args "app/**/*.kt" 200 args "!**/build/**/*.kt" 201 args "buildSrc/**/*.kt" 202 args "--reporter=json,output=build/reports/ktlint/ktlint.json" 203 args "--reporter=plain" 204 } 205 206 207 tasks.register('ktlintFormat', JavaExec) { 208 description = "Fix Kotlin code style deviations." 209 classpath = configurations.ktlint 210 mainClass.set("com.pinterest.ktlint.Main") 211 args "-F" 212 args "app/**/*.kt" 213 args "!**/build/**/*.kt" 214 args "buildSrc/**/*.kt" 215 args "--reporter=json,output=build/reports/ktlint/ktlintFormat.json" 216 args "--reporter=plain" 217 jvmArgs("--add-opens", "java.base/java.lang=ALL-UNNAMED") 218 } 219 220 tasks.register("listRepositories") { 221 def reposData = project.provider { 222 project.repositories.collect { repo -> 223 [name: repo.name, url: repo.url.toString()] 224 } 225 } 226 doLast { 227 println "Repositories:" 228 reposData.get().each { println "Name: " + it.name + "; url: " + it.url } 229 } 230 }