From 20cc14f25881c66fe13b62a80280188e8d018946 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Fri, 9 Jun 2023 12:30:28 +0600 Subject: [PATCH 1/3] update gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 854602ef..5705dbab 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ .idea /vendor + +**/.DS_Store From df7207f32484fbc0d1039557a0a47be951cd9d39 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Fri, 9 Jun 2023 12:32:47 +0600 Subject: [PATCH 2/3] feat(java): capture licenses from pom.xml --- pkg/java/pom/artifact.go | 4 ++- pkg/java/pom/parse.go | 20 ++++++++----- pkg/java/pom/parse_test.go | 30 +++++++++++++++++++ pkg/java/pom/pom.go | 19 ++++++++++-- .../pom/testdata/multiply-licenses/pom.xml | 23 ++++++++++++++ 5 files changed, 85 insertions(+), 11 deletions(-) create mode 100644 pkg/java/pom/testdata/multiply-licenses/pom.xml diff --git a/pkg/java/pom/artifact.go b/pkg/java/pom/artifact.go index 41338143..11ee2522 100644 --- a/pkg/java/pom/artifact.go +++ b/pkg/java/pom/artifact.go @@ -18,6 +18,7 @@ type artifact struct { GroupID string ArtifactID string Version version + License string Exclusions map[string]struct{} @@ -25,11 +26,12 @@ type artifact struct { Root bool } -func newArtifact(groupID, artifactID, version string, props map[string]string) artifact { +func newArtifact(groupID, artifactID, version, license string, props map[string]string) artifact { return artifact{ GroupID: evaluateVariable(groupID, props, nil), ArtifactID: evaluateVariable(artifactID, props, nil), Version: newVersion(evaluateVariable(version, props, nil)), + License: license, } } diff --git a/pkg/java/pom/parse.go b/pkg/java/pom/parse.go index ae74f500..04bf9759 100644 --- a/pkg/java/pom/parse.go +++ b/pkg/java/pom/parse.go @@ -114,7 +114,7 @@ func (p *parser) parseRoot(root artifact) ([]types.Library, []types.Dependency, libs []types.Library deps []types.Dependency rootDepManagement []pomDependency - uniqArtifacts = map[string]version{} + uniqArtifacts = map[string]artifact{} ) // Iterate direct and transitive dependencies @@ -136,8 +136,8 @@ func (p *parser) parseRoot(root artifact) ([]types.Library, []types.Dependency, } // For soft requirements, skip dependency resolution that has already been resolved. - if v, ok := uniqArtifacts[art.Name()]; ok { - if !v.shouldOverride(art.Version) { + if uniqueArt, ok := uniqArtifacts[art.Name()]; ok { + if !uniqueArt.Version.shouldOverride(art.Version) { continue } } @@ -169,15 +169,19 @@ func (p *parser) parseRoot(root artifact) ([]types.Library, []types.Dependency, // Offline mode may be missing some fields. if !art.IsEmpty() { // Override the version - uniqArtifacts[art.Name()] = art.Version + uniqArtifacts[art.Name()] = artifact{ + Version: art.Version, + License: art.License, + } } } // Convert to []types.Library - for name, ver := range uniqArtifacts { + for name, art := range uniqArtifacts { libs = append(libs, types.Library{ Name: name, - Version: ver.String(), + Version: art.Version.String(), + License: art.License, }) } @@ -336,7 +340,7 @@ func (p *parser) resolveDepManagement(props map[string]string, depManagement []p // Managed dependencies with a scope of "import" should be processed after other managed dependencies. // cf. https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#importing-dependencies for _, imp := range imports { - art := newArtifact(imp.GroupID, imp.ArtifactID, imp.Version, props) + art := newArtifact(imp.GroupID, imp.ArtifactID, imp.Version, "", props) result, err := p.resolve(art, nil) if err != nil { continue @@ -386,7 +390,7 @@ func excludeDep(exclusions map[string]struct{}, art artifact) bool { func (p *parser) parseParent(currentPath string, parent pomParent) (analysisResult, error) { // Pass nil properties so that variables in are not evaluated. - target := newArtifact(parent.GroupId, parent.ArtifactId, parent.Version, nil) + target := newArtifact(parent.GroupId, parent.ArtifactId, parent.Version, "", nil) if target.IsEmpty() { return analysisResult{}, nil } diff --git a/pkg/java/pom/parse_test.go b/pkg/java/pom/parse_test.go index 521e3c14..e6fcce57 100644 --- a/pkg/java/pom/parse_test.go +++ b/pkg/java/pom/parse_test.go @@ -32,6 +32,7 @@ func TestPom_Parse(t *testing.T) { { Name: "com.example:happy", Version: "1.0.0", + License: "Apache 2.0", }, { Name: "org.example:example-api", @@ -47,6 +48,7 @@ func TestPom_Parse(t *testing.T) { { Name: "com.example:happy", Version: "1.0.0", + License: "Apache 2.0", }, { Name: "org.example:example-api", @@ -74,6 +76,7 @@ func TestPom_Parse(t *testing.T) { { Name: "com.example:child", Version: "1.0.0", + License: "Apache 2.0", }, { Name: "org.example:example-api", @@ -138,6 +141,7 @@ func TestPom_Parse(t *testing.T) { { Name: "com.example:child", Version: "1.0.0-SNAPSHOT", + License: "Apache 2.0", }, { Name: "org.example:example-api", @@ -153,6 +157,7 @@ func TestPom_Parse(t *testing.T) { { Name: "com.example:child", Version: "3.0.0", + License: "Apache 2.0", }, { Name: "org.example:example-api", @@ -168,6 +173,7 @@ func TestPom_Parse(t *testing.T) { { Name: "com.example:base", Version: "4.0.0", + License: "Apache 2.0", }, { Name: "org.example:example-api", @@ -187,6 +193,7 @@ func TestPom_Parse(t *testing.T) { { Name: "com.example:child", Version: "1.0.0", + License: "Apache 2.0", }, { Name: "org.example:example-api", @@ -202,6 +209,7 @@ func TestPom_Parse(t *testing.T) { { Name: "org.example:child", Version: "1.0.0", + License: "Apache 2.0", }, { Name: "org.example:example-api", @@ -217,6 +225,7 @@ func TestPom_Parse(t *testing.T) { { Name: "com.example:soft", Version: "1.0.0", + License: "Apache 2.0", }, { Name: "org.example:example-api", @@ -259,6 +268,7 @@ func TestPom_Parse(t *testing.T) { { Name: "com.example:hard", Version: "1.0.0", + License: "Apache 2.0", }, { Name: "org.example:example-api", @@ -278,6 +288,7 @@ func TestPom_Parse(t *testing.T) { { Name: "com.example:hard", Version: "1.0.0", + License: "Apache 2.0", }, }, }, @@ -289,6 +300,7 @@ func TestPom_Parse(t *testing.T) { { Name: "com.example:import", Version: "2.0.0", + License: "Apache 2.0", }, { Name: "org.example:example-api", @@ -304,6 +316,7 @@ func TestPom_Parse(t *testing.T) { { Name: "com.example:import", Version: "2.0.0", + License: "Apache 2.0", }, { Name: "org.example:example-api", @@ -361,10 +374,12 @@ func TestPom_Parse(t *testing.T) { { Name: "com.example:aggregation", Version: "1.0.0", + License: "Apache 2.0", }, { Name: "com.example:module", Version: "1.1.1", + License: "Apache 2.0", }, { Name: "org.example:example-api", @@ -457,6 +472,7 @@ func TestPom_Parse(t *testing.T) { { Name: "com.example:no-parent", Version: "1.0-SNAPSHOT", + License: "Apache 2.0", }, { Name: "org.example:example-api", @@ -472,6 +488,7 @@ func TestPom_Parse(t *testing.T) { { Name: "com.example:not-found-dependency", Version: "1.0.0", + License: "Apache 2.0", }, { Name: "org.example:example-not-found", @@ -487,6 +504,19 @@ func TestPom_Parse(t *testing.T) { { Name: "com.example:aggregation", Version: "1.0.0", + License: "Apache 2.0", + }, + }, + }, + { + name: "multiply licenses", + inputFile: filepath.Join("testdata", "multiply-licenses", "pom.xml"), + local: true, + want: []types.Library{ + { + Name: "com.example:multiply-licenses", + Version: "1.0.0", + License: "MIT, Apache 2.0", }, }, }, diff --git a/pkg/java/pom/pom.go b/pkg/java/pom/pom.go index 2a130fa1..848da068 100644 --- a/pkg/java/pom/pom.go +++ b/pkg/java/pom/pom.go @@ -91,7 +91,17 @@ func (p pom) listProperties(val reflect.Value) map[string]string { } func (p pom) artifact() artifact { - return newArtifact(p.content.GroupId, p.content.ArtifactId, p.content.Version, p.content.Properties) + return newArtifact(p.content.GroupId, p.content.ArtifactId, p.content.Version, p.joinLicenses(), p.content.Properties) +} + +func (p pom) joinLicenses() string { + var licenses []string + for _, license := range p.content.Licenses.License { + if license.Name != "" { + licenses = append(licenses, license.Name) + } + } + return strings.Join(licenses, ", ") } func (p pom) repositories() []string { @@ -109,7 +119,12 @@ type pomXML struct { GroupId string `xml:"groupId"` ArtifactId string `xml:"artifactId"` Version string `xml:"version"` - Modules struct { + Licenses struct { + License []struct { + Name string `xml:"name"` + } `xml:"license"` + } `xml:"licenses"` + Modules struct { Text string `xml:",chardata"` Module []string `xml:"module"` } `xml:"modules"` diff --git a/pkg/java/pom/testdata/multiply-licenses/pom.xml b/pkg/java/pom/testdata/multiply-licenses/pom.xml new file mode 100644 index 00000000..1f9609e6 --- /dev/null +++ b/pkg/java/pom/testdata/multiply-licenses/pom.xml @@ -0,0 +1,23 @@ + + 4.0.0 + + com.example + multiply-licenses + 1.0.0 + + multiply-licenses + Example + + + + MIT + All source code is under the MIT license. + + + Apache 2.0 + http://www.apache.org/licenses/LICENSE-2.0.html + repo + + + From 13bd24f44f453dfdced0c4ceaa1fb1910ff3b7db Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Tue, 13 Jun 2023 13:30:45 +0600 Subject: [PATCH 3/3] update test --- pkg/java/pom/parse_test.go | 4 ++-- pkg/java/pom/testdata/happy/pom.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/java/pom/parse_test.go b/pkg/java/pom/parse_test.go index e6fcce57..afe65f2e 100644 --- a/pkg/java/pom/parse_test.go +++ b/pkg/java/pom/parse_test.go @@ -32,7 +32,7 @@ func TestPom_Parse(t *testing.T) { { Name: "com.example:happy", Version: "1.0.0", - License: "Apache 2.0", + License: "BSD-3-Clause", }, { Name: "org.example:example-api", @@ -48,7 +48,7 @@ func TestPom_Parse(t *testing.T) { { Name: "com.example:happy", Version: "1.0.0", - License: "Apache 2.0", + License: "BSD-3-Clause", }, { Name: "org.example:example-api", diff --git a/pkg/java/pom/testdata/happy/pom.xml b/pkg/java/pom/testdata/happy/pom.xml index 36e9f2a3..3da117ee 100644 --- a/pkg/java/pom/testdata/happy/pom.xml +++ b/pkg/java/pom/testdata/happy/pom.xml @@ -11,8 +11,8 @@ - Apache 2.0 - http://www.apache.org/licenses/LICENSE-2.0.html + BSD-3-Clause + https://opensource.org/licenses/BSD-3-Clause repo