Skip to content

license-gather: add a task for verifying license compatibility #49

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 6 additions & 107 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,45 +54,8 @@ CRLF Plugin
Adds Kotlin DSL to specify CRLF/LF filtering for `CopySpec`.
Enables to use `.gitignore` and `.gitattributes` for building `CopySpec`.

Usage
-----
See [crlf-plugin description](plugins/crlf-plugin/README.md) for configuration options.

Kotlin DSL:

```kotlin
// Loads .gitattributes and .gitignore from rootDir (and subdirs)
val gitProps by tasks.registering(FindGitAttributes::class) {
// Scanning for .gitignore and .gitattributes files in a task avoids doing that
// when distribution build is not required (e.g. code is just compiled)
root.set(rootDir)
}

fun CrLfSpec.sourceLayout() = copySpec {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
gitattributes(gitProps)
into(baseFolder) {
// Note: license content is taken from "/build/..", so gitignore should not be used
// Note: this is a "license + third-party licenses", not just Apache-2.0
dependencyLicenses(sourceLicense)
// Include all the source files
from(rootDir) {
gitignore(gitProps)
}
}
}

for (archive in listOf(Zip::class, Tar::class)) {
tasks.register("dist${archive.simpleName}", archive) {
val eol = if (archive == Tar::class) LineEndings.LF else LineEndings.CRLF
if (this is Tar) {
compression = Compression.GZIP
}
CrLfSpec(eol).run {
with(sourceLayout())
}
}
}
```

IDE Plugin
==========
Expand All @@ -104,74 +67,9 @@ IDE Plugin
License Gather Plugin
=====================

The purpose of the plugin is to analyze and infer license names for the dependencies.
The plugin checks for 3 places: MANIFEST.MF (`Bundle-License` attribute),
`pom.xml` (`licenses/license` tags), and finally `LICENSE`-like files.
Note: for now only fuzzy-match is implemented, and by default a similarity threshold of 42% is used.

License Gather Plugin uses https://github.com/spdx/license-list-data for the list of licenses.

Prior art
---------

https://github.com/jk1/Gradle-License-Report

Gradle-License-Report is nice (it is), however there are certain pecularities (as of 2019-06-04)

* It can't generate multiple lists within a single project (e.g. license for source / binary artifacts)
* The model for imported/discovered licenses is differnet
* There's no way to override license detection

https://github.com/eskatos/honker-gradle

