add staticAnalysis gradle
This commit is contained in:
parent
ce23c714e5
commit
e9a8433e8c
|
|
@ -0,0 +1,243 @@
|
|||
import groovy.transform.InheritConstructors
|
||||
import groovy.transform.ToString
|
||||
import groovy.transform.TupleConstructor
|
||||
import groovy.xml.MarkupBuilder
|
||||
|
||||
apply plugin: 'io.gitlab.arturbosch.detekt'
|
||||
|
||||
task staticAnalysis {
|
||||
|
||||
dependsOn 'cleanAnalyzerReports'
|
||||
if (static_analyzer_enable_detekt) {
|
||||
dependsOn ':detekt'
|
||||
}
|
||||
if (static_analyzer_enable_lint) {
|
||||
dependsOn ':app:lint'
|
||||
}
|
||||
|
||||
doLast {
|
||||
def reportDir = new File(static_analyzer_report_dir)
|
||||
|
||||
def detektErrors = collectDetektCodeAnalyzerErrors(reportDir)
|
||||
def lintErrors = collectLintCodeAnalyzerErrors(reportDir)
|
||||
|
||||
def totalReportFile = new File(reportDir, 'total_report.html')
|
||||
|
||||
totalReportFile << generateReportHtml(detektErrors, lintErrors)
|
||||
|
||||
println("|----------------------static_analyzer--------------------------------")
|
||||
println("| static_analyzer_fail_on_lint_error : $static_analyzer_fail_on_lint_error")
|
||||
println("| static_analyzer_fail_on_detect_error : $static_analyzer_fail_on_detect_error")
|
||||
println("|")
|
||||
println("| total_detekt_errors : ${detektErrors.size()}" + (static_analyzer_enable_detekt ? "" : " [DISABLED]"))
|
||||
println("| total_lint_errors : ${lintErrors.size()}" + (static_analyzer_enable_lint ? "" : " [DISABLED]"))
|
||||
println("| total_errors : ${detektErrors.size() + lintErrors.size()}")
|
||||
println("|")
|
||||
println("| Successfully generated HtmlTotalReport at ${totalReportFile.path}")
|
||||
println("|-------------------------------------------------------------------")
|
||||
|
||||
if (static_analyzer_fail_on_lint_error || static_analyzer_fail_on_detect_error) {
|
||||
def message = ""
|
||||
def hasLintError = static_analyzer_fail_on_lint_error && !lintErrors.isEmpty()
|
||||
def hasDetektError = static_analyzer_fail_on_detect_error && !detektErrors.isEmpty()
|
||||
|
||||
if (hasLintError) {
|
||||
message += "There is ${lintErrors.size()} lint errors; "
|
||||
}
|
||||
if (hasDetektError) {
|
||||
message += "There is ${detektErrors.size()} detekt errors; "
|
||||
}
|
||||
|
||||
if (hasLintError || hasDetektError) {
|
||||
message += "\n See report at ${totalReportFile.path}"
|
||||
throw new StaticAnalysisException(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
detekt {
|
||||
debug = true
|
||||
//filters = ".*test.*,.*androidTest.*,.*//*resources/.*,.*//*build/.*"
|
||||
input = files("$rootDir/app/src/main/kotlin", "$rootDir/data/src/main/kotlin", "$rootDir/domain/src/main/kotlin")
|
||||
config = files("$static_analyzer_config_dir/detekt-config.yml")
|
||||
|
||||
reports {
|
||||
xml {
|
||||
enabled = true
|
||||
destination = file("$static_analyzer_report_dir/report_detekt.xml")
|
||||
}
|
||||
html {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task cleanAnalyzerReports(type: Delete) {
|
||||
delete static_analyzer_report_dir
|
||||
}
|
||||
|
||||
static def collectDetektCodeAnalyzerErrors(File reportDir) {
|
||||
|
||||
def detektReport = new File("$reportDir/report_detekt.xml")
|
||||
|
||||
if (detektReport == null) {
|
||||
println("can't find detekt report")
|
||||
return Collections.emptyList()
|
||||
}
|
||||
|
||||
return new XmlSlurper()
|
||||
.parse(detektReport)
|
||||
.children()
|
||||
.inject(new ArrayList<CodeAnalyzerError>()) { acc, file ->
|
||||
|
||||
println(file)
|
||||
|
||||
def fileName = file.@name
|
||||
|
||||
file.children().each { error ->
|
||||
acc.add(
|
||||
new CodeAnalyzerError(
|
||||
position: "$fileName:${error.@line ?: "-"}:${error.@column ?: "-"}",
|
||||
severity: error.@severity,
|
||||
message: error.@message,
|
||||
source: error.@source
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
acc
|
||||
}
|
||||
.sort { error -> error.position }
|
||||
}
|
||||
|
||||
static def collectLintCodeAnalyzerErrors(File reportDir) {
|
||||
|
||||
def lintReports = reportDir.listFiles().findAll { file -> file.name.matches("^lint.*xml\$") }
|
||||
|
||||
if (lintReports == null || lintReports.isEmpty()) {
|
||||
println("can't find any lint report")
|
||||
return Collections.emptyList()
|
||||
}
|
||||
|
||||
|
||||
return lintReports.inject(new ArrayList<CodeAnalyzerError>()) { acc, report ->
|
||||
acc.addAll(parseLintReport(report))
|
||||
acc
|
||||
}.sort { error -> error.position }
|
||||
}
|
||||
|
||||
static def parseLintReport(File report) {
|
||||
|
||||
return new XmlSlurper()
|
||||
.parse(report)
|
||||
.children()
|
||||
.inject(new ArrayList<CodeAnalyzerError>()) { acc, issue ->
|
||||
|
||||
def fileName = issue.location.@file
|
||||
def line = issue.location.@line ?: "-"
|
||||
def column = issue.location.@column ?: "-"
|
||||
|
||||
acc.add(
|
||||
new CodeAnalyzerError(
|
||||
position: "$fileName:$line:$column",
|
||||
severity: issue.@severity,
|
||||
message: issue.@message,
|
||||
source: issue.@id
|
||||
)
|
||||
)
|
||||
acc
|
||||
}
|
||||
}
|
||||
|
||||
MarkupBuilder.metaClass.appendErrorsTable { errors ->
|
||||
delegate.table {
|
||||
tr {
|
||||
th(["class": "Position"], "Position")
|
||||
th(["class": "Severity"], "Severity")
|
||||
th(["class": "Source"], "Source")
|
||||
th(["class": "Message"], "Message")
|
||||
}
|
||||
|
||||
errors.forEach { error ->
|
||||
tr {
|
||||
td(error.position)
|
||||
td(error.severity.toLowerCase())
|
||||
td(error.source)
|
||||
td(error.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
def generateReportHtml(List<CodeAnalyzerError> detektErrors, List<CodeAnalyzerError> lintErrors) {
|
||||
def sb = new StringWriter()
|
||||
|
||||
def html = new MarkupBuilder(sb)
|
||||
|
||||
html.doubleQuotes = true
|
||||
html.expandEmptyElements = true
|
||||
html.omitEmptyAttributes = false
|
||||
html.omitNullAttributes = false
|
||||
|
||||
html.html(lang: 'en') {
|
||||
head {
|
||||
meta('http-equiv': '"Content-Type" content="text/html; charset=utf-8"')
|
||||
title('Static analyzer report')
|
||||
mkp.yieldUnescaped(getErrorTableStyle())
|
||||
}
|
||||
body {
|
||||
println("class: " + owner)
|
||||
|
||||
h2("Detekt errors: ${detektErrors.size()}")
|
||||
appendErrorsTable(detektErrors)
|
||||
|
||||
h2("Lint errors: ${lintErrors.size()}")
|
||||
appendErrorsTable(lintErrors)
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
static def getErrorTableStyle() {
|
||||
return """
|
||||
<style>
|
||||
h2 { margin-top: 50px; }
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
th, td {
|
||||
text-align: left;
|
||||
padding: 8px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
tr:nth-child(even) { background-color: #f2f2f2; }
|
||||
|
||||
.Position { width: 40%; }
|
||||
|
||||
.Severity { width: 10%; }
|
||||
|
||||
.Source { width: 15%; }
|
||||
|
||||
.Message { width: 35%; }
|
||||
</style>
|
||||
"""
|
||||
}
|
||||
|
||||
@ToString
|
||||
@TupleConstructor
|
||||
class CodeAnalyzerError {
|
||||
String position, severity, message, source
|
||||
}
|
||||
|
||||
@InheritConstructors
|
||||
class StaticAnalysisException extends GradleException {}
|
||||
Loading…
Reference in New Issue