Git Product home page Git Product logo

licensee's Introduction

Licensee ๐Ÿ“œ๐Ÿ‘€

A Gradle plugin which validates the licenses of your dependency graph match what you expect, or it fails your build!

Jump to: Introduction | Usage | Configuration | Development | License

Introduction

Imagine your closed-source product depends on an Apache 2-licensed artifact.

implementation 'com.example:example:1.0'

The developer releases a new version and you dutifully upgrade.

-implementation 'com.example:example:1.0'
+implementation 'com.example:example:1.1'

This new version has a transitive dependency on a GPL-licensed artifact which is incompatible with your closed-source product. Did you catch it?

You may have seen the new dependency in a dependency tree diff, but did you check its license?

-+--- com.example:example:1.0
++--- com.example:example:1.1
+     \--- com.other:other:2.5

With the Licensee plugin applied, you don't have to. First, configure it to allow Apache 2-licensed dependencies.

licensee {
  allow('Apache-2.0')
}

Now attempting to upgrade the dependency will fail the build.

> Task :app:licensee FAILED
com.other:other:2.5
 - SPDX identifier 'GPL-3.0-or-later' is NOT allowed

Crisis averted!

Usage

Add the dependency and apply the plugin to the module whose dependency graph you want to check.

buildscript {
  repositories {
    mavenCentral()
  }
  dependencies {
    classpath 'app.cash.licensee:licensee-gradle-plugin:1.11.0'
  }
}

apply plugin: 'app.cash.licensee'
Snapshots of the development version are available in Sonatype's snapshots repository.

buildscript {
  repositories {
    mavenCentral()
    maven {
      url 'https://oss.sonatype.org/content/repositories/snapshots/'
    }
  }
  dependencies {
    classpath 'app.cash.licensee:licensee-gradle-plugin:1.12.0-SNAPSHOT'
  }
}

apply plugin: 'app.cash.licensee'

The plugin's tasks will walk the entire transitive dependency graph, so it only needs to be applied to "leaf" modules (those without downstream dependencies) such as applications and services. If you are building a library, however, apply it to each library module.

Licensee requires a supported language/platform plugin to also be applied to the same module:

  • java-library
  • java
  • com.android.application
  • com.android.library
  • org.jetbrains.kotlin.jvm
  • org.jetbrains.kotlin.js
  • org.jetbrains.kotlin.multiplatform

Configure the list of allowed licenses using the licensee DSL:

licensee {
  allow('Apache-2.0')
}

For more configuration options, see the configuration section.

The licensee task will be added to your build and automatically added as a dependency of the check task. Android and Kotlin multiplatform modules will have variant-specific versions of this task (such as licenseeDebug and licenseeJs) with the licensee task merely aggregating them together.

In addition to failing the build on detection of a disallowed license, the plugin will always generate some report files.

  1. artifacts.json

    A JSON file with license information on every artifact in the dependency graph.

  2. validation.txt

    A plain text report containing each artifact and whether its licenses are allowed or disallowed.

These files are generated into <buildDir>/reports/licensee, or for Android modules <buildDir>/reports/licensee/<variant name>/.

Configuration

The following functions are available on the licensee DSL and/or app.cash.licensee.LicenseeExtension type.

allow

Allow artifacts with a license that matches a SPDX identifier.

licensee {
  allow('Apache-2.0')
  allow('MIT')
}

A full list of supported identifiers is available at spdx.org/licenses/.

allowUrl

Allow artifacts with an unknown (non-SPDX) license which matches a URL.

licensee {
  allowUrl('https://example.com/license.html')
}

A reason string can be supplied to document why the URL is allowed.

