Pick the most recent chart/tag for ambiguous semver matches
Signed-off-by: Illia Ovchynnikov <illia.ovchynnikov@gmail.com>
This commit is contained in:
parent
ae91271dc1
commit
394b5c3bd0
|
@ -98,11 +98,7 @@ func (r *ChartRepository) Get(name, version string) (*repo.ChartVersion, error)
|
|||
if err != nil {
|
||||
continue
|
||||
}
|
||||
// NB: given the entries are already sorted in LoadIndex,
|
||||
// there is a high probability the first match would be
|
||||
// the right match to return. However, due to the fact that
|
||||
// we use a different semver package than Helm does, we still
|
||||
// need to sort it by our own rules.
|
||||
|
||||
if match != nil && !match(v) {
|
||||
continue
|
||||
}
|
||||
|
@ -112,7 +108,25 @@ func (r *ChartRepository) Get(name, version string) (*repo.ChartVersion, error)
|
|||
if len(filteredVersions) == 0 {
|
||||
return nil, fmt.Errorf("no chart version found for %s-%s", name, version)
|
||||
}
|
||||
sort.Sort(sort.Reverse(filteredVersions))
|
||||
|
||||
// Sort versions
|
||||
sort.SliceStable(filteredVersions, func(i, j int) bool {
|
||||
// Reverse
|
||||
return !(func() bool {
|
||||
left := filteredVersions[i]
|
||||
right := filteredVersions[j]
|
||||
|
||||
if !left.EQ(right) {
|
||||
return left.LT(right)
|
||||
}
|
||||
|
||||
// Having chart creation timestamp at our disposal, we put package with the
|
||||
// same version into a chronological order. This is especially important for
|
||||
// versions that differ only by build metadata, because it is not considered
|
||||
// a part of the comparable version in Semver
|
||||
return lookup[left.String()].Created.Before(lookup[right.String()].Created)
|
||||
})()
|
||||
})
|
||||
|
||||
latest := filteredVersions[0]
|
||||
if latestStable {
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/getter"
|
||||
|
@ -104,6 +105,11 @@ func TestChartRepository_Get(t *testing.T) {
|
|||
i.Add(&chart.Metadata{Name: "chart", Version: "exact"}, "chart-exact.tgz", "http://example.com/charts", "sha256:1234567890")
|
||||
i.Add(&chart.Metadata{Name: "chart", Version: "0.1.0"}, "chart-0.1.0.tgz", "http://example.com/charts", "sha256:1234567890abc")
|
||||
i.Add(&chart.Metadata{Name: "chart", Version: "0.1.1"}, "chart-0.1.1.tgz", "http://example.com/charts", "sha256:1234567890abc")
|
||||
i.Add(&chart.Metadata{Name: "chart", Version: "0.1.5+b.min.minute"}, "chart-0.1.5+b.min.minute.tgz", "http://example.com/charts", "sha256:1234567890abc")
|
||||
i.Entries["chart"][len(i.Entries["chart"])-1].Created = time.Now().Add(-time.Minute)
|
||||
i.Add(&chart.Metadata{Name: "chart", Version: "0.1.5+a.min.hour"}, "chart-0.1.5+a.min.hour.tgz", "http://example.com/charts", "sha256:1234567890abc")
|
||||
i.Entries["chart"][len(i.Entries["chart"])-1].Created = time.Now().Add(-time.Hour)
|
||||
i.Add(&chart.Metadata{Name: "chart", Version: "0.1.5+c.now"}, "chart-0.1.5+c.now.tgz", "http://example.com/charts", "sha256:1234567890abc")
|
||||
i.Add(&chart.Metadata{Name: "chart", Version: "0.2.0"}, "chart-0.2.0.tgz", "http://example.com/charts", "sha256:1234567890abc")
|
||||
i.Add(&chart.Metadata{Name: "chart", Version: "1.0.0"}, "chart-1.0.0.tgz", "http://example.com/charts", "sha256:1234567890abc")
|
||||
i.Add(&chart.Metadata{Name: "chart", Version: "1.1.0-rc.1"}, "chart-1.1.0-rc.1.tgz", "http://example.com/charts", "sha256:1234567890abc")
|
||||
|
@ -152,6 +158,12 @@ func TestChartRepository_Get(t *testing.T) {
|
|||
chartName: "non-existing",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "match newest if ambiguous",
|
||||
chartName: "chart",
|
||||
chartVersion: "0.1.5",
|
||||
wantVersion: "0.1.5+c.now",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
|
@ -19,6 +19,8 @@ package git
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/blang/semver/v4"
|
||||
"github.com/go-git/go-git/v5"
|
||||
|
@ -189,7 +191,19 @@ func (c *CheckoutSemVer) Checkout(ctx context.Context, path, url string, auth tr
|
|||
}
|
||||
|
||||
tags := make(map[string]string)
|
||||
tagTimestamps := make(map[string]time.Time)
|
||||
_ = repoTags.ForEach(func(t *plumbing.Reference) error {
|
||||
revision := plumbing.Revision(t.Name().String())
|
||||
hash, err := repo.ResolveRevision(revision)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to resolve tag revision: %w", err)
|
||||
}
|
||||
commit, err := repo.CommitObject(*hash)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to resolve commit of a tag revision: %w", err)
|
||||
}
|
||||
tagTimestamps[t.Name().Short()] = commit.Committer.When
|
||||
|
||||
tags[t.Name().Short()] = t.Strings()[1]
|
||||
return nil
|
||||
})
|
||||
|
@ -203,12 +217,25 @@ func (c *CheckoutSemVer) Checkout(ctx context.Context, path, url string, auth tr
|
|||
svTags[v.String()] = tag
|
||||
}
|
||||
}
|
||||
|
||||
if len(svers) == 0 {
|
||||
return nil, "", fmt.Errorf("no match found for semver: %s", c.semVer)
|
||||
}
|
||||
|
||||
semver.Sort(svers)
|
||||
// Sort versions
|
||||
sort.SliceStable(svers, func(i, j int) bool {
|
||||
left := svers[i]
|
||||
right := svers[j]
|
||||
|
||||
if !left.EQ(right) {
|
||||
return left.LT(right)
|
||||
}
|
||||
|
||||
// Having tag target timestamps at our disposal, we further try to sort
|
||||
// versions into a chronological order. This is especially important for
|
||||
// versions that differ only by build metadata, because it is not considered
|
||||
// a part of the comparable version in Semver
|
||||
return tagTimestamps[left.String()].Before(tagTimestamps[right.String()])
|
||||
})
|
||||
v := svers[len(svers)-1]
|
||||
t := svTags[v.String()]
|
||||
|
||||
|
|
Loading…
Reference in New Issue