Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 109 additions & 8 deletions enrichment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/ecosyste-ms/ecosystems-go"
"github.com/ecosyste-ms/ecosystems-go/packages"
"github.com/git-pkgs/registries"
"github.com/oapi-codegen/nullable"
)

Expand Down Expand Up @@ -399,22 +400,122 @@ func TestHasRepositoryURL(t *testing.T) {
}
}

func TestPURLType(t *testing.T) {
tests := []struct {
purl string
want string
}{
{"pkg:npm/lodash", "npm"},
{"not a purl", ""},
}

for _, tt := range tests {
t.Run(tt.purl, func(t *testing.T) {
got := purlType(tt.purl)
if got != tt.want {
t.Errorf("purlType(%q) = %q, want %q", tt.purl, got, tt.want)
}
})
}
}

func TestFindLatestVersion(t *testing.T) {
tests := []struct {
name string
versions []VersionInfo
scheme string
want string
}{
{nil, ""},
{[]VersionInfo{{Number: "1.0.0"}}, "1.0.0"},
{[]VersionInfo{{Number: "1.0.0"}, {Number: "2.0.0"}, {Number: "1.5.0"}}, "2.0.0"},
{[]VersionInfo{{Number: "3.0.0"}, {Number: "1.0.0"}}, "3.0.0"},
{
name: "empty",
},
{
name: "single version",
versions: []VersionInfo{{Number: "1.0.0"}},
scheme: "npm",
want: "1.0.0",
},
{
name: "highest semver",
versions: []VersionInfo{
{Number: "1.0.0"},
{Number: "2.0.0"},
{Number: "1.5.0"},
},
scheme: "npm",
want: "2.0.0",
},
{
name: "keeps initial latest",
versions: []VersionInfo{
{Number: "3.0.0"},
{Number: "1.0.0"},
},
scheme: "npm",
want: "3.0.0",
},
{
name: "uses scheme ordering",
versions: []VersionInfo{
{Number: "1.0~rc1"},
{Number: "1.0"},
},
scheme: "deb",
want: "1.0",
},
{
name: "skips yanked status",
versions: []VersionInfo{
{Number: "2.0.0", Status: string(registries.StatusYanked)},
{Number: "1.0.0"},
},
scheme: "npm",
want: "1.0.0",
},
{
name: "skips deprecated status",
versions: []VersionInfo{
{Number: "2.0.0", Status: string(registries.StatusDeprecated)},
{Number: "1.0.0"},
},
scheme: "npm",
want: "1.0.0",
},
{
name: "skips retracted status",
versions: []VersionInfo{
{Number: "2.0.0", Status: string(registries.StatusRetracted)},
{Number: "1.0.0"},
},
scheme: "npm",
want: "1.0.0",
},
{
name: "skips yanked boolean",
versions: []VersionInfo{
{Number: "2.0.0", Yanked: true},
{Number: "1.0.0"},
},
scheme: "npm",
want: "1.0.0",
},
{
name: "returns empty when all unavailable",
versions: []VersionInfo{
{Number: "2.0.0", Status: string(registries.StatusYanked)},
{Number: "1.0.0", Status: string(registries.StatusDeprecated)},
},
scheme: "npm",
},
}

for _, tt := range tests {
got := findLatestVersion(tt.versions)
if got != tt.want {
t.Errorf("findLatestVersion() = %q, want %q", got, tt.want)
}
t.Run(tt.name, func(t *testing.T) {
got := findLatestVersion(tt.versions, tt.scheme)
if got != tt.want {
t.Errorf("findLatestVersion() = %q, want %q", got, tt.want)
}
})
}
}

Expand Down
41 changes: 29 additions & 12 deletions registries.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (c *RegistriesClient) BulkLookup(ctx context.Context, purls []string) (map[
if err != nil || len(versions) == 0 {
return
}
latest := findLatestVersion(versions)
latest := findLatestVersion(versions, purlType(purlStr))
mu.Lock()
latestVersions[purlStr] = latest
mu.Unlock()
Expand All @@ -76,11 +76,7 @@ func (c *RegistriesClient) BulkLookup(ctx context.Context, purls []string) (map[
continue
}

p, _ := purl.Parse(purlStr)
ecosystem := ""
if p != nil {
ecosystem = p.Type
}
ecosystem := purlType(purlStr)

info := &PackageInfo{
Ecosystem: ecosystem,
Expand Down Expand Up @@ -112,20 +108,41 @@ func acquireSemaphore(ctx context.Context, sem chan<- struct{}) bool {
}
}

// findLatestVersion returns the highest version from a list using semver comparison.
func findLatestVersion(versions []VersionInfo) string {
if len(versions) == 0 {
func purlType(purlStr string) string {
p, err := purl.Parse(purlStr)
if err != nil || p == nil {
return ""
}
latest := versions[0].Number
for _, v := range versions[1:] {
if vers.Compare(v.Number, latest) > 0 {
return p.Type
}

// findLatestVersion returns the highest available version using ecosystem ordering.
func findLatestVersion(versions []VersionInfo, scheme string) string {
var latest string
for _, v := range versions {
if unavailableVersion(v) {
continue
}
if latest == "" || vers.CompareWithScheme(v.Number, latest, scheme) > 0 {
latest = v.Number
}
}
return latest
}

func unavailableVersion(v VersionInfo) bool {
if v.Yanked {
return true
}

switch v.Status {
case string(registries.StatusYanked), string(registries.StatusDeprecated), string(registries.StatusRetracted):
return true
default:
return false
}
}

func (c *RegistriesClient) GetVersions(ctx context.Context, purlStr string) ([]VersionInfo, error) {
reg, name, _, err := registries.NewFromPURL(purlStr, c.client)
if err != nil {
Expand Down