diff --git a/build.gradle b/build.gradle index e4da99cf9b..190f5f0714 100644 --- a/build.gradle +++ b/build.gradle @@ -52,7 +52,6 @@ buildscript { } allprojects { - apply from: rootProject.file('codequality/pmd.gradle') repositories { mavenLocal() maven { url 'http://nexus.zhidaoauto.com/repository/maven-releases/' } @@ -73,6 +72,17 @@ allprojects { } google() } + + if (isCodeInspectEnable ) { + def basePath = new File(codequality, 'code_inspect_increment.gradle').path + apply from: "$basePath" + def pmdPath = new File(codequality, 'pmd.gradle').path + apply from: "$pmdPath" + def detektPath = new File(codequality, 'detekt.gradle').path + apply from: "$detektPath" + def codeInspectPath = new File(codequality, 'code_inspect.gradle').path + apply from: "$codeInspectPath" + } } task clean(type: Delete) { diff --git a/codequality/code_inspect.gradle b/codequality/code_inspect.gradle new file mode 100644 index 0000000000..ab96a4c056 --- /dev/null +++ b/codequality/code_inspect.gradle @@ -0,0 +1,24 @@ +task runCodeInspect { + group = "codeInspect" + description = "静态代码检查,统一触发pmd detekt lint任务" +} + +project.afterEvaluate { + bindTask("pmd", "runCodeInspect") + bindTask("detekt", "runCodeInspect") +} + +/** + * 绑定任务 + * @param taskName 任务名称 + * @param targetTaskName 被绑定的任务名称 + * @param action taskName指定的任务执行完成后的回调 + */ +def bindTask(String taskName, String targetTaskName) { + def task = project.tasks.findByName(taskName) + if (task != null) { + logger.lifecycle("${task} will be run") + def targetTask = project.tasks.findByName(targetTaskName) + targetTask.finalizedBy(task) + } +} diff --git a/codequality/code_inspect_increment.gradle b/codequality/code_inspect_increment.gradle new file mode 100644 index 0000000000..4b5e517f92 --- /dev/null +++ b/codequality/code_inspect_increment.gradle @@ -0,0 +1,186 @@ +ext { + //存储增量的Java文件,给pmd使用 + commitJavaFiles = new ArrayList() + //存储增量的kotlin文件,给detekt使用 + commitKotlinFiles = new ArrayList() + commitAuthor = "" + appVersionName = "" +} + +/** + * 增量开关 + */ +def isIncrement = false + +/** + * 通过cmd命令获取结果值 + * @return string 结果值 + */ +def getResultFromCmd(String cmd) { + logger.lifecycle("${project.name} cmd:$cmd") + def out = new ByteArrayOutputStream() + if (System.properties['os.name'].toLowerCase().contains('windows')) { + project.exec { + ExecSpec execSpec -> + executable 'cmd' + args '/c', "$cmd" + standardOutput = out + }.assertNormalExitValue() + } else { + project.exec { + ExecSpec execSpec -> + executable 'bash' + args '-c', "$cmd" + standardOutput = out + }.assertNormalExitValue() + } + return out.toString().trim() +} + +/** + * 获取提交作者 + * @return 提交作者 + */ +def getCommitAuthor() { + def commitAuthor = "" +// if (isCiServer()) { +// commitAuthor = "${System.env.CI_COMMIT_AUTHOR}" +// commitAuthor = commitAuthor.substring(0, commitAuthor.indexOf('<')).trim() +// } else { + commitAuthor = getResultFromCmd("git config --get user.name") +// } + return commitAuthor +} + +/** + * 获取提交 sha,用于 git diff 出增量文件,其它项目仓库,这个方法需要更改实现 + * @return 提交 sha + */ +def getCommitTargetSha() { + //目前这个仓库只能根据上一个merge节点,进行代码增量检测 + def commitTargetSha = getResultFromCmd("git log --max-count=1 --pretty=%H --merges") + return commitTargetSha +} + +/** + * 获取提交文件,只包含.java和.kt的文件 + * @return 文件相对路径数组 + */ +def getCommitFiles() { + def commitTargetSha = getCommitTargetSha() + def commitSha = getResultFromCmd("git log --max-count=1 --pretty=%H") + def commitAuthor = getCommitAuthor() + def cmd = "git log --name-only --author=$commitAuthor --pretty=\"format:\" $commitTargetSha..$commitSha" + def result = getResultFromCmd(cmd) + def projectStartPath = getProjectStartPath() + logger.lifecycle("projectStartPath=$projectStartPath") + if (result != null && result.trim().length() > 0) { + def files = result.readLines() + .findAll { it.startsWith("${projectStartPath}") && isFilePathValid(it) }.toArray() + return files.toUnique() + } + return null +} + +/** + * 判断文件路径是否合理 + * @param path 文件路径 + * @return true合理,否则不合理 + */ +static def isFilePathValid(String path) { + return (path.endsWith('.kt') || path.endsWith('.java') || path.endsWith('.xml') || path.endsWith('.png')) && !path.contains('/test/') && !path.contains('/androidTest/') && !path.contains('/generated/') +} + +/** + * 获取src目录下的所有文件,只包含.java和.kt的文件 + * @return 文件相对路径数组 + */ +def getAllFiles() { + def fileCollection = project.files("src") + if (fileCollection == null) { + return null + } + def files = fileCollection.asFileTree.getFiles() + def iterator = files.iterator() + def allFiles = new ArrayList(files.size()) + while (iterator.hasNext()) { + File file = iterator.next() + def path = getProjectStartPath() + File.separator + project.relativePath(file.path) + if (path != null && isFilePathValid(path)) { + allFiles.add(path) + } + } + return allFiles.toArray(new Object[allFiles.size()]) +} + +/** + * 获取项目名称,如gradleengine,framework/asmbase + * @return 项目名称 + */ +def getProjectStartPath() { + def projectRelativePath = project.relativePath(project.path).replaceAll(':', '/') + return projectRelativePath.substring(1) +} + +/** + * 存储提交文件 + * @param commitFiles 提交文件 + */ +def saveCommitFiles(Object[] commitFiles) { + //commitFiles 是对象 + def lintBuildDir = new File(project.buildDir, "code_inspect") + if (!lintBuildDir.exists()) { + lintBuildDir.mkdirs() + } + def changedFile = new File(lintBuildDir, "commit_files.txt") + def fileOutputStream = new FileOutputStream(changedFile) + def rootProjectPath = project.rootProject.rootDir.path + File.separator + //存储绝对路径 + for (int i = 0; i < commitFiles.length; i++) { + def commitFile = commitFiles[i].toString() + fileOutputStream.write((rootProjectPath + commitFile).getBytes("utf-8")) + if (i != commitFiles.length - 1) + fileOutputStream.write("\n".getBytes("utf-8")) + } + fileOutputStream.flush() + fileOutputStream.close() + logger.lifecycle("Save Commit Files In: ${changedFile.path} \n$commitFiles") +} + + +task runCodeInspectIncrement { + group = "codeInspect" + description = "存储增量文件" + def commitJavaFiles = new ArrayList() + def commitKotlinFiles = new ArrayList() + + def commitFiles = new Object[0] + if (isIncrement) { + commitFiles = getCommitFiles() + } else { + commitFiles = getAllFiles() + } + saveCommitFiles(commitFiles) + if (commitFiles != null && commitFiles.length > 0) { + def projectStartPath = getProjectStartPath() + for (String s : commitFiles) { + def commitFile = s.toString().trim() + if (commitFile.endsWith('.kt')) { + commitKotlinFiles.add(commitFile.substring(projectStartPath.length() + 1)) + } else if (commitFile.endsWith('.java')) { + commitJavaFiles.add(commitFile.substring(projectStartPath.length() + 1)) + } + } + } + if (!commitKotlinFiles.isEmpty()) { + logger.lifecycle("${project.name} commitKotlinFiles:$commitKotlinFiles") + } + if (!commitJavaFiles.isEmpty()) { + logger.lifecycle("${project.name} commitJavaFiles:$commitJavaFiles") + } + project.setProperty("commitKotlinFiles", commitKotlinFiles) + project.setProperty("commitJavaFiles", commitJavaFiles) + project.setProperty("commitAuthor", getCommitAuthor()) +} + + diff --git a/codequality/detekt.gradle b/codequality/detekt.gradle index b6f417e01b..196d02a2ba 100644 --- a/codequality/detekt.gradle +++ b/codequality/detekt.gradle @@ -1,53 +1,40 @@ -plugins { - id("io.gitlab.arturbosch.detekt") version "1.15.0" -} +//apply plugin: 'io.gitlab.arturbosch.detekt' def pmdConfigPath = rootProject.file("codequality").path -detekt{ - //将配置文件应用于detekt的默认配置文件之上 - buildUponDefaultConfig = true - source = files( - "src/main/kotlin", - "src/main/java", - "src/jinlvvan/java", - "src/jinlvvan/kotlin", - "src/driverm1/java", - "src/driverm1/kotlin" - ) - //规则集 - config.setFrom("${pmdConfigPath}/detekt.yml") - //指定基准文件。在detekt的后续运行中,所有发现都存储在此文件中 - baseline = files("${pmdConfigPath}/baseline.xml") - //指定格式化报告中文件路径的基本路径 - basePath = projectDir.path +//detekt { +// //将配置文件应用于detekt的默认配置文件之上 +// buildUponDefaultConfig = true +// source = files( +// "src/main/kotlin", +// "src/main/java", +// "src/jinlvvan/java", +// "src/jinlvvan/kotlin", +// "src/driverm1/java", +// "src/driverm1/kotlin" +// ) +// //规则集 +// config.setFrom("${pmdConfigPath}/detekt.yml") +// //指定基准文件。在detekt的后续运行中,所有发现都存储在此文件中 +// baseline = files("${pmdConfigPath}/baseline.xml") +// //指定格式化报告中文件路径的基本路径 +// basePath = projectDir.path +// +// // Android: Don't create tasks for the specified build types (e.g. "release") +//// ignoredBuildTypes = ["release"] +// // Android: Don't create tasks for the specified build flavor (e.g. "production") +//// ignoredFlavors = ["production"] +// // Android: Don't create tasks for the specified build variants (e.g. "productionRelease") +//// ignoredVariants = ["productionRelease"] +//} - // Android: Don't create tasks for the specified build types (e.g. "release") -// ignoredBuildTypes = ["release"] - // Android: Don't create tasks for the specified build flavor (e.g. "production") -// ignoredFlavors = ["production"] - // Android: Don't create tasks for the specified build variants (e.g. "productionRelease") -// ignoredVariants = ["productionRelease"] -} - -dependencies { - detektPlugins "io.gitlab.arturbosch.detekt:detekt-formatting:1.21.0" -} - -tasks.detekt.jvmTarget = "1.8" - -tasks.named("detekt").configure { - reports { - // Enable/Disable HTML report (default: true) - def destination = new File(new File("${project.rootProject.buildDir.path}/reports/detekt"), "${project.name}-detekt.html") - html.required.set(true) - html.outputLocation.set(destination) - } -} - -project.afterEvaluate { - if (tasks.findByName("preBuild") != null) { - project.preBuild.dependsOn tasks.findByName("detekt") - println("project.preBuild.dependsOn tasks.findByName(\"detekt\")") - } -} \ No newline at end of file +//tasks.detekt.jvmTarget = "1.8" +// +//tasks.named("detekt").configure { +// reports { +// // Enable/Disable HTML report (default: true) +// def destination = new File(new File("${project.rootProject.buildDir.path}/reports/detekt"), "${project.name}-detekt.html") +// html.required.set(true) +// html.outputLocation.set(destination) +// } +//} diff --git a/config.gradle b/config.gradle index d5d4d49b8c..01d3248be9 100644 --- a/config.gradle +++ b/config.gradle @@ -2,6 +2,12 @@ apply from: rootProject.file('gradle/ext.gradle') ext { time = "" kotlin_version = "1.6.21" + + //插件工具存放目录 + codequality = new File(projectDir, 'codequality') + //静态代码检查开关 + isCodeInspectEnable = true + dependencies = [ // androidx androidxappcompat : "androidx.appcompat:appcompat:1.3.1",