* There's no way to override license files
* [SPDX](https://spdx.org/licenses/) is not used

Features
--------
The purpose of the plugin is to analyze and infer license names for the dependencies, and verify license compatibility.

* LICENSE file generation
* License whitelisting
* The detected licenses can be overridden
* Support for incremental-builds (discovery does not run in case dependencies do not change)
* Type-safe license enumeration (based on SPDX):

com.github.vlsi.gradle.license.api.SpdxLicense#Apache_2_0

Usage
-----

Gradle (Groovy DSL):
```groovy
plugins {
id('com.github.vlsi.license-gather') version '1.0.0'
}

tasks.register('generateLicense', GatherLicenseTask.class) {
configurations.add(project.configurations.runtimeClasspath)
outputFile.set(file("$buildDir/result.txt"))

doLast {
println(outputFile.get().asFile.text)
}
}
```

Gradle (Kotlin DSL):
```groovy
plugins {
id("com.github.vlsi.license-gather") version "1.0.0"
}

tasks.register("generateLicense", GatherLicenseTask::class) {
configurations.add(project.configurations.runtimeClasspath)
outputFile.set(file("$buildDir/result.txt"))

doLast {
println(outputFile.get().asFile.readText())
}
}
```
See [license-gather-plugin description](plugins/license-gather-plugin/README.md) for configuration options.

Gettext Plugin
==============
Expand All @@ -191,8 +89,9 @@ Change log
----------
v1.78
* chore: bump Gradle 6.7 -> 6.9.1
* license-gather: ignore xml namespaces when parsing POM files (see #43)
* license-gather: fix license inference from Bundle-License manifest attribute (see #48)
* license-gather: ignore xml namespaces when parsing POM files (see [issue #43](https://github.com/vlsi/vlsi-release-plugins/issues/43))
* license-gather: fix license inference from Bundle-License manifest attribute (see [issue #48](https://github.com/vlsi/vlsi-release-plugins/issues/48))
* license-gather: implement VerifyLicenseCompatibilityTask for verifying license compatibility (see [pr #49](https://github.com/vlsi/vlsi-release-plugins/pull/49))

Thanks to [Florian Dreier](https://github.com/DreierF) for identifying bugs and suggesting fixes.

Expand Down
2 changes: 1 addition & 1 deletion plugins/checksum-dependency-plugin/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[![Gradle Plugin Portal](https://img.shields.io/maven-metadata/v/https/plugins.gradle.org/m2/com/github/vlsi/gradle/checksum-dependency-plugin/maven-metadata.xml.svg?colorB=007ec6&label=gradle)](https://plugins.gradle.org/plugin/com.github.vlsi.checksum-dependency)
[![Gradle Plugin Portal](https://img.shields.io/maven-metadata/v/https/repo1.maven.org/maven2/com/github/vlsi/gradle/checksum-dependency-plugin/maven-metadata.xml.svg?colorB=007ec6&label=latest%20version)](https://plugins.gradle.org/plugin/com.github.vlsi.checksum-dependency)

Checksum Dependency Plugin
==========================
Expand Down
47 changes: 47 additions & 0 deletions plugins/crlf-plugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
[![Gradle Plugin Portal](https://img.shields.io/maven-metadata/v/https/repo1.maven.org/maven2/com/github/vlsi/gradle/crlf-plugin/maven-metadata.xml.svg?colorB=007ec6&label=latest%20version)](https://plugins.gradle.org/plugin/com.github.vlsi.crlf)

CRLF Plugin
===========

Adds Kotlin DSL to specify CRLF/LF filtering for `CopySpec`.
Enables to use `.gitignore` and `.gitattributes` for building `CopySpec`.

Usage
-----

Kotlin DSL:

```kotlin
// Loads .gitattributes and .gitignore from rootDir (and subdirs)
val gitProps by tasks.registering(FindGitAttributes::class) {
// Scanning for .gitignore and .gitattributes files in a task avoids doing that
// when distribution build is not required (e.g. code is just compiled)
root.set(rootDir)
}

fun CrLfSpec.sourceLayout() = copySpec {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
gitattributes(gitProps)
into(baseFolder) {
// Note: license content is taken from "/build/..", so gitignore should not be used
// Note: this is a "license + third-party licenses", not just Apache-2.0
dependencyLicenses(sourceLicense)
// Include all the source files
from(rootDir) {
gitignore(gitProps)
}
}
}

for (archive in listOf(Zip::class, Tar::class)) {
tasks.register("dist${archive.simpleName}", archive) {
val eol = if (archive == Tar::class) LineEndings.LF else LineEndings.CRLF
if (this is Tar) {
compression = Compression.GZIP
}
CrLfSpec(eol).run {
with(sourceLayout())
}
}
}
```
2 changes: 1 addition & 1 deletion plugins/gradle-extensions-plugin/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[![Gradle Plugin Portal](https://img.shields.io/maven-metadata/v/https/plugins.gradle.org/m2/com/github/vlsi/gradle/gradle-extensions-plugin/maven-metadata.xml.svg?colorB=007ec6&label=gradle)](https://plugins.gradle.org/plugin/com.github.vlsi.gradle-extensions)
[![Gradle Plugin Portal](https://img.shields.io/maven-metadata/v/https/repo1.maven.org/maven2/com/github/vlsi/gradle/gradle-extensions-plugin/maven-metadata.xml.svg?colorB=007ec6&label=latest%20version)](https://plugins.gradle.org/plugin/com.github.vlsi.gradle-extensions)

Gradle Extensions Plugin
=========================
Expand Down
2 changes: 1 addition & 1 deletion plugins/jandex-plugin/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[![Gradle Plugin Portal](https://img.shields.io/maven-metadata/v/https/plugins.gradle.org/m2/com/github/vlsi/jandex/jandex-plugin/maven-metadata.xml.svg?colorB=007ec6&label=gradle)](https://plugins.gradle.org/plugin/com.github.vlsi.jandex)
[![Gradle Plugin Portal](https://img.shields.io/maven-metadata/v/https/repo1.maven.org/maven2/com/github/vlsi/jandex/jandex-plugin/maven-metadata.xml.svg?colorB=007ec6&label=latest%20version)](https://plugins.gradle.org/plugin/com.github.vlsi.jandex)

Jandex Gradle Plugin
====================
Expand Down
143 changes: 143 additions & 0 deletions plugins/license-gather-plugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
[![Gradle Plugin Portal](https://img.shields.io/maven-metadata/v/https/repo1.maven.org/maven2/com/github/vlsi/gradle/license-gather-plugin/maven-metadata.xml.svg?colorB=007ec6&label=latest%20version)](https://plugins.gradle.org/plugin/com.github.vlsi.license-gather)

License Gather Plugin
=====================

The purpose of the plugin is to analyze and infer license names for the dependencies, and verify license compatibility.
The plugin checks for 3 places: MANIFEST.MF (`Bundle-License` attribute),
`pom.xml` (`licenses/license` tags), and finally `LICENSE`-like files.
Note: for now only fuzzy-match is implemented, and by default a similarity threshold of 42% is used.

License Gather Plugin uses https://github.com/spdx/license-list-data for the list of licenses.

Prior art
---------

https://github.com/jk1/Gradle-License-Report

Gradle-License-Report is nice (it is), however there are certain pecularities (as of 2019-06-04)

* It can't generate multiple lists within a single project (e.g. license for source / binary artifacts)
* The model for imported/discovered licenses is differnet
* There's no way to override license detection

https://github.com/eskatos/honker-gradle

* There's no way to override license files
* [SPDX](https://spdx.org/licenses/) is not used

License Gather Plugin Features
------------------------------

* LICENSE file generation
* License whitelisting
* The detected licenses can be overridden
* Verify license compatibility
* Type-safe license enumeration (based on SPDX):

com.github.vlsi.gradle.license.api.SpdxLicense.Apache_2_0

Usage
-----

Gradle (Groovy DSL):
```groovy
import com.github.vlsi.gradle.license.GatherLicenseTask
import com.github.vlsi.gradle.license.VerifyLicenseCompatibilityTask
import com.github.vlsi.gradle.release.AsfLicenseCategory
import com.github.vlsi.gradle.license.api.SpdxLicense
import com.github.vlsi.gradle.license.api.SimpleLicense

plugins {
id('com.github.vlsi.license-gather') version '1.78'
}

// Gathers license information and license files from the runtime dependencies
def gatherLicense = tasks.register('gatherLicense', GatherLicenseTask.class) {
configurations.add(project.configurations.runtimeClasspath)
}

tasks.register("verifyLicenses", VerifyLicenseCompatibilityTask.class) {
metadata.from(gatherLicense)
allow(SpdxLicense.EPL_2_0) {
// The message would be displayed, so the verification results are easier to understand
because("ISSUE-23: EPL-2.0 is fine in our projects")
}
allow(new SimpleLicense("The W3C License", uri("http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/java-binding.zip"))) {
because("ISSUE-42: John Smith decided the license is OK")
}
// License category
// See https://www.apache.org/legal/resolved.html
allow(AsfLicenseCategory.A) {
because("The ASF category A is allowed")
}
reject(AsfLicenseCategory.X) {
because("The ASF category X is forbidden")
}
}
```

Gradle (Kotlin DSL):
```kotlin
import com.github.vlsi.gradle.license.GatherLicenseTask
import com.github.vlsi.gradle.license.VerifyLicenseCompatibilityTask
import com.github.vlsi.gradle.release.AsfLicenseCategory
import com.github.vlsi.gradle.license.api.SpdxLicense
import com.github.vlsi.gradle.license.api.SimpleLicense

plugins {
id("com.github.vlsi.license-gather") version "1.78"
}

// Gathers license information and license files from the runtime dependencies
val generateLicense by tasks.registering(GatherLicenseTask::class) {
configurations.add(project.configurations.runtimeClasspath)
// In the ideal case, each dependency should ship a copy of the full license text
// just in case it has been modified.
// For instance, "MIT licence" and "BSD-* license" are almost always modified,
// and they have custom "copyright" section.
// However, certain licenses like Apache-2.0, MPL-2.0, have fixed texts, so
// we can ignore the failure if project is MPL-2.0 licensed, and it omits the license file
ignoreMissingLicenseFor.add(SpdxLicense.Apache_2_0.asExpression())

defaultTextFor.add(SpdxLicense.MPL_2_0.asExpression())

// Artifact version in override is optional
overrideLicense("com.thoughtworks.xstream:xstream:1.4.11") {
// This version reads "BSD style" in pom.xml, however, their license
// is the same as BSD-3-Clause, so we override it
// expectedLicense helps to protect from accidental overrides if the project changes version
expectedLicense = SimpleLicense("BSD style", uri("http://x-stream.github.io/license.html"))
// https://github.com/x-stream/xstream/issues/151
// https://github.com/x-stream/xstream/issues/153
effectiveLicense = SpdxLicense.BSD_3_Clause
}

overrideLicense("com.formdev:svgSalamander") {
// See https://github.com/blackears/svgSalamander/blob/d6b6fe9a8ece7d0e0e7aeb3de82f027a38a6fe25/www/license/license-bsd.txt
effectiveLicense = SpdxLicense.BSD_3_Clause
}
}

val verifyLicenses by tasks.registering(VerifyLicenseCompatibilityTask::class) {
metadata.from(gatherLicense)
// License with SPDX ID (see https://spdx.org/licenses/)
allow(SpdxLicense.EPL_2_0) {
// The message would be displayed, so the verification results are easier to understand
because("ISSUE-23: EPL-2.0 is fine in our projects")
}
// A custom license that is not present in SPDX
allow(SimpleLicense("The W3C License", uri("http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/java-binding.zip"))) {
because("ISSUE-42: John Smith decided the license is OK")
}
// License category
// See https://www.apache.org/legal/resolved.html
allow(AsfLicenseCategory.A) {
// The reason will be displayed
because("The ASF category A is allowed")
}
reject(AsfLicenseCategory.X) {
because("The ASF category X is forbidden")
}
}
```
Loading