From 082757ece1500833edc7854af8b0a14e296b18ca Mon Sep 17 00:00:00 2001 From: Matthew de Detrich Date: Sat, 15 Apr 2023 13:41:53 +0200 Subject: [PATCH] Support report generation for aggregate and all projects --- README.md | 4 ++ .../sbtlicensereport/SbtLicenseReport.scala | 34 ++++++++++++-- .../license/LicenseReport.scala | 4 +- .../aggregate-report/example.sbt | 45 +++++++++++++++++++ .../aggregate-report/project/plugins.sbt | 1 + .../dumpLicenseReport/aggregate-report/test | 5 +++ .../anyproject-report/example.sbt | 31 +++++++++++++ .../anyproject-report/project/plugins.sbt | 1 + .../dumpLicenseReport/anyproject-report/test | 5 +++ 9 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 src/sbt-test/dumpLicenseReport/aggregate-report/example.sbt create mode 100644 src/sbt-test/dumpLicenseReport/aggregate-report/project/plugins.sbt create mode 100644 src/sbt-test/dumpLicenseReport/aggregate-report/test create mode 100644 src/sbt-test/dumpLicenseReport/anyproject-report/example.sbt create mode 100644 src/sbt-test/dumpLicenseReport/anyproject-report/project/plugins.sbt create mode 100644 src/sbt-test/dumpLicenseReport/anyproject-report/test diff --git a/README.md b/README.md index 15e0623..90a1f4e 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,10 @@ Create a file in your project called `project/license.sbt` with the following co This dumps a report of all the licenses used in a project, with an attempt to organize them. These are dumped, by default, to the `target/license-reports` directory. +If you happen to be using a multi project sbt build, you can instead use `dumpLicenseReportAggregate` (which collects the results +from `aggregate` on the root project) or `dumpLicenseReportAnyProject` (which collects the results for all projects in the sbt build). +In either case the results will be merged into a single report file in a format that mirrors `dumpLicenseReport`. + ## Configuration The license report plugin can be configured to dump any number of reports, but the default report diff --git a/src/main/scala/sbtlicensereport/SbtLicenseReport.scala b/src/main/scala/sbtlicensereport/SbtLicenseReport.scala index b4b2993..8d5da34 100644 --- a/src/main/scala/sbtlicensereport/SbtLicenseReport.scala +++ b/src/main/scala/sbtlicensereport/SbtLicenseReport.scala @@ -21,16 +21,22 @@ object SbtLicenseReport extends AutoPlugin { def Csv = sbtlicensereport.license.Csv // Keys - val updateLicenses = taskKey[LicenseReport]("Construct a report of used licenses in a project.") + val updateLicenses = taskKey[LicenseReport]("Construct a report of used licenses in a build.") val licenseReportConfigurations = taskKey[Seq[LicenseReportConfiguration]]("Configuration for each license report we're generating.") val dumpLicenseReport = taskKey[File]("Dumps a report file of the license report (using the target language).") + val dumpLicenseReportAggregate = taskKey[File]( + "Dumps a report file against project aggregates of the license report (using the target language) and combines it into a single file." + ) + val dumpLicenseReportAnyProject = taskKey[File]( + "Dumps a report file against all projects of the license report (using the target language) and combines it into a single file." + ) val licenseReportDir = settingKey[File]("The location where we'll write the license reports.") val licenseReportStyleRules = settingKey[Option[String]]("The style rules for license report styling.") val licenseReportTitle = settingKey[String]("The name of the license report.") val licenseConfigurations = settingKey[Set[String]]("The ivy configurations we wish a report of.") val licenseSelection = settingKey[Seq[LicenseCategory]]( - "A priority-order list mechanism we can use to select licenses for projects that have more than one." + "A priority-order list mechanism we can use to select licenses for builds that have more than one." ) val licenseReportMakeHeader = settingKey[TargetLanguage => String]("A mechanism of generating the header for the license report file.") @@ -48,6 +54,14 @@ object SbtLicenseReport extends AutoPlugin { val autoImport = autoImportImpl import autoImport._ + private lazy val aggregateUpdateLicenses = Def.taskDyn { + updateLicenses.all(ScopeFilter(inAggregates(thisProjectRef.value))) + } + + private lazy val anyProjectUpdateLicenses = Def.taskDyn { + updateLicenses.all(ScopeFilter(inAnyProject)) + } + override def projectSettings: Seq[Setting[_]] = Seq( licenseSelection := LicenseCategory.all, @@ -95,7 +109,21 @@ object SbtLicenseReport extends AutoPlugin { val report = updateLicenses.value val dir = licenseReportDir.value for (config <- licenseReportConfigurations.value) - LicenseReport.dumpLicenseReport(report, config) + LicenseReport.dumpLicenseReport(report.licenses, config) + dir + }, + dumpLicenseReportAggregate := { + val reports = aggregateUpdateLicenses.value + val dir = licenseReportDir.value + for (config <- licenseReportConfigurations.value) + LicenseReport.dumpLicenseReport(reports.flatMap(_.licenses).distinct, config) + dir + }, + dumpLicenseReportAnyProject := { + val reports = anyProjectUpdateLicenses.value + val dir = licenseReportDir.value + for (config <- licenseReportConfigurations.value) + LicenseReport.dumpLicenseReport(reports.flatMap(_.licenses).distinct, config) dir } ) diff --git a/src/main/scala/sbtlicensereport/license/LicenseReport.scala b/src/main/scala/sbtlicensereport/license/LicenseReport.scala index 9776d4b..a72751c 100644 --- a/src/main/scala/sbtlicensereport/license/LicenseReport.scala +++ b/src/main/scala/sbtlicensereport/license/LicenseReport.scala @@ -34,9 +34,9 @@ object LicenseReport { } } - def dumpLicenseReport(report: LicenseReport, config: LicenseReportConfiguration): Unit = { + def dumpLicenseReport(reportLicenses: Seq[DepLicense], config: LicenseReportConfiguration): Unit = { import config._ - val ordered = report.licenses.filter(l => licenseFilter(l.license.category)) sortWith { + val ordered = reportLicenses.filter(l => licenseFilter(l.license.category)) sortWith { case (l, r) => if (l.license.category != r.license.category) l.license.category.name < r.license.category.name else { diff --git a/src/sbt-test/dumpLicenseReport/aggregate-report/example.sbt b/src/sbt-test/dumpLicenseReport/aggregate-report/example.sbt new file mode 100644 index 0000000..2b043c5 --- /dev/null +++ b/src/sbt-test/dumpLicenseReport/aggregate-report/example.sbt @@ -0,0 +1,45 @@ +name := "example" + +excludeDependencies in ThisBuild += "org.scala-lang" + +lazy val one = project.in(file("one")).settings( + List( + libraryDependencies += "com.fasterxml.jackson.core" % "jackson-databind" % "2.5.4", + libraryDependencies += "junit" % "junit" % "4.12" % "test" + ) +) + +lazy val two = project.in(file("two")).settings( + List( + libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.4.6" + ) +) + +// Deliberately excluded from project root aggregate so we can test that it doesn't get included +// in report +lazy val three = project.in(file("three")).settings( + List( + libraryDependencies += "com.google.guava" % "guava" % "31.1-jre" + ) +) + +lazy val root = project.in(file(".")).aggregate( + one, two +) + +TaskKey[Unit]("check") := { + val contents = sbt.IO.read(target.value / "license-reports" / "example-licenses.md") + if (!contents.contains("[The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [com.fasterxml.jackson.core # jackson-databind # 2.5.4](http://github.com/FasterXML/jackson)")) + sys.error("Expected report to contain jackson-databind with Apache license: " + contents) + if (!contents.contains("jackson-databind")) + sys.error("Expected report to contain jackson-databind: " + contents) + if (!contents.contains("logback-classic")) + sys.error("Expected report to contain logback-classic:" + contents) + if (contents.contains("guava")) + sys.error("Expected report to NOT contain guava:" + contents) + if (!contents.contains("[Eclipse Public License 1.0](http://www.eclipse.org/legal/epl-v10.html) | [junit # junit # 4.12](http://junit.org)")) + sys.error("Expected report to contain junit with EPL license: " + contents) + // Test whether exclusions are included. + if (contents.contains("scala-library")) + sys.error("Expected report to NOT contain scala-library: " + contents) +} diff --git a/src/sbt-test/dumpLicenseReport/aggregate-report/project/plugins.sbt b/src/sbt-test/dumpLicenseReport/aggregate-report/project/plugins.sbt new file mode 100644 index 0000000..9c089ab --- /dev/null +++ b/src/sbt-test/dumpLicenseReport/aggregate-report/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.github.sbt" % "sbt-license-report" % sys.props("plugin.version")) diff --git a/src/sbt-test/dumpLicenseReport/aggregate-report/test b/src/sbt-test/dumpLicenseReport/aggregate-report/test new file mode 100644 index 0000000..b8b2bfb --- /dev/null +++ b/src/sbt-test/dumpLicenseReport/aggregate-report/test @@ -0,0 +1,5 @@ +> dumpLicenseReportAggregate +$ exists target/license-reports/example-licenses.md +$ exists target/license-reports/example-licenses.html +$ exists target/license-reports/example-licenses.csv +> check diff --git a/src/sbt-test/dumpLicenseReport/anyproject-report/example.sbt b/src/sbt-test/dumpLicenseReport/anyproject-report/example.sbt new file mode 100644 index 0000000..8f3376c --- /dev/null +++ b/src/sbt-test/dumpLicenseReport/anyproject-report/example.sbt @@ -0,0 +1,31 @@ +name := "example" + +excludeDependencies in ThisBuild += "org.scala-lang" + +lazy val one = project.in(file("one")).settings( + List( + libraryDependencies += "com.fasterxml.jackson.core" % "jackson-databind" % "2.5.4", + libraryDependencies += "junit" % "junit" % "4.12" % "test" + ) +) + +lazy val two = project.in(file("two")).settings( + List( + libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.4.6" + ) +) + +TaskKey[Unit]("check") := { + val contents = sbt.IO.read(target.value / "license-reports" / "example-licenses.md") + if (!contents.contains("[The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) | [com.fasterxml.jackson.core # jackson-databind # 2.5.4](http://github.com/FasterXML/jackson)")) + sys.error("Expected report to contain jackson-databind with Apache license: " + contents) + if (!contents.contains("jackson-databind")) + sys.error("Expected report to contain jackson-databind: " + contents) + if (!contents.contains("logback-classic")) + sys.error("Expected report to contain logback-classic:" + contents) + if (!contents.contains("[Eclipse Public License 1.0](http://www.eclipse.org/legal/epl-v10.html) | [junit # junit # 4.12](http://junit.org)")) + sys.error("Expected report to contain junit with EPL license: " + contents) + // Test whether exclusions are included. + if (contents.contains("scala-library")) + sys.error("Expected report to NOT contain scala-library: " + contents) +} diff --git a/src/sbt-test/dumpLicenseReport/anyproject-report/project/plugins.sbt b/src/sbt-test/dumpLicenseReport/anyproject-report/project/plugins.sbt new file mode 100644 index 0000000..9c089ab --- /dev/null +++ b/src/sbt-test/dumpLicenseReport/anyproject-report/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.github.sbt" % "sbt-license-report" % sys.props("plugin.version")) diff --git a/src/sbt-test/dumpLicenseReport/anyproject-report/test b/src/sbt-test/dumpLicenseReport/anyproject-report/test new file mode 100644 index 0000000..787e58b --- /dev/null +++ b/src/sbt-test/dumpLicenseReport/anyproject-report/test @@ -0,0 +1,5 @@ +> dumpLicenseReportAnyProject +$ exists target/license-reports/example-licenses.md +$ exists target/license-reports/example-licenses.html +$ exists target/license-reports/example-licenses.csv +> check