licensee {
  allowUrl('https://example.com/license.html') {
    because 'Apache-2.0, but self-hosted copy of the license'
}

allowDependency

Allow an artifact with a specific groupId, artifactId, and version. This is useful for artifacts which contain no license data or have invalid/incorrect license data.

licensee {
  allowDependency('com.example', 'example', '1.0')
}

A reason string can be supplied to document why the dependency is being allowed despite missing or invalid license data.

licensee {
  allowDependency('com.jetbrains', 'annotations', '16.0.1') {
    because 'Apache-2.0, but typo in license URL fixed in newer versions'
  }
}

Reason strings will be included in validation reports.

ignoreDependencies

Ignore a single dependency or group of dependencies during dependency graph resolution. Artifacts targeted with this method will not be analyzed for license information and will not show up in any report files.

This function can be used to ignore internal, closed-source libraries and commercial libraries for which you've purchased a license.

There are overloads which accept either a groupId or a groupId:artifactId pair.

licensee {
  ignoreDependencies('com.mycompany.internal')
  ignoreDependencies('com.mycompany.utils', 'utils')
}

A reason string can be supplied to document why the dependencies are being ignored.

licensee {
  ignoreDependencies('com.example.sdk', 'sdk') {
    because "commercial SDK"
  }
}

An ignore can be marked as transitive which will ignore an entire branch of the dependency tree. This will ignore the target artifact's dependencies regardless of the artifact coordinates or license info. Since it is especially dangerous, a reason string is required.

licensee {
  ignoreDependencies('com.other.sdk', 'sdk') {
    transitive = true
    because "commercial SDK"
  }
}

Development

Updating embedded license info

Run the updateLicenses task to update the embedded SPDX license file in src/main/resources/.

License

Copyright 2021 Square, Inc.

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

   http://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.

licensee's People

Contributors

autonomousapps avatar dellisd avatar dependabot[bot] avatar goooler avatar hfhbd avatar jakewharton avatar jonapoul avatar justasm avatar matthewmichihara avatar mattprecious avatar msfjarvis avatar mxalbert1996 avatar remcomokveld avatar renovate[bot] avatar takahirom avatar vanniktech avatar warting avatar whosnickdoglio avatar zacsweers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

licensee's Issues

Dependencies with license name provided as `MIT` can't get identified

Here is the output for using e.g. version 3.1.0, I assume it will be the same for 3.2.0 as well:

io.github.g0dkar:qrcode-kotlin-jvm:3.1.0
 - ERROR: Unknown license URL 'https://github.com/g0dkar/qrcode-kotlin/blob/main/LICENSE' is NOT allowed

According to https://mvnrepository.com/artifact/io.github.g0dkar/qrcode-kotlin-jvm/3.1.0 the license name is published as MIT, so I assume it should get identfied as MIT when I'm looking at the fallback logic in licenses.kt.

I used the version 1.6.0 of this plugin to get the described results.

Replace buildscript with plugins

licensee/README.md

Lines 81 to 91 in 7b8b139

buildscript {
repository {
mavenCental()
maven {
url 'https://oss.sonatype.org/content/repositories/snapshots/'
}
}
dependencies {
classpath 'app.cash.licensee:licensee-gradle-plugin:1.5.0-SNAPSHOT'
}
}

Using the plugins API, this is how it would look alike:

plugins {
    id 'app.cash.licensee' version '1.5.0-SNAPSHOT' apply false
}
plugins {
    id 'app.cash.licensee'
}

Repositories can be set up in settings.gradle:

import org.gradle.api.initialization.resolve.RepositoriesMode

pluginManagement {
    repositories {
        maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
        mavenCentral()
    }
}

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
    repositories {
        maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
        mavenCentral()
    }
}

rootProject.name = "Licensee"

"Unknown license URL 'null'" when POM only includes license name

I have a reference to mockito-kotlin 3.2.0 in my project, which has the following in its POM:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <!-- ...snip... -->
  <licenses>
    <license>
      <name>MIT</name>
    </license>
  </licenses>
</project>

This causes licensee to fail with this error message:

> Task :app:licensee FAILED
org.mockito.kotlin:mockito-kotlin:3.2.0
 - ERROR: Unknown license URL 'null' is NOT allowed

In this case, I'd expect licensee to use the <name> element and not attempt to match on the non-existent URL.

FeatureRequest: Add Configuration For File Directory


As an android developer
I want to be able to configure the location of the artefacts.json file
So that I can bundle it in my app as part of the ./assets directory


We use the .json file to create a screen that shows the licences to our users. It would be nice if we can easily add that file as part of the build/ci pipeline.

"Artifact declares no licenses" error since 1.6.0

Since version 1.6.0 we suddenly receive the following error. Interestingly only on our CI server and not locally.

 - ERROR: Artifact declares no licenses!

> Task :app:licenseeBeta FAILED
WARNING: Allowed license URL 'https://api.github.com/licenses/apache-2.0' is unused

com.github.chrisbanes:PhotoView:2.3.0

Downgrading to 1.5.0 "fixes" this.

License for com.russhwolf:multiplatform-settings:0.8 can't be retrieved

When using:

sourceSets.commonMain.dependencies {
  api "com.russhwolf:multiplatform-settings:0.8.0"
}

I'm getting:

com.russhwolf:multiplatform-settings:0.8
 - ERROR: Artifact declares no licenses!

Looking at the POM it's present.

I'm applying the module to my app, while the API is declared in a shared KMP module.

AllowUrl: Add lambda to set the spdx

I really like the because function in allowDependency because it documents why this license is allowed. But for allowUrl, I use this syntax: allowUrl("https://foo.app") // MIT. Instead, I would like to use this syntax:

