diff --git a/pkg/lockfile/fixtures/maven/with-dependency-management-and-duplicates.xml b/pkg/lockfile/fixtures/maven/with-dependency-management-and-duplicates.xml new file mode 100644 index 00000000..b4d1c76b --- /dev/null +++ b/pkg/lockfile/fixtures/maven/with-dependency-management-and-duplicates.xml @@ -0,0 +1,35 @@ + + + 3.0 + + + + + com.fasterxml.jackson.core + jackson-annotations + 2.13.3 + + + + com.fasterxml.jackson.core + jackson-databind + 2.13.0 + + + + + + + com.fasterxml.jackson.core + jackson-databind + 2.13.4 + + + + com.fasterxml.jackson.core + jackson-databind + 2.13.4.1 + + + + diff --git a/pkg/lockfile/fixtures/maven/with-duplicate-packages.xml b/pkg/lockfile/fixtures/maven/with-duplicate-packages.xml new file mode 100644 index 00000000..a77baf0f --- /dev/null +++ b/pkg/lockfile/fixtures/maven/with-duplicate-packages.xml @@ -0,0 +1,25 @@ + + + 3.0 + + + + + com.fasterxml.jackson.core + jackson-annotations + 2.13.3 + + + + com.fasterxml.jackson.core + jackson-databind + 2.13.4 + + + + com.fasterxml.jackson.core + jackson-databind + 2.13.4.1 + + + diff --git a/pkg/lockfile/parse-maven-lock.go b/pkg/lockfile/parse-maven-lock.go index 6491b25e..e0445f02 100644 --- a/pkg/lockfile/parse-maven-lock.go +++ b/pkg/lockfile/parse-maven-lock.go @@ -64,6 +64,28 @@ type MavenLockFile struct { ManagedDependencies []MavenLockDependency `xml:"dependencyManagement>dependencies>dependency"` } +func (mlf *MavenLockFile) collectPackages(dependencies []MavenLockDependency) map[string]PackageDetails { + details := map[string]PackageDetails{} + + for _, lockPackage := range dependencies { + finalName := lockPackage.GroupID + ":" + lockPackage.ArtifactID + + // the first declaration of a dependency at a specific depth wins + if _, ok := details[finalName]; ok { + continue + } + + details[finalName] = PackageDetails{ + Name: finalName, + Version: lockPackage.ResolveVersion(*mlf), + Ecosystem: MavenEcosystem, + CompareAs: MavenEcosystem, + } + } + + return details +} + const MavenEcosystem Ecosystem = "Maven" type MavenLockProperties struct { @@ -113,29 +135,11 @@ func ParseMavenLock(pathToLockfile string) ([]PackageDetails, error) { return []PackageDetails{}, fmt.Errorf("could not parse %s: %w", pathToLockfile, err) } - details := map[string]PackageDetails{} - - for _, lockPackage := range parsedLockfile.Dependencies { - finalName := lockPackage.GroupID + ":" + lockPackage.ArtifactID - - details[finalName] = PackageDetails{ - Name: finalName, - Version: lockPackage.ResolveVersion(*parsedLockfile), - Ecosystem: MavenEcosystem, - CompareAs: MavenEcosystem, - } - } + details := parsedLockfile.collectPackages(parsedLockfile.Dependencies) // managed dependencies take precedent over standard dependencies - for _, lockPackage := range parsedLockfile.ManagedDependencies { - finalName := lockPackage.GroupID + ":" + lockPackage.ArtifactID - - details[finalName] = PackageDetails{ - Name: finalName, - Version: lockPackage.ResolveVersion(*parsedLockfile), - Ecosystem: MavenEcosystem, - CompareAs: MavenEcosystem, - } + for k, detail := range parsedLockfile.collectPackages(parsedLockfile.ManagedDependencies) { + details[k] = detail } return pkgDetailsMapToSlice(details), nil diff --git a/pkg/lockfile/parse-maven-lock_test.go b/pkg/lockfile/parse-maven-lock_test.go index d7ef4c87..c3f0ed88 100644 --- a/pkg/lockfile/parse-maven-lock_test.go +++ b/pkg/lockfile/parse-maven-lock_test.go @@ -89,6 +89,31 @@ func TestParseMavenLock_TwoPackages(t *testing.T) { }) } +func TestParseMavenLock_WithDuplicatePackages(t *testing.T) { + t.Parallel() + + packages, err := lockfile.ParseMavenLock("fixtures/maven/with-duplicate-packages.xml") + + if err != nil { + t.Errorf("Got unexpected error: %v", err) + } + + expectPackages(t, packages, []lockfile.PackageDetails{ + { + Name: "com.fasterxml.jackson.core:jackson-annotations", + Version: "2.13.3", + Ecosystem: lockfile.MavenEcosystem, + CompareAs: lockfile.MavenEcosystem, + }, + { + Name: "com.fasterxml.jackson.core:jackson-databind", + Version: "2.13.4", + Ecosystem: lockfile.MavenEcosystem, + CompareAs: lockfile.MavenEcosystem, + }, + }) +} + func TestParseMavenLock_WithDependencyManagement(t *testing.T) { t.Parallel() @@ -120,6 +145,31 @@ func TestParseMavenLock_WithDependencyManagement(t *testing.T) { }) } +func TestParseMavenLock_WithDependencyManagementAndDuplicates(t *testing.T) { + t.Parallel() + + packages, err := lockfile.ParseMavenLock("fixtures/maven/with-dependency-management-and-duplicates.xml") + + if err != nil { + t.Errorf("Got unexpected error: %v", err) + } + + expectPackages(t, packages, []lockfile.PackageDetails{ + { + Name: "com.fasterxml.jackson.core:jackson-annotations", + Version: "2.13.3", + Ecosystem: lockfile.MavenEcosystem, + CompareAs: lockfile.MavenEcosystem, + }, + { + Name: "com.fasterxml.jackson.core:jackson-databind", + Version: "2.13.4", + Ecosystem: lockfile.MavenEcosystem, + CompareAs: lockfile.MavenEcosystem, + }, + }) +} + func TestParseMavenLock_Interpolation(t *testing.T) { t.Parallel()