diff --git a/internal/helm/chart/builder_remote_test.go b/internal/helm/chart/builder_remote_test.go index e76503e43..01ed111bc 100644 --- a/internal/helm/chart/builder_remote_test.go +++ b/internal/helm/chart/builder_remote_test.go @@ -64,10 +64,14 @@ func (m *mockRegistryClient) Logout(url string, opts ...registry.LogoutOption) e type mockIndexChartGetter struct { IndexResponse []byte ChartResponse []byte + ErrorResponse error requestedURL string } func (g *mockIndexChartGetter) Get(u string, _ ...helmgetter.Option) (*bytes.Buffer, error) { + if g.ErrorResponse != nil { + return nil, g.ErrorResponse + } g.requestedURL = u r := g.ChartResponse if strings.HasSuffix(u, "index.yaml") { @@ -248,6 +252,15 @@ func TestRemoteBuilder_BuildFromOCIChatRepository(t *testing.T) { RegistryClient: registryClient, } } + mockRepoWithoutChart := func() *repository.OCIChartRepository { + return &repository.OCIChartRepository{ + URL: *u, + Client: &mockIndexChartGetter{ + ErrorResponse: fmt.Errorf("chart doesn't exist"), + }, + RegistryClient: registryClient, + } + } tests := []struct { name string @@ -278,8 +291,8 @@ func TestRemoteBuilder_BuildFromOCIChatRepository(t *testing.T) { { name: "chart version not in repository", reference: RemoteReference{Name: "grafana", Version: "1.1.1"}, - repository: mockRepo(), - wantErr: "failed to get chart version for remote reference", + repository: mockRepoWithoutChart(), + wantErr: "failed to download chart for remote reference", }, { name: "invalid version metadata", @@ -334,7 +347,7 @@ func TestRemoteBuilder_BuildFromOCIChatRepository(t *testing.T) { cb, err := b.Build(context.TODO(), tt.reference, targetPath, tt.buildOpts) if tt.wantErr != "" { - g.Expect(err).To(HaveOccurred()) + g.Expect(err).To(HaveOccurred(), "expected error '%s'", tt.wantErr) g.Expect(err.Error()).To(ContainSubstring(tt.wantErr)) g.Expect(cb).To(BeZero()) return diff --git a/internal/helm/repository/oci_chart_repository.go b/internal/helm/repository/oci_chart_repository.go index e68a350d8..b659baec1 100644 --- a/internal/helm/repository/oci_chart_repository.go +++ b/internal/helm/repository/oci_chart_repository.go @@ -124,6 +124,22 @@ func (r *OCIChartRepository) Get(name, ver string) (*repo.ChartVersion, error) { // Either in an index file or from a registry. cpURL := r.URL cpURL.Path = path.Join(cpURL.Path, name) + + // if ver is a valid semver version, take a shortcut here so we don't need to list all tags which can be an + // expensive operation. + if _, err := version.ParseVersion(ver); err == nil { + return &repo.ChartVersion{ + URLs: []string{fmt.Sprintf("%s:%s", cpURL.String(), ver)}, + Metadata: &chart.Metadata{ + Name: name, + Version: ver, + }, + }, nil + } + + // ver doesn't denote a concrete version so we interpret it as a semver range and try to find the best-matching + // version from the list of tags in the registry. + cvs, err := r.getTags(cpURL.String()) if err != nil { return nil, err diff --git a/internal/helm/repository/oci_chart_repository_test.go b/internal/helm/repository/oci_chart_repository_test.go index a41f2dd99..87bf300f2 100644 --- a/internal/helm/repository/oci_chart_repository_test.go +++ b/internal/helm/repository/oci_chart_repository_test.go @@ -118,59 +118,68 @@ func TestOCIChartRepository_Get(t *testing.T) { testURL := "oci://localhost:5000/my_repo" testCases := []struct { - name string - url string - version string - expected string - expectedErr string + name string + registryClient RegistryClient + url string + version string + expected string + expectedErr string }{ { - name: "should return latest stable version", - version: "", - url: testURL, - expected: "1.0.0", + name: "should return latest stable version", + registryClient: registryClient, + version: "", + url: testURL, + expected: "1.0.0", }, { - name: "should return latest stable version (asterisk)", - version: "*", - url: testURL, - expected: "1.0.0", + name: "should return latest stable version (asterisk)", + registryClient: registryClient, + version: "*", + url: testURL, + expected: "1.0.0", }, { - name: "should return latest stable version (semver range)", - version: ">=0.1.5", - url: testURL, - expected: "1.0.0", + name: "should return latest stable version (semver range)", + registryClient: registryClient, + version: ">=0.1.5", + url: testURL, + expected: "1.0.0", }, { - name: "should return 0.2.0 (semver range)", - version: "0.2.x", - url: testURL, - expected: "0.2.0", + name: "should return 0.2.0 (semver range)", + registryClient: registryClient, + version: "0.2.x", + url: testURL, + expected: "0.2.0", }, { - name: "should return a perfect match", - version: "0.1.0", - url: testURL, - expected: "0.1.0", + name: "should return a perfect match", + registryClient: nil, + version: "0.1.0", + url: testURL, + expected: "0.1.0", }, { - name: "should return 0.10.0", - version: "0.*", - url: testURL, - expected: "0.10.0", + name: "should return 0.10.0", + registryClient: registryClient, + version: "0.*", + url: testURL, + expected: "0.10.0", }, { - name: "should an error for unfunfilled range", - version: ">2.0.0", - url: testURL, - expectedErr: "could not locate a version matching provided version string >2.0.0", + name: "should an error for unfulfilled range", + registryClient: registryClient, + version: ">2.0.0", + url: testURL, + expectedErr: "could not locate a version matching provided version string >2.0.0", }, { - name: "shouldn't error out with trailing slash", - version: "", - url: "oci://localhost:5000/my_repo/", - expected: "1.0.0", + name: "shouldn't error out with trailing slash", + registryClient: registryClient, + version: "", + url: "oci://localhost:5000/my_repo/", + expected: "1.0.0", }, } @@ -178,7 +187,7 @@ func TestOCIChartRepository_Get(t *testing.T) { t.Run(tc.name, func(t *testing.T) { g := NewWithT(t) - r, err := NewOCIChartRepository(tc.url, WithOCIRegistryClient(registryClient), WithOCIGetter(providers)) + r, err := NewOCIChartRepository(tc.url, WithOCIRegistryClient(tc.registryClient), WithOCIGetter(providers)) g.Expect(err).ToNot(HaveOccurred()) g.Expect(r).ToNot(BeNil())