licensee {
  allow("MIT")
  allowUrl("https://foo.app") {
    because(spdx = "MIT")
  }
}

This should also overwrite the spdx in the artifacts.json

Add ability to set Configuration for licensee

I have one copy-pasted dependency which is not (should not) included in configuration, but I need it to included in information so that it is validated and included into artifacts.json.
I think it would be great if I:

  • can add custom dependency, like
    licensee {
      addDependency("a:b:c")
    }
    (but this seems hard to implement and has poor extensibility)
  • can set Configuration that is used to validate licenses.
    // do custom stuff with myConfiguration
    licensee {
      /* this. */ extraConfigurations += project.configurations["myConfiguration"] // or extraConfiguration = ...
    }
    This dummy configuration is only used for licensee, not used for dependencies or something.

ClosureBackedAction will be removed in Gradle 9.0

There is still a lot of time until then but the ClosureBackedAction used by this plugin will be removed in the future.

Usage: https://github.com/cashapp/licensee/blob/trunk/src/main/kotlin/app/cash/licensee/pluginExtension.kt

Docs:

This class is only here to maintain binary compatibility with existing plugins.
To apply a configuration (represented by a Groovy closure) on an object, use [Project.configure(Object, Closure)](https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html#configure-java.lang.Object-groovy.lang.Closure-).

https://docs.gradle.org/current/javadoc/org/gradle/util/ClosureBackedAction.html

Licensee doesn't find license

I'm getting this error

com.freeletics.mad:navigator-runtime:0.3.0-alpha27
 - ERROR: Artifact declares no licenses!

however the license is in the pom and the previous release which looks the same worked just fine. My theory is that licensee gets confused by the newer release using Android's new multi variant publishing, even though that doesn't have any influence on the pom.

Warning allowed dependency is unused in KMP Project

When I run the aggregation task licensee all of the tasks for each applicable plugin are ran. Since the configuration is shared there are some warnings:

> Task :core:licenseeJvm
WARNING: Allowed dependency 'org.jetbrains.kotlinx:kotlinx-serialization-core-iosx64:1.3.0' is unused
WARNING: Allowed dependency 'org.jetbrains.kotlinx:kotlinx-serialization-core-iosarm64:1.3.0' is unused
WARNING: Allowed dependency 'org.jetbrains.kotlinx:kotlinx-serialization-json-iosx64:1.3.0' is unused
WARNING: Allowed dependency 'org.jetbrains.kotlinx:kotlinx-serialization-json-iosarm64:1.3.0' is unused

Obviously, jvm does not need ios targeted dependencies.

In my project where I have a common module that's being used on Android, iOS & Server I get 96 of those warnings.

Not only is that a lot, actually removing a custom URL / license becomes impossible since I'd need to try it out, rerun everything.


Since the warnings come from the fine grained task, I guess the one solution would be to have custom logic inside licensee which does it's own validation without delegating to other tasks.

Another solution would be to have different configurations for each target.

Kotlin Native without dependencies: Stdlib not found

I know this is a very very rare case, so feel free to close it if you don't see a useful use-case.

plugins {
    kotlin("multiplatform") version "1.7.10"
    id("app.cash.licensee") version "1.5.0"
}

repositories {
    mavenCentral()
}

kotlin {
    linuxX64()
    macosArm64()
}

licensee {
    allow("Apache-2.0")
}

The artifact.json file is empty, so the licensee task succeeds:

[
]

But the default std lib is missing, so the warning Allowed SPDX identifier 'Apache-2.0' is unused is printed.
Using the jvm works as expected:

[
    {
        "groupId": "org.jetbrains",
        "artifactId": "annotations",
        "version": "13.0",
        "name": "IntelliJ IDEA Annotations",
        "spdxLicenses": [
            {
                "identifier": "Apache-2.0",
                "name": "Apache License 2.0",
                "url": "https://www.apache.org/licenses/LICENSE-2.0"
            }
        ],
        "scm": {
            "url": "https://github.com/JetBrains/intellij-community"
        }
    },
    {
        "groupId": "org.jetbrains.kotlin",
        "artifactId": "kotlin-stdlib",
        "version": "1.7.10",
        "name": "Kotlin Stdlib",
        "spdxLicenses": [
            {
                "identifier": "Apache-2.0",
                "name": "Apache License 2.0",
                "url": "https://www.apache.org/licenses/LICENSE-2.0"
            }
        ],
        "scm": {
            "url": "https://github.com/JetBrains/kotlin"
        }
    },
    {
        "groupId": "org.jetbrains.kotlin",
        "artifactId": "kotlin-stdlib-common",
        "version": "1.7.10",
        "name": "Kotlin Stdlib Common",
        "spdxLicenses": [
            {
                "identifier": "Apache-2.0",
                "name": "Apache License 2.0",
                "url": "https://www.apache.org/licenses/LICENSE-2.0"
            }
        ],
        "scm": {
            "url": "https://github.com/JetBrains/kotlin"
        }
    },
    {
        "groupId": "org.jetbrains.kotlin",
        "artifactId": "kotlin-stdlib-jdk7",
        "version": "1.7.10",
        "name": "Kotlin Stdlib Jdk7",
        "spdxLicenses": [
            {
                "identifier": "Apache-2.0",
                "name": "Apache License 2.0",
                "url": "https://www.apache.org/licenses/LICENSE-2.0"
            }
        ],
        "scm": {
            "url": "https://github.com/JetBrains/kotlin"
        }
    },
    {
        "groupId": "org.jetbrains.kotlin",
        "artifactId": "kotlin-stdlib-jdk8",
        "version": "1.7.10",
        "name": "Kotlin Stdlib Jdk8",
        "spdxLicenses": [
            {
                "identifier": "Apache-2.0",
                "name": "Apache License 2.0",
                "url": "https://www.apache.org/licenses/LICENSE-2.0"
            }
        ],
        "scm": {
            "url": "https://github.com/JetBrains/kotlin"
        }
    }
]
org.jetbrains:annotations:13.0
 - SPDX identifier 'Apache-2.0' allowed
org.jetbrains.kotlin:kotlin-stdlib:1.7.10
 - SPDX identifier 'Apache-2.0' allowed
org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10
 - SPDX identifier 'Apache-2.0' allowed
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.10
 - SPDX identifier 'Apache-2.0' allowed
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10
 - SPDX identifier 'Apache-2.0' allowed

License-url `http://www.eclipse.org/org/documents/edl-v10.php` specified as `unknown`, but it should be `EPL-1.0`

When having e.g. org.glassfish.jaxb:jaxb-core:4.0.0 in your dependency tree, the license check fails with the statement that the license-url http://www.eclipse.org/org/documents/edl-v10.php is unknown. But as far as I can see this should resolve to "EPL-1.0" as defined in licenses.kt.

I'm using version 1.6.0.

Here are a few examples for dependencies having the same problem:

com.sun.istack:istack-commons-runtime:4.1.1
 - ERROR: Unknown license URL 'http://www.eclipse.org/org/documents/edl-v10.php' is NOT allowed
jakarta.activation:jakarta.activation-api:2.1.0
 - ERROR: Unknown license URL 'http://www.eclipse.org/org/documents/edl-v10.php' is NOT allowed
jakarta.xml.bind:jakarta.xml.bind-api:4.0.0
 - ERROR: Unknown license URL 'http://www.eclipse.org/org/documents/edl-v10.php' is NOT allowed
org.eclipse.angus:angus-activation:1.0.0
 - ERROR: Unknown license URL 'http://www.eclipse.org/org/documents/edl-v10.php' is NOT allowed
org.glassfish.jaxb:jaxb-core:4.0.0
 - ERROR: Unknown license URL 'http://www.eclipse.org/org/documents/edl-v10.php' is NOT allowed
org.glassfish.jaxb:jaxb-runtime:4.0.0
 - ERROR: Unknown license URL 'http://www.eclipse.org/org/documents/edl-v10.php' is NOT allowed
org.glassfish.jaxb:txw2:4.0.0
 - ERROR: Unknown license URL 'http://www.eclipse.org/org/documents/edl-v10.php' is NOT allowed

Disable dependency verification on created configurations

When using Gradle dependency verification on projects I believe it is quite common to ignore pom files by setting verify-metadata to false in verification-metadata.xml This means no POM files gets listed in this XML file. However, when running the licensee plugin it adds pom file dependencies which then gets included in dependency verification, causing builds to fail verification. Since the plugin is not adding any dependencies for real to the project I believe it would make sense for it to disable verification on its created, detached configuration as outlined in 1:

val pomCoordinates = with(id) { "$group:$artifact:$version@pom" }
val pomDependency = project.dependencies.create(pomCoordinates)
val detachedConfiguration = project.configurations
.detachedConfiguration(pomDependency)
detachedConfiguration.resolutionStrategy.disableDependencyVerification()
val pomConfiguration = detachedConfiguration.resolvedConfiguration
.lenientConfiguration

Feature request: Ability to disable license validation and only generate artifacts.json

First off, thanks for the great plugin! We recently integrated it into our app and it's working well.

I was wondering if it would be possible to have an option to disable license validation and only generate artifacts.json for the project dependencies? Main reasoning is that we already have a tool that does license validation so we are having to update the plugin manually quite frequently.

Perhaps, something similar to how we have allow() or ignoreDependencies but allowAll() or equivalent?

java.lang.IllegalArgumentException: List has more than one element

I'm testing out the plugin to potentially use it in an app with lots of sub-modules and libraries. Following the README, I have added the plugin and config to the build.gradle to the main app module as I would like to check all app dependencies. However, this is throwing an error List has more than one element which seems to come from here:

  val resolvedFiles = pomConfiguration.allModuleDependencies.flatMap { it.allModuleArtifacts }.map { it.file }
  val pomDocument = factory.newDocumentBuilder().parse(resolvedFiles.single())

in dependencyGraph.kt

I noticed that the info in README suggests that we should be adding the plugin to leaf modules. After doing so, I got the correct output for that individual module and artifacts.json was generated properly. I then added it to another separate module which worked again for that specific module but it created a second artifacts.json specific to that module.

Is there a way to setup the plugin so that it can traverse the entire dependency graph of the project and generate a single artifacts.json for all dependencies in the app? (Apologies if I missed something in the README file)

An example of how it's used in cashapp would be much appreciated!

Parent pom licenses incorrectly merged with local ones instead of being overridden

I use org.ow2.asm:asm-util:9.3, which is licensed under BSD-3-Clause: https://asm.ow2.io/license.html

The pom file https://repo.maven.apache.org/maven2/org/ow2/asm/asm-util/9.3/asm-util-9.3.pom and the gradle file use this name: https://gitlab.ow2.org/asm/asm/-/blob/master/build.gradle#L384

But licensee finds the Apache-2.0 license:

org.ow2.asm:asm-util:9.3
 - ERROR: SPDX identifier 'Apache-2.0' is NOT allowed
 - ERROR: Unknown license URL 'https://asm.ow2.io/license.html' is NOT allowed

repro:

plugins {
    kotlin("jvm") version "1.6.21"
    id("app.cash.licensee") version "1.3.1"
}

repositories {
    mavenCentral()
}

dependencies {
    // https://repo.maven.apache.org/maven2/org/ow2/asm/asm-util/9.3/asm-util-9.3.pom
    implementation("org.ow2.asm:asm-util:9.3")
    """
    org.ow2.asm:asm-util:9.3
    - ERROR: SPDX identifier 'Apache-2.0' is NOT allowed
    - ERROR: Unknown license URL 'https://asm.ow2.io/license.html' is NOT allowed
    """
    // but is: BSD-3-Clause
}

fo.zip

Adding SPDX identifier for custom url

Can you provide a way to map a custom license url to a SPDX indentifier?

For example, one of our dependency has this license url: https://opensource.org/licenses/mit-license. It's pretty oblivious that this dependency has MIT license, but there is no way to pass this knowledge to the plugin. Something like:

licensee {
   assumeLicense('https://opensource.org/licenses/mit-license', 'MIT')
}

would be very helpful ๐Ÿ™‚

No license found for compose (desktop) modules

I am using composereorderable (https://repo1.maven.org/maven2/org/burnoutcrew/composereorderable/reorderable/0.6.2/) and this tool says it has no licenses even though it has the apache 2 license.

The reason seems to be that one of the artifacts is not having any resolvedFiles. If it has no files, it is safe to assume that no license is needed for that? I've made a PR that solves my issue, but I'm not sure it is the correct approach to solve it.

Please have a look #57

Allow for group and module regex matching

Due to weirdnesses with the maven publish plugin and same module names within nested gradle middle-modules, for our internal library the group name often times has a suffix:

I.e with a module structure like this:

featureA:presentation
featureA:data
featureB:presentation
featureB:data

We publish artifacts like:

my.company.library.featureA:presentation
my.company.library.featureA:data
my.company.library.featureB:presentation
my.company.library.featureB:data

It would be great if licensee allowed a regex matching so we can specify sth like:

ignoreDependenciesByRegex(my.company.*)

This could work similar to gradles exclusiveContent matching:

dependencyResolutionManagement {

  repositories {

    exclusiveContent {
      forRepository {
        maven {
          url 'https://maven.google.com'
        }
      }
      filter {
        includeGroupByRegex("androidx.*")
        includeGroupByRegex("com.android.tools.build.*")
        includeGroupByRegex("com.android.*")
        includeGroup("com.google.firebase")

No dependencies found with Kotlin Native

With 1.5.0 variant support, kotlin native still does not work. Maybe they don't use variants, but something else?

plugins {
    kotlin("multiplatform") version "1.7.10"
    id("app.cash.licensee") version "1.5.0"
}

repositories {
    mavenCentral()
}

kotlin {
    linuxX64()
    macosArm64()

    sourceSets {
        commonMain {
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
            }
        }
    }
}

licensee {
    allow("Apache-2.0")
}

The artifact.json file is empty, so the licensee task succeeds:

[
]

reproducer.zip

Fails to find license with Kotlin Multiplatform Javascript Target

STEPS TO REPRODUCE

  1. Create a gradle module with multiplatform libraries like com.benasher44:uuid:0.3.1, a javascript target, and applying version 1.3.0 of the licensee plugin. E.g.
plugins {
    kotlin("multiplatform")
    id("app.cash.licensee")
}
kotlin {
    jvm()
    js(IR)
    sourceSets {
        val commonMain by getting {
            dependencies {
                api("com.benasher44:uuid:0.3.1")
            }
        }
}

RESULTS
Actual:

com.benasher44:uuid-js:0.3.1
 - ERROR: Artifact declares no licenses!

Expected:
It finds the license for the JVM target, so it should also succeed with the Javascript target.

NOTES
I don't know if there's a limitation in the Kotlin Multiplatform Gradle plugin where we need to file an issue with JetBrains, but I thought I'd start here.

Missing Apache 2.0 License URL

STEPS TO REPRODUCE

  1. Configure a project with the licensee Gradle plugin, allowing Apache 2.0, and using the dependency com.epam:parso:2.0.12

RESULTS
Actual:

com.epam:parso:2.0.12
 - ERROR: Unknown license URL 'http://www.apache.org/licenses/LICENSE-2.0.html' is NOT allowed

Expected:
No error, since the license is Apache 2.0

NOTES
Looks like another Apache 2.0 URL variation needs to be added for http://www.apache.org/licenses/LICENSE-2.0.html

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

This repository currently has no open or pending branches.

Detected dependencies

github-actions
.github/workflows/build.yaml
  • actions/checkout v4
  • actions/setup-java v4
  • gradle/actions v4
.github/workflows/release.yaml
  • actions/checkout v4
  • actions/setup-java v4
  • gradle/actions v4
  • ffurrer2/extract-release-notes v2
gradle
gradle.properties
settings.gradle
  • org.gradle.toolchains.foojay-resolver-convention 0.8.0
build.gradle
gradle/libs.versions.toml
  • com.android.tools.build:gradle-api 8.5.2
  • org.jetbrains.kotlin:kotlin-gradle-plugin 2.0.10
  • junit:junit 4.13.2
  • com.willowtreeapps.assertk:assertk 0.28.1
  • com.google.testparameterinjector:test-parameter-injector 1.16
  • org.jetbrains.kotlinx:kotlinx-serialization-json 1.7.1
  • org.apache.maven:maven-model-builder 3.9.8
  • androidx.lint:lint-gradle 1.0.0-alpha01
  • com.pinterest.ktlint:ktlint-cli 1.3.1
  • com.squareup:kotlinpoet 1.18.1
  • com.android.application 8.5.2
  • com.android.library 8.5.2
  • com.android.lint 8.5.2
  • com.android.dynamic-feature 8.5.2
  • org.jetbrains.kotlin.jvm 2.0.10
  • org.jetbrains.kotlin.multiplatform 2.0.10
  • org.jetbrains.kotlin.js 2.0.10
  • org.jetbrains.kotlin.plugin.serialization 2.0.10
  • com.diffplug.spotless 6.25.0
  • com.vanniktech.maven.publish 0.29.0
  • org.jetbrains.dokka 1.9.20
gradle/build-logic/settings.gradle
gradle/build-logic/build.gradle.kts
gradle/build-logic/src/main/kotlin/app.cash.licensee.repos.settings.gradle.kts
gradle-wrapper
gradle/wrapper/gradle-wrapper.properties
  • gradle 8.9

  • Check this box to trigger a request for Renovate to run again on this repository

Up-to-date check fails to detect actual dependency changes

The current Gradle task doesn't seem to take the actual dependency tree into account when determining its up-to-date state. This means any changes made to a project's dependencies will not be detected unless using --rerun-tasks or clean between runs.

Probably trying to keep and evaluate the tree would be as expensive as just always running the task so my initial suggestion would be to simply mark the task as an @UntrackedTask as the task itself doesn't seem that heavy-weight to begin with.

Support Android dynamic feature modules

As far as I can tell the plugin doesn't currently work for dynamic feature modules used in Android applications. It would be a nice thing to have as dynamic features is becoming more and more common, at least in larger Android projects. Perhaps it would be possible from the application module to detect android.dynamicFeatures dependencies and traverse into them to find additional third-parties to check?

Failure with Application and Gradle 7.3

Steps to reproduce

  1. Create a Kotlin multiplatform project that applies the Java application plugin
plugins {
    kotlin("multiplatform")
    id("application")
    id("app.cash.licensee")
}

kotlin {
    jvm()
}
  1. Build with Gradle 7.3

Results

Caused by: org.gradle.api.internal.tasks.DefaultTaskContainer$DuplicateTaskException: Cannot add task 'licensee' as a task with that name already exists.
        at org.gradle.api.internal.tasks.DefaultTaskContainer.failOnDuplicateTask(DefaultTaskContainer.java:257)
        at org.gradle.api.internal.tasks.DefaultTaskContainer.registerTask(DefaultTaskContainer.java:398)
        at org.gradle.api.internal.tasks.DefaultTaskContainer.register(DefaultTaskContainer.java:393)
        at org.gradle.api.internal.tasks.DefaultTaskContainer.register(DefaultTaskContainer.java:381)
        at org.gradle.api.internal.tasks.DefaultTaskContainer.register(DefaultTaskContainer.java:387)
        at app.cash.licensee.LicenseePlugin.apply$lambda-8(plugin.kt:97)

Notes

The symptoms appear similar to #62 but the steps to reproduce are different. The withJava is not necessary to reproduce this time. This time, the trigger is the combination of Gradle 7.3 and the application plugin. If I roll back to Gradle 7.2, the issue goes away. Likewise if I remove the application plugin, the issue goes away.

MIT-0 license not recognized anymore

I've got a library with this license in their pom (in particular reactive-streams):

  <licenses>
    <license>
      <name>MIT-0</name>
      <url>https://spdx.org/licenses/MIT-0.html</url>
      <distribution>repo</distribution>
    </license>
  </licenses>

Since 1.4.0 this will fail with the following error even if we have allow("MIT-0") set

ERROR: Unknown license URL 'https://spdx.org/licenses/MIT-0.html' is NOT allowed

The allowed identifier is also reported as unused.

The url does appear in licenses.json:

    {
      "reference": "https://spdx.org/licenses/MIT-0.html",
      "isDeprecatedLicenseId": false,
      "detailsUrl": "https://spdx.org/licenses/MIT-0.json",
      "referenceNumber": 439,
      "name": "MIT No Attribution",
      "licenseId": "MIT-0",
      "seeAlso": [
        "https://github.com/aws/mit-0",
        "https://romanrm.net/mit-zero",
        "https://github.com/awsdocs/aws-cloud9-user-guide/blob/master/LICENSE-SAMPLECODE"
      ],
      "isOsiApproved": true
    },

I think the issue might be that detailsUrl which is used in code (as spdxUrl) now contains the .json url and not the .html url. Before the file was re-generated in #90 it was the other way around. If this is the case I'm not sure why other licenses like Apache-2.0 are not affected.

Could not initialize class app.cash.licensee.LicensesKt

project/build.gradle:

buildscript {
    dependencies {
        classpath 'app.cash.licensee:licensee-gradle-plugin:1.0.2'
    }
}

project/app/build.gradle:

apply plugin: 'app.cash.licensee'

licensee {
    allow('Apache-2.0')
}

Running the task ./gradlew :app:licensee fails the build with the following stacktrace:

> Task :app:licenseeDebug FAILED

Execution failed for task ':app:licenseeDebug'.
> Could not initialize class app.cash.licensee.LicensesKt

* Try:
Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:licenseeDebug'.
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:200)
	at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:263)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:198)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:179)
	at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:109)
	at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
	at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:62)
	at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
	at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
	at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:62)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$call$2(DefaultBuildOperationExecutor.java:76)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.callWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:54)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:76)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
	at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:41)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:372)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:359)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:352)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:338)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:127)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:191)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:182)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:124)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
