diff --git a/checkstyle/configuration/google_checks.xml b/checkstyle/configuration/google_checks.xml
deleted file mode 100755
index 441f1af..0000000
--- a/checkstyle/configuration/google_checks.xml
+++ /dev/null
@@ -1,210 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/checkstyle/configuration/touchin_checkstyle.xml b/checkstyle/configuration/touchin_checkstyle.xml
deleted file mode 100755
index b36d47f..0000000
--- a/checkstyle/configuration/touchin_checkstyle.xml
+++ /dev/null
@@ -1,339 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/findbugs/filters/findbugs-filter.xml b/findbugs/filters/findbugs-filter.xml
deleted file mode 100644
index bb462be..0000000
--- a/findbugs/filters/findbugs-filter.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/gradle/apiGenerator.gradle b/gradle/apiGenerator.gradle
deleted file mode 100644
index fc9dae3..0000000
--- a/gradle/apiGenerator.gradle
+++ /dev/null
@@ -1,44 +0,0 @@
-repositories {
- maven {
- url 'https://dl.bintray.com/touchin/touchin-tools'
- metadataSources {
- artifact()
- }
- }
-}
-
-configurations {
- apigenerator
-}
-
-dependencies {
- apigenerator 'ru.touchin:api-generator:1.4.0-beta3'
-}
-
-android.libraryVariants.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",
- "KOTLIN",
- "--specification-path",
- rootProject.extensions.findByName("pathToApiSchemes"),
- "--kotlin-methods-generation-mode",
- "COROUTINE",
- "--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
deleted file mode 100644
index 66676b5..0000000
--- a/gradle/apiGeneratorKotlinServer.gradle
+++ /dev/null
@@ -1,38 +0,0 @@
-repositories {
- maven {
- url "https://dl.bintray.com/touchin/touchin-tools"
- 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
deleted file mode 100644
index b929257..0000000
--- a/gradle/commonStaticAnalysis.gradle
+++ /dev/null
@@ -1,233 +0,0 @@
-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 "http://dl.bintray.com/touchin/touchin-tools" }
-}
-
-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'
-}
diff --git a/gradle/plugins/.gitignore b/gradle/plugins/.gitignore
new file mode 100644
index 0000000..d7e7478
--- /dev/null
+++ b/gradle/plugins/.gitignore
@@ -0,0 +1,19 @@
+# Generated files
+bin/
+gen/
+
+# Gradle files
+.gradle/
+build/
+/*/build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Log Files
+*.log
+.gradle
+.idea
+.DS_Store
+/captures
+*.iml
diff --git a/gradle/plugins/build.gradle.kts b/gradle/plugins/build.gradle.kts
new file mode 100644
index 0000000..3611bcb
--- /dev/null
+++ b/gradle/plugins/build.gradle.kts
@@ -0,0 +1,52 @@
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+plugins {
+ `java-gradle-plugin`
+ `kotlin-dsl`
+}
+
+// The kotlin-dsl plugin requires a repository to be declared
+repositories {
+ jcenter()
+ google()
+}
+
+dependencies {
+ // android gradle plugin, required by custom plugin
+ implementation("com.android.tools.build:gradle:4.0.1")
+
+ implementation("io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.10.0")
+ implementation("de.aaschmid:gradle-cpd-plugin:3.1")
+
+ // kotlin plugin, required by custom plugin
+ implementation(kotlin("gradle-plugin", embeddedKotlinVersion))
+
+ gradleKotlinDsl()
+ implementation(kotlin("stdlib-jdk8"))
+}
+
+val compileKotlin: KotlinCompile by tasks
+compileKotlin.kotlinOptions {
+ jvmTarget = "1.8"
+}
+
+gradlePlugin {
+ plugins {
+ create("api-generator-android") {
+ id = "api-generator-android"
+ implementationClass = "apigen.ApiGeneratorAndroidPlugin"
+ }
+ create("api-generator-backend") {
+ id = "api-generator-backend"
+ implementationClass = "apigen.ApiGeneratorBackendPlugin"
+ }
+ create("static-analysis-android") {
+ id = "static-analysis-android"
+ implementationClass = "static_analysis.plugins.StaticAnalysisAndroidPlugin"
+ }
+ create("static-analysis-backend") {
+ id = "static-analysis-backend"
+ implementationClass = "static_analysis.plugins.StaticAnalysisBackendPlugin"
+ }
+ }
+}
diff --git a/gradle/plugins/settings.gradle.kts b/gradle/plugins/settings.gradle.kts
new file mode 100644
index 0000000..e69de29
diff --git a/gradle/plugins/src/main/java/apigen/ApiGeneratorAndroidPlugin.kt b/gradle/plugins/src/main/java/apigen/ApiGeneratorAndroidPlugin.kt
new file mode 100644
index 0000000..fa417b0
--- /dev/null
+++ b/gradle/plugins/src/main/java/apigen/ApiGeneratorAndroidPlugin.kt
@@ -0,0 +1,37 @@
+package apigen
+
+import com.android.build.gradle.LibraryExtension
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.getByType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+class ApiGeneratorAndroidPlugin : ApiGeneratorPlugin() {
+
+ override fun apply(target: Project) {
+ super.apply(target)
+
+ with(target) {
+ val extension = getExtension()
+ val outputDir = getDirectoryForGeneration()
+
+ extension.outputDirPath = outputDir.path
+ extension.recreateOutputDir = true
+
+ afterEvaluate {
+ extensions.getByType().apply {
+ sourceSets.getByName("main")
+ .java
+ .srcDir(outputDir)
+ }
+ tasks
+ .filterIsInstance(KotlinCompile::class.java)
+ .forEach {
+ it.source(outputDir)
+ }
+ }
+ }
+ }
+
+ private fun Project.getDirectoryForGeneration() = file("$buildDir/generated/api")
+
+}
diff --git a/gradle/plugins/src/main/java/apigen/ApiGeneratorBackendPlugin.kt b/gradle/plugins/src/main/java/apigen/ApiGeneratorBackendPlugin.kt
new file mode 100644
index 0000000..b68eccf
--- /dev/null
+++ b/gradle/plugins/src/main/java/apigen/ApiGeneratorBackendPlugin.kt
@@ -0,0 +1,19 @@
+package apigen
+
+import org.gradle.api.Project
+
+class ApiGeneratorBackendPlugin : ApiGeneratorPlugin() {
+
+ override fun apply(target: Project) {
+ super.apply(target)
+
+ with(target) {
+ val extension = getExtension()
+
+ extension.outputDirPath = file("src/main/kotlin").path
+ extension.recreateOutputDir = false
+ extension.outputLanguage = OutputLanguage.KotlinServer
+
+ }
+ }
+}
diff --git a/gradle/plugins/src/main/java/apigen/ApiGeneratorExtension.kt b/gradle/plugins/src/main/java/apigen/ApiGeneratorExtension.kt
new file mode 100644
index 0000000..76e0ed9
--- /dev/null
+++ b/gradle/plugins/src/main/java/apigen/ApiGeneratorExtension.kt
@@ -0,0 +1,22 @@
+package apigen
+
+open class ApiGeneratorExtension(
+ var pathToApiSchemes: String? = null,
+ var outputPackageName: String = "",
+ var outputDirPath: String = "",
+ var recreateOutputDir: Boolean = false,
+ var outputLanguage: OutputLanguage? = null
+)
+
+sealed class OutputLanguage(val argName: String, val methodOutputType: MethodOutputType? = null) {
+ object KotlinServer : OutputLanguage("KOTLIN_SERVER")
+ class KotlinAndroid(methodOutputType: MethodOutputType = MethodOutputType.Rx) : OutputLanguage("KOTLIN", methodOutputType)
+ object Java : OutputLanguage("JAVA")
+ object Swift : OutputLanguage("SWIFT")
+}
+
+sealed class MethodOutputType(val argName: String) {
+ object Rx : MethodOutputType("REACTIVE")
+ object RetrofitCall : MethodOutputType("CALL")
+ object Coroutine : MethodOutputType("COROUTINE")
+}
diff --git a/gradle/plugins/src/main/java/apigen/ApiGeneratorPlugin.kt b/gradle/plugins/src/main/java/apigen/ApiGeneratorPlugin.kt
new file mode 100644
index 0000000..ff272ce
--- /dev/null
+++ b/gradle/plugins/src/main/java/apigen/ApiGeneratorPlugin.kt
@@ -0,0 +1,76 @@
+package apigen
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.Task
+import org.gradle.kotlin.dsl.create
+import org.gradle.kotlin.dsl.dependencies
+import org.gradle.kotlin.dsl.repositories
+
+abstract class ApiGeneratorPlugin : Plugin {
+
+ companion object {
+ const val API_GENERATOR_CONFIG = "apiGenerator"
+ const val API_GENERATOR_EXT_NAME = "apiGenerator"
+ const val API_GENERATOR_VERSION = "1.4.0-beta4"
+ }
+
+ override fun apply(target: Project) {
+ with(target) {
+ repositories {
+ maven {
+ url = uri("https://dl.bintray.com/touchin/touchin-tools")
+ metadataSources {
+ artifact()
+ }
+ }
+ }
+
+ configurations.create(API_GENERATOR_CONFIG)
+
+ dependencies {
+ add(API_GENERATOR_CONFIG, "ru.touchin:api-generator:$API_GENERATOR_VERSION")
+ }
+
+ extensions.create(API_GENERATOR_EXT_NAME)
+
+ val apiGenTask = createApiGeneratorTask()
+
+ gradle.projectsEvaluated {
+ tasks.getByName("preBuild").dependsOn(apiGenTask)
+ }
+ }
+ }
+
+ protected fun Project.getExtension(): ApiGeneratorExtension = extensions.getByName(API_GENERATOR_EXT_NAME) as ApiGeneratorExtension
+
+ private fun Project.createApiGeneratorTask(): Task = tasks.create(API_GENERATOR_CONFIG).doLast {
+
+ val extension = getExtension()
+
+ val pathToApiSchemes = extension.pathToApiSchemes ?: throw IllegalStateException("Configure path to api schemes for api generator plugin")
+ val outputLanguage = extension.outputLanguage ?: throw IllegalStateException("Configure output language code for api generator plugin")
+
+ javaexec {
+ main = "-jar"
+ workingDir = rootDir
+ args = listOfNotNull(
+ configurations.getByName("apiGenerator").asPath,
+ "generate-client-code",
+ "--output-language",
+ outputLanguage.argName,
+ "--specification-path",
+ pathToApiSchemes,
+ "--kotlin-methods-generation-mode".takeIf { outputLanguage.methodOutputType != null },
+ outputLanguage.methodOutputType?.argName,
+ "--output-path",
+ extension.outputDirPath,
+ "--package-name",
+ extension.outputPackageName,
+ "--recreate_output_dirs",
+ extension.recreateOutputDir.toString()
+ )
+ }
+ }
+
+}
diff --git a/gradle/plugins/src/main/java/static_analysis/errors/AndroidLintError.kt b/gradle/plugins/src/main/java/static_analysis/errors/AndroidLintError.kt
new file mode 100644
index 0000000..aee4a44
--- /dev/null
+++ b/gradle/plugins/src/main/java/static_analysis/errors/AndroidLintError.kt
@@ -0,0 +1,12 @@
+package static_analysis.errors
+
+class AndroidLintError(
+ private val filePath: String,
+ private val fileLine: String,
+ private val errorId: String,
+ private val description: String
+) : StaticAnalysisError {
+
+ override fun print(count: Int): String = "\n$count. Android Lint. $description ($errorId)\n\tat [$filePath:$fileLine]"
+
+}
diff --git a/gradle/plugins/src/main/java/static_analysis/errors/CpdError.kt b/gradle/plugins/src/main/java/static_analysis/errors/CpdError.kt
new file mode 100644
index 0000000..cca1c8a
--- /dev/null
+++ b/gradle/plugins/src/main/java/static_analysis/errors/CpdError.kt
@@ -0,0 +1,12 @@
+package static_analysis.errors
+
+class CpdError(
+ private val duplications: List>,
+ private val codeFragment: String
+) : StaticAnalysisError {
+
+ override fun print(count: Int): String = "\n$count. CPD. Code duplication in files: " +
+ duplications.joinToString(separator = "") { (file, line) -> "\n\t[$file:$line]" } +
+ "\n\n Duplicated code:\n\n$codeFragment\n"
+
+}
diff --git a/gradle/plugins/src/main/java/static_analysis/errors/DetektError.kt b/gradle/plugins/src/main/java/static_analysis/errors/DetektError.kt
new file mode 100644
index 0000000..3aa9c09
--- /dev/null
+++ b/gradle/plugins/src/main/java/static_analysis/errors/DetektError.kt
@@ -0,0 +1,12 @@
+package static_analysis.errors
+
+class DetektError(
+ private val filePath: String,
+ private val fileLine: String,
+ private val errorId: String,
+ private val description: String
+) : StaticAnalysisError {
+
+ override fun print(count: Int): String = "\n$count. Detekt. $description ($errorId)\n\tat [$filePath:$fileLine]"
+
+}
diff --git a/gradle/plugins/src/main/java/static_analysis/errors/StaticAnalysisError.kt b/gradle/plugins/src/main/java/static_analysis/errors/StaticAnalysisError.kt
new file mode 100644
index 0000000..f932aca
--- /dev/null
+++ b/gradle/plugins/src/main/java/static_analysis/errors/StaticAnalysisError.kt
@@ -0,0 +1,5 @@
+package static_analysis.errors
+
+interface StaticAnalysisError {
+ fun print(count: Int): String
+}
diff --git a/gradle/plugins/src/main/java/static_analysis/linters/AndroidLinter.kt b/gradle/plugins/src/main/java/static_analysis/linters/AndroidLinter.kt
new file mode 100644
index 0000000..f299d22
--- /dev/null
+++ b/gradle/plugins/src/main/java/static_analysis/linters/AndroidLinter.kt
@@ -0,0 +1,65 @@
+package static_analysis.linters
+
+import com.android.build.gradle.AppExtension
+import com.android.build.gradle.AppPlugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.findByType
+import static_analysis.errors.AndroidLintError
+import static_analysis.errors.StaticAnalysisError
+import static_analysis.plugins.StaticAnalysisExtension
+import static_analysis.utils.typedChildren
+import static_analysis.utils.xmlParser
+
+class AndroidLinter : Linter {
+
+ override val name: String = "Android lint"
+
+ override fun getErrors(project: Project): List = xmlParser(project.getLintReportFile())
+ .typedChildren()
+ .filter { it.name() == "issue" && (it.attribute("severity") as String) == "Error" }
+ .map { errorNode ->
+ errorNode
+ .typedChildren()
+ .filter { it.name() == "location" }
+ .map { locationNode ->
+ AndroidLintError(
+ filePath = locationNode.attribute("file") as String,
+ fileLine = locationNode.attribute("line") as String,
+ errorId = errorNode.attribute("id") as String,
+ description = errorNode.attribute("message") as String
+ )
+ }
+ }
+ .flatten()
+
+ override fun setupForProject(project: Project, extension: StaticAnalysisExtension) {
+ project.gradle.projectsEvaluated {
+ project.subprojects
+ .mapNotNull { it.extensions.findByType() }
+ .first()
+ .lintOptions.apply {
+ isAbortOnError = false
+ isCheckAllWarnings = true
+ isWarningsAsErrors = false
+ xmlReport = true
+ htmlReport = false
+ isCheckDependencies = true
+ disable("MissingConstraints", "VectorRaster")
+ xmlOutput = project.getLintReportFile()
+ lintConfig = project.file("${extension.buildScriptDir}/static_analysis_configs/lint.xml")
+ }
+ }
+ }
+
+ override fun getTaskNames(project: Project, buildType: String?): List = project
+ .subprojects
+ .filter { it.plugins.hasPlugin(AppPlugin::class.java) }
+ .mapNotNull { subproject: Project ->
+ subproject.tasks.find { task ->
+ task.name.contains(buildType!!, ignoreCase = true) && task.name.contains("lint")
+ }?.path
+ }
+
+ private fun Project.getLintReportFile() = file("${rootProject.buildDir}/reports/lint-report.xml")
+
+}
diff --git a/gradle/plugins/src/main/java/static_analysis/linters/CpdLinter.kt b/gradle/plugins/src/main/java/static_analysis/linters/CpdLinter.kt
new file mode 100644
index 0000000..ca3ff7e
--- /dev/null
+++ b/gradle/plugins/src/main/java/static_analysis/linters/CpdLinter.kt
@@ -0,0 +1,57 @@
+package static_analysis.linters
+
+import de.aaschmid.gradle.plugins.cpd.Cpd
+import de.aaschmid.gradle.plugins.cpd.CpdExtension
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.findByType
+import org.gradle.kotlin.dsl.withType
+import static_analysis.errors.CpdError
+import static_analysis.errors.StaticAnalysisError
+import static_analysis.plugins.StaticAnalysisExtension
+import static_analysis.utils.getSources
+import static_analysis.utils.typedChildren
+import static_analysis.utils.xmlParser
+
+class CpdLinter : Linter {
+
+ override val name: String = "CPD"
+
+ override fun getErrors(project: Project): List = xmlParser(project.getCpdReportFile())
+ .typedChildren()
+ .filter { it.name() == "duplication" }
+ .map { duplicationNode ->
+
+ val children = duplicationNode
+ .typedChildren()
+
+ CpdError(
+ duplications = children
+ .filter { it.name() == "file" }
+ .map { fileNode -> fileNode.attribute("path") as String to fileNode.attribute("line") as String },
+ codeFragment = children.findLast { it.name() == "codefragment" }!!.text()
+ )
+
+ }
+
+ override fun setupForProject(project: Project, extension: StaticAnalysisExtension) {
+ project.extensions.findByType()!!.apply {
+ isSkipLexicalErrors = true
+ language = "kotlin"
+ minimumTokenCount = 60
+ }
+ project.tasks.withType {
+ reports.xml.destination = project.getCpdReportFile()
+ ignoreFailures = true
+ source = project.getSources(extension.excludes)
+ }
+ }
+
+ override fun getTaskNames(project: Project, buildType: String?): List = project
+ .rootProject
+ .tasks
+ .withType()
+ .map { it.path }
+
+ private fun Project.getCpdReportFile() = file("${rootProject.buildDir}/reports/cpd.xml")
+
+}
diff --git a/gradle/plugins/src/main/java/static_analysis/linters/DetektLinter.kt b/gradle/plugins/src/main/java/static_analysis/linters/DetektLinter.kt
new file mode 100644
index 0000000..0aafb22
--- /dev/null
+++ b/gradle/plugins/src/main/java/static_analysis/linters/DetektLinter.kt
@@ -0,0 +1,62 @@
+package static_analysis.linters
+
+import io.gitlab.arturbosch.detekt.Detekt
+import org.gradle.api.Project
+import static_analysis.errors.DetektError
+import static_analysis.errors.StaticAnalysisError
+import static_analysis.plugins.StaticAnalysisExtension
+import static_analysis.utils.getSources
+import static_analysis.utils.typedChildren
+import static_analysis.utils.xmlParser
+
+class DetektLinter : Linter {
+
+ override val name: String = "Detekt"
+
+ override fun getErrors(project: Project): List = xmlParser(project.getDetektReportFile())
+ .typedChildren()
+ .filter { fileNode -> fileNode.name() == "file" }
+ .map { fileNode ->
+ fileNode
+ .typedChildren()
+ .filter { it.name() == "error" }
+ .map { errorNode ->
+ DetektError(
+ filePath = fileNode.attribute("name") as String,
+ fileLine = errorNode.attribute("line") as String,
+ errorId = errorNode.attribute("source") as String,
+ description = errorNode.attribute("message") as String
+ )
+ }
+ }
+ .flatten()
+
+ override fun setupForProject(project: Project, extension: StaticAnalysisExtension) {
+ project
+ .tasks
+ .withType(Detekt::class.java) {
+ exclude("**/test/**")
+ exclude("resources/")
+ exclude("build/")
+ exclude("tmp/")
+ jvmTarget = "1.8"
+
+ config.setFrom(project.files("${extension.buildScriptDir!!}/static_analysis_configs/detekt-config.yml"))
+ reports {
+ txt.enabled = false
+ html.enabled = false
+ xml {
+ enabled = true
+ destination = project.getDetektReportFile()
+ }
+ }
+
+ source = project.getSources(extension.excludes)
+ }
+ }
+
+ override fun getTaskNames(project: Project, buildType: String?): List = listOf(":detekt")
+
+ private fun Project.getDetektReportFile() = file("${rootProject.buildDir}/reports/detekt.xml")
+
+}
diff --git a/gradle/plugins/src/main/java/static_analysis/linters/Linter.kt b/gradle/plugins/src/main/java/static_analysis/linters/Linter.kt
new file mode 100644
index 0000000..65421a1
--- /dev/null
+++ b/gradle/plugins/src/main/java/static_analysis/linters/Linter.kt
@@ -0,0 +1,12 @@
+package static_analysis.linters
+
+import org.gradle.api.Project
+import static_analysis.errors.StaticAnalysisError
+import static_analysis.plugins.StaticAnalysisExtension
+
+interface Linter {
+ val name: String
+ fun getErrors(project: Project): List
+ fun setupForProject(project: Project, extension: StaticAnalysisExtension)
+ fun getTaskNames(project: Project, buildType: String? = null): List
+}
diff --git a/gradle/plugins/src/main/java/static_analysis/plugins/StaticAnalysisAndroidPlugin.kt b/gradle/plugins/src/main/java/static_analysis/plugins/StaticAnalysisAndroidPlugin.kt
new file mode 100644
index 0000000..c433e81
--- /dev/null
+++ b/gradle/plugins/src/main/java/static_analysis/plugins/StaticAnalysisAndroidPlugin.kt
@@ -0,0 +1,43 @@
+package static_analysis.plugins
+
+import com.android.build.gradle.AppExtension
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.getByType
+import static_analysis.linters.AndroidLinter
+import static_analysis.linters.CpdLinter
+import static_analysis.linters.DetektLinter
+import static_analysis.linters.Linter
+
+class StaticAnalysisAndroidPlugin : StaticAnalysisPlugin() {
+
+ override fun createStaticAnalysisTasks(project: Project, linters: List) {
+ project.subprojects {
+ if (plugins.hasPlugin("com.android.application")) {
+
+ extensions.getByType().apply {
+ applicationVariants.forEach { variant ->
+ project.tasks.register("staticAnalysis${variant.name.capitalize()}") {
+ setupStaticAnalysisTask(linters, variant.name)
+ }
+ }
+
+ project.tasks.register("staticAnalysis") {
+ setupStaticAnalysisTask(
+ linters = linters,
+ buildVariant = applicationVariants.first { it.name.contains("Debug") }.name
+ )
+ }
+ }
+
+
+ }
+ }
+ }
+
+ override fun createLinters(): List = listOf(
+ DetektLinter(),
+ CpdLinter(),
+ AndroidLinter()
+ )
+
+}
diff --git a/gradle/plugins/src/main/java/static_analysis/plugins/StaticAnalysisBackendPlugin.kt b/gradle/plugins/src/main/java/static_analysis/plugins/StaticAnalysisBackendPlugin.kt
new file mode 100644
index 0000000..fa35f1d
--- /dev/null
+++ b/gradle/plugins/src/main/java/static_analysis/plugins/StaticAnalysisBackendPlugin.kt
@@ -0,0 +1,21 @@
+package static_analysis.plugins
+
+import org.gradle.api.Project
+import static_analysis.linters.CpdLinter
+import static_analysis.linters.DetektLinter
+import static_analysis.linters.Linter
+
+class StaticAnalysisBackendPlugin : StaticAnalysisPlugin() {
+
+ override fun createStaticAnalysisTasks(project: Project, linters: List) {
+ project.tasks.register("staticAnalysis") {
+ setupStaticAnalysisTask(linters)
+ }
+ }
+
+ override fun createLinters(): List = listOf(
+ CpdLinter(),
+ DetektLinter()
+ )
+
+}
diff --git a/gradle/plugins/src/main/java/static_analysis/plugins/StaticAnalysisExtension.kt b/gradle/plugins/src/main/java/static_analysis/plugins/StaticAnalysisExtension.kt
new file mode 100644
index 0000000..dfa698d
--- /dev/null
+++ b/gradle/plugins/src/main/java/static_analysis/plugins/StaticAnalysisExtension.kt
@@ -0,0 +1,6 @@
+package static_analysis.plugins
+
+open class StaticAnalysisExtension(
+ var excludes: String = "",
+ var buildScriptDir: String? = null
+)
diff --git a/gradle/plugins/src/main/java/static_analysis/plugins/StaticAnalysisPlugin.kt b/gradle/plugins/src/main/java/static_analysis/plugins/StaticAnalysisPlugin.kt
new file mode 100644
index 0000000..38ded00
--- /dev/null
+++ b/gradle/plugins/src/main/java/static_analysis/plugins/StaticAnalysisPlugin.kt
@@ -0,0 +1,47 @@
+package static_analysis.plugins
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.Task
+import org.gradle.kotlin.dsl.create
+import org.gradle.kotlin.dsl.getByType
+import static_analysis.linters.Linter
+import static_analysis.utils.ReportGenerator
+
+abstract class StaticAnalysisPlugin : Plugin {
+
+ companion object {
+ const val DETEKT_ID = "io.gitlab.arturbosch.detekt"
+ const val CPD_ID = "de.aaschmid.cpd"
+ const val STATIC_ANALYSIS_EXT_NAME = "staticAnalysis"
+ }
+
+ override fun apply(target: Project) {
+
+ with(target) {
+ pluginManager.apply(CPD_ID)
+ pluginManager.apply(DETEKT_ID)
+
+ extensions.create(STATIC_ANALYSIS_EXT_NAME)
+
+ val linters = createLinters()
+
+ afterEvaluate {
+ linters.forEach { it.setupForProject(target, extensions.getByType()) }
+ }
+
+ gradle.projectsEvaluated {
+ createStaticAnalysisTasks(target, linters)
+ }
+ }
+ }
+
+ fun Task.setupStaticAnalysisTask(linters: List, buildVariant: String? = null) {
+ doFirst { ReportGenerator.generate(linters, project) }
+ dependsOn(*(linters.map { it.getTaskNames(project, buildVariant) }.flatten().toTypedArray()))
+ }
+
+ abstract fun createLinters(): List
+ abstract fun createStaticAnalysisTasks(project: Project, linters: List)
+
+}
diff --git a/gradle/plugins/src/main/java/static_analysis/utils/Extensions.kt b/gradle/plugins/src/main/java/static_analysis/utils/Extensions.kt
new file mode 100644
index 0000000..c53ce16
--- /dev/null
+++ b/gradle/plugins/src/main/java/static_analysis/utils/Extensions.kt
@@ -0,0 +1,33 @@
+package static_analysis.utils
+
+import groovy.util.Node
+import groovy.util.XmlParser
+import org.gradle.api.Project
+import org.gradle.api.file.FileTree
+import java.io.File
+
+fun Node.typedChildren() = children() as List
+
+fun xmlParser(file: File) = XmlParser().parse(file)
+
+fun Project.getSources(excludes: String): FileTree = files(
+ project
+ .rootProject
+ .subprojects
+ .filter { subproject -> subproject.subprojects.isEmpty() && !excludes.contains(subproject.path) }
+ .map { subproject -> subproject.file("${subproject.projectDir.path}/src/main") }
+ .filter { it.exists() && it.isDirectory }
+ .flatMap { srcDir ->
+ srcDir
+ .listFiles()
+ .orEmpty()
+ .flatMap {
+ listOf(
+ File(srcDir.path, "java"),
+ File(srcDir.path, "kotlin")
+ )
+ }
+ }
+ .filter { it.exists() && it.isDirectory }
+ .map { it.path }
+).asFileTree
diff --git a/gradle/plugins/src/main/java/static_analysis/utils/ReportGenerator.kt b/gradle/plugins/src/main/java/static_analysis/utils/ReportGenerator.kt
new file mode 100644
index 0000000..caf543e
--- /dev/null
+++ b/gradle/plugins/src/main/java/static_analysis/utils/ReportGenerator.kt
@@ -0,0 +1,52 @@
+package static_analysis.utils
+
+import org.gradle.api.Project
+import static_analysis.errors.StaticAnalysisError
+import static_analysis.linters.Linter
+
+object ReportGenerator {
+
+ fun generate(linters: List, project: Project) {
+
+ val groupedErrors = linters
+ .map { linter -> linter to linter.getErrors(project) }
+
+ val lintersResults = groupedErrors
+ .map { it.first.name to it.second.size }
+
+ val allErrors = groupedErrors
+ .map { it.second }
+ .flatten()
+
+ val consoleReport = StringBuilder("\nSTATIC ANALYSIS ERRORS:").apply {
+ appendAllErrors(allErrors)
+ append("\nREPORT:\n")
+ appendReportsSummary(lintersResults)
+ appendOverallSummary(allErrors)
+ }
+
+ if (allErrors.isEmpty()) {
+ println(consoleReport)
+ } else {
+ throw Exception(consoleReport.toString())
+ }
+
+ }
+
+ private fun StringBuilder.appendAllErrors(errors: List) = errors
+ .mapIndexed { index, staticAnalysisError -> staticAnalysisError.print(index + 1) }
+ .forEach { error -> append(error) }
+
+ private fun StringBuilder.appendReportsSummary(lintersResults: List>) = lintersResults
+ .forEach { this.appendSummary(it.first, it.second) }
+
+ private fun StringBuilder.appendOverallSummary(errors: List) = appendSummary("Overall", errors.size)
+
+ private fun StringBuilder.appendSummary(header: String, quantityOfErrors: Int) {
+ assert(quantityOfErrors < 0)
+
+ append("\n$header: ")
+ append(if (quantityOfErrors == 0) "PASSED" else "FAILED ($quantityOfErrors errors)")
+ }
+
+}
diff --git a/gradle/applicationFileNaming.gradle b/gradle/scripts/applicationFileNaming.gradle
similarity index 100%
rename from gradle/applicationFileNaming.gradle
rename to gradle/scripts/applicationFileNaming.gradle
diff --git a/gradle/stringGenerator.gradle b/gradle/scripts/stringGenerator.gradle
similarity index 100%
rename from gradle/stringGenerator.gradle
rename to gradle/scripts/stringGenerator.gradle
diff --git a/gradle/staticAnalysis.gradle b/gradle/staticAnalysis.gradle
deleted file mode 100644
index b952ec9..0000000
--- a/gradle/staticAnalysis.gradle
+++ /dev/null
@@ -1,166 +0,0 @@
-buildscript {
- repositories {
- maven { url "https://plugins.gradle.org/m2" }
- }
- dependencies {
- classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.5.1"
- }
-}
-
-def getServerProjectSources
-def getAndroidProjectSources
-
-apply from: "$buildScriptsDir/gradle/commonStaticAnalysis.gradle"
-
-gradle.projectsEvaluated {
-
- tasks.withType(JavaCompile) {
- options.compilerArgs <<
- "-Xlint:cast" <<
- "-Xlint:divzero" <<
- "-Xlint:empty" <<
- "-Xlint:deprecation" <<
- "-Xlint:finally" <<
- "-Xlint:overrides" <<
- "-Xlint:path" <<
- "-Werror"
- }
-
- def excludes = rootProject.extensions.findByName("staticAnalysisExcludes")
-
- def androidSources = getAndroidProjectSources(excludes)
- def androidStaticAnalysisTasks = getStaticAnalysisTaskNames(true, androidSources, null)
- def androidIdeaFormatTask = getIdeaFormatTask(true, androidSources)
-
- task staticAnalysisWithFormatting {
- androidStaticAnalysisTasks.each { task ->
- tasks.findByName(task)?.mustRunAfter(androidIdeaFormatTask)
- }
- dependsOn androidIdeaFormatTask
- dependsOn androidStaticAnalysisTasks
- doFirst {
- generateReport(true)
- }
- }
-
- task staticAnalysis {
- dependsOn androidStaticAnalysisTasks
- doFirst {
- generateReport(true)
- }
- }
-
- def serverStaticAnalysisTasks = getStaticAnalysisTaskNames(false, getServerProjectSources(excludes), null)
- def serverIdeaFormatTask = getIdeaFormatTask(false, getServerProjectSources(excludes))
-
- task serverStaticAnalysisWithFormatting {
- serverStaticAnalysisTasks.each { task ->
- tasks.findByName(task)?.mustRunAfter(serverIdeaFormatTask)
- }
- dependsOn serverIdeaFormatTask
- dependsOn serverStaticAnalysisTasks
- doFirst {
- generateReport(false)
- }
- }
-
- task serverStaticAnalysis {
- dependsOn serverStaticAnalysisTasks
- doFirst {
- generateReport(false)
- }
- }
-
- subprojects { subproject ->
- if (subproject.plugins.hasPlugin("com.android.application")) {
- subproject.android {
- lintOptions.abortOnError = false
- lintOptions.checkAllWarnings = true
- lintOptions.warningsAsErrors = false
- lintOptions.xmlReport = true
- lintOptions.xmlOutput = file "$rootProject.buildDir/reports/lint_report.xml"
- lintOptions.htmlReport = false
- lintOptions.lintConfig = file "$buildScriptsDir/lint/lint.xml"
- lintOptions.checkDependencies true
- lintOptions.disable 'MissingConstraints', 'VectorRaster'
-
- applicationVariants.all { variant ->
- task("staticAnalysis${variant.name.capitalize()}") {
- dependsOn getStaticAnalysisTaskNames(true, androidSources, variant)
- doFirst { generateReport(true) }
- }
- }
- }
- }
-
- def regex = ~':detekt$'
- tasks.forEach { task ->
- if (!task.name.contains(":libs") && task.path =~ regex) {
- task.exclude '**/test/**'
- task.exclude 'resources/'
- task.exclude 'build/'
- task.exclude 'tmp/'
-
- task.jvmTarget = "1.8"
- }
- }
-
- detekt {
- config = files("$buildScriptsDir/kotlin/detekt-config.yml")
-
- reports {
- txt.enabled = false
- html.enabled = false
- xml {
- enabled = true
- destination = file("${rootProject.buildDir}/reports/kotlin-detekt-${subproject.name}.xml")
- }
- }
- }
- }
-}
-
-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)
- }
- if (kotlinSourceDirectory.exists() && kotlinSourceDirectory.isDirectory()) {
- sources.add(kotlinSourceDirectory.absolutePath)
- }
- }
- return sources
-}
-
-getAndroidProjectSources = { 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 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)
- }
- }
- }
- return sources
-}
diff --git a/lint/lint.xml b/lint/lint.xml
deleted file mode 100644
index 57a80e9..0000000
--- a/lint/lint.xml
+++ /dev/null
@@ -1,272 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/pmd/rulesets/java/android.xml b/pmd/rulesets/java/android.xml
deleted file mode 100644
index debe6f4..0000000
--- a/pmd/rulesets/java/android.xml
+++ /dev/null
@@ -1,131 +0,0 @@
-
-
-
- Every Java Rule in PMD
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/export_src.sh b/scripts/export_src.sh
similarity index 100%
rename from export_src.sh
rename to scripts/export_src.sh
diff --git a/kotlin/detekt-config.yml b/static_analysis_configs/detekt-config.yml
similarity index 99%
rename from kotlin/detekt-config.yml
rename to static_analysis_configs/detekt-config.yml
index 3afb6fa..5ea4cce 100644
--- a/kotlin/detekt-config.yml
+++ b/static_analysis_configs/detekt-config.yml
@@ -23,7 +23,7 @@ formatting:
active: true
console-reports:
- active: true
+ active: false
exclude:
# - 'ProjectStatisticsReport'
# - 'ComplexityReport'
diff --git a/static_analysis_configs/lint.xml b/static_analysis_configs/lint.xml
new file mode 100644
index 0000000..98227d4
--- /dev/null
+++ b/static_analysis_configs/lint.xml
@@ -0,0 +1,273 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+