-
Notifications
You must be signed in to change notification settings - Fork 377
Expand file tree
/
Copy pathbuild.gradle.kts
More file actions
228 lines (186 loc) · 8.71 KB
/
build.gradle.kts
File metadata and controls
228 lines (186 loc) · 8.71 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
/*
* 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
plugins {
// Apply third-party plugins.
alias(libs.plugins.gitSemver)
alias(libs.plugins.ideaExt)
}
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")
}
}
}
// 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)
}
}
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)
val checkCopyrightsInNoticeFile by tasks.registering {
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 by tasks.registering {
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 by tasks.registering {
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.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)
}