Caused by: java.lang.NoClassDefFoundError: Could not initialize class app.cash.licensee.LicensesKt
	at app.cash.licensee.LicenseeTask.execute(task.kt:134)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:104)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:58)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$3.run(ExecuteActionsTaskExecuter.java:555)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:71)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:71)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:540)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:523)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.access$300(ExecuteActionsTaskExecuter.java:108)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.executeWithPreviousOutputFiles(ExecuteActionsTaskExecuter.java:271)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.execute(ExecuteActionsTaskExecuter.java:260)
	at org.gradle.internal.execution.steps.ExecuteStep.lambda$execute$1(ExecuteStep.java:34)
	at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:34)
	at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:26)
	at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:67)
	at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:36)
	at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:49)
	at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:34)
	at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:43)
	at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:73)
	at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:54)
	at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:44)
	at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:54)
	at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:38)
	at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:42)
	at org.gradle.internal.execution.steps.CacheStep.executeWithoutCache(CacheStep.java:159)
	at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:72)
	at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:43)
	at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:44)
	at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:33)
	at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:38)
	at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:24)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:92)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$0(SkipUpToDateStep.java:85)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:55)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:39)
	at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:76)
	at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:37)
	at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:36)
	at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:26)
	at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:94)
	at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:49)
	at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:79)
	at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:53)
	at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:74)
	at org.gradle.internal.execution.steps.SkipEmptyWorkStep.lambda$execute$2(SkipEmptyWorkStep.java:78)
	at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:78)
	at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:34)
	at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:39)
	at org.gradle.internal.execution.steps.LoadExecutionStateStep.execute(LoadExecutionStateStep.java:40)
	at org.gradle.internal.execution.steps.LoadExecutionStateStep.execute(LoadExecutionStateStep.java:28)
	at org.gradle.internal.execution.impl.DefaultWorkExecutor.execute(DefaultWorkExecutor.java:33)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:187)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:179)
	at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:109)
	at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
	at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:62)
	at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
	at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
	at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:62)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$call$2(DefaultBuildOperationExecutor.java:76)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.callWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:54)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:76)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
	at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:41)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:372)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:359)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:352)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:338)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:127)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:191)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:182)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:124)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)

