-
Notifications
You must be signed in to change notification settings - Fork 392
Expand file tree
/
Copy pathbuild.gradle.kts
More file actions
313 lines (257 loc) · 11.3 KB
/
Copy pathbuild.gradle.kts
File metadata and controls
313 lines (257 loc) · 11.3 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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
/*
* Copyright (C) 2017 The ORT Project Copyright Holders <https://github.com/oss-review-toolkit/ort/blob/main/NOTICE>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* License-Filename: LICENSE
*/
import git.semver.plugin.gradle.PrintTask
import org.eclipse.jgit.ignore.FastIgnoreRule
import org.jetbrains.gradle.ext.Gradle
import org.jetbrains.gradle.ext.runConfigurations
import org.jetbrains.gradle.ext.settings
val javaLanguageVersion = project.property("javaLanguageVersion") as String
plugins {
// Apply third-party plugins.
alias(libs.plugins.gitSemver)
alias(libs.plugins.ideaExt)
}
dependencyAnalysis {
issues {
all {
onUnusedDependencies {
severity("fail")
// Exclude modules which are automatically added by the "ort-kotlin-conventions".
exclude("org.junit.jupiter:junit-jupiter")
exclude(libs.kotest.runner.junit5)
exclude(libs.kotest.assertions.core)
exclude(libs.kotest.property)
exclude(libs.log4j.api.kotlin)
}
onUsedTransitiveDependencies {
// Ignore this rule for now as it creates a massive amount of findings.
severity("ignore")
}
onIncorrectConfiguration { severity("fail") }
onCompileOnly { severity("fail") }
onRuntimeOnly { severity("fail") }
onUnusedAnnotationProcessors { severity("fail") }
onRedundantPlugins { severity("fail") }
}
val cliCommandRegex = Regex("^cli.*|.*-command$")
subprojects.forEach { subproject ->
if (subproject.name.matches(cliCommandRegex)) {
project(subproject.path) {
onUnusedDependencies {
exclude(libs.clikt)
exclude(libs.mordant)
}
}
}
}
project(projects.cliHelper) {
onUnusedDependencies {
// XZOutputStream is a supertype of XZCompressorOutputStream.
exclude(libs.xz)
}
}
project(projects.cliTestLauncher) {
onUnusedDependencies {
severity("ignore")
}
}
project(projects.notifier) {
onUnusedDependencies {
exclude(libs.jiraRestClient.app)
}
}
project(projects.plugins.packageManagers.bundlerPackageManager) {
onUnusedDependencies {
exclude(libs.jruby)
}
}
project(projects.utils.ortUtils) {
onUnusedDependencies {
// XZOutputStream is a supertype of XZCompressorOutputStream.
exclude(libs.xz)
}
}
}
reporting {
printBuildHealth(true)
}
useTypesafeProjectAccessors(true)
}
semver {
// Do not create an empty release commit when running the "releaseVersion" task.
createReleaseCommit = false
// Do not let untracked files bump the version or add a "-SNAPSHOT" suffix.
noDirtyCheck = true
}
// Only override a default version (which usually is "unspecified"), but not a custom version.
if (version == Project.DEFAULT_VERSION) {
version = semver.semVersion.takeIf { it.isPreRelease }
// To get rid of a build part's "+" prefix because Docker tags do not support it, use only the original "build"
// part as the "pre-release" part.
?.toString()?.replace("${semver.defaultPreRelease}+", "")
// Fall back to a plain version without pre-release or build parts.
?: semver.version
}
logger.lifecycle("Building ORT version $version.")
idea {
project {
settings {
runConfigurations {
// Disable "condensed" multi-line diffs when running tests from the IDE via Gradle run configurations to
// more easily accept actual results as expected results.
defaults(Gradle::class.java) {
jvmArgs = "-Dkotest.assertions.multi-line-diff=simple"
}
}
}
}
}
// Automatically accept the Gradle Build Scan ToS when running in CI, to allow build scans to be published.
if (System.getenv("CI") == "true") {
extensions.findByName("develocity")?.withGroovyBuilder {
getProperty("buildScan")?.withGroovyBuilder {
setProperty("termsOfUseUrl", "https://gradle.com/terms-of-service")
setProperty("termsOfUseAgree", "yes")
}
}
}
val checkCopyrightsInNoticeFile = tasks.register("checkCopyrightsInNoticeFile") {
val gitFilesProvider = providers.of(GitFilesValueSource::class) { parameters { workingDir = rootDir } }
val files = CopyrightableFiles.filter(gitFilesProvider)
val noticeFile = rootDir.resolve("NOTICE")
val genericHolderPrefix = "The ORT Project Copyright Holders"
inputs.files(files)
doLast {
val allCopyrights = mutableSetOf<String>()
var hasViolations = false
files.forEach { file ->
val copyrights = CopyrightUtils.extract(file)
if (copyrights.isNotEmpty()) {
allCopyrights += copyrights
} else {
hasViolations = true
logger.error("The file '$file' has no Copyright statement.")
}
}
val notices = noticeFile.readLines()
CopyrightUtils.extractHolders(allCopyrights).forEach { holder ->
if (!holder.startsWith(genericHolderPrefix) && notices.none { holder in it }) {
hasViolations = true
logger.error("The '$holder' Copyright holder is not captured in '$noticeFile'.")
}
}
if (hasViolations) throw GradleException("There were errors in Copyright statements.")
}
}
val checkLicenseHeaders = tasks.register("checkLicenseHeaders") {
val gitFilesProvider = providers.of(GitFilesValueSource::class) { parameters { workingDir = rootDir } }
val files = CopyrightableFiles.filter(gitFilesProvider)
inputs.files(files)
// To be on the safe side in case any called helper functions are not thread safe.
mustRunAfter(checkCopyrightsInNoticeFile)
doLast {
var hasErrors = false
files.forEach { file ->
val headerLines = LicenseUtils.extractHeader(file)
val holders = CopyrightUtils.extractHolders(headerLines)
if (holders.singleOrNull() != CopyrightUtils.EXPECTED_HOLDER) {
hasErrors = true
logger.error("Unexpected copyright holder(s) in file '$file': $holders")
}
if (!headerLines.joinToString("\n").endsWith(LicenseUtils.expectedHeader)) {
hasErrors = true
logger.error("Unexpected license header in file '$file'.")
}
}
if (hasErrors) throw GradleException("There were errors in license headers.")
}
}
val checkGitAttributes = tasks.register("checkGitAttributes") {
val gitFilesProvider = providers.of(GitFilesValueSource::class) { parameters { workingDir = rootDir } }
inputs.files(gitFilesProvider)
doLast {
var hasErrors = false
val files = gitFilesProvider.get()
val gitAttributesFiles = files.filter { it.endsWith(".gitattributes") }
val commentChars = setOf('#', '/')
gitAttributesFiles.forEach { gitAttributesFile ->
logger.lifecycle("Checking file '$gitAttributesFile'...")
val ignoreRules = gitAttributesFile.readLines()
// Skip empty and comment lines.
.map { it.trim() }
.filter { it.isNotEmpty() && it.first() !in commentChars }
// The pattern is the part before the first whitespace.
.mapTo(mutableSetOf()) { line -> line.takeWhile { !it.isWhitespace() } }
// Create ignore rules from valid patterns.
.mapIndexedNotNull { index, pattern ->
runCatching {
FastIgnoreRule(pattern)
}.onFailure {
logger.warn("File '$gitAttributesFile' contains an invalid pattern in line ${index + 1}: $it")
}.getOrNull()
}
// Check only those files that are in scope of this ".gitattributes" file.
val gitAttributesDir = gitAttributesFile.parentFile
val filesInScope = files.filter { it.startsWith(gitAttributesDir) }
ignoreRules.forEach { rule ->
val matchesAnything = filesInScope.any { file ->
val relativeFile = file.relativeTo(gitAttributesDir)
rule.isMatch(relativeFile.invariantSeparatorsPath, /* directory = */ false)
}
if (!matchesAnything) {
hasErrors = true
logger.error("Rule '$rule' does not match anything.")
}
}
}
if (hasErrors) throw GradleException("There were stale '.gitattribute' entries.")
}
}
tasks.named<UpdateDaemonJvm>("updateDaemonJvm") {
languageVersion = JavaLanguageVersion.of(javaLanguageVersion)
vendor = JvmVendorSpec.ADOPTIUM
}
// Gradle's "dependencies" task selector only executes on a single / the current project [1]. However, sometimes viewing
// all dependencies at once is beneficial, e.g. for debugging version conflict resolution.
// [1]: https://docs.gradle.org/current/userguide/viewing_debugging_dependencies.html#sec:listing_dependencies
tasks.register("allDependencies") {
group = "Help"
description = "Displays all dependencies declared in all projects."
val dependenciesTasks = getTasksByName("dependencies", /* recursive = */ true)
dependsOn(dependenciesTasks)
// Ensure deterministic output by requiring to run tasks after each other in always the same order.
dependenciesTasks.sorted().zipWithNext().forEach { (a, b) ->
b.mustRunAfter(a)
}
}
tasks.register<GeneratePluginDocsTask>("generatePluginDocs") {
val kspKotlinTasks = getTasksByName("kspKotlin", /* recursive = */ true)
val outputFiles = kspKotlinTasks.flatMap { it.outputs.files }
inputFiles = files(outputFiles).asFileTree.matching { include("**/META-INF/plugin/*.json") }
// TODO: This explicit dependency should not be necessary if tasks were following the best practice described at
// https://docs.gradle.org/current/samples/sample_cross_project_output_sharing.html. However, this requires
// larger refactorings.
dependsOn(kspKotlinTasks)
}
open class OrtPrintTask : PrintTask({ "" }, "Prints the current project version", "") {
private val projectVersion = project.version.toString()
@TaskAction
fun printVersion() = println(projectVersion)
}
tasks.replace("printVersion", OrtPrintTask::class.java)