一款靜態代碼檢測工具,包含阿里java規約檢測和lint檢測,支持自定義pmd和lint配置,結合git在代碼提交時進行增量檢測插件,赫卡同克瑞斯,也就是百臂巨人,來自希臘神話,是天空神烏拉諾斯和地神蓋婭的兒子,擁有50頭和100個手臂,在幫助宙斯奪得神位後,成爲了塔爾塔羅斯的守門人,塔爾塔羅斯就是希臘神話中的地獄。html
不少時候有些bug就是由於代碼不規範形成的,這種低級錯誤每每會形成重大損失,以前就曾經碰到過在主線程加載圖片的狀況,以前由於運營配置的圖片較小,因此也就沒什麼事,直到有一天運營配置了一個大圖,直接致使大面積的ANR,這是一個低級錯誤,後來我寫了一個自定義lint檢測工具,用來檢測這種在主線程使用BitmapFactory的狀況。以後又寫了一些其餘的lint檢測規則,以後遇到了另外兩個問題,第一,個人lint檢測出來了,標註出來了,可是開發者依舊會對他進行忽視,檢測出來而不修改那不就是白搞了?如何強制開發者進行檢測,這是一個問題。第二,項目龐大,總體檢測時間很長,並且檢測出的問題都上萬了,這些問題誰來改?陳芝麻爛穀子的代碼,又有誰願意改?爲此我須要一個增量檢測的方案,結合git,只對要提交的修改的文件進行檢測,這樣誰修改誰倒黴,聽天由命,避免抱怨。java
增量檢測,必然要相應的文件,這裏利用了git的命令git
fun getCommitFiles(): List<File> {
val command =
arrayOf("/bin/bash", "-c", "git diff --name-only --diff-filter=ACMRTUXB HEAD")
val process = Runtime.getRuntime().exec(command)
process.waitFor()
val commitFileList = mutableListOf<File>()
try {
val inputReader = BufferedReader(InputStreamReader(process.inputStream))
var fileName = inputReader.readLine()
while (fileName != null) {
commitFileList.add(File(fileName))
fileName = inputReader.readLine()
}
inputReader.close()
} catch (e: IOException) {
e.printStackTrace()
} catch (e: Exception) {
e.printStackTrace()
}
return commitFileList
}
複製代碼
除了刪除的文件,其餘文件都會做爲增量文件提取出來github
阿里對Java代碼規範作了詳盡的說明,這裏咱們利用阿里規約中的檢測插件中的檢測工具進行java文件的檢測 首先爲項目添加p3c依賴api
private fun configPmdDependency(project: Project) {
project.plugins.apply(PMD)
val pmdConfig = project.configurations.getByName(PMD_CONFIGURATION)
pmdConfig.dependencies.add(project.dependencies.create(P3C_PMD_DEPENDENCY))
pmdConfig.dependencies.add(project.dependencies.create(PMD_DEPENDENCY))
}
複製代碼
這樣就引用了阿里規約的pmd規則,同時因爲引入pmd,支持相應的配置bash
private fun configPmdTask(project: Project) {
project.afterEvaluate {
val pmdExtension = project.extensions.findByName(PMD) as PmdExtension
val pmdTask = project.tasks.create(PMDTASK, Pmd::class.java)
pmdTask.targetJdk = pmdExtension.targetJdk
pmdTask.ignoreFailures = pmdExtension.isIgnoreFailures
ALIRULESETS.addAll(pmdExtension.ruleSets)
pmdTask.ruleSets = ALIRULESETS
pmdTask.ruleSetFiles = pmdExtension.ruleSetFiles
pmdTask.source(project.rootDir)
pmdTask.isConsoleOutput = pmdExtension.isConsoleOutput
pmdTask.rulePriority = pmdExtension.rulePriority
pmdTask.reports {
it.xml.isEnabled = true
it.xml.destination = File(pmdExtension.reportsDir, "report.xml")
it.html.isEnabled = true
it.html.destination = File(pmdExtension.reportsDir, "report.html")
}
pmdTask.group = GOUP_NAME
pmdTask.include(GitUtil.getCommitFilesPathForPMD())
pmdTask.exclude("**/build/**", "**/res/**", "**/*.xml", "**/*.gradle", "**/*.kt")
}
}
複製代碼
lint檢測流程圖app
默認的linttask是對所有文件進行檢測的,爲了實現對增量文件的檢測,須要重寫LintGradleClient的createLintRequest方法,爲此我寫了一個IncrementLintGradleClientide
class IncrementLintGradleClient(
version: String,
issueRegistry: IssueRegistry,
lintFlags: LintCliFlags,
gradleProject: org.gradle.api.Project,
sdkHome: File?,
variant: Variant?,
variantInputs: VariantInputs?,
buildToolInfo: BuildToolInfo?,
isAndroid: Boolean
) : LintGradleClient(
version,
issueRegistry,
lintFlags,
gradleProject,
sdkHome,
variant,
variantInputs,
buildToolInfo,
isAndroid
) {
override fun createLintRequest(files: MutableList<File>?): LintRequest {
val lintRequest = super.createLintRequest(files)
val commitFiles = GitUtil.getCommitFiles()
lintRequest.getProjects()?.forEach { project ->
commitFiles.forEach {
project.addFile(it)
}
}
return lintRequest
}
}
複製代碼
lint的api常常變化,並且修改幅度還很大,爲了屏蔽相應的lint api,gradle差別以及kotlin compiler的差別,咱們使用IncrementReflectiveLintRunner來調用lint檢測,這個和原項目插件中ReflectiveLintRunner沒什麼區別,只不過使用了咱們本身的IncrementLintGradleExecution來分析增量文件,同時在插件中讓當前項目使用lintclasspath引用插件工具
private fun addLintClassPath(project: Project) {
project.gradle.rootProject.configurations
val classPathConfiguration = project.gradle.rootProject.buildscript.configurations.getByName("classpath")
var hecatoncheiresDependency: Dependency? = null
classPathConfiguration.dependencies.forEach {
if (it.name.contains(Constants.HECATONCHEIRESEXTENSION_NAME)) {
hecatoncheiresDependency = it
return@forEach
}
}
val lintConfiguration = project.configurations.getByName(LintBaseTask.LINT_CLASS_PATH)
project.dependencies.add(
lintConfiguration.name,
hecatoncheiresDependency
)
}
複製代碼
這樣插件的jar包路徑就能被IncrementReflectiveLintRunner得到,而且可使用本身的classloader用來加載IncrementLintGradleExecutiongradle
這個項目感受算是一個較爲完善的靜態檢測方法,使用方法與demo見下面連接