Multi-module Detekt support

* Updated EasyGradle in order to ensure to have declared explicitly all the libs versions in versionsConfig.kt - previous version had default values
* Renamed `Project` in buildSrc to ProtonMail.kt, in order to avoid conflicts with Gradle's Project type
* Created setup for Detekt in detekt.kt
* Changed report path into .gitlab-ci.yml
* Clean up for Project's build.gradle.kts with help of kotlin.kt
Affected: Build Config

MAILAND-698
This commit is contained in:
Davide Farella 2020-05-29 09:16:38 +02:00 committed by Zorica Stojchevska
parent b09106a039
commit edb9235fbb
11 changed files with 232 additions and 59 deletions

View File

@ -32,10 +32,10 @@ detekt analysis:
tags:
- android
script:
- ./gradlew detekt
- ./gradlew multiModuleDetekt
artifacts:
reports:
codequality: detekt/report.json
codequality: detekt/reports/mergedReport.json
build debug:
stage: build

View File

@ -16,14 +16,13 @@
* You should have received a copy of the GNU General Public License
* along with ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
import java.io.FileInputStream
import java.util.*
import studio.forface.easygradle.dsl.*
import studio.forface.easygradle.dsl.android.*
import java.io.FileInputStream
import java.util.*
plugins {
`android-application`
`detekt`
`kotlin-android`
`kotlin-android-extensions`
`kotlin-kapt`
@ -36,22 +35,6 @@ kapt {
correctErrorTypes = true
}
detekt {
failFast = false
config = files("$rootDir/detekt/config.yml")
reports {
xml.enabled = false
html.enabled = false
txt.enabled = false
custom {
reportId = "DetektQualityOutputReport"
destination = file("$rootDir/detekt/report.json")
}
}
}
configurations { detekt }
val privateProperties = Properties().apply {
load(FileInputStream("privateConfig/private.properties"))
}
@ -206,11 +189,6 @@ dependencies {
testImplementation(project(Module.testAndroid))
androidTestImplementation(project(Module.testAndroidInstrumented))
// Detekt
detekt(`detekt-cli`)
detektPlugins(`detekt-code-analysis`)
detektPlugins(`detekt-formatting`)
}
apply(from = "old.build.gradle")

View File

@ -16,11 +16,11 @@
* You should have received a copy of the GNU General Public License
* along with ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
initVersions()
import setup.setupDetekt
import setup.setupKotlin
buildscript {
initVersions()
repositories(repos)
dependencies(classpathDependencies)
}
@ -33,27 +33,13 @@ allprojects {
repositories(repos)
}
subprojects {
// Options for Kotlin
tasks.withType<KotlinCompile> {
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs = freeCompilerArgs +
"-XXLanguage:+NewInference" +
"-Xuse-experimental=kotlin.Experimental"
}
}
// Disable Javadoc
tasks.withType<Javadoc> { enabled = false }
}
setupKotlin()
setupDetekt { "tokenAutoComplete" !in it.name }
tasks.register("clean", Delete::class.java) {
delete(rootProject.buildDir)
}
tasks.register("injectLicenses") {
description = "Add license header to source code files"

View File

@ -26,11 +26,21 @@ repositories {
}
dependencies {
val android = "3.5.0" // Updated: Aug 08, 2019
val easyGradle = "1.2.3-beta-4" // Updated: Mar 01, 2020
val sentry = "1.7.22" // Updated:
val android = "3.5.0" // Released: Aug 08, 2019
val detekt = "1.9.1" // Released: May 17, 2020
val easyGradle = "1.3.2" // Released: May 22, 2020
val kotlin = "1.3.72" // Released: Apr 14, 2020
val sentry = "1.7.22" // Released:
// Needed for setup Android config
implementation("com.android.tools.build:gradle:$android")
// Needed to setup Detekt config
implementation("io.gitlab.arturbosch.detekt:detekt-gradle-plugin:$detekt")
// Needed for many utils
implementation("studio.forface.easygradle:dsl-android:$easyGradle")
// Needed for setup Kotlin options
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin")
implementation("io.sentry:sentry-android-gradle-plugin:$sentry")
}

View File

@ -28,13 +28,13 @@ import studio.forface.easygradle.dsl.android.*
*/
fun org.gradle.api.Project.android(
appIdSuffix: String? = null,
minSdk: Int = Project.minSdk,
targetSdk: Int = Project.targetSdk,
version: Version? = null,
versionCode: Int = Project.versionCode,
versionName: String = Project.versionName,
config: ExtraConfig = {}
appIdSuffix: String? = null,
minSdk: Int = ProtonMail.minSdk,
targetSdk: Int = ProtonMail.targetSdk,
version: Version? = null,
versionCode: Int = ProtonMail.versionCode,
versionName: String = ProtonMail.versionName,
config: ExtraConfig = {}
) = (this as ExtensionAware).extensions.configure<TestedExtension> {

View File

@ -21,7 +21,7 @@
* Params for the Application and various modules
* @author Davide Farella
*/
object Project {
object ProtonMail {
const val versionName = "1.13.7"
const val versionCode = 724

View File

@ -23,7 +23,7 @@ import org.gradle.plugin.use.PluginDependencySpec
val PluginDependenciesSpec.`android-application` get() = plugin("com.android.application")
val PluginDependenciesSpec.`android-library` get() = plugin("com.android.library")
val PluginDependenciesSpec.`detekt` get() = plugin("io.gitlab.arturbosch.detekt")
val PluginDependenciesSpec.`detekt` get() = plugin(`detekt id`)
val PluginDependenciesSpec.`hugo` get() = plugin("com.jakewharton.hugo")
val PluginDependenciesSpec.`java-library` get() = plugin("java-library")
val PluginDependenciesSpec.`kotlin` get() = plugin("kotlin")
@ -34,5 +34,6 @@ val PluginDependenciesSpec.`kotlin-serialization` get() = kotlin("plugin.s
val PluginDependenciesSpec.`sentry-android` get() = plugin("io.sentry.android.gradle")
val PluginDependenciesSpec.`sonarQube` get() = plugin("org.sonarqube") version `sonarQube version`
val `detekt id` get() = "io.gitlab.arturbosch.detekt"
private fun PluginDependenciesSpec.plugin(id: String): PluginDependencySpec = id(id)

View File

@ -0,0 +1,143 @@
/*
* Copyright (c) 2020 Proton Technologies AG
*
* This file is part of ProtonMail.
*
* ProtonMail is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonMail is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
package setup
import `detekt id`
import io.gitlab.arturbosch.detekt.extensions.DetektExtension
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.register
import studio.forface.easygradle.dsl.*
import java.io.BufferedWriter
import java.io.File
/**
* Setup Detekt for whole Project.
* It will:
* * apply Detekt plugin to sub-projects
* * configure Detekt Extension
* * add accessor Detekt dependencies
* * register [MergeDetektReports] Task, in order to generate an unique json report for all the
* module
*
* @param filter filter [Project.subprojects] to attach Detekt to
*
*
* @author Davide Farella
*/
fun Project.setupDetekt(filter: (Project) -> Boolean = { true }) {
val detektRootDir = File("$rootDir/detekt")
val detektReportsDir = File(detektRootDir, "reports")
// Configure sub-projects
for (sub in subprojects.filter(filter)) {
sub.apply(plugin = `detekt id`)
sub.extensions.configure<DetektExtension> {
failFast = false
config = files(File(detektRootDir, "config.yml"))
reports {
xml.enabled = false
html.enabled = false
txt.enabled = false
custom {
reportId = "DetektQualityOutputReport"
destination = File(detektReportsDir, "${sub.name}.json")
}
}
}
sub.dependencies {
add("detekt", `detekt-cli`)
add("detektPlugins", `detekt-code-analysis`)
add("detektPlugins", `detekt-formatting`)
}
}
tasks.register<MergeDetektReports>("multiModuleDetekt") {
reportsDir = detektReportsDir
// Execute after 'detekt' is completed for sub-projects
val subTasks = subprojects.flatMap { getTasksByName("detekt", true) }
dependsOn(subTasks)
}
}
internal open class MergeDetektReports : DefaultTask() {
@InputDirectory lateinit var reportsDir: File
@Input var outputName: String = "mergedReport.json"
@TaskAction
fun run() {
val mergedReport = File(reportsDir, outputName)
.apply { if (exists()) writeText("") }
mergedReport.bufferedWriter().use { writer ->
val reportFiles = reportsDir
// Take json files, excluding the merged report
.listFiles { _, name -> name.endsWith(".json") && name != outputName }
?.filterNotNull()
// Skip modules without issues
?.filter {
it.bufferedReader().use { reader ->
return@filter reader.readLine() != "[]"
}
}
// Return if no file is found
?.takeIf { it.isNotEmpty() } ?: return
// Open array
writer.append("[")
// Write body
writer.handleFile(reportFiles.first())
reportFiles.drop(1).forEach {
writer.append(",")
writer.handleFile(it)
}
// Close array
writer.newLine()
writer.append("]")
}
}
private fun BufferedWriter.handleFile(file: File) {
val allLines = file.bufferedReader().lineSequence()
// Drop first and write 'prev' in order to skip array open and close
var prev: String? = null
allLines.drop(1).forEach { s ->
prev?.let {
newLine()
append(it)
}
prev = s
}
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2020 Proton Technologies AG
*
* This file is part of ProtonMail.
*
* ProtonMail is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonMail is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
package setup
import org.gradle.api.Project
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
/**
* Setup Kotlin for whole Project.
* It will setup Kotlin compile options to sub-projects
*
* @param filter filter [Project.subprojects] to configure
*
*
* @author Davide Farella
*/
fun Project.setupKotlin(filter: (Project) -> Boolean = { true }) {
// Configure sub-projects
for (sub in subprojects.filter(filter)) {
// Options for Kotlin
sub.tasks.withType<KotlinCompile> {
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs = freeCompilerArgs +
"-XXLanguage:+NewInference" +
"-Xuse-experimental=kotlin.Experimental" +
"-XXLanguage:+InlineClasses"
}
}
// Disable JavaDoc
sub.tasks.withType<Javadoc> { enabled = false }
}
}

View File

@ -49,6 +49,8 @@ fun initVersions() {
// endregion
// region Others
`detekt version` = "1.9.1" // Released: May 17, 2020
`detect-code-analysis version` = "0.3.2" // Released:
`mockK version` = "1.10.0" // Released: Apr 19, 2020
`retrofit version` = "2.6.1" // Released: Jul 31, 2019
`retrofit-kotlin-serialization version` = ""
@ -78,8 +80,6 @@ const val `playServices version` = "17.0.0" // Released: Jun 19,
// Other
const val `apache-commons-lang version` = "3.4" // Released: Apr 03, 2015
const val `butterKnife version` = "10.1.0" // Released: Feb 14, 201
const val `detekt version` = "1.8.0" // Released: Apr 25, 2020
const val `detect-code-analysis version` = "0.3.2" // Released:
const val `gson version` = "2.8.5" // Released: May 22, 201
const val `hugo version` = "1.2.1" // Released: Feb 18, 201
const val `jsoup version` = "1.8.3" // Released: Aug 02, 2015

View File

@ -33,6 +33,7 @@ dependencies {
implementation(
// Kotlin
`kotlin-jdk7`,
`kotlin-reflect`,
`coroutines-android`,
// Android