diff --git a/checkstyle/configuration/touchin_checkstyle.xml b/checkstyle/configuration/touchin_checkstyle.xml index a0153a3..6357dd8 100755 --- a/checkstyle/configuration/touchin_checkstyle.xml +++ b/checkstyle/configuration/touchin_checkstyle.xml @@ -142,7 +142,7 @@ - + diff --git a/code.style.schemes b/code.style.schemes new file mode 100644 index 0000000..825ffd3 --- /dev/null +++ b/code.style.schemes @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/code.style.schemes.xml b/code.style.schemes.xml new file mode 100644 index 0000000..ef3f32c --- /dev/null +++ b/code.style.schemes.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/codestyles/TouchInstinct.xml b/codestyles/TouchInstinct.xml new file mode 100644 index 0000000..2beec96 --- /dev/null +++ b/codestyles/TouchInstinct.xml @@ -0,0 +1,254 @@ + + + + \ No newline at end of file diff --git a/gradle/commonStaticAnalysis.gradle b/gradle/commonStaticAnalysis.gradle new file mode 100644 index 0000000..da16080 --- /dev/null +++ b/gradle/commonStaticAnalysis.gradle @@ -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() + 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(""); + + 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
\n"); + fullReport.append(""); + + 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") + + report.append("\n\t\t" + number + "") + + report.append("\n\t\t" + analyzer + "") + + report.append("\n\t\t") + if (analyzer == "Lint") { + report.append("\n\t\t\t" + description + " (" + errorId + ")") + } else if (analyzer == "Detekt") { + report.append("\n\t\t\t" + description + " (" + errorId + ")") + } else { + report.append("\n\t\t\t" + description + " (" + errorId + ")") + } + report.append("\n\t\t") + + def indexOfSrc = file.indexOf("src") + def deeplink = (indexOfSrc > 0 ? file.substring(indexOfSrc) : file).replace('\\', '/') + report.append("\n\t\t") + report.append("\n\t\t\t" + file + ":" + line + "") + report.append("\n\t\t") + + report.append("\n\t") + 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") + + report.append("\n\t\t" + count + "") + + report.append("\n\t\tCPD") + + def fragment = "Code duplication:

" + 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

" + } + links += "Code fragment " + (duplicationIndex + 1) + "
" + links += "\n\t\t\t" + file + ":" + line + "" + duplicationPoints += "\n\tat " + file + ":" + line + duplicationIndex++ + } else if (filePointNode.name().equals("codefragment")) { + fragment += filePointNode.text().replace("\n", "
").replace(" ", " ") + } + } + report.append("\n\t\t" + fragment + "\n\t\t") + + report.append("\n\t\t" + links + "\n\t\t") + + report.append("\n\t") + 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() + + 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() + 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' +} \ No newline at end of file diff --git a/gradle/staticAnalysis.gradle b/gradle/staticAnalysis.gradle index 94ec805..e1db99a 100644 --- a/gradle/staticAnalysis.gradle +++ b/gradle/staticAnalysis.gradle @@ -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(""); + 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
\n"); - fullReport.append(""); - - 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() - 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() + 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") - - report.append("\n\t\t" + number + "") - - report.append("\n\t\t" + analyzer + "") - - report.append("\n\t\t") - if (!analyzer.equals("Lint")) { - report.append("\n\t\t\t" + description + " (" + errorId + ")") - } else { - report.append("\n\t\t\t" + description + " (" + errorId + ")") - } - report.append("\n\t\t") - - def indexOfSrc = file.indexOf("src") - def deeplink = (indexOfSrc > 0 ? file.substring(indexOfSrc) : file).replace('\\', '/') - report.append("\n\t\t") - report.append("\n\t\t\t" + file + ":" + line + "") - report.append("\n\t\t") - - report.append("\n\t") - 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") - - report.append("\n\t\t" + count + "") - - report.append("\n\t\tCPD") - - def fragment = "Code duplication:

" - 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

" - } - links += "Code fragment " + (duplicationIndex + 1) + "
" - links += "\n\t\t\t" + file + ":" + line + "" - duplicationPoints += "\n\tat " + file + ":" + line - duplicationIndex++ - } else if (filePointNode.name().equals("codefragment")) { - fragment += filePointNode.text().replace("\n", "
").replace(" ", " ") - } - } - report.append("\n\t\t" + fragment + "\n\t\t") - - report.append("\n\t\t" + links + "\n\t\t") - - report.append("\n\t") - 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() - 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() 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() - - 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() - try { - tasksNames.add(getCpdTask(sources)) - tasksNames.add(getCheckstyleTask(sources)) - tasksNames.add(getPmdTask(sources)) - tasksNames.addAll(getLintTasks()) - } catch (Exception exception) { - println(exception.toString()) - } - return tasksNames -} diff --git a/kotlin/detekt-config.yml b/kotlin/detekt-config.yml new file mode 100644 index 0000000..3a384cf --- /dev/null +++ b/kotlin/detekt-config.yml @@ -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 \ No newline at end of file diff --git a/lint/lint.xml b/lint/lint.xml index 76b110b..dab6ff4 100644 --- a/lint/lint.xml +++ b/lint/lint.xml @@ -8,16 +8,7 @@ - - - - - - +