forked from detekt/detekt
/
DetektMultiplatform.kt
170 lines (157 loc) · 6.92 KB
/
DetektMultiplatform.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package io.gitlab.arturbosch.detekt.internal
import com.android.build.gradle.BaseExtension
import io.gitlab.arturbosch.detekt.DetektPlugin
import io.gitlab.arturbosch.detekt.extensions.DetektExtension
import io.gitlab.arturbosch.detekt.extensions.DetektReport
import io.gitlab.arturbosch.detekt.extensions.DetektReports
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.androidJvm
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.jvm
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
import java.io.File
internal class DetektMultiplatform(private val project: Project) {
fun registerTasks(extension: DetektExtension) {
project.registerMultiplatformTasks(extension)
}
private fun Project.registerMultiplatformTasks(extension: DetektExtension) {
project.extensions.getByType(KotlinMultiplatformExtension::class.java).targets.all { target ->
target.compilations.all { compilation ->
val inputSource = compilation.kotlinSourceSets
.map { it.kotlin.sourceDirectories }
.fold(project.files() as FileCollection) { collection, next -> collection.plus(next) }
if (compilation is KotlinJvmAndroidCompilation) {
project.registerMultiplatformTasksForAndroidTarget(
compilation = compilation,
target = target,
extension = extension,
inputSource = inputSource
)
} else {
project.registerMultiplatformTasksForNonAndroidTarget(
compilation = compilation,
target = target,
extension = extension,
inputSource = inputSource
)
}
}
}
}
private fun Project.registerMultiplatformTasksForAndroidTarget(
compilation: KotlinJvmAndroidCompilation,
target: KotlinTarget,
extension: DetektExtension,
inputSource: FileCollection
) {
// For Android targets we delegate to DetektAndroid as we need to access
// BaseVariant and other AGP apis to properly setup the classpath.
extensions.findByType(BaseExtension::class.java)?.let {
val bootClasspath = files(provider { it.bootClasspath })
val variant = compilation.androidVariant
val detektTaskName = DetektPlugin.DETEKT_TASK_NAME +
target.name.capitalize() + variant.name.capitalize()
val baselineTaskName = DetektPlugin.BASELINE_TASK_NAME +
target.name.capitalize() + variant.name.capitalize()
registerAndroidDetektTask(
bootClasspath,
extension,
compilation.androidVariant,
detektTaskName,
inputSource
)
registerAndroidCreateBaselineTask(
bootClasspath,
extension,
compilation.androidVariant,
baselineTaskName,
inputSource
)
}
}
@Suppress("LongMethod")
private fun Project.registerMultiplatformTasksForNonAndroidTarget(
compilation: KotlinCompilation<KotlinCommonOptions>,
target: KotlinTarget,
extension: DetektExtension,
inputSource: FileCollection
) {
val taskSuffix = target.name.capitalize() + compilation.name.capitalize()
val runWithTypeResolution = target.runWithTypeResolution
registerDetektTask(
DetektPlugin.DETEKT_TASK_NAME + taskSuffix,
extension
) {
setSource(inputSource)
if (runWithTypeResolution) {
classpath.setFrom(inputSource, compilation.compileDependencyFiles)
}
// If a baseline file is configured as input file, it must exist to be configured, otherwise the task fails.
// We try to find the configured baseline or alternatively a specific variant matching this task.
if (runWithTypeResolution) {
extension.baseline?.existingVariantOrBaseFile(compilation.name)
} else {
extension.baseline?.takeIf { it.exists() }
}?.let { baselineFile ->
baseline.convention(layout.file(provider { baselineFile }))
}
setReportOutputConventions(reports, extension, compilation.name)
description =
"Run detekt analysis for target ${target.name} and source set ${compilation.name}"
if (runWithTypeResolution) {
description = "EXPERIMENTAL: $description with type resolution."
}
}
registerCreateBaselineTask(
DetektPlugin.BASELINE_TASK_NAME + taskSuffix,
extension
) {
setSource(inputSource)
if (runWithTypeResolution) {
classpath.setFrom(inputSource, compilation.compileDependencyFiles)
}
val variantBaselineFile = if (runWithTypeResolution) {
extension.baseline?.addVariantName(compilation.name)
} else {
extension.baseline
}
baseline.convention(
layout.file(provider { variantBaselineFile })
)
description =
"Creates detekt baseline for ${target.name} and source set ${compilation.name}"
if (runWithTypeResolution) {
description = "EXPERIMENTAL: $description with type resolution."
}
}
}
}
internal fun Project.setReportOutputConventions(reports: DetektReports, extension: DetektExtension, name: String) {
setReportOutputConvention(extension, reports.xml, name, "xml")
setReportOutputConvention(extension, reports.html, name, "html")
setReportOutputConvention(extension, reports.txt, name, "txt")
setReportOutputConvention(extension, reports.sarif, name, "sarif")
setReportOutputConvention(extension, reports.md, name, "md")
}
private fun Project.setReportOutputConvention(
extension: DetektExtension,
report: DetektReport,
name: String,
format: String
) {
report.outputLocation.convention(
layout.projectDirectory.file(
providers.provider {
File(extension.reportsDir, "$name.$format").absolutePath
}
)
)
}
// We currently run type resolution only for Jvm & Android targets as
// native/js targets needs a different compiler classpath.
private val KotlinTarget.runWithTypeResolution: Boolean
get() = platformType in setOf(jvm, androidJvm)