Skip to content

Latest commit

 

History

History
510 lines (416 loc) · 19.6 KB

File metadata and controls

510 lines (416 loc) · 19.6 KB

Gradle License Plugin

License Maven Gradle Plugin Portal Build Twitter Follow

This plugin provides a task to generate a HTML license report based on the configuration. (eg. licenseDebugReport for all debug dependencies in an Android project).

Applying this to an Android or Java project will generate the license reports in <project>/build/reports/licenses/, named after the task that produced them - licenseReport.html for a Java project, licenseDebugReport.html for an Android debug variant, and so on. CSV, HTML, JSON and text reports are generated by default.

Also, for Android projects the reports are copied into the asset directory of the variant that produced them - <project>/src/debug/assets/, <project>/src/release/assets/ and so on - and it is only there that they are named open_source_licenses.<ext>. Every variant gets its own, so a debug build cannot ship a release build's report.

Compatibility Matrix

Plugin Version Minimum Gradle Version Minimum AGP Version
<= 0.9.4 <= 7.0.2 3.6.4+
0.9.5 7.0.2 3.6.4+
0.9.6 7.1.3 3.6.4+
0.9.7 7.2.2 3.6.4+
0.9.8 7.2.2 3.6.4+
0.9.9 8.2 8.0.0+
0.9.91 8.2 8.0.0+

