diff --git a/gradle/apiGenerator.gradle b/gradle/apiGenerator.gradle new file mode 100644 index 0000000..62a7f67 --- /dev/null +++ b/gradle/apiGenerator.gradle @@ -0,0 +1,42 @@ +repositories { + maven { + url "https://maven.dev.touchin.ru" + metadataSources { + artifact() + } + } +} + +configurations { + apigenerator +} + +dependencies { + apigenerator 'ru.touchin:api-generator:1.4.0-beta1' +} + +android.applicationVariants.all { variant -> + final File generatedModelsDirectory = new File("${project.buildDir}/generated/source/models/${variant.dirName}") + + def generateJsonModelsTask = tasks.create("apiGenerator${variant.name}") doLast { + javaexec { + main = "-jar" + workingDir = file("${rootDir}") + args = [ + configurations.apigenerator.asPath, + "generate-client-code", + "--output-language", + "JAVA", + "--specification-path", + rootProject.extensions.findByName("pathToApiSchemes"), + "--output-path", + "${generatedModelsDirectory.path}", + "--package-name", + "${rootProject.extensions.findByName("applicationId") ?: applicationId}" + ] + } + } + + generateJsonModelsTask.description = 'Generates Java classes for JSON models' + variant.registerJavaGeneratingTask generateJsonModelsTask, generatedModelsDirectory +} diff --git a/gradle/apiGeneratorKotlinServer.gradle b/gradle/apiGeneratorKotlinServer.gradle new file mode 100644 index 0000000..cffa86d --- /dev/null +++ b/gradle/apiGeneratorKotlinServer.gradle @@ -0,0 +1,38 @@ +repositories { + maven { + url "https://maven.dev.touchin.ru" + metadataSources { + artifact() + } + } +} + +configurations { + apigeneratorKotlinServer +} + +dependencies { + apigeneratorKotlinServer 'ru.touchin:api-generator:1.4.0-beta1' +} + +task generateApiModelsKotlinServer doLast { + javaexec { + main = "-jar" + workingDir = file("${rootDir}") + args = [ + configurations.apigeneratorKotlinServer.asPath, + "generate-client-code", + "--output-language", + "KOTLIN_SERVER", + "--specification-path", + rootProject.extensions.findByName("pathToApiSchemes"), + "--output-path", + "${rootDir}/src/main/kotlin", + "--package-name", + rootProject.extensions.findByName("apiPackageName"), + "--recreate_output_dirs", + false + ] + } +} + diff --git a/gradle/commonStaticAnalysis.gradle b/gradle/commonStaticAnalysis.gradle new file mode 100644 index 0000000..7022d71 --- /dev/null +++ b/gradle/commonStaticAnalysis.gradle @@ -0,0 +1,233 @@ +apply plugin: 'cpd' +apply plugin: 'io.gitlab.arturbosch.detekt' + +def getCpdTask +def getLintTask +def getKotlinDetektTasks + +def appendError +def appendCpdErrors +def appendKotlinErrors +def appendLintErrors + +repositories { + maven { url "https://maven.dev.touchin.ru" } +} + +configurations { + pngtastic +} + +cpd { + skipLexicalErrors = true +} + +import org.apache.tools.ant.taskdefs.condition.Os + +ext.getIdeaFormatTask = { isAndroidProject, sources -> + def ideaPath = System.getenv("IDEA_HOME") + if (ideaPath == null) { + return tasks.create((isAndroidProject ? "android" : "server") + "donothing") + } + return tasks.create((isAndroidProject ? "android" : "server") + "IdeaFormat_$project.name", Exec) { + def inspectionPath + def params = ["-r", "-mask", "*.java,*.kt,*.xml"] + for (String source : sources) { + params.add(source) + } + + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + inspectionPath = ['cmd', '/c', "\"${ideaPath}\\bin\\format.bat\" ${params.join(" ")}"] + } else { + inspectionPath = ["$ideaPath/bin/format.sh"] + } + commandLine inspectionPath + if (!Os.isFamily(Os.FAMILY_WINDOWS)) { + args = params + } + } +} + +ext.getStaticAnalysisTaskNames = { isAndroidProject, sources, buildVariant -> + def tasksNames = new ArrayList() + try { + tasksNames.add(getCpdTask(isAndroidProject, sources)) + tasksNames.addAll(getKotlinDetektTasks()) + if (isAndroidProject) { + tasksNames.add(getLintTask(buildVariant)) + } + } catch (Exception exception) { + println(exception.toString()) + } + return tasksNames +} + +ext.generateReport = { isAndroidProject -> + StringBuilder consoleReport = new StringBuilder() + consoleReport.append("STATIC ANALYSIS RESULTS:") + def count = 0 + + def previousCount = count + count = appendCpdErrors(count, new File("${project.buildDir}/reports/cpd.xml")) + if (count - previousCount > 0) { + consoleReport.append("\nCPD: FAILED (" + (count - previousCount) + " errors)") + } else { + consoleReport.append("\nCPD: PASSED") + } + + previousCount = count + subprojects.forEach { subproject -> + def reportFile = new File("${rootProject.buildDir}/reports/kotlin-detekt-${subproject.name}.xml") + if (reportFile.exists()) { + count = appendKotlinErrors(count, reportFile).toInteger() + } + } + if (count - previousCount > 0) { + consoleReport.append("\nKotlin-detekt: FAILED (" + (count - previousCount) + " errors)") + } else { + consoleReport.append("\nKotlin-detekt: PASSED") + } + + if (isAndroidProject) { + previousCount = count + count = appendLintErrors(count, new File("${rootProject.buildDir}/reports/lint_report.xml")) + if (count - previousCount > 0) { + consoleReport.append("\nLint: FAILED (" + (count - previousCount) + " errors)") + } else { + consoleReport.append("\nLint: PASSED") + } + } + + if (count > 0) { + consoleReport.append("\nOverall: FAILED (" + count + " errors)") + throw new Exception(consoleReport.toString()) + } else { + consoleReport.append("\nOverall: PASSED") + println(consoleReport.toString()) + } +} + +appendError = { number, analyzer, file, line, errorId, errorLink, description -> + println("$number. $analyzer : $description ($errorId)\n\tat $file: $line") +} + +appendKotlinErrors = { count, checkstyleFile -> + def rootNode = new XmlParser().parse(checkstyleFile) + for (def fileNode : rootNode.children()) { + if (!fileNode.name().equals("file")) { + continue + } + + for (def errorNode : fileNode.children()) { + if (!errorNode.name().equals("error")) { + continue + } + count++ + + appendError(count, "Detekt", fileNode.attribute("name"), errorNode.attribute("line"), errorNode.attribute("source"), "", errorNode.attribute("message")) + } + } + return count +} + +appendCpdErrors = { count, cpdFile -> + def rootNode = new XmlParser().parse(cpdFile) + for (def duplicationNode : rootNode.children()) { + if (!duplicationNode.name().equals("duplication")) { + continue + } + count++ + + def duplicationIndex = 0 + + String duplicationPoints = "" + for (def filePointNode : duplicationNode.children()) { + if (filePointNode.name().equals("file")) { + def file = filePointNode.attribute("path") + def line = filePointNode.attribute("line") + duplicationPoints += "\n " + file + ":" + line + duplicationIndex++ + } + } + println("$count CPD: code duplication $duplicationPoints") + } + return count +} + +appendLintErrors = { count, lintFile -> + def rootNode = new XmlParser().parse(lintFile) + for (def issueNode : rootNode.children()) { + if (!issueNode.name().equals("issue") + || !issueNode.attribute("severity").equals("Error")) { + continue + } + for (def locationNode : issueNode.children()) { + if (!locationNode.name().equals("location")) { + continue + } + count++ + appendError(count, "Lint", locationNode.attribute("file"), locationNode.attribute("line"), + issueNode.attribute("id"), issueNode.attribute("explanation"), issueNode.attribute("message")) + } + } + return count +} + +getCpdTask = { isAndroidProject, sources -> + def taskName = (isAndroidProject ? "android" : "server") + "cpd_${rootProject.name}" + def task = tasks.findByName(taskName) + if (task == null) { + task = tasks.create(taskName, tasks.findByName('cpdCheck').getClass().getSuperclass()) { + minimumTokenCount = 60 + source = files(sources) + ignoreFailures = true + reports { + xml { + enabled = true + destination = file("${rootProject.buildDir}/reports/cpd.xml") + } + } + } + } + return task.path +} + +getLintTask = { buildVariant -> + def appProject = subprojects.find { it.plugins.hasPlugin("com.android.application") } + def lintTaskPath + if (buildVariant != null) { + lintTaskPath = ":${appProject.name}:lint${buildVariant.name.capitalize()}" + } else { + def lintDebugTasks = appProject.tasks.matching { it.getName().contains("lint") && it.getName().contains("Debug") } + lintTaskPath = lintDebugTasks.first().path + } + if (lintTaskPath == null) { + throw IllegalStateException("Unable to find lint debug task for build variant: ${buildVariant}") + } + return lintTaskPath +} + +getKotlinDetektTasks = { + subprojects + .findResults { it.tasks.findByName("detekt")?.path } + .findAll { !it.contains(":libs") } +} + +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 { + pngtastic 'com.github.depsypher:pngtastic:1.2' +}