Kotlin analysis and Idea formating (#17)
* kotlin analysis via detekt * detekt config tuning * IdeaFormatTask * format wip * idea format * IDEA_HOME var is optional * fix enum pattern * analysis wip * analysis wip * IDEA_HOME var * separate task for server * fix * name fixes * fix unix build * final fix! * detekt M13.2, some new rules * do nothing if there is no IDEA_HOME * NewLineAtEndOfFile false * отключил проверки unsafeCast и unsafeCall * supress lint MissingRegistered
This commit is contained in:
parent
4386bfeb61
commit
51cb1ddb55
|
|
@ -142,7 +142,7 @@
|
|||
<property name="caseIndent" value="4"/>
|
||||
<property name="throwsIndent" value="4"/>
|
||||
<property name="lineWrappingIndentation" value="4"/>
|
||||
<property name="arrayInitIndent" value="4"/>
|
||||
<property name="arrayInitIndent" value="8"/>
|
||||
</module>
|
||||
<module name="InnerAssignment"/>
|
||||
<module name="InnerTypeLast"/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
<application>
|
||||
<component name="CodeStyleSettingsManager">
|
||||
<option name="PER_PROJECT_SETTINGS">
|
||||
<value />
|
||||
</option>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="TouchInstinct" />
|
||||
</component>
|
||||
</application>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<application>
|
||||
<component name="CodeStyleSchemeSettings">
|
||||
<option name="CURRENT_SCHEME_NAME" value="TouchInstinct" />
|
||||
</component>
|
||||
</application>
|
||||
|
|
@ -0,0 +1,254 @@
|
|||
<code_scheme name="TouchInstinct">
|
||||
<option name="GENERATE_FINAL_LOCALS" value="true" />
|
||||
<option name="GENERATE_FINAL_PARAMETERS" value="true" />
|
||||
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
|
||||
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
|
||||
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
|
||||
<value />
|
||||
</option>
|
||||
<option name="IMPORT_LAYOUT_TABLE">
|
||||
<value>
|
||||
<package name="android" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="com" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="junit" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="net" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="org" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="java" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="javax" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="" withSubpackages="true" static="true" />
|
||||
<emptyLine />
|
||||
</value>
|
||||
</option>
|
||||
<option name="RIGHT_MARGIN" value="150" />
|
||||
<option name="JD_P_AT_EMPTY_LINES" value="false" />
|
||||
<AndroidXmlCodeStyleSettings>
|
||||
<option name="USE_CUSTOM_SETTINGS" value="true" />
|
||||
</AndroidXmlCodeStyleSettings>
|
||||
<JavaCodeStyleSettings>
|
||||
<option name="DO_NOT_WRAP_AFTER_SINGLE_ANNOTATION" value="true" />
|
||||
<option name="ANNOTATION_PARAMETER_WRAP" value="1" />
|
||||
<option name="ALIGN_MULTILINE_ANNOTATION_PARAMETERS" value="true" />
|
||||
</JavaCodeStyleSettings>
|
||||
<Objective-C-extensions>
|
||||
<file>
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
|
||||
</file>
|
||||
<class>
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
|
||||
</class>
|
||||
<extensions>
|
||||
<pair source="cpp" header="h" />
|
||||
<pair source="c" header="h" />
|
||||
</extensions>
|
||||
</Objective-C-extensions>
|
||||
<XML>
|
||||
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
|
||||
</XML>
|
||||
<codeStyleSettings language="JAVA">
|
||||
<option name="RIGHT_MARGIN" value="150" />
|
||||
<option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" />
|
||||
<option name="CALL_PARAMETERS_WRAP" value="1" />
|
||||
<option name="METHOD_PARAMETERS_WRAP" value="1" />
|
||||
<option name="RESOURCE_LIST_WRAP" value="1" />
|
||||
<option name="EXTENDS_LIST_WRAP" value="1" />
|
||||
<option name="THROWS_LIST_WRAP" value="1" />
|
||||
<option name="EXTENDS_KEYWORD_WRAP" value="1" />
|
||||
<option name="THROWS_KEYWORD_WRAP" value="1" />
|
||||
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
|
||||
<option name="BINARY_OPERATION_WRAP" value="1" />
|
||||
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
|
||||
<option name="TERNARY_OPERATION_WRAP" value="1" />
|
||||
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
|
||||
<option name="FOR_STATEMENT_WRAP" value="1" />
|
||||
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
|
||||
<option name="ASSIGNMENT_WRAP" value="1" />
|
||||
<option name="PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE" value="true" />
|
||||
<option name="IF_BRACE_FORCE" value="3" />
|
||||
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||
<option name="WHILE_BRACE_FORCE" value="3" />
|
||||
<option name="FOR_BRACE_FORCE" value="3" />
|
||||
<option name="WRAP_LONG_LINES" value="true" />
|
||||
<option name="PARAMETER_ANNOTATION_WRAP" value="1" />
|
||||
<option name="VARIABLE_ANNOTATION_WRAP" value="1" />
|
||||
<option name="ENUM_CONSTANTS_WRAP" value="2" />
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
<option name="FORCE_REARRANGE_MODE" value="1" />
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:layout_width</NAME>
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:layout_height</NAME>
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:layout_.*</NAME>
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:width</NAME>
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:height</NAME>
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
|
|
@ -0,0 +1,438 @@
|
|||
apply plugin: 'checkstyle'
|
||||
apply plugin: 'pmd'
|
||||
apply plugin: 'cpd'
|
||||
|
||||
def getCpdTask
|
||||
def getPmdTask
|
||||
def getCheckstyleTask
|
||||
def getLintTasks
|
||||
def getKotlinDetektTask
|
||||
|
||||
def appendError
|
||||
def appendCpdErrors
|
||||
def appendKotlinErrors
|
||||
def appendCheckstyleErrors
|
||||
def appendPmdErrors
|
||||
def appendLintErrors
|
||||
|
||||
def normalizeFileUrl
|
||||
|
||||
repositories {
|
||||
maven { url "http://dl.bintray.com/touchin/touchin-tools" }
|
||||
}
|
||||
|
||||
configurations {
|
||||
pngtastic
|
||||
detekt
|
||||
}
|
||||
|
||||
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") + "do nothing")
|
||||
}
|
||||
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 ->
|
||||
def tasksNames = new ArrayList<String>()
|
||||
try {
|
||||
tasksNames.add(getCpdTask(isAndroidProject, sources))
|
||||
tasksNames.add(getKotlinDetektTask(isAndroidProject))
|
||||
if (isAndroidProject) {
|
||||
tasksNames.add(getCheckstyleTask(sources))
|
||||
tasksNames.add(getPmdTask(sources))
|
||||
tasksNames.addAll(getLintTasks())
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
println(exception.toString())
|
||||
}
|
||||
return tasksNames
|
||||
}
|
||||
|
||||
ext.generateHtmlReport = { isAndroidProject ->
|
||||
StringBuilder fullReport = new StringBuilder()
|
||||
|
||||
fullReport.append("<table cellpadding='10px' border='2px' cellspacing='0px' cols='4'>");
|
||||
|
||||
StringBuilder consoleReport = new StringBuilder()
|
||||
consoleReport.append("STATIC ANALYSIS RESULTS:")
|
||||
def count = 0
|
||||
|
||||
def previousCount = count
|
||||
count = appendCpdErrors(fullReport, count, new File("${project.buildDir}/reports/cpd.xml"))
|
||||
if (count - previousCount > 0) {
|
||||
consoleReport.append("\n\u001B[31mCPD: FAILED (" + (count - previousCount) + " errors)\u001B[0m " +
|
||||
normalizeFileUrl("file://${project.buildDir}/reports/cpd.xml"))
|
||||
} else {
|
||||
consoleReport.append("\n\u001B[32mCPD: PASSED\u001B[0m")
|
||||
}
|
||||
|
||||
previousCount = count
|
||||
count = appendKotlinErrors(fullReport, count, new File("${project.buildDir}/reports/kotlin-detekt.xml"))
|
||||
if (count - previousCount > 0) {
|
||||
consoleReport.append("\n\u001B[31mKotlin-detekt: FAILED (" + (count - previousCount) + " errors)\u001B[0m " +
|
||||
normalizeFileUrl("file://${project.buildDir}/reports/kotlin-detekt.xml"))
|
||||
} else {
|
||||
consoleReport.append("\n\u001B[32mKotlin-detekt: PASSED\u001B[0m")
|
||||
}
|
||||
|
||||
if (isAndroidProject) {
|
||||
previousCount = count
|
||||
count = appendPmdErrors(fullReport, count, new File("${project.buildDir}/reports/pmd.xml"))
|
||||
if (count - previousCount > 0) {
|
||||
consoleReport.append("\n\u001B[31mPMD: FAILED (" + (count - previousCount) + " errors)\u001B[0m " +
|
||||
normalizeFileUrl("file://${project.buildDir}/reports/pmd.html"))
|
||||
} else {
|
||||
consoleReport.append("\n\u001B[32mPMD: PASSED\u001B[0m")
|
||||
}
|
||||
|
||||
previousCount = count
|
||||
count = appendLintErrors(fullReport, count, new File("${project.buildDir}/reports/lint_report.xml"))
|
||||
if (count - previousCount > 0) {
|
||||
consoleReport.append("\n\u001B[31mLint: FAILED (" + (count - previousCount) + " errors)\u001B[0m " +
|
||||
normalizeFileUrl("file://${project.buildDir}/reports/lint.html"))
|
||||
} else {
|
||||
consoleReport.append("\n\u001B[32mLint: PASSED\u001B[0m")
|
||||
}
|
||||
|
||||
previousCount = count
|
||||
count = appendCheckstyleErrors(fullReport, count, new File("${project.buildDir}/reports/checkstyle.xml"))
|
||||
if (count - previousCount > 0) {
|
||||
consoleReport.append("\n\u001B[31mCheckstyle: FAILED (" + (count - previousCount) + " errors)\u001B[0m " +
|
||||
normalizeFileUrl("file://${project.buildDir}/reports/checkstyle.xml"))
|
||||
} else {
|
||||
consoleReport.append("\n\u001B[32mCheckstyle: PASSED\u001B[0m")
|
||||
}
|
||||
}
|
||||
|
||||
fullReport.append("\n</table>\n");
|
||||
fullReport.append("<script>\n" +
|
||||
"\tfunction visitPage(file, line) {\n" +
|
||||
"\t\tfor (port = 63330; port < 63340; port++) {\n" +
|
||||
"\t\t\tvar theUrl='http://127.0.0.1:' + port + '/file?file=' + file + '&line=' + line;\n" +
|
||||
"\t\t\tvar xmlHttp = new XMLHttpRequest();\n" +
|
||||
"\t\t\txmlHttp.open('GET', theUrl, true);\n" +
|
||||
"\t\t\txmlHttp.send(null);\n" +
|
||||
"\t\t}\n" +
|
||||
"\t}\n" +
|
||||
"</script>");
|
||||
|
||||
File fullReportFile = new File("${project.buildDir}/reports/full_report.html")
|
||||
fullReportFile.write(fullReport.toString());
|
||||
|
||||
if (count > 0) {
|
||||
consoleReport.append("\n\u001B[31mOverall: FAILED (" + count + " errors)\u001B[0m "
|
||||
+ normalizeFileUrl("file://${project.buildDir}/reports/full_report.html"))
|
||||
throw new Exception(consoleReport.toString())
|
||||
} else {
|
||||
consoleReport.append("\n\u001B[32mOverall: PASSED\u001B[0m")
|
||||
println(consoleReport.toString())
|
||||
}
|
||||
}
|
||||
|
||||
normalizeFileUrl = { url ->
|
||||
return url.replace("\\", "/")
|
||||
}
|
||||
|
||||
appendError = { report, number, analyzer, file, line, errorId, errorLink, description ->
|
||||
report.append("\n\t<tr>")
|
||||
|
||||
report.append("\n\t\t<td>" + number + "</td>")
|
||||
|
||||
report.append("\n\t\t<td>" + analyzer + "</td>")
|
||||
|
||||
report.append("\n\t\t<td>")
|
||||
if (analyzer == "Lint") {
|
||||
report.append("\n\t\t\t<a href='javascript:alert(\"" + errorLink.replace("'", "'") + "\")'>" + description + " (" + errorId + ")</a>")
|
||||
} else if (analyzer == "Detekt") {
|
||||
report.append("\n\t\t\t" + description + " (" + errorId + ")")
|
||||
} else {
|
||||
report.append("\n\t\t\t<a target='_blank' href='" + errorLink + "'>" + description + " (" + errorId + ")</a>")
|
||||
}
|
||||
report.append("\n\t\t</td>")
|
||||
|
||||
def indexOfSrc = file.indexOf("src")
|
||||
def deeplink = (indexOfSrc > 0 ? file.substring(indexOfSrc) : file).replace('\\', '/')
|
||||
report.append("\n\t\t<td>")
|
||||
report.append("\n\t\t\t<a href='javascript:visitPage(\"" + deeplink + "\", " + line + ")'>" + file + ":" + line + "</a>")
|
||||
report.append("\n\t\t</td>")
|
||||
|
||||
report.append("\n\t</tr>")
|
||||
println("\n\u001B[31m" + number + " " + analyzer + ": " + description + " (" + errorId + ")\n\tat " + file + ":" + line + "\u001B[0m")
|
||||
}
|
||||
|
||||
appendKotlinErrors = { report, 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++
|
||||
|
||||
def error = errorNode.attribute("source")
|
||||
appendError(report, count, "Detekt", fileNode.attribute("name"), errorNode.attribute("line"), error, "", errorNode.attribute("message"))
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
appendCpdErrors = { report, count, cpdFile ->
|
||||
def rootNode = new XmlParser().parse(cpdFile)
|
||||
for (def duplicationNode : rootNode.children()) {
|
||||
if (!duplicationNode.name().equals("duplication")) {
|
||||
continue
|
||||
}
|
||||
count++
|
||||
|
||||
report.append("\n\t<tr>")
|
||||
|
||||
report.append("\n\t\t<td>" + count + "</td>")
|
||||
|
||||
report.append("\n\t\t<td>CPD</td>")
|
||||
|
||||
def fragment = "<b>Code duplication:</b></br></br>"
|
||||
def links = ""
|
||||
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");
|
||||
def indexOfSrc = file.indexOf("src")
|
||||
def deeplink = (indexOfSrc > 0 ? file.substring(indexOfSrc) : file).replace('\\', '/')
|
||||
if (duplicationIndex > 0) {
|
||||
links += "\n\t\t\t</br></br>"
|
||||
}
|
||||
links += "Code fragment " + (duplicationIndex + 1) + "</br>"
|
||||
links += "\n\t\t\t<a href='javascript:visitPage(\"" + deeplink + "\", " + line + ")'>" + file + ":" + line + "</a>"
|
||||
duplicationPoints += "\n\tat " + file + ":" + line
|
||||
duplicationIndex++
|
||||
} else if (filePointNode.name().equals("codefragment")) {
|
||||
fragment += filePointNode.text().replace("\n", "</br>").replace(" ", " ")
|
||||
}
|
||||
}
|
||||
report.append("\n\t\t<td>" + fragment + "\n\t\t</td>")
|
||||
|
||||
report.append("\n\t\t<td>" + links + "\n\t\t</td>")
|
||||
|
||||
report.append("\n\t</tr>")
|
||||
println("\u001B[31m" + count + " CPD: code duplication" + duplicationPoints + "\u001B[0m")
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
appendCheckstyleErrors = { report, 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++;
|
||||
|
||||
def error = errorNode.attribute("source")
|
||||
def link = "http://checkstyle.sourceforge.net/apidocs/" + error.replace('.', '/') + ".html"
|
||||
appendError(report, count, "Checkstyle", fileNode.attribute("name"), errorNode.attribute("line"), error, link, errorNode.attribute("message"))
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
appendPmdErrors = { report, count, pmdFile ->
|
||||
def rootNode = new XmlParser().parse(pmdFile)
|
||||
for (def fileNode : rootNode.children()) {
|
||||
if (!fileNode.name().equals("file")) {
|
||||
continue
|
||||
}
|
||||
|
||||
for (def errorNode : fileNode.children()) {
|
||||
if (!errorNode.name().equals("violation")) {
|
||||
continue;
|
||||
}
|
||||
count++;
|
||||
|
||||
appendError(report, count, "PMD", fileNode.attribute("name"), errorNode.attribute("beginline"),
|
||||
errorNode.attribute("rule").trim(), errorNode.attribute("externalInfoUrl").trim(), errorNode.text().trim())
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
appendLintErrors = { report, 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(report, 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_${project.name}"
|
||||
tasks.create(taskName, tasks.findByName('cpdCheck').getClass().getSuperclass()) {
|
||||
minimumTokenCount = 60
|
||||
source = files(sources)
|
||||
ignoreFailures = true
|
||||
reports {
|
||||
xml {
|
||||
enabled = true
|
||||
destination "${project.buildDir}/reports/cpd.xml"
|
||||
}
|
||||
}
|
||||
}
|
||||
return taskName
|
||||
}
|
||||
|
||||
getPmdTask = { sources ->
|
||||
def taskName = "pmd_${project.name}"
|
||||
tasks.create(taskName, Pmd) {
|
||||
pmdClasspath = configurations.pmd.asFileTree
|
||||
ruleSetFiles = files("${rootDir}/libraries/BuildScripts/pmd/rulesets/java/android.xml")
|
||||
ruleSets = []
|
||||
source files(sources)
|
||||
ignoreFailures = true
|
||||
reports {
|
||||
html {
|
||||
enabled = true
|
||||
destination "${project.buildDir}/reports/pmd.html"
|
||||
}
|
||||
xml {
|
||||
enabled = true
|
||||
destination "${project.buildDir}/reports/pmd.xml"
|
||||
}
|
||||
}
|
||||
}
|
||||
return taskName
|
||||
}
|
||||
|
||||
getLintTasks = {
|
||||
def lintTaskNames = new ArrayList<String>()
|
||||
|
||||
def lintReleaseTask = tasks.matching {
|
||||
it.getName().contains("lint") && it.getName().contains("Release")
|
||||
}.first();
|
||||
//TODO return on jack lintReleaseTask.dependsOn.clear()
|
||||
lintTaskNames.add(lintReleaseTask.getName())
|
||||
|
||||
def lintDebugTask = tasks.matching {
|
||||
it.getName().contains("lint") && it.getName().contains("Debug")
|
||||
}.first();
|
||||
//TODO return on jack lintDebugTask.dependsOn.clear()
|
||||
lintTaskNames.add(lintDebugTask.getName())
|
||||
|
||||
android.lintOptions.abortOnError = false
|
||||
android.lintOptions.checkAllWarnings = true
|
||||
android.lintOptions.warningsAsErrors = false
|
||||
android.lintOptions.xmlReport = true
|
||||
android.lintOptions.xmlOutput = file("${project.buildDir}/reports/lint_report.xml")
|
||||
android.lintOptions.htmlReport = true
|
||||
android.lintOptions.htmlOutput = file("${project.buildDir}/reports/lint_report.html")
|
||||
android.lintOptions.lintConfig = file("${rootDir}/libraries/BuildScripts/lint/lint.xml")
|
||||
return lintTaskNames
|
||||
}
|
||||
|
||||
getCheckstyleTask = { sources ->
|
||||
def taskName = "checkstyle_${project.name}"
|
||||
def compileReleaseTask = tasks.matching {
|
||||
it.getName().contains("compile") && it.getName().contains("Release") && it.getName().contains("Java") && !it.getName().contains("UnitTest")
|
||||
}.last()
|
||||
tasks.create(taskName, Checkstyle) {
|
||||
ignoreFailures = true
|
||||
showViolations = false
|
||||
source files(sources)
|
||||
configFile file("${rootDir}/libraries/BuildScripts/checkstyle/configuration/touchin_checkstyle.xml")
|
||||
checkstyleClasspath = configurations.checkstyle.asFileTree
|
||||
classpath = files(System.getenv("ANDROID_HOME") + "/platforms/" + android.compileSdkVersion + "/android.jar") +
|
||||
files(System.properties.'java.home' + "/lib/rt.jar") +
|
||||
compileReleaseTask.classpath
|
||||
reports {
|
||||
xml {
|
||||
enabled = true
|
||||
destination "${project.buildDir}/reports/checkstyle.xml"
|
||||
}
|
||||
}
|
||||
}
|
||||
return taskName
|
||||
}
|
||||
|
||||
getKotlinDetektTask = { isAndroidProject ->
|
||||
def taskName = (isAndroidProject ? "android" : "server") + "detektCheck_${project.name}"
|
||||
tasks.create(taskName, JavaExec) {
|
||||
main = "io.gitlab.arturbosch.detekt.cli.Main"
|
||||
classpath = configurations.detekt
|
||||
def input = "${rootDir}"
|
||||
def output = "${project.buildDir}/reports/kotlin-detekt.xml"
|
||||
def config = "${rootDir}/libraries/BuildScripts/kotlin/detekt-config.yml"
|
||||
|
||||
// TODO add excludes from rootProject.extensions.findByName("staticAnalysisExcludes")
|
||||
def filters = ".*src/test.*,.*/resources/.*,.*/tmp/.*"
|
||||
def params = ['-i', input, '-o', output, '-c', config, '-f', filters]
|
||||
args(params)
|
||||
}
|
||||
return taskName
|
||||
}
|
||||
|
||||
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 {
|
||||
pmd 'net.sourceforge.pmd:pmd-core:5.5.3'
|
||||
pmd 'net.sourceforge.pmd:pmd-java:5.5.3'
|
||||
|
||||
checkstyle 'ru.touchin:checkstyle:7.6.2-fork'
|
||||
|
||||
pngtastic 'com.github.depsypher:pngtastic:1.2'
|
||||
|
||||
detekt 'io.gitlab.arturbosch.detekt:detekt-cli:1.0.0.M13.2'
|
||||
detekt 'io.gitlab.arturbosch.detekt:detekt-formatting:1.0.0.M13.2'
|
||||
}
|
||||
|
|
@ -1,42 +1,7 @@
|
|||
apply plugin: 'checkstyle'
|
||||
apply plugin: 'pmd'
|
||||
apply plugin: 'cpd'
|
||||
def getServerProjectSources
|
||||
def getAndroidProjectSources
|
||||
|
||||
def getBinaries
|
||||
def getSources
|
||||
def getCpdTask
|
||||
def getPmdTask
|
||||
def getLintTasks
|
||||
def getCheckstyleTask
|
||||
|
||||
def getStaticAnalysisTasks
|
||||
|
||||
def appendError
|
||||
def appendCheckstyleErrors
|
||||
def appendPmdErrors
|
||||
def appendCpdErrors
|
||||
def appendLintErrors
|
||||
def normilizeFileUrl
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url "http://dl.bintray.com/touchin/touchin-tools"
|
||||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
pngtastic
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
pmd 'net.sourceforge.pmd:pmd-core:5.5.3'
|
||||
pmd 'net.sourceforge.pmd:pmd-java:5.5.3'
|
||||
|
||||
checkstyle 'ru.touchin:checkstyle:7.6.2-fork'
|
||||
|
||||
pngtastic 'com.github.depsypher:pngtastic:1.2'
|
||||
}
|
||||
apply from: "${rootDir}/libraries/BuildScripts/gradle/commonStaticAnalysis.gradle"
|
||||
|
||||
gradle.projectsEvaluated {
|
||||
|
||||
|
|
@ -53,243 +18,68 @@ gradle.projectsEvaluated {
|
|||
"-Werror"
|
||||
}
|
||||
|
||||
def excludes = rootProject.extensions.findByName("staticAnalysisExcludes")
|
||||
|
||||
def androidStaticAnalysisTasks = getStaticAnalysisTaskNames(true, getAndroidProjectSources(excludes))
|
||||
def androidIdeaFormatTask = getIdeaFormatTask(true, getAndroidProjectSources(excludes))
|
||||
task staticAnalysis {
|
||||
def excludes = rootProject.extensions.findByName("staticAnalysisExcludes");
|
||||
dependsOn getStaticAnalysisTasks(getSources(excludes), getBinaries(excludes))
|
||||
|
||||
androidStaticAnalysisTasks.each { task ->
|
||||
tasks.findByName(task).mustRunAfter(androidIdeaFormatTask)
|
||||
}
|
||||
dependsOn androidIdeaFormatTask
|
||||
dependsOn androidStaticAnalysisTasks
|
||||
doFirst {
|
||||
StringBuilder fullReport = new StringBuilder()
|
||||
generateHtmlReport(true)
|
||||
}
|
||||
}
|
||||
|
||||
fullReport.append("<table cellpadding='10px' border='2px' cellspacing='0px' cols='4'>");
|
||||
task staticAnalysisWithoutFormatting {
|
||||
dependsOn androidStaticAnalysisTasks
|
||||
doFirst {
|
||||
generateHtmlReport(true)
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder consoleReport = new StringBuilder()
|
||||
consoleReport.append("STATIC ANALYSIS RESULTS:")
|
||||
def count = 0
|
||||
def serverStaticAnalysisTasks = getStaticAnalysisTaskNames(false, getServerProjectSources(excludes))
|
||||
def serverIdeaFormatTask = getIdeaFormatTask(false, getServerProjectSources(excludes))
|
||||
task serverStaticAnalysis {
|
||||
serverStaticAnalysisTasks.each { task ->
|
||||
tasks.findByName(task).mustRunAfter(serverIdeaFormatTask)
|
||||
}
|
||||
dependsOn serverIdeaFormatTask
|
||||
dependsOn serverStaticAnalysisTasks
|
||||
doFirst {
|
||||
generateHtmlReport(false)
|
||||
}
|
||||
}
|
||||
|
||||
def previousCount = count
|
||||
count = appendCpdErrors(fullReport, count, new File("${project.buildDir}/reports/cpd_${project.name}.xml"))
|
||||
if (count - previousCount > 0) {
|
||||
consoleReport.append("\n\u001B[31mCPD: FAILED (" + (count - previousCount) + " errors)\u001B[0m " +
|
||||
normilizeFileUrl("file://${project.buildDir}/reports/cpd_${project.name}.xml"))
|
||||
} else {
|
||||
consoleReport.append("\n\u001B[32mCPD: PASSED\u001B[0m")
|
||||
}
|
||||
|
||||
previousCount = count
|
||||
count = appendPmdErrors(fullReport, count, new File("${project.buildDir}/reports/pmd_${project.name}.xml"))
|
||||
if (count - previousCount > 0) {
|
||||
consoleReport.append("\n\u001B[31mPMD: FAILED (" + (count - previousCount) + " errors)\u001B[0m " +
|
||||
normilizeFileUrl("file://${project.buildDir}/reports/pmd_${project.name}.html"))
|
||||
} else {
|
||||
consoleReport.append("\n\u001B[32mPMD: PASSED\u001B[0m")
|
||||
}
|
||||
|
||||
previousCount = count
|
||||
count = appendLintErrors(fullReport, count, new File("${project.buildDir}/reports/lint_${project.name}.xml"))
|
||||
if (count - previousCount > 0) {
|
||||
consoleReport.append("\n\u001B[31mLint: FAILED (" + (count - previousCount) + " errors)\u001B[0m " +
|
||||
normilizeFileUrl("file://${project.buildDir}/reports/lint_${project.name}.html"))
|
||||
} else {
|
||||
consoleReport.append("\n\u001B[32mLint: PASSED\u001B[0m")
|
||||
}
|
||||
|
||||
previousCount = count
|
||||
count = appendCheckstyleErrors(fullReport, count, new File("${project.buildDir}/reports/checkstyle_${project.name}.xml"))
|
||||
if (count - previousCount > 0) {
|
||||
consoleReport.append("\n\u001B[31mCheckstyle: FAILED (" + (count - previousCount) + " errors)\u001B[0m " +
|
||||
normilizeFileUrl("file://${project.buildDir}/reports/checkstyle_${project.name}.xml"))
|
||||
} else {
|
||||
consoleReport.append("\n\u001B[32mCheckstyle: PASSED\u001B[0m")
|
||||
}
|
||||
|
||||
fullReport.append("\n</table>\n");
|
||||
fullReport.append("<script>\n" +
|
||||
"\tfunction visitPage(file, line) {\n" +
|
||||
"\t\tfor (port = 63330; port < 63340; port++) {\n" +
|
||||
"\t\t\tvar theUrl='http://127.0.0.1:' + port + '/file?file=' + file + '&line=' + line;\n" +
|
||||
"\t\t\tvar xmlHttp = new XMLHttpRequest();\n" +
|
||||
"\t\t\txmlHttp.open('GET', theUrl, true);\n" +
|
||||
"\t\t\txmlHttp.send(null);\n" +
|
||||
"\t\t}\n" +
|
||||
"\t}\n" +
|
||||
"</script>");
|
||||
|
||||
File fullReportFile = new File("${project.buildDir}/reports/full_report.html")
|
||||
fullReportFile.write(fullReport.toString());
|
||||
|
||||
if (count > 0) {
|
||||
consoleReport.append("\n\u001B[31mOverall: FAILED (" + count + " errors)\u001B[0m "
|
||||
+ normilizeFileUrl("file://${project.buildDir}/reports/full_report.html"))
|
||||
throw new Exception(consoleReport.toString())
|
||||
} else {
|
||||
consoleReport.append("\n\u001B[32mOverall: PASSED\u001B[0m")
|
||||
println(consoleReport.toString())
|
||||
}
|
||||
task serverStaticAnalysisWithoutFormatting {
|
||||
dependsOn serverStaticAnalysisTasks
|
||||
doFirst {
|
||||
generateHtmlReport(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
getServerProjectSources = { excludes ->
|
||||
def sources = new ArrayList<String>()
|
||||
def sourcesDirectory = new File(project.projectDir.path, 'src')
|
||||
|
||||
for (def sourceFlavorDirectory : sourcesDirectory.listFiles()) {
|
||||
def javaSourceDirectory = new File(sourceFlavorDirectory.path, 'java')
|
||||
def kotlinSourceDirectory = new File(sourceFlavorDirectory.path, 'kotlin')
|
||||
|
||||
if (javaSourceDirectory.exists() && javaSourceDirectory.isDirectory()) {
|
||||
sources.add(javaSourceDirectory.absolutePath)
|
||||
}
|
||||
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}") }
|
||||
}
|
||||
}
|
||||
|
||||
normilizeFileUrl = { url ->
|
||||
return url.replace("\\", "/");
|
||||
}
|
||||
|
||||
appendError = { report, number, analyzer, file, line, errorId, errorLink, description ->
|
||||
report.append("\n\t<tr>")
|
||||
|
||||
report.append("\n\t\t<td>" + number + "</td>")
|
||||
|
||||
report.append("\n\t\t<td>" + analyzer + "</td>")
|
||||
|
||||
report.append("\n\t\t<td>")
|
||||
if (!analyzer.equals("Lint")) {
|
||||
report.append("\n\t\t\t<a target='_blank' href='" + errorLink + "'>" + description + " (" + errorId + ")</a>")
|
||||
} else {
|
||||
report.append("\n\t\t\t<a href='javascript:alert(\"" + errorLink.replace("'", "'") + "\")'>" + description + " (" + errorId + ")</a>")
|
||||
}
|
||||
report.append("\n\t\t</td>")
|
||||
|
||||
def indexOfSrc = file.indexOf("src")
|
||||
def deeplink = (indexOfSrc > 0 ? file.substring(indexOfSrc) : file).replace('\\', '/')
|
||||
report.append("\n\t\t<td>")
|
||||
report.append("\n\t\t\t<a href='javascript:visitPage(\"" + deeplink + "\", " + line + ")'>" + file + ":" + line + "</a>")
|
||||
report.append("\n\t\t</td>")
|
||||
|
||||
report.append("\n\t</tr>")
|
||||
println("\n\u001B[31m" + number + " " + analyzer + ": " + description + " (" + errorId + ")\n\tat " + file + ":" + line + "\u001B[0m")
|
||||
}
|
||||
|
||||
appendCheckstyleErrors = { report, 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++;
|
||||
|
||||
def error = errorNode.attribute("source")
|
||||
def link = "http://checkstyle.sourceforge.net/apidocs/" + error.replace('.', '/') + ".html"
|
||||
appendError(report, count, "Checkstyle", fileNode.attribute("name"), errorNode.attribute("line"), error, link, errorNode.attribute("message"))
|
||||
if (kotlinSourceDirectory.exists() && kotlinSourceDirectory.isDirectory()) {
|
||||
sources.add(kotlinSourceDirectory.absolutePath)
|
||||
}
|
||||
}
|
||||
return count
|
||||
return sources
|
||||
}
|
||||
|
||||
appendPmdErrors = { report, count, pmdFile ->
|
||||
def rootNode = new XmlParser().parse(pmdFile)
|
||||
for (def fileNode : rootNode.children()) {
|
||||
if (!fileNode.name().equals("file")) {
|
||||
continue
|
||||
}
|
||||
|
||||
for (def errorNode : fileNode.children()) {
|
||||
if (!errorNode.name().equals("violation")) {
|
||||
continue;
|
||||
}
|
||||
count++;
|
||||
|
||||
appendError(report, count, "PMD", fileNode.attribute("name"), errorNode.attribute("beginline"),
|
||||
errorNode.attribute("rule").trim(), errorNode.attribute("externalInfoUrl").trim(), errorNode.text().trim())
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
appendCpdErrors = { report, count, cpdFile ->
|
||||
def rootNode = new XmlParser().parse(cpdFile)
|
||||
for (def duplicationNode : rootNode.children()) {
|
||||
if (!duplicationNode.name().equals("duplication")) {
|
||||
continue
|
||||
}
|
||||
count++;
|
||||
|
||||
report.append("\n\t<tr>")
|
||||
|
||||
report.append("\n\t\t<td>" + count + "</td>")
|
||||
|
||||
report.append("\n\t\t<td>CPD</td>")
|
||||
|
||||
def fragment = "<b>Code duplication:</b></br></br>"
|
||||
def links = ""
|
||||
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");
|
||||
def indexOfSrc = file.indexOf("src")
|
||||
def deeplink = (indexOfSrc > 0 ? file.substring(indexOfSrc) : file).replace('\\', '/')
|
||||
if (duplicationIndex > 0) {
|
||||
links += "\n\t\t\t</br></br>"
|
||||
}
|
||||
links += "Code fragment " + (duplicationIndex + 1) + "</br>"
|
||||
links += "\n\t\t\t<a href='javascript:visitPage(\"" + deeplink + "\", " + line + ")'>" + file + ":" + line + "</a>"
|
||||
duplicationPoints += "\n\tat " + file + ":" + line
|
||||
duplicationIndex++
|
||||
} else if (filePointNode.name().equals("codefragment")) {
|
||||
fragment += filePointNode.text().replace("\n", "</br>").replace(" ", " ")
|
||||
}
|
||||
}
|
||||
report.append("\n\t\t<td>" + fragment + "\n\t\t</td>")
|
||||
|
||||
report.append("\n\t\t<td>" + links + "\n\t\t</td>")
|
||||
|
||||
report.append("\n\t</tr>")
|
||||
println("\u001B[31m" + count + " CPD: code duplication" + duplicationPoints + "\u001B[0m")
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
appendLintErrors = { report, 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(report, count, "Lint", locationNode.attribute("file"), locationNode.attribute("line"),
|
||||
issueNode.attribute("id"), issueNode.attribute("explanation"), issueNode.attribute("message"))
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
getBinaries = { excludes ->
|
||||
def binaries = new ArrayList<String>()
|
||||
for (def project : rootProject.subprojects) {
|
||||
if (!project.subprojects.isEmpty() || (excludes != null && excludes.contains(project.path))) {
|
||||
continue
|
||||
}
|
||||
binaries.add("${project.projectDir}/build/intermediates/classes")
|
||||
}
|
||||
return binaries
|
||||
}
|
||||
|
||||
getSources = { excludes ->
|
||||
getAndroidProjectSources = { excludes ->
|
||||
def sources = new ArrayList<String>()
|
||||
for (def project : rootProject.subprojects) {
|
||||
if (!project.subprojects.isEmpty() || (excludes != null && excludes.contains(project.path))) {
|
||||
|
|
@ -302,113 +92,18 @@ getSources = { excludes ->
|
|||
}
|
||||
|
||||
for (def sourceFlavorDirectory : sourcesDirectory.listFiles()) {
|
||||
def sourceSetDirectory = new File(sourceFlavorDirectory.path, 'java');
|
||||
if (!sourceSetDirectory.exists() || !sourceSetDirectory.isDirectory()) {
|
||||
continue
|
||||
def javaSourceDirectory = new File(sourceFlavorDirectory.path, 'java')
|
||||
def kotlinSourceDirectory = new File(sourceFlavorDirectory.path, 'kotlin')
|
||||
|
||||
if (javaSourceDirectory.exists() && javaSourceDirectory.isDirectory()) {
|
||||
sources.add(javaSourceDirectory.absolutePath)
|
||||
}
|
||||
if (kotlinSourceDirectory.exists() && kotlinSourceDirectory.isDirectory()) {
|
||||
sources.add(kotlinSourceDirectory.absolutePath)
|
||||
}
|
||||
sources.add(sourceSetDirectory.absolutePath)
|
||||
}
|
||||
}
|
||||
return sources
|
||||
}
|
||||
|
||||
getCpdTask = { sources ->
|
||||
def taskName = "cpd_${project.name}"
|
||||
tasks.create(taskName, tasks.findByName('cpdCheck').getClass().getSuperclass()) {
|
||||
minimumTokenCount = 60
|
||||
source = files(sources)
|
||||
ignoreFailures = true
|
||||
reports {
|
||||
xml {
|
||||
enabled = true
|
||||
destination "${project.buildDir}/reports/${taskName}.xml"
|
||||
}
|
||||
}
|
||||
}
|
||||
return taskName
|
||||
}
|
||||
|
||||
getPmdTask = { sources ->
|
||||
def taskName = "pmd_${project.name}"
|
||||
tasks.create(taskName, Pmd) {
|
||||
pmdClasspath = configurations.pmd.asFileTree
|
||||
ruleSetFiles = files("${rootDir}/libraries/BuildScripts/pmd/rulesets/java/android.xml")
|
||||
ruleSets = []
|
||||
source files(sources)
|
||||
ignoreFailures = true
|
||||
reports {
|
||||
html {
|
||||
enabled = true
|
||||
destination "${project.buildDir}/reports/${taskName}.html"
|
||||
}
|
||||
xml {
|
||||
enabled = true
|
||||
destination "${project.buildDir}/reports/${taskName}.xml"
|
||||
}
|
||||
}
|
||||
}
|
||||
return taskName
|
||||
}
|
||||
|
||||
getCheckstyleTask = { sources ->
|
||||
def taskName = "checkstyle_${project.name}"
|
||||
def compileReleaseTask = tasks.matching {
|
||||
it.getName().contains("compile") && it.getName().contains("Release") && it.getName().contains("Java") && !it.getName().contains("UnitTest")
|
||||
}.last()
|
||||
tasks.create(taskName, Checkstyle) {
|
||||
ignoreFailures = true
|
||||
showViolations = false
|
||||
source files(sources)
|
||||
configFile file("${rootDir}/libraries/BuildScripts/checkstyle/configuration/touchin_checkstyle.xml")
|
||||
checkstyleClasspath = configurations.checkstyle.asFileTree
|
||||
classpath = files(System.getenv("ANDROID_HOME") + "/platforms/" + android.compileSdkVersion + "/android.jar") +
|
||||
files(System.properties.'java.home' + "/lib/rt.jar") +
|
||||
compileReleaseTask.classpath
|
||||
reports {
|
||||
xml {
|
||||
enabled = true
|
||||
destination "${project.buildDir}/reports/${taskName}.xml"
|
||||
}
|
||||
}
|
||||
}
|
||||
return taskName
|
||||
}
|
||||
|
||||
getLintTasks = {
|
||||
def lintTaskNames = new ArrayList<String>()
|
||||
|
||||
def lintReleaseTask = tasks.matching {
|
||||
it.getName().contains("lint") && it.getName().contains("Release")
|
||||
}.first();
|
||||
//TODO return on jack lintReleaseTask.dependsOn.clear()
|
||||
lintTaskNames.add(lintReleaseTask.getName())
|
||||
|
||||
def lintDebugTask = tasks.matching {
|
||||
it.getName().contains("lint") && it.getName().contains("Debug")
|
||||
}.first();
|
||||
//TODO return on jack lintDebugTask.dependsOn.clear()
|
||||
lintTaskNames.add(lintDebugTask.getName())
|
||||
|
||||
android.lintOptions.abortOnError = false
|
||||
android.lintOptions.checkAllWarnings = true
|
||||
android.lintOptions.warningsAsErrors = false
|
||||
android.lintOptions.xmlReport = true
|
||||
android.lintOptions.xmlOutput = file("${project.buildDir}/reports/lint_${project.name}.xml")
|
||||
android.lintOptions.htmlReport = true
|
||||
android.lintOptions.htmlOutput = file("${project.buildDir}/reports/lint_${project.name}.html")
|
||||
android.lintOptions.lintConfig = file("${rootDir}/libraries/BuildScripts/lint/lint.xml")
|
||||
return lintTaskNames
|
||||
}
|
||||
|
||||
getStaticAnalysisTasks = { sources, binaries ->
|
||||
def tasksNames = new ArrayList<String>()
|
||||
try {
|
||||
tasksNames.add(getCpdTask(sources))
|
||||
tasksNames.add(getCheckstyleTask(sources))
|
||||
tasksNames.add(getPmdTask(sources))
|
||||
tasksNames.addAll(getLintTasks())
|
||||
} catch (Exception exception) {
|
||||
println(exception.toString())
|
||||
}
|
||||
return tasksNames
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,142 @@
|
|||
autoCorrect: true
|
||||
|
||||
build:
|
||||
warningThreshold: 1
|
||||
failThreshold: 100500
|
||||
weights:
|
||||
complexity: 2
|
||||
formatting: 0
|
||||
LongParameterList: 1
|
||||
comments: 0.5
|
||||
|
||||
potential-bugs:
|
||||
active: true
|
||||
DuplicateCaseInWhenExpression:
|
||||
active: true
|
||||
EqualsWithHashCodeExist:
|
||||
active: true
|
||||
ExplicitGarbageCollectionCall:
|
||||
active: true
|
||||
LateinitUsage:
|
||||
active: false
|
||||
UnsafeCallOnNullableType:
|
||||
active: false
|
||||
UnsafeCast:
|
||||
active: false
|
||||
|
||||
performance:
|
||||
active: true
|
||||
ForEachOnRange:
|
||||
active: true
|
||||
SpreadOperator:
|
||||
active: true
|
||||
|
||||
exceptions:
|
||||
active: false
|
||||
|
||||
empty-blocks:
|
||||
active: true
|
||||
|
||||
complexity:
|
||||
active: true
|
||||
LongMethod:
|
||||
threshold: 40
|
||||
LongParameterList:
|
||||
threshold: 10
|
||||
LargeClass:
|
||||
threshold: 800
|
||||
ComplexMethod:
|
||||
threshold: 10
|
||||
TooManyFunctions:
|
||||
threshold: 20
|
||||
ComplexCondition:
|
||||
threshold: 6
|
||||
|
||||
code-smell:
|
||||
active: true
|
||||
FeatureEnvy:
|
||||
threshold: 0.5
|
||||
weight: 0.45
|
||||
base: 0.5
|
||||
|
||||
formatting:
|
||||
active: true
|
||||
useTabs: true
|
||||
Indentation:
|
||||
active: false
|
||||
indentSize: 4
|
||||
ConsecutiveBlankLines:
|
||||
active: true
|
||||
autoCorrect: false
|
||||
MultipleSpaces:
|
||||
active: true
|
||||
autoCorrect: true
|
||||
SpacingAfterComma:
|
||||
active: true
|
||||
autoCorrect: true
|
||||
SpacingAfterKeyword:
|
||||
active: true
|
||||
autoCorrect: true
|
||||
SpacingAroundColon:
|
||||
active: true
|
||||
autoCorrect: true
|
||||
SpacingAroundCurlyBraces:
|
||||
active: true
|
||||
autoCorrect: true
|
||||
SpacingAroundOperator:
|
||||
active: true
|
||||
autoCorrect: true
|
||||
TrailingSpaces:
|
||||
active: true
|
||||
autoCorrect: true
|
||||
UnusedImports:
|
||||
active: true
|
||||
autoCorrect: true
|
||||
OptionalSemicolon:
|
||||
active: true
|
||||
autoCorrect: true
|
||||
OptionalUnit:
|
||||
active: true
|
||||
autoCorrect: true
|
||||
ExpressionBodySyntax:
|
||||
active: true
|
||||
autoCorrect: false
|
||||
ExpressionBodySyntaxLineBreaks:
|
||||
active: true
|
||||
autoCorrect: false
|
||||
OptionalReturnKeyword:
|
||||
active: true
|
||||
autoCorrect: false
|
||||
|
||||
style:
|
||||
active: true
|
||||
NewLineAtEndOfFile:
|
||||
active: false
|
||||
ForbiddenComment:
|
||||
active: true
|
||||
values: 'STOPSHIP:'
|
||||
WildcardImport:
|
||||
active: true
|
||||
MaxLineLength:
|
||||
active: true
|
||||
maxLineLength: 150
|
||||
excludePackageStatements: false
|
||||
excludeImportStatements: false
|
||||
NamingConventionViolation:
|
||||
active: true
|
||||
variablePattern: '^[a-z][a-z0-9][a-zA-Z0-9]*$'
|
||||
constantPattern: '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$'
|
||||
methodPattern: '^[a-z][a-z0-9][a-zA-Z0-9_]*$'
|
||||
classPattern: '^[A-Z][a-zA-Z0-9]*$'
|
||||
enumEntryPattern: '^[A-Z][a-zA-Z0-9_]*$'
|
||||
|
||||
comments:
|
||||
active: false
|
||||
CommentOverPrivateMethod:
|
||||
active: false
|
||||
CommentOverPrivateProperty:
|
||||
active: false
|
||||
UndocumentedPublicClass:
|
||||
active: false
|
||||
UndocumentedPublicFunction:
|
||||
active: false
|
||||
|
|
@ -8,16 +8,7 @@
|
|||
<ignore regexp="A newer version of de.ruedigermoeller:fst than .+ is available: .+"/>
|
||||
</issue>
|
||||
<!-- todo: lint bug? -->
|
||||
<issue id="MissingRegistered" severity="error">
|
||||
<ignore
|
||||
regexp="Class referenced in the layout file, `ru.touchin.roboswag.components.views.TypefacedTextView`, was not found in the project or the libraries"/>
|
||||
<ignore
|
||||
regexp="Class referenced in the layout file, `ru.touchin.roboswag.components.views.TypefacedEditText`, was not found in the project or the libraries"/>
|
||||
<ignore
|
||||
regexp="Class referenced in the layout file, `ru.touchin.roboswag.components.views.AspectRatioFrameLayout`, was not found in the project or the libraries"/>
|
||||
<ignore
|
||||
regexp="Class referenced in the layout file, `ru.touchin.roboswag.components.views.MaterialLoadingBar`, was not found in the project or the libraries"/>
|
||||
</issue>
|
||||
<issue id="MissingRegistered" severity="ignore"/>
|
||||
<!-- todo: lint bug? -->
|
||||
<issue id="MissingPermission" severity="ignore"/>
|
||||
<!-- todo: lint bug? -->
|
||||
|
|
|
|||
Loading…
Reference in New Issue