Skip to content

Commit 248a20f

Browse files
committed
implement defaultCheckType to change behavior how dependency licenses are matched against allowedLicenses
The default behavior is that a dependency is fine when any of its licenses are found inside allowedLicenses. This fixes jk1#285
1 parent 135292c commit 248a20f

File tree

6 files changed

+182
-63
lines changed

6 files changed

+182
-63
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ licenseReport {
8585
// This is for the allowed-licenses-file in checkLicense Task
8686
// Accepts File, URL or String path to local or remote file
8787
allowedLicensesFile = new File("$projectDir/config/allowed-licenses.json")
88+
89+
// When ANY is set, it will not give an error if any license of a dependency is matched in allowedLicenses
90+
// When ALL is set, it will give an error when not all licenses of a dependency are found in allowedLicenses
91+
defaultCheckType = ANY
8892
}
8993
```
9094

src/main/groovy/com/github/jk1/license/LicenseReportExtension.groovy

+5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package com.github.jk1.license
1717

18+
import com.github.jk1.license.check.CheckType
1819
import com.github.jk1.license.filter.DependencyFilter
1920
import com.github.jk1.license.importer.DependencyDataImporter
2021
import com.github.jk1.license.render.ReportRenderer
@@ -41,6 +42,7 @@ class LicenseReportExtension {
4142
public String[] excludeGroups
4243
public String[] excludes
4344
public Object allowedLicensesFile
45+
public CheckType defaultCheckType
4446

4547
LicenseReportExtension(Project project) {
4648
unionParentPomLicenses = true
@@ -55,6 +57,7 @@ class LicenseReportExtension {
5557
excludes = []
5658
importers = []
5759
filters = []
60+
defaultCheckType = CheckType.ANY
5861
}
5962

6063
@Nested
@@ -104,6 +107,8 @@ class LicenseReportExtension {
104107
snapshot += excludes
105108
snapshot << 'unionParentPomLicenses'
106109
snapshot += unionParentPomLicenses
110+
snapshot << "defaultCheckType"
111+
snapshot += defaultCheckType
107112
snapshot.join("!")
108113
}
109114

src/main/groovy/com/github/jk1/license/check/LicenseChecker.groovy

+49-39
Original file line numberDiff line numberDiff line change
@@ -18,70 +18,80 @@ package com.github.jk1.license.check
1818
import groovy.json.JsonOutput
1919
import org.gradle.api.GradleException
2020

21+
/**
22+
* This class compares the found licences with the allowed licenses and creates a report for any missing license
23+
*/
2124
class LicenseChecker {
22-
23-
void checkAllDependencyLicensesAreAllowed(
24-
Object allowedLicensesFile, File projectLicensesDataFile, File notPassedDependenciesOutputFile) {
25+
static void checkAllDependencyLicensesAreAllowed(
26+
Object allowedLicensesFile,
27+
File projectLicensesDataFile,
28+
File notPassedDependenciesOutputFile,
29+
CheckType checkType) {
2530
List<Dependency> allDependencies = LicenseCheckerFileReader.importDependencies(projectLicensesDataFile)
2631
List<AllowedLicense> allowedLicenses = LicenseCheckerFileReader.importAllowedLicenses(allowedLicensesFile)
27-
List<Dependency> notPassedDependencies = searchForNotAllowedDependencies(allDependencies, allowedLicenses)
32+
List<Tuple2<Dependency, List<ModuleLicense>>> notPassedDependencies = getNotAllowedLicenses(allDependencies, allowedLicenses)
33+
if (checkType == CheckType.ANY) {
34+
// when we have ANY_MATCH check type, we will not show an error if any license is allowed
35+
// this means: we are only interested in those dependencies where all licenses are not allowed
36+
notPassedDependencies = notPassedDependencies.findAll { it.get(0).moduleLicenses == null || it.get(1).size() == it.get(0).moduleLicenses.size() }
37+
}
2838
generateNotPassedDependenciesFile(notPassedDependencies, notPassedDependenciesOutputFile)
2939

3040
if (!notPassedDependencies.isEmpty()) {
31-
throw new GradleException("Some library licenses are not allowed.\n" +
32-
"Read [$notPassedDependenciesOutputFile.path] for more information.")
41+
throw new GradleException("Some library licenses are not allowed:\n" +
42+
"$notPassedDependenciesOutputFile.text\n\n" +
43+
"Read [$notPassedDependenciesOutputFile.path] for more information.")
3344
}
3445
}
3546

36-
private List<Dependency> searchForNotAllowedDependencies(
37-
List<Dependency> dependencies, List<AllowedLicense> allowedLicenses) {
38-
return dependencies.findAll { !isDependencyHasAllowedLicense(it, allowedLicenses) }
39-
}
40-
41-
private void generateNotPassedDependenciesFile(
42-
List<Dependency> notPassedDependencies, File notPassedDependenciesOutputFile) {
43-
notPassedDependenciesOutputFile.text =
44-
JsonOutput.prettyPrint(JsonOutput.toJson(
45-
["dependenciesWithoutAllowedLicenses": notPassedDependencies.collect { toAllowedLicenseList(it) }.flatten()]))
46-
}
47-
48-
private boolean isDependencyHasAllowedLicense(Dependency dependency, List<AllowedLicense> allowedLicenses) {
49-
for(allowedLicense in allowedLicenses) {
50-
if (isDependencyMatchesAllowedLicense(dependency, allowedLicense)) return true
47+
private static List<Tuple2<Dependency, List<ModuleLicense>>> getNotAllowedLicenses(List<Dependency> dependencies, List<AllowedLicense> allowedLicenses) {
48+
List<Tuple2<Dependency, List<ModuleLicense>>> result = new ArrayList<>()
49+
for (Dependency dependency : dependencies) {
50+
List<AllowedLicense> perDependencyAllowedLicenses = allowedLicenses.findAll { isDependencyNameMatchesAllowedLicense(dependency, it) && isDependencyVersionMatchesAllowedLicense(dependency, it) }
51+
// allowedLicense matches anything, so we don't need to further check
52+
if (perDependencyAllowedLicenses.any { it.moduleLicense == null || it.moduleLicense == ".*" }) {
53+
continue
54+
}
55+
def notAllowedLicenses = dependency.moduleLicenses.findAll { !isDependencyLicenseMatchesAllowedLicense(it, perDependencyAllowedLicenses) }
56+
if (!notAllowedLicenses.isEmpty()) {
57+
result.add(Tuple2.of(dependency, notAllowedLicenses))
58+
}
5159
}
52-
return false
60+
return result
5361
}
5462

55-
private boolean isDependencyMatchesAllowedLicense(Dependency dependency, AllowedLicense allowedLicense) {
56-
return isDependencyNameMatchesAllowedLicense(dependency, allowedLicense) &&
57-
isDependencyLicenseMatchesAllowedLicense(dependency, allowedLicense) &&
58-
isDependencyVersionMatchesAllowedLicense(dependency, allowedLicense)
63+
private static void generateNotPassedDependenciesFile(
64+
List<Tuple2<Dependency, List<ModuleLicense>>> notPassedDependencies, File notPassedDependenciesOutputFile) {
65+
notPassedDependenciesOutputFile.text =
66+
JsonOutput.prettyPrint(JsonOutput.toJson(
67+
["dependenciesWithoutAllowedLicenses": notPassedDependencies.collect { toAllowedLicenseList(it.get(0), it.get(1)) }.flatten()]))
5968
}
6069

61-
private boolean isDependencyNameMatchesAllowedLicense(Dependency dependency, AllowedLicense allowedLicense) {
70+
private static boolean isDependencyNameMatchesAllowedLicense(Dependency dependency, AllowedLicense allowedLicense) {
6271
return dependency.moduleName ==~ allowedLicense.moduleName || allowedLicense.moduleName == null ||
63-
dependency.moduleName == allowedLicense.moduleName
72+
dependency.moduleName == allowedLicense.moduleName
6473
}
6574

66-
private boolean isDependencyVersionMatchesAllowedLicense(Dependency dependency, AllowedLicense allowedLicense) {
75+
private static boolean isDependencyVersionMatchesAllowedLicense(Dependency dependency, AllowedLicense allowedLicense) {
6776
return dependency.moduleVersion ==~ allowedLicense.moduleVersion || allowedLicense.moduleVersion == null ||
68-
dependency.moduleVersion == allowedLicense.moduleVersion
77+
dependency.moduleVersion == allowedLicense.moduleVersion
6978
}
7079

71-
private boolean isDependencyLicenseMatchesAllowedLicense(Dependency dependency, AllowedLicense allowedLicense) {
72-
if (allowedLicense.moduleLicense == null || allowedLicense.moduleLicense == ".*") return true
80+
private static boolean isDependencyLicenseMatchesAllowedLicense(ModuleLicense moduleLicense, List<AllowedLicense> allowedLicenses) {
81+
for (AllowedLicense allowedLicense : allowedLicenses) {
82+
if (allowedLicense.moduleLicense == null || allowedLicense.moduleLicense == ".*") return true
7383

74-
for (moduleLicenses in dependency.moduleLicenses)
75-
if (moduleLicenses.moduleLicense ==~ allowedLicense.moduleLicense ||
76-
moduleLicenses.moduleLicense == allowedLicense.moduleLicense) return true
84+
if (moduleLicense.moduleLicense ==~ allowedLicense.moduleLicense ||
85+
moduleLicense.moduleLicense == allowedLicense.moduleLicense) return true
86+
}
7787
return false
7888
}
7989

80-
private List<AllowedLicense> toAllowedLicenseList(Dependency dependency) {
81-
if (dependency.moduleLicenses.isEmpty()) {
82-
return [ new AllowedLicense(dependency.moduleName, dependency.moduleVersion, null) ]
90+
private static List<AllowedLicense> toAllowedLicenseList(Dependency dependency, List<ModuleLicense> moduleLicenses) {
91+
if (moduleLicenses.isEmpty()) {
92+
return [new AllowedLicense(dependency.moduleName, dependency.moduleVersion, null)]
8393
} else {
84-
return dependency.moduleLicenses.collect { new AllowedLicense(dependency.moduleName, dependency.moduleVersion, it.moduleLicense) }
94+
return moduleLicenses.findAll { it }.collect { new AllowedLicense(dependency.moduleName, dependency.moduleVersion, it.moduleLicense) }
8595
}
8696
}
8797
}

src/main/groovy/com/github/jk1/license/check/LicenseCheckerModel.groovy

+14-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import groovy.transform.EqualsAndHashCode
1919

2020
@EqualsAndHashCode
2121
class AllowedLicense {
22-
String moduleName, moduleLicense, moduleVersion
22+
String moduleName, moduleLicense, moduleVersion
2323

2424
AllowedLicense(String moduleName, String moduleVersion, String moduleLicense) {
2525
this.moduleName = moduleName
@@ -41,7 +41,7 @@ class Dependency {
4141
Dependency(Map dependencies) {
4242
this.moduleName = dependencies.moduleName
4343
this.moduleVersion = dependencies.moduleVersion
44-
this.moduleLicenses = [ new ModuleLicense(dependencies.moduleLicense) ]
44+
this.moduleLicenses = [new ModuleLicense(dependencies.moduleLicense)]
4545
}
4646
}
4747

@@ -52,3 +52,15 @@ class ModuleLicense {
5252
this.moduleLicense = moduleLicense
5353
}
5454
}
55+
56+
57+
enum CheckType {
58+
/**
59+
* When checking the licenses of a dependency, it is allowed as long as one of them is inside the allowedLicenses
60+
*/
61+
ANY,
62+
/**
63+
* When checking the licenses of a dependency, it is allowed when all of them are inside the allowedLicenses
64+
*/
65+
ALL
66+
}

src/main/groovy/com/github/jk1/license/task/CheckLicenseTask.groovy

+13-1
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@
1616
package com.github.jk1.license.task
1717

1818
import com.github.jk1.license.LicenseReportExtension
19+
import com.github.jk1.license.check.CheckType
1920
import com.github.jk1.license.check.LicenseChecker
2021
import org.gradle.api.DefaultTask
2122
import org.gradle.api.logging.Logger
2223
import org.gradle.api.logging.Logging
2324
import org.gradle.api.tasks.CacheableTask
2425
import org.gradle.api.tasks.Input
2526
import org.gradle.api.tasks.InputFile
27+
import org.gradle.api.tasks.InputFiles
28+
import org.gradle.api.tasks.Optional
2629
import org.gradle.api.tasks.OutputFile
2730
import org.gradle.api.tasks.PathSensitive
2831
import org.gradle.api.tasks.TaskAction
@@ -58,12 +61,21 @@ class CheckLicenseTask extends DefaultTask {
5861
new File("${config.absoluteOutputDir}/$NOT_PASSED_DEPENDENCIES_FILE")
5962
}
6063

64+
@Input
65+
CheckType getDefaultCheckType() {
66+
return config.defaultCheckType
67+
}
68+
6169
@TaskAction
6270
void checkLicense() {
6371
LOGGER.info("Startup CheckLicense for ${getProject().name}")
6472
LicenseChecker licenseChecker = new LicenseChecker()
6573
LOGGER.info("Check licenses if they are allowed to use.")
6674
licenseChecker.checkAllDependencyLicensesAreAllowed(
67-
getAllowedLicenseFile(), getProjectDependenciesData(), notPassedDependenciesFile)
75+
getAllowedLicenseFile(),
76+
getProjectDependenciesData(),
77+
notPassedDependenciesFile,
78+
getDefaultCheckType()
79+
)
6880
}
6981
}

0 commit comments

Comments
 (0)