Skip to content

Commit

Permalink
Merge pull request #287 from balrok/feature/resolve-bom-license
Browse files Browse the repository at this point in the history
Fix license resolution for pom-dependencies (usually "bom"-packages)
  • Loading branch information
jk1 authored Apr 12, 2024
2 parents e188ed0 + c3d9a18 commit 135292c
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@ import com.github.jk1.license.task.ReportTask
import org.gradle.api.Project
import org.gradle.api.artifacts.ResolvedArtifact
import org.gradle.api.artifacts.ResolvedDependency
import org.gradle.api.artifacts.result.ResolvedArtifactResult
import org.gradle.api.internal.artifacts.query.DefaultArtifactResolutionQuery
import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
import org.gradle.maven.MavenModule
import org.gradle.maven.MavenPomArtifact

interface ModuleReader {
ModuleData read(Project project, ResolvedDependency dependency)
Expand All @@ -48,7 +52,7 @@ class ModuleReaderImpl implements ModuleReader {
dependency.moduleArtifacts.each { ResolvedArtifact artifact ->
LOGGER.info("Processing artifact: $artifact ($artifact.file)")
moduleData.hasArtifactFile = artifact.file.exists()
if (moduleData.hasArtifactFile){
if (moduleData.hasArtifactFile) {
def pom = pomReader.readPomData(project, artifact)
def manifest = manifestReader.readManifestData(artifact)
def licenseFile = filesReader.read(artifact)
Expand All @@ -60,8 +64,39 @@ class ModuleReaderImpl implements ModuleReader {
LOGGER.info("Skipping artifact file $artifact.file as it does not exist")
}
}
if (dependency.moduleArtifacts.isEmpty()) {
def extraPomResults = resolvePom(project, dependency)
extraPomResults.each { ResolvedArtifactResult artifact ->
LOGGER.info("Processing artifact: $artifact ($artifact.file)")
if (artifact.file.exists()) {
def pom = pomReader.readPomData(artifact)
if (pom) moduleData.poms << pom
} else {
LOGGER.info("Skipping artifact file $artifact.file as it does not exist")
}
}
}
return moduleData
}

private static Collection<ResolvedArtifactResult> resolvePom(Project project, ResolvedDependency dependency) {
try {
DefaultArtifactResolutionQuery resolutionQuery = (DefaultArtifactResolutionQuery) project.dependencies.createArtifactResolutionQuery()
return resolutionQuery
.forModule(dependency.moduleGroup, dependency.moduleName, dependency.moduleVersion)
.withArtifacts(MavenModule, MavenPomArtifact)
.execute()
.resolvedComponents
.collectMany {
it.getArtifacts(MavenPomArtifact)
.findAll { it instanceof ResolvedArtifactResult }
.collect { (ResolvedArtifactResult) it }
}
} catch (Exception e) {
project.logger.info("Failed to resolve the pom artifact", e)
return[]
}
}
}

class CachedModuleReader implements ModuleReader {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import groovy.xml.XmlSlurper
import groovy.xml.slurpersupport.GPathResult
import org.gradle.api.Project
import org.gradle.api.artifacts.ResolvedArtifact
import org.gradle.api.artifacts.result.ResolvedArtifactResult
import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
import org.xml.sax.SAXException
Expand Down Expand Up @@ -73,6 +74,11 @@ class PomReader {
}
}

PomData readPomData(ResolvedArtifactResult artifact) {
GPathResult pomContent = findAndSlurpPom(artifact.file)
return readPomFile(pomContent)
}

private GPathResult findAndSlurpPom(File toSlurp) {
if (toSlurp.name == "pom.xml") {
LOGGER.debug("Slurping pom from pom.xml file: $toSlurp")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Copyright 2018 Evgeny Naumenko <jk.vc@mail.ru>
*
* 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.
*/
package com.github.jk1.license.reader

import com.github.jk1.license.AbstractGradleRunnerFunctionalSpec
import org.gradle.testkit.runner.TaskOutcome

/**
* Dependencies, which are just available as .pom (usually "-bom"-modules) require a slightly different strategy, because
* gradle will not put the artifacts inside ResolvedDependency.
*/
class PomDependencyResolutionFuncSpec extends AbstractGradleRunnerFunctionalSpec {

def setup() {
settingsGradle = new File(testProjectDir, "settings.gradle")

buildFile << """
plugins {
id 'com.github.jk1.dependency-license-report'
id 'java'
}
repositories {
mavenCentral()
}
"""
}

def "report task resolves bom license"() {
setup:
buildFile << generateBuildWith(
"""
implementation platform("com.fasterxml.jackson:jackson-bom:2.12.3")
""".trim()
)

when:
def runResult = runGradleBuild()

def resultFileGPath = jsonSlurper.parse(rawJsonFile)
removeDevelopers(resultFileGPath)
def configurationsGPath = resultFileGPath.configurations
def configurationsString = prettyPrintJson(configurationsGPath)

then:
runResult.task(":generateLicenseReport").outcome == TaskOutcome.SUCCESS
configurationsString == """[
{
"dependencies": [
{
"group": "com.fasterxml.jackson",
"manifests": [
],
"hasArtifactFile": false,
"version": "2.12.3",
"poms": [
{
"inceptionYear": "",
"projectUrl": "https://github.com/FasterXML/jackson-bom",
"description": "Bill of Materials pom for getting full, complete set of compatible versions\\nof Jackson components maintained by FasterXML.com\\n ",
"name": "Jackson BOM",
"organization": {
"url": "http://fasterxml.com/",
"name": "FasterXML"
},
"licenses": [
{
"url": "http://www.apache.org/licenses/LICENSE-2.0.txt",
"name": "Apache License, Version 2.0"
}
]
}
],
"licenseFiles": [
],
"empty": false,
"name": "jackson-bom"
}
],
"name": "runtimeClasspath"
}
]"""
}

private def generateBuildWith(String dependencies) {
"""
import com.github.jk1.license.render.*
dependencies {
$dependencies
}
licenseReport {
outputDir = "${fixPathForBuildFile(outputDir.absolutePath)}"
renderers = [new com.github.jk1.license.render.RawProjectDataJsonRenderer()]
configurations = ["runtimeClasspath"]
}
"""
}

static void removeDevelopers(Map rawFile) {
rawFile.configurations*.dependencies.flatten().poms.flatten().each { it.remove("developers") }
}
}

0 comments on commit 135292c

Please sign in to comment.