BuildScripts/gradle/commonStaticAnalysis.gradle

239 lines
7.7 KiB
Groovy

apply plugin: 'cpd'
apply plugin: 'io.gitlab.arturbosch.detekt'
def getCpdTask
def getLintTask
def getKotlinDetektTasks
def appendError
def appendCpdErrors
def appendKotlinErrors
def appendLintErrors
repositories {
maven { url "http://dl.bintray.com/touchin/touchin-tools" }
}
configurations {
pngtastic
}
cpd {
skipLexicalErrors = true
}
import org.apache.tools.ant.taskdefs.condition.Os
ext.getIdeaFormatTask = { isAndroidProject, sources ->
def ideaPath = System.getenv("IDEA_HOME")
if (ideaPath == null) {
return tasks.create((isAndroidProject ? "android" : "server") + "donothing")
}
return tasks.create((isAndroidProject ? "android" : "server") + "IdeaFormat_$project.name", Exec) {
def inspectionPath
def params = ["-r", "-mask", "*.java,*.kt,*.xml"]
for (String source : sources) {
params.add(source)
}
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
inspectionPath = ['cmd', '/c', "\"${ideaPath}\\bin\\format.bat\" ${params.join(" ")}"]
} else {
inspectionPath = ["$ideaPath/bin/format.sh"]
}
commandLine inspectionPath
if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
args = params
}
}
}
ext.getStaticAnalysisTaskNames = { isAndroidProject, sources, buildVariant ->
def tasksNames = new ArrayList<String>()
try {
tasksNames.add(getCpdTask(isAndroidProject, sources))
tasksNames.addAll(getKotlinDetektTasks())
if (isAndroidProject) {
tasksNames.add(getLintTask(buildVariant))
}
} catch (Exception exception) {
println(exception.toString())
}
return tasksNames
}
ext.generateReport = { isAndroidProject ->
StringBuilder consoleReport = new StringBuilder()
consoleReport.append("STATIC ANALYSIS RESULTS:")
def count = 0
def previousCount = count
count = appendCpdErrors(count, new File("${project.buildDir}/reports/cpd.xml"))
if (count - previousCount > 0) {
consoleReport.append("\nCPD: FAILED (" + (count - previousCount) + " errors)")
} else {
consoleReport.append("\nCPD: PASSED")
}
previousCount = count
subprojects.forEach { subproject ->
def reportFile = new File("${rootProject.buildDir}/reports/kotlin-detekt-${subproject.name}.xml")
if (reportFile.exists()) {
count = count + appendKotlinErrors(count, reportFile)
}
}
if (count - previousCount > 0) {
consoleReport.append("\nKotlin-detekt: FAILED (" + (count - previousCount) + " errors)")
} else {
consoleReport.append("\nKotlin-detekt: PASSED")
}
if (isAndroidProject) {
previousCount = count
count = appendLintErrors(count, new File("${rootProject.buildDir}/reports/lint_report.xml"))
if (count - previousCount > 0) {
consoleReport.append("\nLint: FAILED (" + (count - previousCount) + " errors)")
} else {
consoleReport.append("\nLint: PASSED")
}
}
if (count > 0) {
consoleReport.append("\nOverall: FAILED (" + count + " errors)")
throw new Exception(consoleReport.toString())
} else {
consoleReport.append("\nOverall: PASSED")
println(consoleReport.toString())
}
}
appendError = { number, analyzer, file, line, errorId, errorLink, description ->
println("$number. $analyzer : $description ($errorId)\n\tat $file: $line")
}
appendKotlinErrors = { count, checkstyleFile ->
def rootNode = new XmlParser().parse(checkstyleFile)
for (def fileNode : rootNode.children()) {
if (!fileNode.name().equals("file")) {
continue
}
for (def errorNode : fileNode.children()) {
if (!errorNode.name().equals("error")) {
continue
}
count++
appendError(count, "Detekt", fileNode.attribute("name"), errorNode.attribute("line"), errorNode.attribute("source"), "", errorNode.attribute("message"))
}
}
return count
}
appendCpdErrors = { count, cpdFile ->
def rootNode = new XmlParser().parse(cpdFile)
for (def duplicationNode : rootNode.children()) {
if (!duplicationNode.name().equals("duplication")) {
continue
}
count++
def duplicationIndex = 0
String duplicationPoints = ""
for (def filePointNode : duplicationNode.children()) {
if (filePointNode.name().equals("file")) {
def file = filePointNode.attribute("path")
def line = filePointNode.attribute("line")
duplicationPoints += "\n " + file + ":" + line
duplicationIndex++
}
}
println("$count CPD: code duplication $duplicationPoints")
}
return count
}
appendLintErrors = { count, lintFile ->
def rootNode = new XmlParser().parse(lintFile)
for (def issueNode : rootNode.children()) {
if (!issueNode.name().equals("issue")
|| !issueNode.attribute("severity").equals("Error")) {
continue
}
for (def locationNode : issueNode.children()) {
if (!locationNode.name().equals("location")) {
continue
}
count++
appendError(count, "Lint", locationNode.attribute("file"), locationNode.attribute("line"),
issueNode.attribute("id"), issueNode.attribute("explanation"), issueNode.attribute("message"))
}
}
return count
}
getCpdTask = { isAndroidProject, sources ->
def taskName = (isAndroidProject ? "android" : "server") + "cpd_${rootProject.name}"
def task = tasks.findByName(taskName)
if (task == null) {
task = tasks.create(taskName, tasks.findByName('cpdCheck').getClass().getSuperclass()) {
minimumTokenCount = 60
source = files(sources)
ignoreFailures = true
reports {
xml {
enabled = true
destination = file("${rootProject.buildDir}/reports/cpd.xml")
}
}
}
}
return task.path
}
getLintTask = { buildVariant ->
def lintTaskPath = null
if (buildVariant != null) {
def projectWithTask = subprojects.find { it.plugins.hasPlugin("com.android.application") }
if (projectWithTask != null) {
lintTaskPath = ":${projectWithTask.name}:lint${buildVariant.name.capitalize()}"
}
} else {
subprojects.find { subproject ->
def lintDebugTasks = subproject.tasks.matching { it.getName().contains("lint") && it.getName().contains("Debug") }
if (lintDebugTasks.isEmpty()) {
return false
} else {
lintTaskPath = lintDebugTasks.first().path
return true
}
}
}
if (lintTaskPath == null) {
throw IllegalStateException("Unable to find lint debug task for build variant: ${buildVariant}")
}
return lintTaskPath
}
getKotlinDetektTasks = { subprojects.collect { it.tasks.findByName("detekt").path }.findAll { !it.contains(":libs") } }
task optimizePng {
doFirst {
def jarArgs = new ArrayList<String>()
jarArgs.add(configurations.pngtastic.asPath)
def relatedPathIndex = "${rootDir}".length() + 1
for (def file : fileTree(dir: "${rootDir}", include: '**/src/**/res/drawable**/*.png')) {
jarArgs.add(file.absolutePath.substring(relatedPathIndex))
}
for (def file : fileTree(dir: "${rootDir}", include: '**/src/**/res/mipmap**/*.png')) {
jarArgs.add(file.absolutePath.substring(relatedPathIndex))
}
javaexec { main = "-jar"; args = jarArgs; workingDir = file("${rootDir}") }
}
}
dependencies {
pngtastic 'com.github.depsypher:pngtastic:1.2'
}