You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by dw...@apache.org on 2019/12/12 18:26:00 UTC
[lucene-solr] 03/03: Add support for validating the presence of
licenses and notices.
This is an automated email from the ASF dual-hosted git repository.
dweiss pushed a commit to branch gradle-master
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git
commit a392a83558dc49e2c429dda64eb9e3e1cb9f4033
Author: Dawid Weiss <dw...@apache.org>
AuthorDate: Thu Dec 12 19:25:46 2019 +0100
Add support for validating the presence of licenses and notices.
---
gradle/validation/jar-checks.gradle | 112 +++++++++++++++++++++++++++++++++---
1 file changed, 103 insertions(+), 9 deletions(-)
diff --git a/gradle/validation/jar-checks.gradle b/gradle/validation/jar-checks.gradle
index e11497e..de29170 100644
--- a/gradle/validation/jar-checks.gradle
+++ b/gradle/validation/jar-checks.gradle
@@ -27,6 +27,23 @@ configure(project(":solr")) {
ext.licensesDir = file("licenses")
}
+// All known license types. If 'noticeOptional' is true then
+// the notice file must accompany the license.
+def licenseTypes = [
+ "ASL": [name: "Apache Software License 2.0"],
+ "BSD": [name: "Berkeley Software Distribution"],
+ //BSD like just means someone has taken the BSD license and put in their name, copyright, or it's a very similar license.
+ "BSD_LIKE": [name: "BSD like license"],
+ "CDDL": [name: "Common Development and Distribution License", noticeOptional: true],
+ "CPL": [name: "Common Public License"],
+ "EPL": [name: "Eclipse Public License Version 1.0", noticeOptional: true],
+ "MIT": [name: "Massachusetts Institute of Tech. License", noticeOptional: true],
+ "MPL": [name: "Mozilla Public License", noticeOptional: true /* NOT SURE on the required notice */],
+ "PD": [name: "Public Domain", noticeOptional: true],
+ "SUN": [name: "Sun Open Source License", noticeOptional: true],
+ "COMPOUND": [name: "Compound license (details in NOTICE file)."],
+]
+
subprojects {
// Configure jarValidation configuration for all projects. Any dependency
// declared on this configuration (or any configuration it extends from) will
@@ -45,6 +62,10 @@ subprojects {
}
}
+ // Collects dependency JAR information for a project and saves it in
+ // project.ext.jarInfos. Each dependency has a map of attributes
+ // which make it easier to process it later on (name, hash, origin module,
+ // see the code below for details).
task collectJarInfos() {
dependsOn configurations.jarValidation
@@ -70,16 +91,14 @@ subprojects {
}
}
+ def failOnError = false
+
+ // Verifies that each JAR has a corresponding checksum and that it matches actual JAR available for this dependency.
task validateJarChecksums() {
group = 'Dependency validation'
- description = "Validate project dependency checksums"
-
- dependsOn configurations.jarValidation
+ description = "Validate checksums of dependencies"
dependsOn collectJarInfos
- // TODO: validation should fail the build but we're out of sync with master.
- def fail = false
-
doLast {
def errors = []
jarInfos.each { dep ->
@@ -91,13 +110,80 @@ subprojects {
def actual = dep.checksum.trim()
if (expected.compareToIgnoreCase(actual) != 0) {
errors << "Dependency checksum mismatch ('${dep.module}'), expected it to be: ${expected}, but was: ${actual}"
+ } else {
+ logger.log(LogLevel.INFO, "Dependency checksum OK ('${dep.module}')")
}
}
}
if (errors) {
def msg = "Dependency checksum validation failed:\n - " + errors.join("\n - ")
- if (fail) {
+ if (failOnError) {
+ throw new GradleException(msg)
+ } else {
+ logger.log(LogLevel.WARN, "WARNING: ${msg}")
+ }
+ }
+ }
+ }
+
+ // Locate the set of license file candidates for this dependency. We
+ // search for [jar-or-prefix]-LICENSE-[type].txt
+ // where 'jar-or-prefix' can be any '-'-delimited prefix of the dependency JAR's name.
+ // So for 'commons-io' it can be 'commons-io-LICENSE-foo.txt' or
+ // 'commons-LICENSE.txt'
+ task validateJarLicenses() {
+ group = 'Dependency validation'
+ description = "Validate license and notice files of dependencies"
+ dependsOn collectJarInfos
+
+ doLast {
+ def errors = []
+ jarInfos.each { dep ->
+ def baseName = dep.name
+ def found = []
+ def candidates = []
+ while (true) {
+ candidates += file("${licensesDir}/${baseName}-LICENSE-[type].txt")
+ found += fileTree(dir: licensesDir, include: "${baseName}-LICENSE-*.txt").files
+ def prefix = baseName.replaceAll(/[\-][^-]+$/, "")
+ if (found || prefix == baseName) {
+ break
+ }
+ baseName = prefix
+ }
+
+ if (found.size() == 0) {
+ errors << "License file missing ('${dep.module}'), expected it at: ${candidates.join(" or ")}," +
+ " where [type] can be any of ${licenseTypes.keySet()}."
+ } else if (found.size() > 1) {
+ errors << "Multiple license files matching for ('${dep.module}'): ${found.join(", ")}"
+ } else {
+ def licenseFile = found.get(0)
+ def m = (licenseFile.name =~ /LICENSE-(.+)\.txt$/)
+ if (!m) throw new GradleException("License file name doesn't contain license type?: ${licenseFile.name}")
+
+ def licenseName = m[0][1]
+ def licenseType = licenseTypes[licenseName]
+ if (!licenseType) {
+ errors << "Unknown license type suffix for ('${dep.module}'): ${licenseFile} (must be one of ${licenseTypes.keySet()})"
+ } else {
+ logger.log(LogLevel.INFO, "Dependency license file OK ('${dep.module}'): " + licenseName)
+
+ // Look for sibling NOTICE file.
+ def noticeFile = file(licenseFile.path.replaceAll(/\-LICENSE-.+/, "-NOTICE.txt"))
+ if (noticeFile.exists()) {
+ logger.log(LogLevel.INFO, "Dependency notice file OK ('${dep.module}'): " + noticeFile)
+ } else if (!licenseType.noticeOptional) {
+ errors << "Notice file missing for ('${dep.module}'), expected it at: ${noticeFile}"
+ }
+ }
+ }
+ }
+
+ if (errors) {
+ def msg = "Certain license/ notice files are missing:\n - " + errors.join("\n - ")
+ if (failOnError) {
throw new GradleException(msg)
} else {
logger.log(LogLevel.WARN, "WARNING: ${msg}")
@@ -105,9 +191,17 @@ subprojects {
}
}
}
+
+ task validateJars() {
+ dependsOn validateJarChecksums, validateJarLicenses
+ }
+
+ check.dependsOn(validateJars)
}
-// Disable validation for these projects.
+// Disable validation for these projects (should it be disabled?)
configure(project(":solr:solr-ref-guide")) {
- validateJarChecksums.enabled = false
+ [validateJarLicenses, validateJarChecksums].each { task ->
+ task.enabled = false
+ }
}
\ No newline at end of file