jk1 / Gradle-License-Report

A plugin for generating reports about the licenses of third party software using Gradle
Other
322 stars 97 forks source link

Licenses from license files are not considered in HTML reports #290

Open Vampire opened 5 months ago

Vampire commented 5 months ago

Neither the simple nor the inventory html report renderer print out the licenses found in a license file. If you for example have in the project-licenses-for-check-license-task.json file

{
  "moduleName": "org.eclipse.platform:org.eclipse.osgi",
  "moduleVersion": "3.19.0",
  "moduleUrls": [
    "http://www.eclipse.org",
    "https://projects.eclipse.org/projects/eclipse.equinox"
  ],
  "moduleLicenses": [
    {
      "moduleLicense": "Apache License, Version 2.0",
      "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
    },
    {
      "moduleLicense": "Eclipse Public License - v 2.0",
      "moduleLicenseUrl": "https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt"
    }
  ]
}

where the EPL was found in the POM and the ASLv2 was found in about.html license file,

The simple HTML report just shows: image

The inventory HTML report also just shows: image

The ASLv2 is nowhere mentioned in those reports for this dependency.

Vampire commented 5 months ago

This of course also means that the checkLicense task is operating on different information than is shown in the HTML reports and might accept a library like the shown for having ASLv2 while the HTML report only shows it in the EPLv2 category.

balrok commented 5 months ago

I have a PR open: #297 which should fix the issue. I think it was not the problem, that the License came from a license file, but that the plugin currently isn't handling multiple licenses so well (checkLicense, and printing reports)

Vampire commented 5 months ago

That does not really fix the issue, as this issue is about missing the information in the report. Multiple licenses handling is sub-optimal yes, but also your PR only partly fixes it. Mutliple licenses can for example mean that a consumer can choose which license to use, or that some parts are under one license and some parts under another license and this can be different from dependency to dependency.

Vampire commented 5 months ago

Here a consumer-side work-around that "fixes" the inventory HTML report in Kotlin:

class EnhancedInventoryHtmlReportRenderer : InventoryHtmlReportRenderer() {
    override fun buildLicenseInventory(data: ProjectData): Map<String, List<ModuleData>> {
        val inventory = super.buildLicenseInventory(data)

        inventory
            .values
            .flatten()
            .distinct()
            .forEach { moduleData ->
                moduleData
                    .licenseFiles
                    .flatMap { it.fileDetails }
                    .filter { it.license != null }
                    .forEach {
                        val moduleDatas = inventory.computeIfAbsent(it.license) {
                            mutableListOf()
                        }

                        if (!moduleDatas.contains(moduleData)) {
                            moduleDatas.add(moduleData)
                        }
                    }
            }

        return inventory
    }

    override fun printDependencyLicenseFiles(licenseFiles: TreeSet<LicenseFileData>) {
        licenseFiles
            .flatMap { it.fileDetails }
            .groupBy { it.file }
            .forEach { (file, details) ->
                val embeddedLicenses = details.joinToString(separator = "<br>") {
                    when {
                        it.license == null -> "No license recognized"
                        it.licenseUrl == null -> it.license
                        maybeLicenseUrl(it.licenseUrl) -> "${it.license} - ${link(it.licenseUrl, it.licenseUrl)}"
                        else -> "${it.license} - ${section("License", it.licenseUrl)}"
                    }
                }
                output.appendText(section("Embedded license file ${link(file, file)}", embeddedLicenses))
            }
    }

    fun section(label: String, value: String) = """
        <label>$label</label>
        <div class='dependency-value'>$value</div>
    """.trimIndent()

    fun link(name: String, url: String) = "<a href='$url'>$name</a>"
}