咱们Android工程pipeline
阶段需求进行静态扫描或者是资源归属查看之类的gradle
任务。这些插件开发同学是不需求感知到。可是由所以用gradle
插件实现的,这样就会对build.gradle
进行不可避免的侵入,也会不可避免的呈现一些条件判别句子。
尤其是sonarquebe
这种插件,装备项又贼多,并且一般开发也彻底不需求明白是做啥的,假如插件被履行到之后还会拖慢同步时间。有没有什么好的手法来避免掉这些胶水代码呢?
案发现场
假如用规范代码接入工程代码大约如下,我会在根节点的build.gradle
内刺进如下逻辑。
buildscript {
repositories {
mavenCenterl()
}
dependencies {
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.5.0.2730"
}
}
// 依据环境装备来区别是不是ci环境
if(System.env.containsKey('CI')){
pluginManager.apply("org.sonarqube")
sonarqube {
properties {
property "sonar.sourceEncoding", "UTF-8"
/* if (projectVersion != null) {
logger.info "${project.path} set sonar.projectVersion=${projectVersion}"
}*/
// property "sonar.projectVersion", projectVersion
// if (debuggable) {
property "sonar.verbose", "true"
property "sonar.cpd.kotlin.minimumLines", 15
property "sonar.cpd.java.minimumLines", 20
property "sonar.projectName", sonar.get("projectName")
property "sonar.projectKey", sonar.get("projectKey")
}
}
subprojects {
def unittest = project.hasProperty("unittest") ? project.ext["unittest"] : ""
tasks.whenTaskAdded { task ->
if (task.name.contains("TestKotlin") || task.name.contains("UnitTest") || task.name.contains("AndroidTest")) {
enabled = unittest == "true"
logger.log(LogLevel.INFO, "Temporarily disable test related task: $task")
}
if (task.name == "lintDebug") {
def sonarTask = rootProject.tasks.findByName("sonar")
if (sonarTask != null) {
sonarTask.dependsOn(task)
}
}
}
afterEvaluate {
sonarqube {
properties {
property "sonar.androidLint.reportPaths", "${project.buildDir}/reports/lint-results-debug.xml"
// detekt.reportPaths
// property "sonar.kotlin.detekt.reportPaths", "build/reports/detekt.xml"
property "sonar.exclusions", "build/**/*," + "src/main/assets/**/*," + "src/**/*.png,src/**/*.jpg,src/**/*.webp," + "src/**/*.so"
}
}
}
}
}
xxxxxxxx
这么一大段代码呢就需求存放在build.gradle
内,就是十分脏的代码。并且大部分开发同学是彻底不需求这些代码的。sonar
不仅需求apply一个plugin,一起还有大量的装备文件,一起还需求参加很多环境变量来进行操控。
另外,因为咱们工程大约40+的复合构建,需求对每个复合构建进行相同的buildscript
导入classpath
,咱们需求对每个根build.gradle
进行调整, 改动量实在是过于可观了。
initscript
Gradle 奇淫技巧之initscript pluginManagement
之前有篇文章介绍过这个东西,其实关于sonar我觉得这个真的就彻底足够了。并且因为initscript
的特殊性,能够给所有的复合构建都添加这部分初始化装备。
首先咱们在pipeline阶段会主动履行gradlew sonar这个任务,那么咱们也能刺进--initscript
之后带入这个gradle脚本。
其次因为initscript的代码履行的优先级是最高的,所以咱们能够在其提供的dsl中履行rootProject的代码,刺进一些buildscript插件。
rootProject {
buildscript {
repositories {
mavenCenterl()
}
dependencies {
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.5.0.2730"
}
}
// 测验成果告诉我,假如加的太早会导致classloader不是同一个,然后安卓工程就无法被辨认
afterEvaluate {
pluginManager.apply("org.sonarqube")
sonarqube {
properties {
property "sonar.sourceEncoding", "UTF-8"
/* if (projectVersion != null) {
logger.info "${project.path} set sonar.projectVersion=${projectVersion}"
}*/
// property "sonar.projectVersion", projectVersion
// if (debuggable) {
property "sonar.verbose", "true"
property "sonar.cpd.kotlin.minimumLines", 15
property "sonar.cpd.java.minimumLines", 20
property "sonar.projectName", sonar.get("projectName")
property "sonar.projectKey", sonar.get("projectKey")
}
}
subprojects {
def unittest = project.hasProperty("unittest") ? project.ext["unittest"] : ""
tasks.whenTaskAdded { task ->
if (task.name.contains("TestKotlin") || task.name.contains("UnitTest") || task.name.contains("AndroidTest")) {
enabled = unittest == "true"
logger.log(LogLevel.INFO, "Temporarily disable test related task: $task")
}
if (task.name == "lintDebug") {
def sonarTask = rootProject.tasks.findByName("sonar")
if (sonarTask != null) {
sonarTask.dependsOn(task)
}
}
}
afterEvaluate {
sonarqube {
properties {
property "sonar.androidLint.reportPaths", "${project.buildDir}/reports/lint-results-debug.xml"
// detekt.reportPaths
// property "sonar.kotlin.detekt.reportPaths", "build/reports/detekt.xml"
property "sonar.exclusions", "build/**/*," + "src/main/assets/**/*," + "src/**/*.png,src/**/*.jpg,src/**/*.webp," + "src/**/*.so"
}
}
}
}
}
}
这个就是咱们从头生成的一份十分干净的sonar.gradle
文件,咱们能够在这个gradle很轻松的给工程装备上一些咱们所需求的插件,并且这部分代码也仅有pipeline
阶段会被履行。
./gradlew --init-script sonar.gradle sonar
经过上述手法咱们就能够把所有逻辑都收在一个sonar.gradle
中,然后在initscript
中刺进就行了。其间sonar.gradle
是指相对路径,最后一个sonar
则代表着履行的taskname。
这部分调整中心仍是按照代码的整齐度视点出发来考虑这个问题的。能够让咱们去把一些非开发环境下的装备经过init-script
方式刺进到工程内去。
还能做些啥
我其实还用--init-script
完成了咱们pipeline
中的增量的UnitTest
的逻辑,依据当前的git diff
之后,判别变更的模块中是否包含UnitTest
然后履行UnitTest
。
这里的代码也比较脏,可是恰巧因为了--init-script
的生命周期最靠前,并且能拿到大部分的回调,另外关于复合构建也是支撑的,所以咱们就采取了这种手法去开发。