-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathArchrulesRunnerPlugin.kt
More file actions
165 lines (154 loc) · 8.15 KB
/
Copy pathArchrulesRunnerPlugin.kt
File metadata and controls
165 lines (154 loc) · 8.15 KB
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
package com.netflix.nebula.archrules.gradle
import com.netflix.nebula.archrules.gradle.ArchRuleAttribute.ARCH_RULES
import com.tngtech.archunit.lang.Priority
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.type.ArtifactTypeDefinition
import org.gradle.api.attributes.Bundling
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.LibraryElements
import org.gradle.api.attributes.Usage
import org.gradle.api.attributes.VerificationType
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.tasks.SourceSet
import org.gradle.internal.extensions.stdlib.capitalized
import org.gradle.kotlin.dsl.add
import org.gradle.kotlin.dsl.create
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.named
import org.gradle.kotlin.dsl.register
import org.gradle.kotlin.dsl.withType
class ArchrulesRunnerPlugin : Plugin<Project> {
companion object {
private const val ARCHRULES_VERSION = "0.+" // keep in sync
private const val JACKSON_VERSION = "3.1.0" // keep in sync with compileOnly dependency
private const val ARCHRULES_DEPENDENCY = "com.netflix.nebula:nebula-archrules-gradle-plugin:$ARCHRULES_VERSION"
private const val JACKSON_DEPENDENCY = "tools.jackson.core:jackson-databind:$JACKSON_VERSION"
}
override fun apply(project: Project) {
val archRulesReportDir = project.layout.buildDirectory.dir("reports/archrules")
project.configurations.register("archRules") {
isCanBeConsumed = false
isCanBeResolved = true
attributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(ARCH_RULES))
attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named<Category>(Category.LIBRARY))
attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.EXTERNAL))
}
}
project.plugins.withId("java") {
project.dependencies.attributesSchema.attribute(Usage.USAGE_ATTRIBUTE) {
compatibilityRules.add(ArchRuleCompatibilityRule::class)
disambiguationRules.add(ArchRuleDisambiguationRule::class)
}
val archRulesExt = project.extensions.create<ArchrulesExtension>("archRules")
archRulesExt.consoleReportEnabled.convention(true)
archRulesExt.jsonReportEnabled.convention(true)
archRulesExt.markdownReportEnabled.convention(true)
archRulesExt.skipPassingSummaries.convention(false)
archRulesExt.sourceSetsToSkip.add("archRulesTest")
archRulesExt.consoleDetailsThreshold.convention(Priority.MEDIUM)
project.extensions.getByType<JavaPluginExtension>().sourceSets
.configureEach {
project.configureCheckTaskForSourceSet(this, archRulesExt)
}
val jsonReportTask = project.tasks.register<PrintJsonReportTask>("archRulesJsonReport") {
dataFiles.from(project.tasks.withType<CheckRulesTask>())
getJsonReportFile().set(archRulesReportDir.map { it.file("report.json").asFile })
reportingClasspath.setFrom(project.configurations.detachedConfiguration(
project.dependencies.create(ARCHRULES_DEPENDENCY),
project.dependencies.create(JACKSON_DEPENDENCY)
))
onlyIf { archRulesExt.jsonReportEnabled.get() }
}
val consoleReportTask = project.tasks.register<PrintConsoleReportTask>("archRulesConsoleReport") {
dataFiles.from(project.tasks.withType<CheckRulesTask>())
summaryForPassingDisabled.set(archRulesExt.skipPassingSummaries)
detailsThreshold.set(archRulesExt.consoleDetailsThreshold)
onlyIf { archRulesExt.consoleReportEnabled.get() }
}
val markdownReportTask = project.tasks.register<PrintMarkdownReportTask>("archRulesMarkdownReport") {
dataFiles.from(project.tasks.withType<CheckRulesTask>())
markdownReportFile.set(archRulesReportDir.map { it.file("report.md") })
detailsThreshold.set(archRulesExt.consoleDetailsThreshold)
onlyIf { archRulesExt.markdownReportEnabled.get() }
}
project.configurations.consumable("archRulesReportElements") {
description = "Report data for ArchRules"
outgoing.artifacts(
project.provider { (project.tasks.withType<CheckRulesTask>().flatMap { it.outputs.files }) }
){
type = ArtifactTypeDefinition.BINARY_DATA_TYPE
builtBy(project.tasks.withType<CheckRulesTask>())
}
attributes {
attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.VERIFICATION))
attribute(VerificationType.VERIFICATION_TYPE_ATTRIBUTE, project.objects.named("arch-rules"))
}
}
val enforceTask = project.tasks.register<EnforceArchRulesTask>("enforceArchRules") {
dataFiles.from(project.tasks.withType<CheckRulesTask>())
failureThreshold.set(archRulesExt.failureThreshold)
warningThreshold.set(archRulesExt.consoleDetailsThreshold)
}
project.tasks.named("check") {
dependsOn(enforceTask)
finalizedBy(jsonReportTask, markdownReportTask, consoleReportTask)
}
}
}
fun Project.configureCheckTaskForSourceSet(sourceSet: SourceSet, ext: ArchrulesExtension) {
val archRulesReportDir = project.layout.buildDirectory.dir("reports/archrules")
val sourceSetArchRulesRuntime = configurations.resolvable(sourceSet.name + "ArchRulesRuntime") {
extendsFrom(
project.configurations.getByName("archRules"),
configurations.getByName(sourceSet.runtimeClasspathConfigurationName)
)
attributes.addAllLater(project.configurations.getByName(sourceSet.runtimeClasspathConfigurationName).attributes)
attributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(ARCH_RULES))
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements.CLASSES))
}
}
tasks.register<CheckRulesTask>("checkArchRules" + sourceSet.name.capitalized()) {
description = "Checks ArchRules on ${sourceSet.name}"
rulesClasspath.setFrom(sourceSetArchRulesRuntime)
predicatesByName.set(
ext.ruleOverrides.map {
it.mapValues { it.value.predicates }
}
)
priorityOverridesByName.set(
ext.ruleOverrides.map {
it.mapValues { it.value.priority }
.filterValues { it != null }
.mapValues { it.value!! } // could be improved by https://youtrack.jetbrains.com/issue/KT-4734
}
)
priorityOverridesByClass.set(
ext.ruleClassOverrides.map {
it.mapValues { it.value.priority }
.filterValues { it != null }
.mapValues { it.value!! } // could be improved by https://youtrack.jetbrains.com/issue/KT-4734
}
)
excludedRules.set(
ext.ruleOverrides.map {
it.filter { it.value.sourceSetsToSkip.contains(sourceSet.name) }.map { it.key }
}
)
excludedRuleClasses.set(
ext.ruleClassOverrides.map {
it.filter { it.value.sourceSetsToSkip.contains(sourceSet.name) }.map { it.key }
}
)
dataFile.set(archRulesReportDir.map {
it.file(sourceSet.name + ".data").asFile
})
sourcesToCheck.from(sourceSet.output.classesDirs)
dependsOn(project.tasks.named(sourceSet.classesTaskName))
val sourceSetName = sourceSet.name
onlyIf { !ext.sourceSetsToSkip.get().contains(sourceSetName) }
}
}
}