The project has about 70 modules.

Document how to ignore AARs

There are some AARs included in the project I tried using Licensee on (e.g. specified like this in my build.gradle: implementation(name:'my-lib-3.5.0', ext:'aar')), and the validation was failing because there wasn't a corresponding POM file included in the project:

Execution failed for task ':app:licensee'.
> Could not find my-lib-3.5.0-.pom (:my-lib-3.5.0:).
  Searched in the following locations:
      file:/Users/me/src/MyApp/app/libs/my-lib-3.5.0.pom

Through some trial and error, I was able to figure out that it could be ignored by configuring Licensee with ignoreDependencies('', 'my-lib-3.5.0'), but it wasn't obvious at first. Originally I tried ignoreDependencies('my-lib-3.5.0'), not realizing that I needed to specify the name as the artifactId, not the groupId.

I wonder if this could be documented, or if the error message could be improved to make it easier to figure this out?

Change license validation behavior to logical OR

https://github.com/facebook/rocksdb is licensed under Apache 2 as well as GPLv2.
https://repo.maven.apache.org/maven2/org/rocksdb/rocksdbjni/7.2.2/rocksdbjni-7.2.2.pom

<licenses>
  <license>
    <name>Apache License 2.0</name>
    <url>http://www.apache.org/licenses/LICENSE-2.0.html</url>
    <distribution>repo</distribution>
  </license>
  <license>
    <name>GNU General Public License, version 2</name>
    <url>http://www.gnu.org/licenses/gpl-2.0.html</url>
    <distribution>repo</distribution>
  </license>
</licenses>

repro:

plugins {
    kotlin("jvm") version "1.7.0-RC"
    id("app.cash.licensee") version "1.3.1"
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.rocksdb:rocksdbjni:7.2.2")
}

licensee {
    allow("Apache-2.0")
}

dual.zip

Feature Request: Support different license policies for different scopes/configs

It would be useful to be able to specify different license policies for different scopes/configurations.

e.g. A license is allowed if on the buildScript classpath, but not if it is in production code.
Also, a license might be allowed only in test and/or debug, but not allowed in release.

This might happen if the license has terms related to distribution. You might distribute your release artifact, but not the tests.

Support for applying plugin to root project

I have a project made up of many subprojects, and I'd like to apply Licensee to all of them.

At the moment, if I apply Licensee to the root project, I get an error like this:

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring root project '<project name redacted>'.
> 'app.cash.licensee' requires compatible language/platform plugin to be applied (root project)

I expected this to work and automatically apply the plugin to all subprojects.

On a related note, it would be great if Licensee supported configuring allow, allowUrl etc. at the root project level, rather than requiring these to be configured on each subproject. At the moment, I have one central set of allows that I apply to all subprojects. However, this then triggers a bunch of warnings that some of them are unused (not every project has every dependency), so it would be great if applying and configuring Licensee at the root project level then considered the usage of every project and only emitted warnings for allows that aren't used anywhere in any subproject.

Failure with Kotlin Multiplatform Projects with Java support

Steps to Reproduce

  1. Create a Kotlin Multiplatform application module
plugins {
    kotlin("multiplatform")
    id("application")
    id("app.cash.licensee")
}

kotlin {
    jvm {
        withJava()
    }
}
  1. Run the license task

Results

Actual

* What went wrong:
A problem occurred configuring project ':app'.
> Cannot add task 'licensee' as a task with that name already exists.

Expected

Task runs as expected

Notes

This is specifically what's triggering the failure:

    jvm {
        withJava()
    }

If I remove the withJava(), then it will succeed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.