Note: 0.9.9+ requires JDK 17+. AGP 9.x additionally requires a newer Gradle than the minimum above, and how much newer depends on the AGP version rather than being a single number - AGP 9.0 needs Gradle 9.1+ and AGP 9.2 needs Gradle 9.5+ (both are AGP requirements, not this plugin's).

Download

Release:

with plugins { }
plugins {
  id("com.jaredsburrows.license") version "0.9.91"
}
with buildscript { }
buildscript {
  repositories {
    mavenCentral()
    google() // For Android projects
  }

  dependencies {
    classpath("com.jaredsburrows:gradle-license-plugin:0.9.91")
  }
}

apply(plugin = "com.android.application") // or "java-library"
apply(plugin = "com.jaredsburrows.license")

Release versions are available in the Sonatype's release repository and here.

Snapshot:

with plugins { }
plugins {
  id("com.jaredsburrows.license") version "0.10.0-SNAPSHOT"
}
with buildscript { }
buildscript {
  repositories {
    maven { url = uri("https://central.sonatype.com/repository/maven-snapshots/") }
    google() // For Android projects
  }

  dependencies {
    classpath("com.jaredsburrows:gradle-license-plugin:0.10.0-SNAPSHOT")
  }
}

apply(plugin = "com.android.application") // or "java-library"
apply(plugin = "com.jaredsburrows.license")

Snapshot versions are available in the Central Portal snapshots repository.

Tasks

  • licenseReport for Java and Kotlin JVM
  • license${variant}Report for Android
  • license${target}Report for Kotlin Multiplatform

Generates a report of all the open source licenses. (eg. licenseDebugReport for all debug dependencies in an Android project).

An Android project gets one task per variant, plus one for each of the variant's test components - licenseDebugReport, licenseReleaseReport, licenseDebugUnitTestReport and so on.

A Kotlin Multiplatform project gets one task per target - licenseJvmReport, licenseJsReport, licenseLinuxX64Report. The common (metadata) target resolves no dependencies of its own and is skipped. A multiplatform module that also applies an Android plugin gets both: its android target is reported per variant by the Android tasks above, and every other target gets its own task. For a module using AGP's multiplatform library plugin that is licenseAndroidMainReport.

Example build.gradle.kts:

dependencies {
  implementation("com.android.support:design:26.1.0")
  implementation("pl.droidsonroids.gif:android-gif-drawable:1.2.3")
  implementation("wsdl4j:wsdl4j:1.5.1") // Very old library with no license info available
}

Example Outputs:

CSV Example (full):
project,description,version,developers,url,year,licenses,license urls,dependency
Android GIF Drawable Library,Views and Drawable for displaying animated GIFs for Android,1.2.3,Karol Wrótniak,https://github.com/koral--/android-gif-drawable,null,The MIT License,http://opensource.org/licenses/MIT,pl.droidsonroids.gif:android-gif-drawable:1.2.3
design,null,26.1.0,null,null,null,The Apache Software License,http://www.apache.org/licenses/LICENSE-2.0.txt,com.android.support:design:26.1.0
HTML Example (license descriptions are minimized):
<!DOCTYPE html>
<html lang="en">
<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <style>body {
    font-family: sans-serif
  }

  pre {
    background-color: #eeeeee;
    padding: 1em;
    white-space: pre-wrap;
    word-break: break-word;
    display: inline-block
  }</style>
  <title>Open source licenses</title>
</head>
<body>
<h3>Notice for packages:</h3>
<ul>
  <li><a href="#1934118923">design</a>
    <dl>
      <dt>Copyright &copy; 20xx The original author or authors</dt>
      <dd></dd>
    </dl>
  </li>
</ul>
<pre id="1934118923">apache-2.0.txt here</pre>
<br>
<hr>
<ul>
  <li><a href="#1783810846">Android GIF Drawable Library</a>
    <dl>
      <dt>Copyright &copy; 20xx Karol WrXXtniak</dt>
      <dd></dd>
    </dl>
  </li>
</ul>
<pre id="1783810846">apache-2.0.txt here</pre>
<br>
<hr>
</body>
</html>

Note, if no license information is found in the POM for a project, "No License Found" will be used. Those will be listed first. Other missing information is provided as default values that can be corrected from other sources. Projects are grouped by license name and the license text is only provided once. Projects with multiple licenses are grouped as if those licenses were a single combined license.

JSON Example (full):
[
  {
    "project": "Android GIF Drawable Library",
    "description": "Views and Drawable for displaying animated GIFs for Android",
    "version": "1.2.3",
    "developers": [
      "Karol Wr\\u00c3\\u00b3tniak"
    ],
    "url": "https://github.com/koral--/android-gif-drawable",
    "year": null,
    "licenses": [
      {
        "license": "The MIT License",
        "license_url": "http://opensource.org/licenses/MIT"
      }
    ],
    "dependency": "pl.droidsonroids.gif:android-gif-drawable:1.2.3"
  },
  {
    "project": "design",
    "description": null,
    "version": "26.1.0",
    "developers": [],
    "url": null,
    "year": null,
    "licenses": [
      {
        "license": "The Apache Software License",
        "license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
      }
    ],
    "dependency": "com.android.support:design:26.1.0"
  }
]

Note, if no license information is found for a component, the licenses element in the JSON output will be an empty array.

Full JSON Example (full):

Each license text is stored once under license_texts and referenced by license_key, so a report covering dozens of dependencies that share a handful of licenses stays small.

{
  "license_texts": {
    "apache-2.0": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/ ...",
    "mit": "MIT License\n\nCopyright (c) [year] [fullname]\n\nPermission is hereby granted, free of charge, ..."
  },
  "dependencies": [
    {
      "project": "Android GIF Drawable Library",
      "description": "Views and Drawable for displaying animated GIFs for Android",
      "version": "1.2.3",
      "developers": [
        "Karol Wr\\u00c3\\u00b3tniak"
      ],
      "url": "https://github.com/koral--/android-gif-drawable",
      "year": null,
      "licenses": [
        {
          "license": "The MIT License",
          "license_url": "http://opensource.org/licenses/MIT",
          "license_key": "mit"
        }
      ],
      "dependency": "pl.droidsonroids.gif:android-gif-drawable:1.2.3"
    },
    {
      "project": "design",
      "description": null,
      "version": "26.1.0",
      "developers": [],
      "url": null,
      "year": null,
      "licenses": [
        {
          "license": "The Apache Software License",
          "license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt",
          "license_key": "apache-2.0"
        }
      ],
      "dependency": "com.android.support:design:26.1.0"
    }
  ]
}

Note, license_key is null for licenses that are not bundled with the plugin - license and license_url always hold what the POM declared, so use those for the ones without a text.

Text Example (full):
Notice for packages


Android GIF Drawable Library (1.2.3) - The MIT License
Views and Drawable for displaying animated GIFs for Android
https://github.com/koral--/android-gif-drawable

design (26.1.0) - The Apache Software License

Configuration

The plugin can be configured to generate specific reports and automatically copy the reports to the assets directory (Android projects only). The default behaviours are:

  • Java projects: Generate CSV, HTML, JSON and text reports.
  • Android projects: Generate CSV, HTML, JSON and text reports, and copy the HTML report to the assets directory.

The plugin can be configured to ignore licenses for certain artifact patterns. The default is that nothing is ignored.

To override the defaults, add the licenseReport configuration closure to the build script.

plugins {
  id("com.jaredsburrows.license")
}

licenseReport {
  // Generate reports
  generateCsvReport = false
  generateHtmlReport = true
  generateJsonReport = false
  generateJsonFullReport = false
  generateTextReport = false

  // Copy reports - These options are ignored for Java projects
  copyCsvReportToAssets = false
  copyHtmlReportToAssets = true
  copyJsonReportToAssets = false
  copyJsonFullReportToAssets = false
  copyTextReportToAssets = false
  useVariantSpecificAssetDirs = true

  // Ignore licenses for certain artifact patterns
  ignoredPatterns = setOf()

  // Show versions in the report - default is false
  showVersions = true
}

Note: the licenseReport { } accessor exists only when the plugin is applied through plugins { }. If you applied it the buildscript { } way with apply(plugin = ...), configure it by type instead:

import com.jaredsburrows.license.LicenseReportExtension

configure<LicenseReportExtension> {
  generateCsvReport = false
}

The copyHtmlReportToAssets option in the above example would have no effect since the HTML report is disabled.

The generateJsonFullReport option generates open_source_licenses.full.json, the JSON report plus the full text of every license the plugin knows about. It is meant for applications that render their own license screen instead of displaying the generated HTML report, so the license text ships with the app and no network call or WebView is needed. It is disabled by default because the license texts make the report larger.

Every license text is stored once under the top level license_texts, keyed by license id, and each dependency references it with license_key. Dependencies overwhelmingly share a handful of licenses, so this keeps the report - and the memory an app needs to parse it - roughly an order of magnitude smaller than repeating the text per dependency.

The useVariantSpecificAssetDirs copies the reports into the source set asset directory of the variant that produced them, which is the default. For example, licensePaidProductionReleaseReport puts its reports in src/paidProductionRelease/assets. Each variant therefore keeps its own report, and the path inside the built APK or AAR is unchanged - still assets/open_source_licenses.<ext>.

Setting it to false sends every variant's report to src/main/assets instead. That is a single shared file, so whichever report task runs last wins and a build can ship another variant's licenses (#226). It was the default before 0.10.0; only set it if you have one variant, or you are relying on the old path and accept that risk.

The ignoredPatterns allows for ignoring artifact patterns. A pattern can cover whole segments of the group:artifact:version coordinate (a group, an artifact, a version, or any combination), but it only matches along segment boundaries: ignoring com.some.group:some.name does not ignore com.some.group:some.name-extra. Both : and . count as boundaries, so a pattern may also cover dot-separated pieces of a group or version - 1.2 still ignores version 1.2.3.

plugins {
  id("com.jaredsburrows.license")
}

licenseReport {
  ignoredPatterns = setOf("com.some.group") // Ignores all artifacts of the given group
  ignoredPatterns = setOf("com.some.group:some.name") // Ignores the given artifact regardless of version
  ignoredPatterns = setOf("com.some.group:some.name:1.2.3") // Ignores the given artifact with the given version
}

Usage Example

For complete, buildable examples - including license screens built from the JSON reports instead of a WebView - see Test Apps.

Create an open source dialog

import android.webkit.WebView
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.viewinterop.AndroidView

@Composable
fun OpenSourceLicensesDialog(onDismiss: () -> Unit) {
  AlertDialog(
    onDismissRequest = onDismiss,
    title = { Text("Open Source Licenses") },
    text = {
      AndroidView(
        factory = { context ->
          WebView(context).apply {
            loadUrl("file:///android_asset/open_source_licenses.html")
          }
        },
      )
    },
    confirmButton = {
      TextButton(onClick = onDismiss) {
        Text("OK")
      }
    },
  )
}

How to use it

var showLicenses by remember { mutableStateOf(false) }

Button(onClick = { showLicenses = true }) {
  Text("Licenses")
}

if (showLicenses) {
  OpenSourceLicensesDialog(onDismiss = { showLicenses = false })
}

Examples - from test-apps

Type License Screen License Details
HTML 01-html-licenses
JSON 03-json-license-list
JSON Full 05-fulljson-library-list 06-fulljson-license-apache

Test Apps

test-apps/ holds three Jetpack Compose applications that apply the plugin from this repository (through an included build) and show a different way of surfacing the licenses:

Module Report Screen
test-app-compose-html open_source_licenses.html The generated HTML full screen in a WebView
test-app-compose-json open_source_licenses.json A Compose list linking out to each license URL
test-app-compose-fulljson open_source_licenses.full.json A custom Compose license screen rendering the bundled license text offline

Each app generates its report and copies it into its variant source set as part of assemble, so building them exercises the plugin end to end:

./gradlew -p test-apps build

License

Copyright (C) 2016 Jared Burrows

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.