commit 92cca73cfc6f3f8fda20a430db5c1e6ac9547ab9 Author: Vsevolod Ivanov Date: Tue Jun 21 19:30:09 2016 +0300 Initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..2c3832e --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# BuildScripts diff --git a/appcode/appcode_inspections_formatter.php b/appcode/appcode_inspections_formatter.php new file mode 100644 index 0000000..9e807c9 --- /dev/null +++ b/appcode/appcode_inspections_formatter.php @@ -0,0 +1,30 @@ +problem as $problem) { + if ($problem->description == 'File is too complex to perform context-sensitive data-flow analysis') { + continue; + } + $problemsCount++; + $html .= ''.$problemsCount.''.$problem->file.''.$problem->line.''.$problem->description.''; + } + } + if ($problemsCount > 0) { + $html = '' + .'' + .'' + .'' + .''.$html.'
NumFileLineProblem
'; + echo 'Found inspection problems: '.$problemsCount.PHP_EOL; + } else { + $html = '

No inspection problems found

'; + } + $html = ''.$html.''; + file_put_contents($reportsPath.DIRECTORY_SEPARATOR.'appcode_inspections.html', $html); +?> diff --git a/checkstyle/configuration/google_checks.xml b/checkstyle/configuration/google_checks.xml new file mode 100755 index 0000000..5c83a08 --- /dev/null +++ b/checkstyle/configuration/google_checks.xml @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/findbugs/filters/findbugs-filter.xml b/findbugs/filters/findbugs-filter.xml new file mode 100644 index 0000000..bb462be --- /dev/null +++ b/findbugs/filters/findbugs-filter.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gradle/staticAnalysis.gradle b/gradle/staticAnalysis.gradle new file mode 100644 index 0000000..47cc383 --- /dev/null +++ b/gradle/staticAnalysis.gradle @@ -0,0 +1,407 @@ +apply plugin: 'checkstyle' +apply plugin: 'pmd' +apply plugin: 'cpd' + +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.4.0' + pmd 'net.sourceforge.pmd:pmd-java:5.4.0' + + checkstyle 'ru.touchin:checkstyle:6.15-fork' + + pngtastic 'com.github.depsypher:pngtastic:1.2' +} + +gradle.projectsEvaluated { + + tasks.withType(JavaCompile) { + options.compilerArgs << + "-Xlint:cast" << + "-Xlint:divzero" << + "-Xlint:empty" << + "-Xlint:deprecation" << + "-Xlint:finally" << + "-Xlint:overrides" << + "-Xlint:path" << + "-Xlint:unchecked" << + "-Werror" + } + + task staticAnalysis { + def excludes = rootProject.extensions.findByName("staticAnalysisExcludes"); + dependsOn getStaticAnalysisTasks(getSources(excludes), getBinaries(excludes)) + + doFirst { + 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_${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 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)) + } + 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 + "") + + //TODO: file fb + 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")) + } + } + 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 +} + +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 -> + def sources = new ArrayList() + for (def project : rootProject.subprojects) { + if (!project.subprojects.isEmpty() || (excludes != null && excludes.contains(project.path))) { + continue + } + + def sourcesDirectory = new File(project.projectDir.path, 'src') + if (!sourcesDirectory.exists() || !sourcesDirectory.isDirectory()) { + continue + } + + for (def sourceFlavorDirectory : sourcesDirectory.listFiles()) { + def sourceSetDirectory = new File(sourceFlavorDirectory.path, 'java'); + if (!sourceSetDirectory.exists() || !sourceSetDirectory.isDirectory()) { + continue + } + 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/google_checks.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() + tasksNames.add(getCpdTask(sources)) + tasksNames.add(getCheckstyleTask(sources)) + tasksNames.add(getPmdTask(sources)) + tasksNames.addAll(getLintTasks()) + return tasksNames +} diff --git a/lint/lint.xml b/lint/lint.xml new file mode 100644 index 0000000..1b7c136 --- /dev/null +++ b/lint/lint.xml @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pmd/rulesets/java/android.xml b/pmd/rulesets/java/android.xml new file mode 100644 index 0000000..8eff332 --- /dev/null +++ b/pmd/rulesets/java/android.xml @@ -0,0 +1,106 @@ + + + + Every Java Rule in PMD + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +