From 1b251fbe0bb69e78e700d2d0d350b0eb13459aef Mon Sep 17 00:00:00 2001 From: Dmitriy Ermakov Date: Sat, 12 Dec 2020 11:05:50 +0300 Subject: [PATCH 01/48] Added flag --list-repo The flag makes helm print the chart repo URL to use with helm repo add. Issue: #7419 Signed-off-by: Dmitriy Ermakov --- cmd/helm/search_hub.go | 41 +++++++++++++++++++++++++++---------- cmd/helm/search_hub_test.go | 28 +++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/cmd/helm/search_hub.go b/cmd/helm/search_hub.go index 89139ec16..4cbf64991 100644 --- a/cmd/helm/search_hub.go +++ b/cmd/helm/search_hub.go @@ -45,6 +45,7 @@ type searchHubOptions struct { searchEndpoint string maxColWidth uint outputFormat output.Format + listRepo bool } func newSearchHubCmd(out io.Writer) *cobra.Command { @@ -62,6 +63,7 @@ func newSearchHubCmd(out io.Writer) *cobra.Command { f := cmd.Flags() f.StringVar(&o.searchEndpoint, "endpoint", "https://hub.helm.sh", "monocular instance to query for charts") f.UintVar(&o.maxColWidth, "max-col-width", 50, "maximum column width for output table") + f.BoolVar(&o.listRepo, "list-repo", false, "toggle chart repo URL display") bindOutputFlag(cmd, &o.outputFormat) return cmd @@ -80,28 +82,35 @@ func (o *searchHubOptions) run(out io.Writer, args []string) error { return fmt.Errorf("unable to perform search against %q", o.searchEndpoint) } - return o.outputFormat.Write(out, newHubSearchWriter(results, o.searchEndpoint, o.maxColWidth)) + return o.outputFormat.Write(out, newHubSearchWriter(results, o.searchEndpoint, o.maxColWidth, o.listRepo)) +} + +type hubChartRepo struct { + URL string `json:"url"` + Name string `json:"name"` } type hubChartElement struct { - URL string `json:"url"` - Version string `json:"version"` - AppVersion string `json:"app_version"` - Description string `json:"description"` + URL string `json:"url"` + Version string `json:"version"` + AppVersion string `json:"app_version"` + Description string `json:"description"` + Repository hubChartRepo `json:"repository"` } type hubSearchWriter struct { elements []hubChartElement columnWidth uint + listRepo bool } -func newHubSearchWriter(results []monocular.SearchResult, endpoint string, columnWidth uint) *hubSearchWriter { +func newHubSearchWriter(results []monocular.SearchResult, endpoint string, columnWidth uint, listRepo bool) *hubSearchWriter { var elements []hubChartElement for _, r := range results { url := endpoint + "/charts/" + r.ID - elements = append(elements, hubChartElement{url, r.Relationships.LatestChartVersion.Data.Version, r.Relationships.LatestChartVersion.Data.AppVersion, r.Attributes.Description}) + elements = append(elements, hubChartElement{url, r.Relationships.LatestChartVersion.Data.Version, r.Relationships.LatestChartVersion.Data.AppVersion, r.Attributes.Description, hubChartRepo{URL: r.Attributes.Repo.URL, Name: r.Attributes.Repo.Name}}) } - return &hubSearchWriter{elements, columnWidth} + return &hubSearchWriter{elements, columnWidth, listRepo} } func (h *hubSearchWriter) WriteTable(out io.Writer) error { @@ -114,9 +123,19 @@ func (h *hubSearchWriter) WriteTable(out io.Writer) error { } table := uitable.New() table.MaxColWidth = h.columnWidth - table.AddRow("URL", "CHART VERSION", "APP VERSION", "DESCRIPTION") + + if h.listRepo { + table.AddRow("REPO", "URL", "CHART VERSION", "APP VERSION", "DESCRIPTION") + } else { + table.AddRow("URL", "CHART VERSION", "APP VERSION", "DESCRIPTION") + } + for _, r := range h.elements { - table.AddRow(r.URL, r.Version, r.AppVersion, r.Description) + if h.listRepo { + table.AddRow(r.Repository.URL, r.URL, r.Version, r.AppVersion, r.Description) + } else { + table.AddRow(r.URL, r.Version, r.AppVersion, r.Description) + } } return output.EncodeTable(out, table) } @@ -134,7 +153,7 @@ func (h *hubSearchWriter) encodeByFormat(out io.Writer, format output.Format) er chartList := make([]hubChartElement, 0, len(h.elements)) for _, r := range h.elements { - chartList = append(chartList, hubChartElement{r.URL, r.Version, r.AppVersion, r.Description}) + chartList = append(chartList, hubChartElement{r.URL, r.Version, r.AppVersion, r.Description, r.Repository}) } switch format { diff --git a/cmd/helm/search_hub_test.go b/cmd/helm/search_hub_test.go index 9fc21cab8..9b56936c7 100644 --- a/cmd/helm/search_hub_test.go +++ b/cmd/helm/search_hub_test.go @@ -51,6 +51,34 @@ func TestSearchHubCmd(t *testing.T) { } } +func TestSearchHubListRepoCmd(t *testing.T) { + + // Setup a mock search service + var searchResult = `{"data":[{"id":"stable/phpmyadmin","type":"chart","attributes":{"name":"phpmyadmin","repo":{"name":"stable","url":"https://charts.helm.sh/stable"},"description":"phpMyAdmin is an mysql administration frontend","home":"https://www.phpmyadmin.net/","keywords":["mariadb","mysql","phpmyadmin"],"maintainers":[{"name":"Bitnami","email":"containers@bitnami.com"}],"sources":["https://github.com/bitnami/bitnami-docker-phpmyadmin"],"icon":""},"links":{"self":"/v1/charts/stable/phpmyadmin"},"relationships":{"latestChartVersion":{"data":{"version":"3.0.0","app_version":"4.9.0-1","created":"2019-08-08T17:57:31.38Z","digest":"119c499251bffd4b06ff0cd5ac98c2ce32231f84899fb4825be6c2d90971c742","urls":["https://charts.helm.sh/stable/phpmyadmin-3.0.0.tgz"],"readme":"/v1/assets/stable/phpmyadmin/versions/3.0.0/README.md","values":"/v1/assets/stable/phpmyadmin/versions/3.0.0/values.yaml"},"links":{"self":"/v1/charts/stable/phpmyadmin/versions/3.0.0"}}}},{"id":"bitnami/phpmyadmin","type":"chart","attributes":{"name":"phpmyadmin","repo":{"name":"bitnami","url":"https://charts.bitnami.com"},"description":"phpMyAdmin is an mysql administration frontend","home":"https://www.phpmyadmin.net/","keywords":["mariadb","mysql","phpmyadmin"],"maintainers":[{"name":"Bitnami","email":"containers@bitnami.com"}],"sources":["https://github.com/bitnami/bitnami-docker-phpmyadmin"],"icon":""},"links":{"self":"/v1/charts/bitnami/phpmyadmin"},"relationships":{"latestChartVersion":{"data":{"version":"3.0.0","app_version":"4.9.0-1","created":"2019-08-08T18:34:13.341Z","digest":"66d77cf6d8c2b52c488d0a294cd4996bd5bad8dc41d3829c394498fb401c008a","urls":["https://charts.bitnami.com/bitnami/phpmyadmin-3.0.0.tgz"],"readme":"/v1/assets/bitnami/phpmyadmin/versions/3.0.0/README.md","values":"/v1/assets/bitnami/phpmyadmin/versions/3.0.0/values.yaml"},"links":{"self":"/v1/charts/bitnami/phpmyadmin/versions/3.0.0"}}}}]}` + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, searchResult) + })) + defer ts.Close() + + // The expected output has the URL to the mocked search service in it + var expected = fmt.Sprintf(`REPO URL CHART VERSION APP VERSION DESCRIPTION +https://charts.helm.sh/stable %s/charts/stable/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend +https://charts.bitnami.com %s/charts/bitnami/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend +`, ts.URL, ts.URL) + + testcmd := "search hub --list-repo --endpoint " + ts.URL + " maria" + storage := storageFixture() + _, out, err := executeActionCommandC(storage, testcmd) + if err != nil { + t.Errorf("unexpected error, %s", err) + } + if out != expected { + t.Error("expected and actual output did not match") + t.Log(out) + t.Log(expected) + } +} + func TestSearchHubOutputCompletion(t *testing.T) { outputFlagCompletionTest(t, "search hub") } From 3d0bb987cb29fcbef5dc8d1ca38097e943a2a039 Mon Sep 17 00:00:00 2001 From: Dmitriy Ermakov Date: Mon, 25 Jan 2021 19:58:09 +0100 Subject: [PATCH 02/48] Removed list-repo flag. Print Repo URL by default Signed-off-by: Dmitriy Ermakov --- cmd/helm/search_hub.go | 22 ++++++---------------- cmd/helm/search_hub_test.go | 34 +++------------------------------- 2 files changed, 9 insertions(+), 47 deletions(-) diff --git a/cmd/helm/search_hub.go b/cmd/helm/search_hub.go index 4cbf64991..a74759a03 100644 --- a/cmd/helm/search_hub.go +++ b/cmd/helm/search_hub.go @@ -45,7 +45,6 @@ type searchHubOptions struct { searchEndpoint string maxColWidth uint outputFormat output.Format - listRepo bool } func newSearchHubCmd(out io.Writer) *cobra.Command { @@ -63,7 +62,7 @@ func newSearchHubCmd(out io.Writer) *cobra.Command { f := cmd.Flags() f.StringVar(&o.searchEndpoint, "endpoint", "https://hub.helm.sh", "monocular instance to query for charts") f.UintVar(&o.maxColWidth, "max-col-width", 50, "maximum column width for output table") - f.BoolVar(&o.listRepo, "list-repo", false, "toggle chart repo URL display") + bindOutputFlag(cmd, &o.outputFormat) return cmd @@ -82,7 +81,7 @@ func (o *searchHubOptions) run(out io.Writer, args []string) error { return fmt.Errorf("unable to perform search against %q", o.searchEndpoint) } - return o.outputFormat.Write(out, newHubSearchWriter(results, o.searchEndpoint, o.maxColWidth, o.listRepo)) + return o.outputFormat.Write(out, newHubSearchWriter(results, o.searchEndpoint, o.maxColWidth)) } type hubChartRepo struct { @@ -101,16 +100,15 @@ type hubChartElement struct { type hubSearchWriter struct { elements []hubChartElement columnWidth uint - listRepo bool } -func newHubSearchWriter(results []monocular.SearchResult, endpoint string, columnWidth uint, listRepo bool) *hubSearchWriter { +func newHubSearchWriter(results []monocular.SearchResult, endpoint string, columnWidth uint) *hubSearchWriter { var elements []hubChartElement for _, r := range results { url := endpoint + "/charts/" + r.ID elements = append(elements, hubChartElement{url, r.Relationships.LatestChartVersion.Data.Version, r.Relationships.LatestChartVersion.Data.AppVersion, r.Attributes.Description, hubChartRepo{URL: r.Attributes.Repo.URL, Name: r.Attributes.Repo.Name}}) } - return &hubSearchWriter{elements, columnWidth, listRepo} + return &hubSearchWriter{elements, columnWidth} } func (h *hubSearchWriter) WriteTable(out io.Writer) error { @@ -124,18 +122,10 @@ func (h *hubSearchWriter) WriteTable(out io.Writer) error { table := uitable.New() table.MaxColWidth = h.columnWidth - if h.listRepo { - table.AddRow("REPO", "URL", "CHART VERSION", "APP VERSION", "DESCRIPTION") - } else { - table.AddRow("URL", "CHART VERSION", "APP VERSION", "DESCRIPTION") - } + table.AddRow("URL", "CHART VERSION", "APP VERSION", "DESCRIPTION", "REPO") for _, r := range h.elements { - if h.listRepo { - table.AddRow(r.Repository.URL, r.URL, r.Version, r.AppVersion, r.Description) - } else { - table.AddRow(r.URL, r.Version, r.AppVersion, r.Description) - } + table.AddRow(r.URL, r.Version, r.AppVersion, r.Description, r.Repository.URL) } return output.EncodeTable(out, table) } diff --git a/cmd/helm/search_hub_test.go b/cmd/helm/search_hub_test.go index 9b56936c7..564c46775 100644 --- a/cmd/helm/search_hub_test.go +++ b/cmd/helm/search_hub_test.go @@ -33,9 +33,9 @@ func TestSearchHubCmd(t *testing.T) { defer ts.Close() // The expected output has the URL to the mocked search service in it - var expected = fmt.Sprintf(`URL CHART VERSION APP VERSION DESCRIPTION -%s/charts/stable/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend -%s/charts/bitnami/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend + var expected = fmt.Sprintf(`URL CHART VERSION APP VERSION DESCRIPTION REPO +%s/charts/stable/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend https://charts.helm.sh/stable +%s/charts/bitnami/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend https://charts.bitnami.com `, ts.URL, ts.URL) testcmd := "search hub --endpoint " + ts.URL + " maria" @@ -51,34 +51,6 @@ func TestSearchHubCmd(t *testing.T) { } } -func TestSearchHubListRepoCmd(t *testing.T) { - - // Setup a mock search service - var searchResult = `{"data":[{"id":"stable/phpmyadmin","type":"chart","attributes":{"name":"phpmyadmin","repo":{"name":"stable","url":"https://charts.helm.sh/stable"},"description":"phpMyAdmin is an mysql administration frontend","home":"https://www.phpmyadmin.net/","keywords":["mariadb","mysql","phpmyadmin"],"maintainers":[{"name":"Bitnami","email":"containers@bitnami.com"}],"sources":["https://github.com/bitnami/bitnami-docker-phpmyadmin"],"icon":""},"links":{"self":"/v1/charts/stable/phpmyadmin"},"relationships":{"latestChartVersion":{"data":{"version":"3.0.0","app_version":"4.9.0-1","created":"2019-08-08T17:57:31.38Z","digest":"119c499251bffd4b06ff0cd5ac98c2ce32231f84899fb4825be6c2d90971c742","urls":["https://charts.helm.sh/stable/phpmyadmin-3.0.0.tgz"],"readme":"/v1/assets/stable/phpmyadmin/versions/3.0.0/README.md","values":"/v1/assets/stable/phpmyadmin/versions/3.0.0/values.yaml"},"links":{"self":"/v1/charts/stable/phpmyadmin/versions/3.0.0"}}}},{"id":"bitnami/phpmyadmin","type":"chart","attributes":{"name":"phpmyadmin","repo":{"name":"bitnami","url":"https://charts.bitnami.com"},"description":"phpMyAdmin is an mysql administration frontend","home":"https://www.phpmyadmin.net/","keywords":["mariadb","mysql","phpmyadmin"],"maintainers":[{"name":"Bitnami","email":"containers@bitnami.com"}],"sources":["https://github.com/bitnami/bitnami-docker-phpmyadmin"],"icon":""},"links":{"self":"/v1/charts/bitnami/phpmyadmin"},"relationships":{"latestChartVersion":{"data":{"version":"3.0.0","app_version":"4.9.0-1","created":"2019-08-08T18:34:13.341Z","digest":"66d77cf6d8c2b52c488d0a294cd4996bd5bad8dc41d3829c394498fb401c008a","urls":["https://charts.bitnami.com/bitnami/phpmyadmin-3.0.0.tgz"],"readme":"/v1/assets/bitnami/phpmyadmin/versions/3.0.0/README.md","values":"/v1/assets/bitnami/phpmyadmin/versions/3.0.0/values.yaml"},"links":{"self":"/v1/charts/bitnami/phpmyadmin/versions/3.0.0"}}}}]}` - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintln(w, searchResult) - })) - defer ts.Close() - - // The expected output has the URL to the mocked search service in it - var expected = fmt.Sprintf(`REPO URL CHART VERSION APP VERSION DESCRIPTION -https://charts.helm.sh/stable %s/charts/stable/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend -https://charts.bitnami.com %s/charts/bitnami/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend -`, ts.URL, ts.URL) - - testcmd := "search hub --list-repo --endpoint " + ts.URL + " maria" - storage := storageFixture() - _, out, err := executeActionCommandC(storage, testcmd) - if err != nil { - t.Errorf("unexpected error, %s", err) - } - if out != expected { - t.Error("expected and actual output did not match") - t.Log(out) - t.Log(expected) - } -} - func TestSearchHubOutputCompletion(t *testing.T) { outputFlagCompletionTest(t, "search hub") } From 2dd88e846fd0d848b00b2e393916328f8eaeacd2 Mon Sep 17 00:00:00 2001 From: Dmitrii Ermakov Date: Sun, 15 Aug 2021 11:28:17 +0200 Subject: [PATCH 03/48] Reintroduce --list-repo flag in search repo Signed-off-by: Dmitrii Ermakov --- cmd/helm/search_hub.go | 21 ++++++++++++++++----- cmd/helm/search_hub_test.go | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/cmd/helm/search_hub.go b/cmd/helm/search_hub.go index 002d909ab..ed3f5bdf2 100644 --- a/cmd/helm/search_hub.go +++ b/cmd/helm/search_hub.go @@ -53,6 +53,7 @@ type searchHubOptions struct { searchEndpoint string maxColWidth uint outputFormat output.Format + listRepoURL bool } func newSearchHubCmd(out io.Writer) *cobra.Command { @@ -70,6 +71,7 @@ func newSearchHubCmd(out io.Writer) *cobra.Command { f := cmd.Flags() f.StringVar(&o.searchEndpoint, "endpoint", "https://hub.helm.sh", "Hub instance to query for charts") f.UintVar(&o.maxColWidth, "max-col-width", 50, "maximum column width for output table") + f.BoolVar(&o.listRepoURL, "list-repo", false, "print charts repository URL") bindOutputFlag(cmd, &o.outputFormat) @@ -89,7 +91,7 @@ func (o *searchHubOptions) run(out io.Writer, args []string) error { return fmt.Errorf("unable to perform search against %q", o.searchEndpoint) } - return o.outputFormat.Write(out, newHubSearchWriter(results, o.searchEndpoint, o.maxColWidth)) + return o.outputFormat.Write(out, newHubSearchWriter(results, o.searchEndpoint, o.maxColWidth, o.listRepoURL)) } type hubChartRepo struct { @@ -108,9 +110,10 @@ type hubChartElement struct { type hubSearchWriter struct { elements []hubChartElement columnWidth uint + listRepoURL bool } -func newHubSearchWriter(results []monocular.SearchResult, endpoint string, columnWidth uint) *hubSearchWriter { +func newHubSearchWriter(results []monocular.SearchResult, endpoint string, columnWidth uint, listRepoURL bool) *hubSearchWriter { var elements []hubChartElement for _, r := range results { // Backwards compatibility for Monocular @@ -123,7 +126,7 @@ func newHubSearchWriter(results []monocular.SearchResult, endpoint string, colum elements = append(elements, hubChartElement{url, r.Relationships.LatestChartVersion.Data.Version, r.Relationships.LatestChartVersion.Data.AppVersion, r.Attributes.Description, hubChartRepo{URL: r.Attributes.Repo.URL, Name: r.Attributes.Repo.Name}}) } - return &hubSearchWriter{elements, columnWidth} + return &hubSearchWriter{elements, columnWidth, listRepoURL} } func (h *hubSearchWriter) WriteTable(out io.Writer) error { @@ -137,10 +140,18 @@ func (h *hubSearchWriter) WriteTable(out io.Writer) error { table := uitable.New() table.MaxColWidth = h.columnWidth - table.AddRow("URL", "CHART VERSION", "APP VERSION", "DESCRIPTION", "REPO") + if h.listRepoURL { + table.AddRow("URL", "CHART VERSION", "APP VERSION", "DESCRIPTION", "REPO URL") + } else { + table.AddRow("URL", "CHART VERSION", "APP VERSION", "DESCRIPTION") + } for _, r := range h.elements { - table.AddRow(r.URL, r.Version, r.AppVersion, r.Description, r.Repository.URL) + if h.listRepoURL { + table.AddRow(r.URL, r.Version, r.AppVersion, r.Description, r.Repository.URL) + } else { + table.AddRow(r.URL, r.Version, r.AppVersion, r.Description) + } } return output.EncodeTable(out, table) } diff --git a/cmd/helm/search_hub_test.go b/cmd/helm/search_hub_test.go index 564c46775..3498845fa 100644 --- a/cmd/helm/search_hub_test.go +++ b/cmd/helm/search_hub_test.go @@ -33,12 +33,44 @@ func TestSearchHubCmd(t *testing.T) { defer ts.Close() // The expected output has the URL to the mocked search service in it - var expected = fmt.Sprintf(`URL CHART VERSION APP VERSION DESCRIPTION REPO + // Trailing spaces are necessary to preserve in "expected" as the uitable package adds + // them during printing. + var expected = fmt.Sprintf(`URL CHART VERSION APP VERSION DESCRIPTION +%s/charts/stable/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend +%s/charts/bitnami/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend +`, ts.URL, ts.URL) + + testcmd := "search hub --endpoint " + ts.URL + " maria" + storage := storageFixture() + _, out, err := executeActionCommandC(storage, testcmd) + if err != nil { + t.Errorf("unexpected error, %s", err) + } + if out != expected { + t.Error("expected and actual output did not match") + t.Log(out) + t.Log(expected) + } +} + +func TestSearchHubListRepoCmd(t *testing.T) { + + // Setup a mock search service + var searchResult = `{"data":[{"id":"stable/phpmyadmin","type":"chart","attributes":{"name":"phpmyadmin","repo":{"name":"stable","url":"https://charts.helm.sh/stable"},"description":"phpMyAdmin is an mysql administration frontend","home":"https://www.phpmyadmin.net/","keywords":["mariadb","mysql","phpmyadmin"],"maintainers":[{"name":"Bitnami","email":"containers@bitnami.com"}],"sources":["https://github.com/bitnami/bitnami-docker-phpmyadmin"],"icon":""},"links":{"self":"/v1/charts/stable/phpmyadmin"},"relationships":{"latestChartVersion":{"data":{"version":"3.0.0","app_version":"4.9.0-1","created":"2019-08-08T17:57:31.38Z","digest":"119c499251bffd4b06ff0cd5ac98c2ce32231f84899fb4825be6c2d90971c742","urls":["https://charts.helm.sh/stable/phpmyadmin-3.0.0.tgz"],"readme":"/v1/assets/stable/phpmyadmin/versions/3.0.0/README.md","values":"/v1/assets/stable/phpmyadmin/versions/3.0.0/values.yaml"},"links":{"self":"/v1/charts/stable/phpmyadmin/versions/3.0.0"}}}},{"id":"bitnami/phpmyadmin","type":"chart","attributes":{"name":"phpmyadmin","repo":{"name":"bitnami","url":"https://charts.bitnami.com"},"description":"phpMyAdmin is an mysql administration frontend","home":"https://www.phpmyadmin.net/","keywords":["mariadb","mysql","phpmyadmin"],"maintainers":[{"name":"Bitnami","email":"containers@bitnami.com"}],"sources":["https://github.com/bitnami/bitnami-docker-phpmyadmin"],"icon":""},"links":{"self":"/v1/charts/bitnami/phpmyadmin"},"relationships":{"latestChartVersion":{"data":{"version":"3.0.0","app_version":"4.9.0-1","created":"2019-08-08T18:34:13.341Z","digest":"66d77cf6d8c2b52c488d0a294cd4996bd5bad8dc41d3829c394498fb401c008a","urls":["https://charts.bitnami.com/bitnami/phpmyadmin-3.0.0.tgz"],"readme":"/v1/assets/bitnami/phpmyadmin/versions/3.0.0/README.md","values":"/v1/assets/bitnami/phpmyadmin/versions/3.0.0/values.yaml"},"links":{"self":"/v1/charts/bitnami/phpmyadmin/versions/3.0.0"}}}}]}` + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, searchResult) + })) + defer ts.Close() + + // The expected output has the URL to the mocked search service in it + // Trailing spaces are necessary to preserve in "expected" as the uitable package adds + // them during printing. + var expected = fmt.Sprintf(`URL CHART VERSION APP VERSION DESCRIPTION REPO URL %s/charts/stable/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend https://charts.helm.sh/stable %s/charts/bitnami/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend https://charts.bitnami.com `, ts.URL, ts.URL) - testcmd := "search hub --endpoint " + ts.URL + " maria" + testcmd := "search hub --list-repo --endpoint " + ts.URL + " maria" storage := storageFixture() _, out, err := executeActionCommandC(storage, testcmd) if err != nil { From 5b101ec504f1c1190dd15134c74881a59a87f829 Mon Sep 17 00:00:00 2001 From: Dmitrii Ermakov Date: Sun, 15 Aug 2021 11:28:17 +0200 Subject: [PATCH 04/48] Reintroduce --list-repo flag in search repo Signed-off-by: Dmitrii Ermakov --- cmd/helm/search_hub.go | 21 ++++++++++++++++----- cmd/helm/search_hub_test.go | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/cmd/helm/search_hub.go b/cmd/helm/search_hub.go index 002d909ab..ed3f5bdf2 100644 --- a/cmd/helm/search_hub.go +++ b/cmd/helm/search_hub.go @@ -53,6 +53,7 @@ type searchHubOptions struct { searchEndpoint string maxColWidth uint outputFormat output.Format + listRepoURL bool } func newSearchHubCmd(out io.Writer) *cobra.Command { @@ -70,6 +71,7 @@ func newSearchHubCmd(out io.Writer) *cobra.Command { f := cmd.Flags() f.StringVar(&o.searchEndpoint, "endpoint", "https://hub.helm.sh", "Hub instance to query for charts") f.UintVar(&o.maxColWidth, "max-col-width", 50, "maximum column width for output table") + f.BoolVar(&o.listRepoURL, "list-repo", false, "print charts repository URL") bindOutputFlag(cmd, &o.outputFormat) @@ -89,7 +91,7 @@ func (o *searchHubOptions) run(out io.Writer, args []string) error { return fmt.Errorf("unable to perform search against %q", o.searchEndpoint) } - return o.outputFormat.Write(out, newHubSearchWriter(results, o.searchEndpoint, o.maxColWidth)) + return o.outputFormat.Write(out, newHubSearchWriter(results, o.searchEndpoint, o.maxColWidth, o.listRepoURL)) } type hubChartRepo struct { @@ -108,9 +110,10 @@ type hubChartElement struct { type hubSearchWriter struct { elements []hubChartElement columnWidth uint + listRepoURL bool } -func newHubSearchWriter(results []monocular.SearchResult, endpoint string, columnWidth uint) *hubSearchWriter { +func newHubSearchWriter(results []monocular.SearchResult, endpoint string, columnWidth uint, listRepoURL bool) *hubSearchWriter { var elements []hubChartElement for _, r := range results { // Backwards compatibility for Monocular @@ -123,7 +126,7 @@ func newHubSearchWriter(results []monocular.SearchResult, endpoint string, colum elements = append(elements, hubChartElement{url, r.Relationships.LatestChartVersion.Data.Version, r.Relationships.LatestChartVersion.Data.AppVersion, r.Attributes.Description, hubChartRepo{URL: r.Attributes.Repo.URL, Name: r.Attributes.Repo.Name}}) } - return &hubSearchWriter{elements, columnWidth} + return &hubSearchWriter{elements, columnWidth, listRepoURL} } func (h *hubSearchWriter) WriteTable(out io.Writer) error { @@ -137,10 +140,18 @@ func (h *hubSearchWriter) WriteTable(out io.Writer) error { table := uitable.New() table.MaxColWidth = h.columnWidth - table.AddRow("URL", "CHART VERSION", "APP VERSION", "DESCRIPTION", "REPO") + if h.listRepoURL { + table.AddRow("URL", "CHART VERSION", "APP VERSION", "DESCRIPTION", "REPO URL") + } else { + table.AddRow("URL", "CHART VERSION", "APP VERSION", "DESCRIPTION") + } for _, r := range h.elements { - table.AddRow(r.URL, r.Version, r.AppVersion, r.Description, r.Repository.URL) + if h.listRepoURL { + table.AddRow(r.URL, r.Version, r.AppVersion, r.Description, r.Repository.URL) + } else { + table.AddRow(r.URL, r.Version, r.AppVersion, r.Description) + } } return output.EncodeTable(out, table) } diff --git a/cmd/helm/search_hub_test.go b/cmd/helm/search_hub_test.go index 564c46775..3498845fa 100644 --- a/cmd/helm/search_hub_test.go +++ b/cmd/helm/search_hub_test.go @@ -33,12 +33,44 @@ func TestSearchHubCmd(t *testing.T) { defer ts.Close() // The expected output has the URL to the mocked search service in it - var expected = fmt.Sprintf(`URL CHART VERSION APP VERSION DESCRIPTION REPO + // Trailing spaces are necessary to preserve in "expected" as the uitable package adds + // them during printing. + var expected = fmt.Sprintf(`URL CHART VERSION APP VERSION DESCRIPTION +%s/charts/stable/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend +%s/charts/bitnami/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend +`, ts.URL, ts.URL) + + testcmd := "search hub --endpoint " + ts.URL + " maria" + storage := storageFixture() + _, out, err := executeActionCommandC(storage, testcmd) + if err != nil { + t.Errorf("unexpected error, %s", err) + } + if out != expected { + t.Error("expected and actual output did not match") + t.Log(out) + t.Log(expected) + } +} + +func TestSearchHubListRepoCmd(t *testing.T) { + + // Setup a mock search service + var searchResult = `{"data":[{"id":"stable/phpmyadmin","type":"chart","attributes":{"name":"phpmyadmin","repo":{"name":"stable","url":"https://charts.helm.sh/stable"},"description":"phpMyAdmin is an mysql administration frontend","home":"https://www.phpmyadmin.net/","keywords":["mariadb","mysql","phpmyadmin"],"maintainers":[{"name":"Bitnami","email":"containers@bitnami.com"}],"sources":["https://github.com/bitnami/bitnami-docker-phpmyadmin"],"icon":""},"links":{"self":"/v1/charts/stable/phpmyadmin"},"relationships":{"latestChartVersion":{"data":{"version":"3.0.0","app_version":"4.9.0-1","created":"2019-08-08T17:57:31.38Z","digest":"119c499251bffd4b06ff0cd5ac98c2ce32231f84899fb4825be6c2d90971c742","urls":["https://charts.helm.sh/stable/phpmyadmin-3.0.0.tgz"],"readme":"/v1/assets/stable/phpmyadmin/versions/3.0.0/README.md","values":"/v1/assets/stable/phpmyadmin/versions/3.0.0/values.yaml"},"links":{"self":"/v1/charts/stable/phpmyadmin/versions/3.0.0"}}}},{"id":"bitnami/phpmyadmin","type":"chart","attributes":{"name":"phpmyadmin","repo":{"name":"bitnami","url":"https://charts.bitnami.com"},"description":"phpMyAdmin is an mysql administration frontend","home":"https://www.phpmyadmin.net/","keywords":["mariadb","mysql","phpmyadmin"],"maintainers":[{"name":"Bitnami","email":"containers@bitnami.com"}],"sources":["https://github.com/bitnami/bitnami-docker-phpmyadmin"],"icon":""},"links":{"self":"/v1/charts/bitnami/phpmyadmin"},"relationships":{"latestChartVersion":{"data":{"version":"3.0.0","app_version":"4.9.0-1","created":"2019-08-08T18:34:13.341Z","digest":"66d77cf6d8c2b52c488d0a294cd4996bd5bad8dc41d3829c394498fb401c008a","urls":["https://charts.bitnami.com/bitnami/phpmyadmin-3.0.0.tgz"],"readme":"/v1/assets/bitnami/phpmyadmin/versions/3.0.0/README.md","values":"/v1/assets/bitnami/phpmyadmin/versions/3.0.0/values.yaml"},"links":{"self":"/v1/charts/bitnami/phpmyadmin/versions/3.0.0"}}}}]}` + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, searchResult) + })) + defer ts.Close() + + // The expected output has the URL to the mocked search service in it + // Trailing spaces are necessary to preserve in "expected" as the uitable package adds + // them during printing. + var expected = fmt.Sprintf(`URL CHART VERSION APP VERSION DESCRIPTION REPO URL %s/charts/stable/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend https://charts.helm.sh/stable %s/charts/bitnami/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend https://charts.bitnami.com `, ts.URL, ts.URL) - testcmd := "search hub --endpoint " + ts.URL + " maria" + testcmd := "search hub --list-repo --endpoint " + ts.URL + " maria" storage := storageFixture() _, out, err := executeActionCommandC(storage, testcmd) if err != nil { From 144048d5fa95ad9e7cef5af2e735b01802e613b2 Mon Sep 17 00:00:00 2001 From: Dmitrii Ermakov Date: Sun, 29 Aug 2021 20:38:13 +0200 Subject: [PATCH 05/48] Replace cli flag --list-repo with --list-repo-url Signed-off-by: Dmitrii Ermakov --- cmd/helm/search_hub.go | 2 +- cmd/helm/search_hub_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/helm/search_hub.go b/cmd/helm/search_hub.go index ed3f5bdf2..b8887efd5 100644 --- a/cmd/helm/search_hub.go +++ b/cmd/helm/search_hub.go @@ -71,7 +71,7 @@ func newSearchHubCmd(out io.Writer) *cobra.Command { f := cmd.Flags() f.StringVar(&o.searchEndpoint, "endpoint", "https://hub.helm.sh", "Hub instance to query for charts") f.UintVar(&o.maxColWidth, "max-col-width", 50, "maximum column width for output table") - f.BoolVar(&o.listRepoURL, "list-repo", false, "print charts repository URL") + f.BoolVar(&o.listRepoURL, "list-repo-url", false, "print charts repository URL") bindOutputFlag(cmd, &o.outputFormat) diff --git a/cmd/helm/search_hub_test.go b/cmd/helm/search_hub_test.go index 60dd4aae2..7df54ea8f 100644 --- a/cmd/helm/search_hub_test.go +++ b/cmd/helm/search_hub_test.go @@ -70,7 +70,7 @@ func TestSearchHubListRepoCmd(t *testing.T) { %s/charts/bitnami/phpmyadmin 3.0.0 4.9.0-1 phpMyAdmin is an mysql administration frontend https://charts.bitnami.com `, ts.URL, ts.URL) - testcmd := "search hub --list-repo --endpoint " + ts.URL + " maria" + testcmd := "search hub --list-repo-url --endpoint " + ts.URL + " maria" storage := storageFixture() _, out, err := executeActionCommandC(storage, testcmd) if err != nil { From 13d86143f8f1b8aac1e0df9410c3699868109af6 Mon Sep 17 00:00:00 2001 From: David Xia Date: Thu, 2 Dec 2021 16:03:03 -0500 Subject: [PATCH 06/48] docs: Clarify use of --set-file and fix non-idiomatic English. replaces https://github.com/helm/helm-www/pull/1239 Signed-off-by: David Xia --- cmd/helm/install.go | 6 +++--- cmd/helm/upgrade.go | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 9e4515d0a..c664828a6 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -49,9 +49,9 @@ a path to an unpacked chart directory or a URL. To override values in a chart, use either the '--values' flag and pass in a file or use the '--set' flag and pass configuration from the command line, to force -a string value use '--set-string'. In case a value is large and therefore -you want not to use neither '--values' nor '--set', use '--set-file' to read the -single large value from file. +a string value use '--set-string'. You can use '--set-file' to set individual +values from a file when the value itself is too long for the command line +or is dynamically generated. $ helm install -f myvalues.yaml myredis ./redis diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index dbcd2d0d6..7f4920ec9 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -49,9 +49,9 @@ version will be specified unless the '--version' flag is set. To override values in a chart, use either the '--values' flag and pass in a file or use the '--set' flag and pass configuration from the command line, to force string -values, use '--set-string'. In case a value is large and therefore -you want not to use neither '--values' nor '--set', use '--set-file' to read the -single large value from file. +values, use '--set-string'. You can use '--set-file' to set individual +values from a file when the value itself is too long for the command line +or is dynamically generated. You can specify the '--values'/'-f' flag multiple times. The priority will be given to the last (right-most) file specified. For example, if both myvalues.yaml and override.yaml From babbb67f89d859eb88e6dfeb76877423e933ee98 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Dec 2021 16:57:21 +0000 Subject: [PATCH 07/48] chore(deps): bump github.com/docker/docker Bumps [github.com/docker/docker](https://github.com/docker/docker) from 20.10.11+incompatible to 20.10.12+incompatible. - [Release notes](https://github.com/docker/docker/releases) - [Changelog](https://github.com/moby/moby/blob/master/CHANGELOG.md) - [Commits](https://github.com/docker/docker/compare/v20.10.11...v20.10.12) --- updated-dependencies: - dependency-name: github.com/docker/docker dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index fc73609cf..d9efa6a93 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/containerd/containerd v1.5.8 github.com/cyphar/filepath-securejoin v0.2.3 github.com/distribution/distribution/v3 v3.0.0-20211118083504-a29a3c99a684 - github.com/docker/docker v20.10.11+incompatible + github.com/docker/docker v20.10.12+incompatible github.com/evanphx/json-patch v4.12.0+incompatible github.com/gobwas/glob v0.2.3 github.com/gofrs/flock v0.8.1 diff --git a/go.sum b/go.sum index 86980f726..1c6eb05d5 100644 --- a/go.sum +++ b/go.sum @@ -350,8 +350,9 @@ github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TT github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v20.10.11+incompatible h1:OqzI/g/W54LczvhnccGqniFoQghHx3pklbLuhfXpqGo= github.com/docker/docker v20.10.11+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.12+incompatible h1:CEeNmFM0QZIsJCZKMkZx0ZcahTiewkrgiwfYD+dfl1U= +github.com/docker/docker v20.10.12+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.4 h1:axCks+yV+2MR3/kZhAmy07yC56WZ2Pwu/fKWtKuZB0o= github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= From 160da867d05ed3a0585e8bc4bf55f9fdeefe0d9f Mon Sep 17 00:00:00 2001 From: "mengjiao.liu" Date: Thu, 25 Mar 2021 12:09:28 +0800 Subject: [PATCH 08/48] validate release name during install Signed-off-by: mengjiao.liu --- cmd/helm/install_test.go | 2 +- cmd/helm/template.go | 2 +- cmd/helm/template_test.go | 2 +- .../testdata/output/install-name-template.txt | 2 +- ...mplate-chart-with-template-lib-archive-dep.txt | 12 ++++++------ .../template-chart-with-template-lib-dep.txt | 12 ++++++------ .../testdata/output/template-name-template.txt | 8 ++++---- cmd/helm/testdata/output/template-set.txt | 8 ++++---- .../output/template-show-only-multiple.txt | 2 +- .../testdata/output/template-show-only-one.txt | 2 +- cmd/helm/testdata/output/template-skip-tests.txt | 2 +- .../testdata/output/template-values-files.txt | 8 ++++---- .../testdata/output/template-with-api-version.txt | 8 ++++---- cmd/helm/testdata/output/template-with-crds.txt | 8 ++++---- .../output/template-with-invalid-yaml-debug.txt | 2 +- .../output/template-with-kube-version.txt | 8 ++++---- cmd/helm/testdata/output/template.txt | 8 ++++---- .../charts/common/README.md | 8 ++++---- cmd/helm/testdata/testcharts/lib-chart/README.md | 8 ++++---- pkg/action/install.go | 15 ++------------- pkg/action/install_test.go | 2 +- pkg/chartutil/validate_name.go | 7 ++++++- 22 files changed, 65 insertions(+), 71 deletions(-) diff --git a/cmd/helm/install_test.go b/cmd/helm/install_test.go index ff025b809..fe98524f6 100644 --- a/cmd/helm/install_test.go +++ b/cmd/helm/install_test.go @@ -123,7 +123,7 @@ func TestInstall(t *testing.T) { // Install, using the name-template { name: "install with name-template", - cmd: "install testdata/testcharts/empty --name-template '{{upper \"foobar\"}}'", + cmd: "install testdata/testcharts/empty --name-template '{{ \"foobar\"}}'", golden: "output/install-name-template.txt", }, // Install, perform chart verification along the way. diff --git a/cmd/helm/template.go b/cmd/helm/template.go index e3c1d421f..f9c51542a 100644 --- a/cmd/helm/template.go +++ b/cmd/helm/template.go @@ -74,7 +74,7 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { } client.DryRun = true - client.ReleaseName = "RELEASE-NAME" + client.ReleaseName = "release-name" client.Replace = true // Skip the name check client.ClientOnly = !validate client.APIVersions = chartutil.VersionSet(extraAPIs) diff --git a/cmd/helm/template_test.go b/cmd/helm/template_test.go index 8fb8292e2..d1f17fe98 100644 --- a/cmd/helm/template_test.go +++ b/cmd/helm/template_test.go @@ -43,7 +43,7 @@ func TestTemplateCmd(t *testing.T) { }, { name: "check name template", - cmd: fmt.Sprintf(`template '%s' --name-template='foobar-{{ b64enc "abc" }}-baz'`, chartPath), + cmd: fmt.Sprintf(`template '%s' --name-template='foobar-{{ b64enc "abc" | lower }}-baz'`, chartPath), golden: "output/template-name-template.txt", }, { diff --git a/cmd/helm/testdata/output/install-name-template.txt b/cmd/helm/testdata/output/install-name-template.txt index 67e06d92b..19952e3c2 100644 --- a/cmd/helm/testdata/output/install-name-template.txt +++ b/cmd/helm/testdata/output/install-name-template.txt @@ -1,4 +1,4 @@ -NAME: FOOBAR +NAME: foobar LAST DEPLOYED: Fri Sep 2 22:04:05 1977 NAMESPACE: default STATUS: deployed diff --git a/cmd/helm/testdata/output/template-chart-with-template-lib-archive-dep.txt b/cmd/helm/testdata/output/template-chart-with-template-lib-archive-dep.txt index dc1aa2907..c954b8e14 100644 --- a/cmd/helm/testdata/output/template-chart-with-template-lib-archive-dep.txt +++ b/cmd/helm/testdata/output/template-chart-with-template-lib-archive-dep.txt @@ -7,7 +7,7 @@ metadata: app: chart-with-template-lib-archive-dep chart: chart-with-template-lib-archive-dep-0.1.0 heritage: Helm - release: RELEASE-NAME + release: release-name name: release-name-chart-with-template-lib-archive-dep spec: ports: @@ -16,30 +16,30 @@ spec: targetPort: http selector: app: chart-with-template-lib-archive-dep - release: RELEASE-NAME + release: release-name type: ClusterIP --- # Source: chart-with-template-lib-archive-dep/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: - name: RELEASE-NAME-chart-with-template-lib-archive-dep + name: release-name-chart-with-template-lib-archive-dep labels: app: chart-with-template-lib-archive-dep chart: chart-with-template-lib-archive-dep-0.1.0 - release: RELEASE-NAME + release: release-name heritage: Helm spec: replicas: 1 selector: matchLabels: app: chart-with-template-lib-archive-dep - release: RELEASE-NAME + release: release-name template: metadata: labels: app: chart-with-template-lib-archive-dep - release: RELEASE-NAME + release: release-name spec: containers: - name: chart-with-template-lib-archive-dep diff --git a/cmd/helm/testdata/output/template-chart-with-template-lib-dep.txt b/cmd/helm/testdata/output/template-chart-with-template-lib-dep.txt index 12adeb28b..74a2a2df8 100644 --- a/cmd/helm/testdata/output/template-chart-with-template-lib-dep.txt +++ b/cmd/helm/testdata/output/template-chart-with-template-lib-dep.txt @@ -7,7 +7,7 @@ metadata: app: chart-with-template-lib-dep chart: chart-with-template-lib-dep-0.1.0 heritage: Helm - release: RELEASE-NAME + release: release-name name: release-name-chart-with-template-lib-dep spec: ports: @@ -16,30 +16,30 @@ spec: targetPort: http selector: app: chart-with-template-lib-dep - release: RELEASE-NAME + release: release-name type: ClusterIP --- # Source: chart-with-template-lib-dep/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: - name: RELEASE-NAME-chart-with-template-lib-dep + name: release-name-chart-with-template-lib-dep labels: app: chart-with-template-lib-dep chart: chart-with-template-lib-dep-0.1.0 - release: RELEASE-NAME + release: release-name heritage: Helm spec: replicas: 1 selector: matchLabels: app: chart-with-template-lib-dep - release: RELEASE-NAME + release: release-name template: metadata: labels: app: chart-with-template-lib-dep - release: RELEASE-NAME + release: release-name spec: containers: - name: chart-with-template-lib-dep diff --git a/cmd/helm/testdata/output/template-name-template.txt b/cmd/helm/testdata/output/template-name-template.txt index b9e7cbbe4..9406048dd 100644 --- a/cmd/helm/testdata/output/template-name-template.txt +++ b/cmd/helm/testdata/output/template-name-template.txt @@ -70,7 +70,7 @@ metadata: name: subchart labels: helm.sh/chart: "subchart-0.1.0" - app.kubernetes.io/instance: "foobar-YWJj-baz" + app.kubernetes.io/instance: "foobar-ywjj-baz" kube-version/major: "1" kube-version/minor: "20" kube-version/version: "v1.20.0" @@ -88,7 +88,7 @@ spec: apiVersion: v1 kind: ConfigMap metadata: - name: "foobar-YWJj-baz-testconfig" + name: "foobar-ywjj-baz-testconfig" annotations: "helm.sh/hook": test data: @@ -98,7 +98,7 @@ data: apiVersion: v1 kind: Pod metadata: - name: "foobar-YWJj-baz-test" + name: "foobar-ywjj-baz-test" annotations: "helm.sh/hook": test spec: @@ -107,7 +107,7 @@ spec: image: "alpine:latest" envFrom: - configMapRef: - name: "foobar-YWJj-baz-testconfig" + name: "foobar-ywjj-baz-testconfig" command: - echo - "$message" diff --git a/cmd/helm/testdata/output/template-set.txt b/cmd/helm/testdata/output/template-set.txt index 177d8e58c..4040991cf 100644 --- a/cmd/helm/testdata/output/template-set.txt +++ b/cmd/helm/testdata/output/template-set.txt @@ -70,7 +70,7 @@ metadata: name: subchart labels: helm.sh/chart: "subchart-0.1.0" - app.kubernetes.io/instance: "RELEASE-NAME" + app.kubernetes.io/instance: "release-name" kube-version/major: "1" kube-version/minor: "20" kube-version/version: "v1.20.0" @@ -88,7 +88,7 @@ spec: apiVersion: v1 kind: ConfigMap metadata: - name: "RELEASE-NAME-testconfig" + name: "release-name-testconfig" annotations: "helm.sh/hook": test data: @@ -98,7 +98,7 @@ data: apiVersion: v1 kind: Pod metadata: - name: "RELEASE-NAME-test" + name: "release-name-test" annotations: "helm.sh/hook": test spec: @@ -107,7 +107,7 @@ spec: image: "alpine:latest" envFrom: - configMapRef: - name: "RELEASE-NAME-testconfig" + name: "release-name-testconfig" command: - echo - "$message" diff --git a/cmd/helm/testdata/output/template-show-only-multiple.txt b/cmd/helm/testdata/output/template-show-only-multiple.txt index 81a1d8e3c..1aac3081a 100644 --- a/cmd/helm/testdata/output/template-show-only-multiple.txt +++ b/cmd/helm/testdata/output/template-show-only-multiple.txt @@ -6,7 +6,7 @@ metadata: name: subchart labels: helm.sh/chart: "subchart-0.1.0" - app.kubernetes.io/instance: "RELEASE-NAME" + app.kubernetes.io/instance: "release-name" kube-version/major: "1" kube-version/minor: "20" kube-version/version: "v1.20.0" diff --git a/cmd/helm/testdata/output/template-show-only-one.txt b/cmd/helm/testdata/output/template-show-only-one.txt index a354bc0cc..9cc34f515 100644 --- a/cmd/helm/testdata/output/template-show-only-one.txt +++ b/cmd/helm/testdata/output/template-show-only-one.txt @@ -6,7 +6,7 @@ metadata: name: subchart labels: helm.sh/chart: "subchart-0.1.0" - app.kubernetes.io/instance: "RELEASE-NAME" + app.kubernetes.io/instance: "release-name" kube-version/major: "1" kube-version/minor: "20" kube-version/version: "v1.20.0" diff --git a/cmd/helm/testdata/output/template-skip-tests.txt b/cmd/helm/testdata/output/template-skip-tests.txt index 8e8181474..5c907b563 100644 --- a/cmd/helm/testdata/output/template-skip-tests.txt +++ b/cmd/helm/testdata/output/template-skip-tests.txt @@ -70,7 +70,7 @@ metadata: name: subchart labels: helm.sh/chart: "subchart-0.1.0" - app.kubernetes.io/instance: "RELEASE-NAME" + app.kubernetes.io/instance: "release-name" kube-version/major: "1" kube-version/minor: "20" kube-version/version: "v1.20.0" diff --git a/cmd/helm/testdata/output/template-values-files.txt b/cmd/helm/testdata/output/template-values-files.txt index 177d8e58c..4040991cf 100644 --- a/cmd/helm/testdata/output/template-values-files.txt +++ b/cmd/helm/testdata/output/template-values-files.txt @@ -70,7 +70,7 @@ metadata: name: subchart labels: helm.sh/chart: "subchart-0.1.0" - app.kubernetes.io/instance: "RELEASE-NAME" + app.kubernetes.io/instance: "release-name" kube-version/major: "1" kube-version/minor: "20" kube-version/version: "v1.20.0" @@ -88,7 +88,7 @@ spec: apiVersion: v1 kind: ConfigMap metadata: - name: "RELEASE-NAME-testconfig" + name: "release-name-testconfig" annotations: "helm.sh/hook": test data: @@ -98,7 +98,7 @@ data: apiVersion: v1 kind: Pod metadata: - name: "RELEASE-NAME-test" + name: "release-name-test" annotations: "helm.sh/hook": test spec: @@ -107,7 +107,7 @@ spec: image: "alpine:latest" envFrom: - configMapRef: - name: "RELEASE-NAME-testconfig" + name: "release-name-testconfig" command: - echo - "$message" diff --git a/cmd/helm/testdata/output/template-with-api-version.txt b/cmd/helm/testdata/output/template-with-api-version.txt index 4b2d4ee84..7e1c35001 100644 --- a/cmd/helm/testdata/output/template-with-api-version.txt +++ b/cmd/helm/testdata/output/template-with-api-version.txt @@ -70,7 +70,7 @@ metadata: name: subchart labels: helm.sh/chart: "subchart-0.1.0" - app.kubernetes.io/instance: "RELEASE-NAME" + app.kubernetes.io/instance: "release-name" kube-version/major: "1" kube-version/minor: "20" kube-version/version: "v1.20.0" @@ -89,7 +89,7 @@ spec: apiVersion: v1 kind: ConfigMap metadata: - name: "RELEASE-NAME-testconfig" + name: "release-name-testconfig" annotations: "helm.sh/hook": test data: @@ -99,7 +99,7 @@ data: apiVersion: v1 kind: Pod metadata: - name: "RELEASE-NAME-test" + name: "release-name-test" annotations: "helm.sh/hook": test spec: @@ -108,7 +108,7 @@ spec: image: "alpine:latest" envFrom: - configMapRef: - name: "RELEASE-NAME-testconfig" + name: "release-name-testconfig" command: - echo - "$message" diff --git a/cmd/helm/testdata/output/template-with-crds.txt b/cmd/helm/testdata/output/template-with-crds.txt index 758e2e39f..dd58480c9 100644 --- a/cmd/helm/testdata/output/template-with-crds.txt +++ b/cmd/helm/testdata/output/template-with-crds.txt @@ -87,7 +87,7 @@ metadata: name: subchart labels: helm.sh/chart: "subchart-0.1.0" - app.kubernetes.io/instance: "RELEASE-NAME" + app.kubernetes.io/instance: "release-name" kube-version/major: "1" kube-version/minor: "20" kube-version/version: "v1.20.0" @@ -105,7 +105,7 @@ spec: apiVersion: v1 kind: ConfigMap metadata: - name: "RELEASE-NAME-testconfig" + name: "release-name-testconfig" annotations: "helm.sh/hook": test data: @@ -115,7 +115,7 @@ data: apiVersion: v1 kind: Pod metadata: - name: "RELEASE-NAME-test" + name: "release-name-test" annotations: "helm.sh/hook": test spec: @@ -124,7 +124,7 @@ spec: image: "alpine:latest" envFrom: - configMapRef: - name: "RELEASE-NAME-testconfig" + name: "release-name-testconfig" command: - echo - "$message" diff --git a/cmd/helm/testdata/output/template-with-invalid-yaml-debug.txt b/cmd/helm/testdata/output/template-with-invalid-yaml-debug.txt index c1f51185c..909c543d3 100644 --- a/cmd/helm/testdata/output/template-with-invalid-yaml-debug.txt +++ b/cmd/helm/testdata/output/template-with-invalid-yaml-debug.txt @@ -3,7 +3,7 @@ apiVersion: v1 kind: Pod metadata: - name: "RELEASE-NAME-my-alpine" + name: "release-name-my-alpine" spec: containers: - name: waiter diff --git a/cmd/helm/testdata/output/template-with-kube-version.txt b/cmd/helm/testdata/output/template-with-kube-version.txt index 836905268..9d326f328 100644 --- a/cmd/helm/testdata/output/template-with-kube-version.txt +++ b/cmd/helm/testdata/output/template-with-kube-version.txt @@ -70,7 +70,7 @@ metadata: name: subchart labels: helm.sh/chart: "subchart-0.1.0" - app.kubernetes.io/instance: "RELEASE-NAME" + app.kubernetes.io/instance: "release-name" kube-version/major: "1" kube-version/minor: "16" kube-version/version: "v1.16.0" @@ -88,7 +88,7 @@ spec: apiVersion: v1 kind: ConfigMap metadata: - name: "RELEASE-NAME-testconfig" + name: "release-name-testconfig" annotations: "helm.sh/hook": test data: @@ -98,7 +98,7 @@ data: apiVersion: v1 kind: Pod metadata: - name: "RELEASE-NAME-test" + name: "release-name-test" annotations: "helm.sh/hook": test spec: @@ -107,7 +107,7 @@ spec: image: "alpine:latest" envFrom: - configMapRef: - name: "RELEASE-NAME-testconfig" + name: "release-name-testconfig" command: - echo - "$message" diff --git a/cmd/helm/testdata/output/template.txt b/cmd/helm/testdata/output/template.txt index 4146a0749..58c480b47 100644 --- a/cmd/helm/testdata/output/template.txt +++ b/cmd/helm/testdata/output/template.txt @@ -70,7 +70,7 @@ metadata: name: subchart labels: helm.sh/chart: "subchart-0.1.0" - app.kubernetes.io/instance: "RELEASE-NAME" + app.kubernetes.io/instance: "release-name" kube-version/major: "1" kube-version/minor: "20" kube-version/version: "v1.20.0" @@ -88,7 +88,7 @@ spec: apiVersion: v1 kind: ConfigMap metadata: - name: "RELEASE-NAME-testconfig" + name: "release-name-testconfig" annotations: "helm.sh/hook": test data: @@ -98,7 +98,7 @@ data: apiVersion: v1 kind: Pod metadata: - name: "RELEASE-NAME-test" + name: "release-name-test" annotations: "helm.sh/hook": test spec: @@ -107,7 +107,7 @@ spec: image: "alpine:latest" envFrom: - configMapRef: - name: "RELEASE-NAME-testconfig" + name: "release-name-testconfig" command: - echo - "$message" diff --git a/cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/README.md b/cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/README.md index ca0459474..0e06414d6 100755 --- a/cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/README.md +++ b/cmd/helm/testdata/testcharts/chart-with-template-lib-dep/charts/common/README.md @@ -13,7 +13,7 @@ A few tips for working with Common: - Be careful when using functions that generate random data (like `common.fullname.unique`). They may trigger unwanted upgrades or have other side effects. -In this document, we use `RELEASE-NAME` as the name of the release. +In this document, we use `release-name` as the name of the release. ## Resource Kinds @@ -733,7 +733,7 @@ metadata: labels: app: metadata heritage: "Tiller" - release: "RELEASE-NAME" + release: "release-name" chart: metadata-0.1.0 first: "matt" last: "butcher" @@ -748,7 +748,7 @@ metadata: labels: app: metadata heritage: "Tiller" - release: "RELEASE-NAME" + release: "release-name" chart: metadata-0.1.0 annotations: ``` @@ -791,7 +791,7 @@ Example output: ```yaml app: labelizer heritage: "Tiller" -release: "RELEASE-NAME" +release: "release-name" chart: labelizer-0.1.0 ``` diff --git a/cmd/helm/testdata/testcharts/lib-chart/README.md b/cmd/helm/testdata/testcharts/lib-chart/README.md index aca257924..87b753f25 100644 --- a/cmd/helm/testdata/testcharts/lib-chart/README.md +++ b/cmd/helm/testdata/testcharts/lib-chart/README.md @@ -13,7 +13,7 @@ A few tips for working with Common: - Be careful when using functions that generate random data (like `common.fullname.unique`). They may trigger unwanted upgrades or have other side effects. -In this document, we use `RELEASE-NAME` as the name of the release. +In this document, we use `release-name` as the name of the release. ## Resource Kinds @@ -733,7 +733,7 @@ metadata: labels: app.kubernetes.io/name: metadata app.kubernetes.io/managed-by: "Helm" - app.kubernetes.io/instance: "RELEASE-NAME" + app.kubernetes.io/instance: "release-name" helm.sh/chart: metadata-0.1.0 first: "matt" last: "butcher" @@ -748,7 +748,7 @@ metadata: labels: app.kubernetes.io/name: metadata app.kubernetes.io/managed-by: "Helm" - app.kubernetes.io/instance: "RELEASE-NAME" + app.kubernetes.io/instance: "release-name" helm.sh/chart: metadata-0.1.0 annotations: ``` @@ -791,7 +791,7 @@ Example output: ```yaml app.kubernetes.io/name: labelizer app.kubernetes.io/managed-by: "Tiller" -app.kubernetes.io/instance: "RELEASE-NAME" +app.kubernetes.io/instance: "release-name" helm.sh/chart: labelizer-0.1.0 ``` diff --git a/pkg/action/install.go b/pkg/action/install.go index e91154515..922f728b0 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -54,13 +54,6 @@ import ( "helm.sh/helm/v3/pkg/storage/driver" ) -// releaseNameMaxLen is the maximum length of a release name. -// -// As of Kubernetes 1.4, the max limit on a name is 63 chars. We reserve 10 for -// charts to add data. Effectively, that gives us 53 chars. -// See https://github.com/helm/helm/issues/1528 -const releaseNameMaxLen = 53 - // NOTESFILE_SUFFIX that we want to treat special. It goes through the templating engine // but it's not a yaml file (resource) hence can't have hooks, etc. And the user actually // wants to see this file after rendering in the status command. However, it must be a suffix @@ -458,14 +451,10 @@ func (i *Install) failRelease(rel *release.Release, err error) (*release.Release // - used by a deleted release, and i.Replace is false func (i *Install) availableName() error { start := i.ReleaseName - if start == "" { - return errors.New("name is required") - } - if len(start) > releaseNameMaxLen { - return errors.Errorf("release name %q exceeds max length of %d", start, releaseNameMaxLen) + if err := chartutil.ValidateReleaseName(start); err != nil { + return errors.Wrapf(err, "release name %q", start) } - if i.DryRun { return nil } diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index b1844b2ce..3d08d7889 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -132,7 +132,7 @@ func TestInstallRelease_NoName(t *testing.T) { if err == nil { t.Fatal("expected failure when no name is specified") } - assert.Contains(t, err.Error(), "name is required") + assert.Contains(t, err.Error(), "no name provided") } func TestInstallRelease_WithNotes(t *testing.T) { diff --git a/pkg/chartutil/validate_name.go b/pkg/chartutil/validate_name.go index d253731ec..8c45d533b 100644 --- a/pkg/chartutil/validate_name.go +++ b/pkg/chartutil/validate_name.go @@ -52,7 +52,12 @@ var ( ) const ( - // maxNameLen is the maximum length Helm allows for a release name + // According to the Kubernetes docs (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#rfc-1035-label-names) + // some resource names have a max length of 63 characters while others have a max + // length of 253 characters. As we cannot be sure the resources used in a chart, we + // therefore need to limit it to 63 chars and reserve 10 chars for additional part to name + // of the resource. The reason is that chart maintainers can use release name as part of + // the resource name (and some additional chars). maxReleaseNameLen = 53 // maxMetadataNameLen is the maximum length Kubernetes allows for any name. maxMetadataNameLen = 253 From b8d3535991dd5089d58bc88c46a5ffe2721ae830 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Fri, 31 Dec 2021 10:49:49 -0500 Subject: [PATCH 09/48] feat(comp): Allow fuzzy matching during completion We had made the assumption that when doing shell completion, we only needed choices that had for *prefix* what the user had typed. However, the zsh and fish shells have a more advanced matching system which first matches on prefix, but if no match is found, then does more advanced matching attempts, such as sub-strings; fish even matches on descriptions of completions. For example, helm status nginx would match releases such as ingress-nginx ingress-nginx-release as long as no release had a prefix of "nginx". Such fuzzy matching can make completion even more useful for users in cases where identical prefixes are common. Signed-off-by: Marc Khouzam --- cmd/helm/docs.go | 9 +---- cmd/helm/docs_test.go | 4 +-- cmd/helm/flags.go | 35 ++++++++----------- cmd/helm/flags_test.go | 7 ++++ cmd/helm/history.go | 10 ++---- cmd/helm/history_test.go | 5 +++ cmd/helm/install_test.go | 4 +++ cmd/helm/list.go | 9 ++++- cmd/helm/plugin_list.go | 5 +-- cmd/helm/plugin_test.go | 10 ++++++ cmd/helm/pull_test.go | 4 +++ cmd/helm/repo_list.go | 5 +-- cmd/helm/repo_remove_test.go | 4 +++ cmd/helm/root.go | 8 ++--- cmd/helm/search_repo.go | 5 +-- cmd/helm/show_test.go | 4 +++ .../output/docs-type-filtered-comp.txt | 3 -- cmd/helm/testdata/output/status-comp.txt | 1 + cmd/helm/upgrade_test.go | 4 +++ 19 files changed, 79 insertions(+), 57 deletions(-) delete mode 100644 cmd/helm/testdata/output/docs-type-filtered-comp.txt diff --git a/cmd/helm/docs.go b/cmd/helm/docs.go index 1a28a47ec..ef64d41a5 100644 --- a/cmd/helm/docs.go +++ b/cmd/helm/docs.go @@ -69,14 +69,7 @@ func newDocsCmd(out io.Writer) *cobra.Command { f.BoolVar(&o.generateHeaders, "generate-headers", false, "generate standard headers for markdown files") cmd.RegisterFlagCompletionFunc("type", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - types := []string{"bash", "man", "markdown"} - var comps []string - for _, t := range types { - if strings.HasPrefix(t, toComplete) { - comps = append(comps, t) - } - } - return comps, cobra.ShellCompDirectiveNoFileComp + return []string{"bash", "man", "markdown"}, cobra.ShellCompDirectiveNoFileComp }) return cmd diff --git a/cmd/helm/docs_test.go b/cmd/helm/docs_test.go index f0082578a..fe5864d5e 100644 --- a/cmd/helm/docs_test.go +++ b/cmd/helm/docs_test.go @@ -26,9 +26,9 @@ func TestDocsTypeFlagCompletion(t *testing.T) { cmd: "__complete docs --type ''", golden: "output/docs-type-comp.txt", }, { - name: "completion for docs --type", + name: "completion for docs --type, no filter", cmd: "__complete docs --type mar", - golden: "output/docs-type-filtered-comp.txt", + golden: "output/docs-type-comp.txt", }} runTestCmd(t, tests) } diff --git a/cmd/helm/flags.go b/cmd/helm/flags.go index aefa836c7..6a59101b7 100644 --- a/cmd/helm/flags.go +++ b/cmd/helm/flags.go @@ -69,9 +69,7 @@ func bindOutputFlag(cmd *cobra.Command, varRef *output.Format) { err := cmd.RegisterFlagCompletionFunc(outputFlag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { var formatNames []string for format, desc := range output.FormatsWithDesc() { - if strings.HasPrefix(format, toComplete) { - formatNames = append(formatNames, fmt.Sprintf("%s\t%s", format, desc)) - } + formatNames = append(formatNames, fmt.Sprintf("%s\t%s", format, desc)) } // Sort the results to get a deterministic order for the tests @@ -153,24 +151,21 @@ func compVersionFlag(chartRef string, toComplete string) ([]string, cobra.ShellC var versions []string if indexFile, err := repo.LoadIndexFile(path); err == nil { for _, details := range indexFile.Entries[chartName] { - version := details.Metadata.Version - if strings.HasPrefix(version, toComplete) { - appVersion := details.Metadata.AppVersion - appVersionDesc := "" - if appVersion != "" { - appVersionDesc = fmt.Sprintf("App: %s, ", appVersion) - } - created := details.Created.Format("January 2, 2006") - createdDesc := "" - if created != "" { - createdDesc = fmt.Sprintf("Created: %s ", created) - } - deprecated := "" - if details.Metadata.Deprecated { - deprecated = "(deprecated)" - } - versions = append(versions, fmt.Sprintf("%s\t%s%s%s", version, appVersionDesc, createdDesc, deprecated)) + appVersion := details.Metadata.AppVersion + appVersionDesc := "" + if appVersion != "" { + appVersionDesc = fmt.Sprintf("App: %s, ", appVersion) + } + created := details.Created.Format("January 2, 2006") + createdDesc := "" + if created != "" { + createdDesc = fmt.Sprintf("Created: %s ", created) + } + deprecated := "" + if details.Metadata.Deprecated { + deprecated = "(deprecated)" } + versions = append(versions, fmt.Sprintf("%s\t%s%s%s", details.Metadata.Version, appVersionDesc, createdDesc, deprecated)) } } diff --git a/cmd/helm/flags_test.go b/cmd/helm/flags_test.go index d5576fe9f..07d28c460 100644 --- a/cmd/helm/flags_test.go +++ b/cmd/helm/flags_test.go @@ -83,6 +83,13 @@ func outputFlagCompletionTest(t *testing.T, cmdName string) { rels: releasesMockWithStatus(&release.Info{ Status: release.StatusDeployed, }), + }, { + name: "completion for output flag, no filter", + cmd: fmt.Sprintf("__complete %s --output jso", cmdName), + golden: "output/output-comp.txt", + rels: releasesMockWithStatus(&release.Info{ + Status: release.StatusDeployed, + }), }} runTestCmd(t, tests) } diff --git a/cmd/helm/history.go b/cmd/helm/history.go index 06ec07d6d..ee6f391e4 100644 --- a/cmd/helm/history.go +++ b/cmd/helm/history.go @@ -20,7 +20,6 @@ import ( "fmt" "io" "strconv" - "strings" "time" "github.com/gosuri/uitable" @@ -191,12 +190,9 @@ func compListRevisions(toComplete string, cfg *action.Configuration, releaseName var revisions []string if hist, err := client.Run(releaseName); err == nil { for _, release := range hist { - version := strconv.Itoa(release.Version) - if strings.HasPrefix(version, toComplete) { - appVersion := fmt.Sprintf("App: %s", release.Chart.Metadata.AppVersion) - chartDesc := fmt.Sprintf("Chart: %s-%s", release.Chart.Metadata.Name, release.Chart.Metadata.Version) - revisions = append(revisions, fmt.Sprintf("%s\t%s, %s", version, appVersion, chartDesc)) - } + appVersion := fmt.Sprintf("App: %s", release.Chart.Metadata.AppVersion) + chartDesc := fmt.Sprintf("Chart: %s-%s", release.Chart.Metadata.Name, release.Chart.Metadata.Version) + revisions = append(revisions, fmt.Sprintf("%s\t%s, %s", strconv.Itoa(release.Version), appVersion, chartDesc)) } return revisions, cobra.ShellCompDirectiveNoFileComp } diff --git a/cmd/helm/history_test.go b/cmd/helm/history_test.go index 2663e9ee9..07f2d85df 100644 --- a/cmd/helm/history_test.go +++ b/cmd/helm/history_test.go @@ -95,6 +95,11 @@ func revisionFlagCompletionTest(t *testing.T, cmdName string) { cmd: fmt.Sprintf("__complete %s musketeers --revision ''", cmdName), rels: releases, golden: "output/revision-comp.txt", + }, { + name: "completion for revision flag, no filter", + cmd: fmt.Sprintf("__complete %s musketeers --revision 1", cmdName), + rels: releases, + golden: "output/revision-comp.txt", }, { name: "completion for revision flag with too few args", cmd: fmt.Sprintf("__complete %s --revision ''", cmdName), diff --git a/cmd/helm/install_test.go b/cmd/helm/install_test.go index ff025b809..df6e9af79 100644 --- a/cmd/helm/install_test.go +++ b/cmd/helm/install_test.go @@ -275,6 +275,10 @@ func TestInstallVersionCompletion(t *testing.T) { name: "completion for install version flag with generate-name", cmd: fmt.Sprintf("%s __complete install --generate-name testing/alpine --version ''", repoSetup), golden: "output/version-comp.txt", + }, { + name: "completion for install version flag, no filter", + cmd: fmt.Sprintf("%s __complete install releasename testing/alpine --version 0.3", repoSetup), + golden: "output/version-comp.txt", }, { name: "completion for install version flag too few args", cmd: fmt.Sprintf("%s __complete install testing/alpine --version ''", repoSetup), diff --git a/cmd/helm/list.go b/cmd/helm/list.go index c361b550d..2f0e3da0b 100644 --- a/cmd/helm/list.go +++ b/cmd/helm/list.go @@ -224,7 +224,14 @@ func compListReleases(toComplete string, ignoredReleaseNames []string, cfg *acti client := action.NewList(cfg) client.All = true client.Limit = 0 - client.Filter = fmt.Sprintf("^%s", toComplete) + // Do not filter so as to get the entire list of releases. + // This will allow zsh and fish to match completion choices + // on other criteria then prefix. For example: + // helm status ingress + // can match + // helm status nginx-ingress + // + // client.Filter = fmt.Sprintf("^%s", toComplete) client.SetStateMask() releases, err := client.Run() diff --git a/cmd/helm/plugin_list.go b/cmd/helm/plugin_list.go index 6c3926a9d..ddf01f6f2 100644 --- a/cmd/helm/plugin_list.go +++ b/cmd/helm/plugin_list.go @@ -18,7 +18,6 @@ package main import ( "fmt" "io" - "strings" "github.com/gosuri/uitable" "github.com/spf13/cobra" @@ -82,9 +81,7 @@ func compListPlugins(toComplete string, ignoredPluginNames []string) []string { if err == nil && len(plugins) > 0 { filteredPlugins := filterPlugins(plugins, ignoredPluginNames) for _, p := range filteredPlugins { - if strings.HasPrefix(p.Metadata.Name, toComplete) { - pNames = append(pNames, fmt.Sprintf("%s\t%s", p.Metadata.Name, p.Metadata.Usage)) - } + pNames = append(pNames, fmt.Sprintf("%s\t%s", p.Metadata.Name, p.Metadata.Usage)) } } return pNames diff --git a/cmd/helm/plugin_test.go b/cmd/helm/plugin_test.go index 4fb834189..33de33522 100644 --- a/cmd/helm/plugin_test.go +++ b/cmd/helm/plugin_test.go @@ -307,6 +307,11 @@ func TestPluginCmdsCompletion(t *testing.T) { cmd: "__complete plugin update ''", golden: "output/plugin_list_comp.txt", rels: []*release.Release{}, + }, { + name: "completion for plugin update, no filter", + cmd: "__complete plugin update full", + golden: "output/plugin_list_comp.txt", + rels: []*release.Release{}, }, { name: "completion for plugin update repetition", cmd: "__complete plugin update args ''", @@ -317,6 +322,11 @@ func TestPluginCmdsCompletion(t *testing.T) { cmd: "__complete plugin uninstall ''", golden: "output/plugin_list_comp.txt", rels: []*release.Release{}, + }, { + name: "completion for plugin uninstall, no filter", + cmd: "__complete plugin uninstall full", + golden: "output/plugin_list_comp.txt", + rels: []*release.Release{}, }, { name: "completion for plugin uninstall repetition", cmd: "__complete plugin uninstall args ''", diff --git a/cmd/helm/pull_test.go b/cmd/helm/pull_test.go index 4d86a5029..901557bd2 100644 --- a/cmd/helm/pull_test.go +++ b/cmd/helm/pull_test.go @@ -371,6 +371,10 @@ func TestPullVersionCompletion(t *testing.T) { name: "completion for pull version flag", cmd: fmt.Sprintf("%s __complete pull testing/alpine --version ''", repoSetup), golden: "output/version-comp.txt", + }, { + name: "completion for pull version flag, no filter", + cmd: fmt.Sprintf("%s __complete pull testing/alpine --version 0.3", repoSetup), + golden: "output/version-comp.txt", }, { name: "completion for pull version flag too few args", cmd: fmt.Sprintf("%s __complete pull --version ''", repoSetup), diff --git a/cmd/helm/repo_list.go b/cmd/helm/repo_list.go index 537f8bd2c..efaf74155 100644 --- a/cmd/helm/repo_list.go +++ b/cmd/helm/repo_list.go @@ -19,7 +19,6 @@ package main import ( "fmt" "io" - "strings" "github.com/gosuri/uitable" "github.com/pkg/errors" @@ -131,9 +130,7 @@ func compListRepos(prefix string, ignoredRepoNames []string) []string { if err == nil && len(f.Repositories) > 0 { filteredRepos := filterRepos(f.Repositories, ignoredRepoNames) for _, repo := range filteredRepos { - if strings.HasPrefix(repo.Name, prefix) { - rNames = append(rNames, fmt.Sprintf("%s\t%s", repo.Name, repo.URL)) - } + rNames = append(rNames, fmt.Sprintf("%s\t%s", repo.Name, repo.URL)) } } return rNames diff --git a/cmd/helm/repo_remove_test.go b/cmd/helm/repo_remove_test.go index d9e77530f..768295655 100644 --- a/cmd/helm/repo_remove_test.go +++ b/cmd/helm/repo_remove_test.go @@ -197,6 +197,10 @@ func TestRepoRemoveCompletion(t *testing.T) { name: "completion for repo remove", cmd: fmt.Sprintf("%s __completeNoDesc repo remove ''", repoSetup), golden: "output/repo_list_comp.txt", + }, { + name: "completion for repo remove, no filter", + cmd: fmt.Sprintf("%s __completeNoDesc repo remove fo", repoSetup), + golden: "output/repo_list_comp.txt", }, { name: "completion for repo remove repetition", cmd: fmt.Sprintf("%s __completeNoDesc repo remove foo ''", repoSetup), diff --git a/cmd/helm/root.go b/cmd/helm/root.go index 0de4a738a..be72bbb84 100644 --- a/cmd/helm/root.go +++ b/cmd/helm/root.go @@ -106,9 +106,7 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string nsNames := []string{} if namespaces, err := client.CoreV1().Namespaces().List(context.Background(), metav1.ListOptions{TimeoutSeconds: &to}); err == nil { for _, ns := range namespaces.Items { - if strings.HasPrefix(ns.Name, toComplete) { - nsNames = append(nsNames, ns.Name) - } + nsNames = append(nsNames, ns.Name) } return nsNames, cobra.ShellCompDirectiveNoFileComp } @@ -133,9 +131,7 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string &clientcmd.ConfigOverrides{}).RawConfig(); err == nil { comps := []string{} for name, context := range config.Contexts { - if strings.HasPrefix(name, toComplete) { - comps = append(comps, fmt.Sprintf("%s\t%s", name, context.Cluster)) - } + comps = append(comps, fmt.Sprintf("%s\t%s", name, context.Cluster)) } return comps, cobra.ShellCompDirectiveNoFileComp } diff --git a/cmd/helm/search_repo.go b/cmd/helm/search_repo.go index ae60292a6..34232fcfa 100644 --- a/cmd/helm/search_repo.go +++ b/cmd/helm/search_repo.go @@ -312,8 +312,9 @@ func compListCharts(toComplete string, includeFiles bool) ([]string, cobra.Shell } repoWithSlash := fmt.Sprintf("%s/", repo) if strings.HasPrefix(toComplete, repoWithSlash) { - // Must complete with charts within the specified repo - completions = append(completions, compListChartsOfRepo(repo, toComplete)...) + // Must complete with charts within the specified repo. + // Don't filter on toComplete to allow for shell fuzzy matching + completions = append(completions, compListChartsOfRepo(repo, "")...) noSpace = false break } else if strings.HasPrefix(repo, toComplete) { diff --git a/cmd/helm/show_test.go b/cmd/helm/show_test.go index 8dba0aea4..2ecb80a43 100644 --- a/cmd/helm/show_test.go +++ b/cmd/helm/show_test.go @@ -98,6 +98,10 @@ func TestShowVersionCompletion(t *testing.T) { name: "completion for show version flag", cmd: fmt.Sprintf("%s __complete show chart testing/alpine --version ''", repoSetup), golden: "output/version-comp.txt", + }, { + name: "completion for show version flag, no filter", + cmd: fmt.Sprintf("%s __complete show chart testing/alpine --version 0.3", repoSetup), + golden: "output/version-comp.txt", }, { name: "completion for show version flag too few args", cmd: fmt.Sprintf("%s __complete show chart --version ''", repoSetup), diff --git a/cmd/helm/testdata/output/docs-type-filtered-comp.txt b/cmd/helm/testdata/output/docs-type-filtered-comp.txt deleted file mode 100644 index 55104f32e..000000000 --- a/cmd/helm/testdata/output/docs-type-filtered-comp.txt +++ /dev/null @@ -1,3 +0,0 @@ -markdown -:4 -Completion ended with directive: ShellCompDirectiveNoFileComp diff --git a/cmd/helm/testdata/output/status-comp.txt b/cmd/helm/testdata/output/status-comp.txt index 4f56ab30a..4c408c974 100644 --- a/cmd/helm/testdata/output/status-comp.txt +++ b/cmd/helm/testdata/output/status-comp.txt @@ -1,4 +1,5 @@ aramis Aramis-chart-0.0.0 -> uninstalled athos Athos-chart-1.2.3 -> deployed +porthos Porthos-chart-111.222.333 -> failed :4 Completion ended with directive: ShellCompDirectiveNoFileComp diff --git a/cmd/helm/upgrade_test.go b/cmd/helm/upgrade_test.go index fc2a22d7d..8afcb139b 100644 --- a/cmd/helm/upgrade_test.go +++ b/cmd/helm/upgrade_test.go @@ -406,6 +406,10 @@ func TestUpgradeVersionCompletion(t *testing.T) { name: "completion for upgrade version flag", cmd: fmt.Sprintf("%s __complete upgrade releasename testing/alpine --version ''", repoSetup), golden: "output/version-comp.txt", + }, { + name: "completion for upgrade version flag, no filter", + cmd: fmt.Sprintf("%s __complete upgrade releasename testing/alpine --version 0.3", repoSetup), + golden: "output/version-comp.txt", }, { name: "completion for upgrade version flag too few args", cmd: fmt.Sprintf("%s __complete upgrade releasename --version ''", repoSetup), From 472eb6f096eda77da8340fac88acab5ba6452ac5 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Wed, 5 Jan 2022 13:34:45 -0500 Subject: [PATCH 10/48] For OCI, convert + to _ before pull, and + to _ before push Signed-off-by: Scott Rigby --- internal/experimental/pusher/ocipusher.go | 5 +++++ pkg/getter/ocigetter.go | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/internal/experimental/pusher/ocipusher.go b/internal/experimental/pusher/ocipusher.go index a1df0da85..e8cf2b799 100644 --- a/internal/experimental/pusher/ocipusher.go +++ b/internal/experimental/pusher/ocipusher.go @@ -79,6 +79,11 @@ func (pusher *OCIPusher) push(chartRef, href string) error { path.Join(strings.TrimPrefix(href, fmt.Sprintf("%s://", registry.OCIScheme)), meta.Metadata.Name), meta.Metadata.Version) + // Convert plus (+) to underscore (_) before push, so OCI doesn't choke + // This must remain right above client.Push() + // See https://github.com/helm/helm/issues/10166 + ref = strings.ReplaceAll(ref, "+", "_") + _, err = client.Push(chartBytes, ref, pushOpts...) return err } diff --git a/pkg/getter/ocigetter.go b/pkg/getter/ocigetter.go index 45c92749c..110dee120 100644 --- a/pkg/getter/ocigetter.go +++ b/pkg/getter/ocigetter.go @@ -54,6 +54,11 @@ func (g *OCIGetter) get(href string) (*bytes.Buffer, error) { ref = fmt.Sprintf("%s:%s", ref, version) } + // Convert plus (+) to underscore (_) in request string before pull + // This must remain right above client.Pull() + // See https://github.com/helm/helm/issues/10166 + ref = strings.ReplaceAll(ref, "+", "_") + result, err := client.Pull(ref, pullOpts...) if err != nil { return nil, err From a30a8481b8d83e64574bb5ba2c1b632046654d63 Mon Sep 17 00:00:00 2001 From: Bridget Kromhout Date: Thu, 6 Jan 2022 12:14:30 -0600 Subject: [PATCH 11/48] Adding Joe Julian as triage maintainer Signed-off-by: Bridget Kromhout --- OWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/OWNERS b/OWNERS index db09856af..2624a6efd 100644 --- a/OWNERS +++ b/OWNERS @@ -9,6 +9,7 @@ maintainers: - SlickNik - technosophos triage: + - joejulian - yxxhero - zonggen emeritus: From 4aacbc44e0357a30ff644b2030f39f728c87ce41 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Sat, 8 Jan 2022 18:50:29 -0500 Subject: [PATCH 12/48] Move plus/underscore change to inside Client. Compare original ref for strict mode Signed-off-by: Scott Rigby --- internal/experimental/pusher/ocipusher.go | 5 ---- internal/experimental/registry/client.go | 31 ++++++++++++++++++++++- pkg/getter/ocigetter.go | 5 ---- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/internal/experimental/pusher/ocipusher.go b/internal/experimental/pusher/ocipusher.go index e8cf2b799..a1df0da85 100644 --- a/internal/experimental/pusher/ocipusher.go +++ b/internal/experimental/pusher/ocipusher.go @@ -79,11 +79,6 @@ func (pusher *OCIPusher) push(chartRef, href string) error { path.Join(strings.TrimPrefix(href, fmt.Sprintf("%s://", registry.OCIScheme)), meta.Metadata.Name), meta.Metadata.Version) - // Convert plus (+) to underscore (_) before push, so OCI doesn't choke - // This must remain right above client.Push() - // See https://github.com/helm/helm/issues/10166 - ref = strings.ReplaceAll(ref, "+", "_") - _, err = client.Push(chartBytes, ref, pushOpts...) return err } diff --git a/internal/experimental/registry/client.go b/internal/experimental/registry/client.go index 495671059..b020cdcce 100644 --- a/internal/experimental/registry/client.go +++ b/internal/experimental/registry/client.go @@ -37,6 +37,13 @@ import ( "helm.sh/helm/v3/pkg/helmpath" ) +// See https://github.com/helm/helm/issues/10166 +const registryUnderscoreMessage = ` +OCI artifact references do not support the plus sign(+). To solve this Helm +adopts the convention of changing plus (+) to underscore (_) in chart version +references during registry push - and OCI artifact reference from underscore +back to plus on registry pull.` + type ( // Client works with OCI-compliant registries Client struct { @@ -207,6 +214,11 @@ type ( // Pull downloads a chart from a registry func (c *Client) Pull(ref string, options ...PullOption) (*PullResult, error) { + // Convert plus (+) to underscore (_) in request string before pull + // This must remain right at the top of client.Pull() + // See https://github.com/helm/helm/issues/10166 + ref = strings.ReplaceAll(ref, "+", "_") + operation := &pullOperation{ withChart: true, // By default, always download the chart layer } @@ -354,8 +366,15 @@ func (c *Client) Pull(ref string, options ...PullOption) (*PullResult, error) { return nil, getProvDescriptorErr } } + fmt.Fprintf(c.out, "Pulled: %s\n", result.Ref) fmt.Fprintf(c.out, "Digest: %s\n", result.Manifest.Digest) + + if strings.Contains(result.Ref, "_") { + fmt.Fprintf(c.out, "%s contains an underscore.\n", result.Ref) + fmt.Fprint(c.out, registryUnderscoreMessage) + } + return result, nil } @@ -411,6 +430,11 @@ type ( // Push uploads a chart to a registry. func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResult, error) { + // Convert plus (+) to underscore (_) before push, so OCI doesn't choke + // See https://github.com/helm/helm/issues/10166 + origRef := ref + ref = strings.ReplaceAll(ref, "+", "_") + operation := &pushOperation{ strictMode: true, // By default, enable strict mode } @@ -422,7 +446,7 @@ func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResu return nil, err } if operation.strictMode { - if !strings.HasSuffix(ref, fmt.Sprintf("/%s:%s", meta.Name, meta.Version)) { + if !strings.HasSuffix(origRef, fmt.Sprintf("/%s:%s", meta.Name, meta.Version)) { return nil, errors.New( "strict mode enabled, ref basename and tag must match the chart name and version") } @@ -495,6 +519,11 @@ func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResu } fmt.Fprintf(c.out, "Pushed: %s\n", result.Ref) fmt.Fprintf(c.out, "Digest: %s\n", result.Manifest.Digest) + if strings.Contains(result.Ref, "_") { + fmt.Fprintf(c.out, "%s contains an underscore.\n", result.Ref) + fmt.Fprint(c.out, registryUnderscoreMessage) + } + return result, err } diff --git a/pkg/getter/ocigetter.go b/pkg/getter/ocigetter.go index 110dee120..45c92749c 100644 --- a/pkg/getter/ocigetter.go +++ b/pkg/getter/ocigetter.go @@ -54,11 +54,6 @@ func (g *OCIGetter) get(href string) (*bytes.Buffer, error) { ref = fmt.Sprintf("%s:%s", ref, version) } - // Convert plus (+) to underscore (_) in request string before pull - // This must remain right above client.Pull() - // See https://github.com/helm/helm/issues/10166 - ref = strings.ReplaceAll(ref, "+", "_") - result, err := client.Pull(ref, pullOpts...) if err != nil { return nil, err From 8424bc2b607118243ea1be4f3371c3947833e3b5 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Sun, 9 Jan 2022 14:54:00 -0500 Subject: [PATCH 13/48] Update registry underscore message with semver note for extra clarity Add newline to registry underscore message Signed-off-by: Scott Rigby --- internal/experimental/registry/client.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/experimental/registry/client.go b/internal/experimental/registry/client.go index b020cdcce..ef70ea8b5 100644 --- a/internal/experimental/registry/client.go +++ b/internal/experimental/registry/client.go @@ -39,10 +39,10 @@ import ( // See https://github.com/helm/helm/issues/10166 const registryUnderscoreMessage = ` -OCI artifact references do not support the plus sign(+). To solve this Helm -adopts the convention of changing plus (+) to underscore (_) in chart version -references during registry push - and OCI artifact reference from underscore -back to plus on registry pull.` +OCI artifact references (e.g. tags) do not support the plus sign (+). To support +storing semantic versions, Helm adopts the convention of changing plus (+) to +an underscore (_) in chart version tags when pushing to a registry and back to +a plus (+) when pulling from a registry.` type ( // Client works with OCI-compliant registries @@ -372,7 +372,7 @@ func (c *Client) Pull(ref string, options ...PullOption) (*PullResult, error) { if strings.Contains(result.Ref, "_") { fmt.Fprintf(c.out, "%s contains an underscore.\n", result.Ref) - fmt.Fprint(c.out, registryUnderscoreMessage) + fmt.Fprint(c.out, registryUnderscoreMessage+"\n") } return result, nil @@ -521,7 +521,7 @@ func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResu fmt.Fprintf(c.out, "Digest: %s\n", result.Manifest.Digest) if strings.Contains(result.Ref, "_") { fmt.Fprintf(c.out, "%s contains an underscore.\n", result.Ref) - fmt.Fprint(c.out, registryUnderscoreMessage) + fmt.Fprint(c.out, registryUnderscoreMessage+"\n") } return result, err From ee73a0263c02a6c53261fdaf2ad97542b18a844c Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Mon, 10 Jan 2022 11:20:50 -0500 Subject: [PATCH 14/48] Fixing issue where OCI handling early causes a bad message Note, there is OCI handling later in the funtion that should handle the situation instead. Closes #10534 Signed-off-by: Matt Farina --- pkg/downloader/manager.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 52f1a1312..fc6c7a432 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -578,8 +578,7 @@ func (m *Manager) resolveRepoNames(deps []*chart.Dependency) (map[string]string, missing := []string{} for _, dd := range deps { // Don't map the repository, we don't need to download chart from charts directory - // When OCI is used there is no Helm repository - if dd.Repository == "" || registry.IsOCI(dd.Repository) { + if dd.Repository == "" { continue } // if dep chart is from local path, verify the path is valid From f82896b0b5bf0199120e372c0778314b8ab7a7fd Mon Sep 17 00:00:00 2001 From: yxxhero Date: Sat, 2 Oct 2021 15:38:14 +0800 Subject: [PATCH 15/48] add more debug msg when helm upgrade Signed-off-by: yxxhero --- pkg/kube/client.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index cc38243ac..3ac94b1c9 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -264,7 +264,7 @@ func (c *Client) Update(original, target ResourceList, force bool) (*Result, err } for _, info := range original.Difference(target) { - c.Log("Deleting %q in %s...", info.Name, info.Namespace) + c.Log("Deleting %s %q in namespace %s...", info.Mapping.GroupVersionKind.Kind, info.Name, info.Namespace) if err := info.Get(); err != nil { c.Log("Unable to get obj %q, err: %s", info.Name, err) @@ -498,7 +498,7 @@ func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, } if patch == nil || string(patch) == "{}" { - c.Log("Looks like there are no changes for %s %q", target.Mapping.GroupVersionKind.Kind, target.Name) + c.Log("Looks like there are no changes for %s %q", kind, target.Name) // This needs to happen to make sure that Helm has the latest info from the API // Otherwise there will be no labels and other functions that use labels will panic if err := target.Get(); err != nil { @@ -507,6 +507,7 @@ func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, return nil } // send patch to server + c.Log("Patch %s %q in namespace %s", kind, target.Name, target.Namespace) obj, err = helper.Patch(target.Namespace, target.Name, patchType, patch, nil) if err != nil { return errors.Wrapf(err, "cannot patch %q with kind %s", target.Name, kind) From fb0eeebf66f290079acb2e957ba5bde93dc33b9f Mon Sep 17 00:00:00 2001 From: Josh Wolf Date: Mon, 10 Jan 2022 11:09:21 -0700 Subject: [PATCH 16/48] add oci reference validation and tag scoped (+) replacement to registry client Push/Pull Signed-off-by: Josh Wolf --- go.mod | 4 +- go.sum | 73 +++++++++++++++++++----- internal/experimental/registry/client.go | 33 ++++++----- internal/experimental/registry/util.go | 23 ++++++++ 4 files changed, 101 insertions(+), 32 deletions(-) diff --git a/go.mod b/go.mod index d9efa6a93..38885ecf8 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/Masterminds/squirrel v1.5.2 github.com/Masterminds/vcs v1.13.1 github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 - github.com/containerd/containerd v1.5.8 + github.com/containerd/containerd v1.5.9 github.com/cyphar/filepath-securejoin v0.2.3 github.com/distribution/distribution/v3 v3.0.0-20211118083504-a29a3c99a684 github.com/docker/docker v20.10.12+incompatible @@ -42,6 +42,6 @@ require ( k8s.io/client-go v0.23.1 k8s.io/klog/v2 v2.30.0 k8s.io/kubectl v0.23.1 - oras.land/oras-go v1.0.0 + oras.land/oras-go v1.1.0-rc2 sigs.k8s.io/yaml v1.3.0 ) diff --git a/go.sum b/go.sum index 1c6eb05d5..d2367febf 100644 --- a/go.sum +++ b/go.sum @@ -109,8 +109,9 @@ github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.4.17 h1:iT12IBVClFevaf8PuVyi3UmZOVh4OqnaLxDTW2O6j3w= github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= +github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= @@ -118,15 +119,19 @@ github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg3 github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= -github.com/Microsoft/hcsshim v0.8.23 h1:47MSwtKGXet80aIn+7h4YI6fwPmwIghAnsx2aOUrG2M= +github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg= +github.com/Microsoft/hcsshim v0.9.1 h1:VfDCj+QnY19ktX5TsH22JHcjaZ05RWQiwDbOyEg5ziM= +github.com/Microsoft/hcsshim v0.9.1/go.mod h1:Y/0uV2jUab5kBI7SQgl62at0AVX7uaruzADAVmxm3eM= github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= @@ -228,8 +233,9 @@ github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1 github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= -github.com/containerd/cgroups v1.0.1 h1:iJnMvco9XGvKUvNQkv88bE4uJXxRQH18efbKo9w5vHQ= github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= +github.com/containerd/cgroups v1.0.2 h1:mZBclaSgNDfPWtfhj2xJY28LZ9nYIgzB0pwSURPl6JM= +github.com/containerd/cgroups v1.0.2/go.mod h1:qpbpJ1jmlqsR9f2IyaLPsdkCdnt0rbDVqIDlhuu5tRY= github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= @@ -248,8 +254,10 @@ github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7 github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s= -github.com/containerd/containerd v1.5.8 h1:NmkCC1/QxyZFBny8JogwLpOy2f+VEbO/f6bV2Mqtwuw= -github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s= +github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= +github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c= +github.com/containerd/containerd v1.5.9 h1:rs6Xg1gtIxaeyG+Smsb/0xaSDu1VgFhOCKBXxMxbsF4= +github.com/containerd/containerd v1.5.9/go.mod h1:fvQqCfadDGga5HZyn3j4+dx56qj2I9YwBrlSdalvJYQ= github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= @@ -277,6 +285,7 @@ github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJ github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/stargz-snapshotter/estargz v0.4.1/go.mod h1:x7Q9dg9QYb4+ELgxmo4gBUeJB0tl5dqH1Sdz0nJU1QM= github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= @@ -344,15 +353,18 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8 github.com/distribution/distribution/v3 v3.0.0-20211118083504-a29a3c99a684 h1:DBZ2sN7CK6dgvHVpQsQj4sRMCbWTmd17l+5SUCjnQSY= github.com/distribution/distribution/v3 v3.0.0-20211118083504-a29a3c99a684/go.mod h1:UfCu3YXJJCI+IdnqGgYP82dk2+Joxmv+mUTVBES6wac= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v20.10.11+incompatible h1:tXU1ezXcruZQRrMP8RN2z9N91h+6egZTS1gsPsKantc= github.com/docker/cli v20.10.11+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v20.10.11+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v20.10.12+incompatible h1:CEeNmFM0QZIsJCZKMkZx0ZcahTiewkrgiwfYD+dfl1U= github.com/docker/docker v20.10.12+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/docker-credential-helpers v0.6.4 h1:axCks+yV+2MR3/kZhAmy07yC56WZ2Pwu/fKWtKuZB0o= github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= @@ -430,15 +442,19 @@ github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTg github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= @@ -534,6 +550,7 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -576,6 +593,7 @@ github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -652,6 +670,7 @@ github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/jmoiron/sqlx v1.3.4 h1:wv+0IJZfL5z0uZoUjlpKgHkgaFSYD+r9CfrXjEXsO7w= github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -676,8 +695,9 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.11.13 h1:eSvu8Tmq6j2psUJqJrLcWH6K3w5Dwc+qipbaA6eVEN4= github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -703,11 +723,13 @@ github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= @@ -740,6 +762,7 @@ github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= @@ -747,6 +770,7 @@ github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= @@ -779,8 +803,9 @@ github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQ github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= -github.com/moby/sys/mountinfo v0.4.1 h1:1O+1cHA1aujwEwwVMa2Xm2l+gIpUHyd3+D+d7LZh1kM= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.5.0 h1:2Ks8/r6lopsxWi9m58nlwjaeSzUX9iiL1vj5qB/9ObI= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 h1:yH0SvLzcbZxcJXho2yh7CqdENGMQe73Cw3woZBpPli0= @@ -813,16 +838,20 @@ github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6 github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= @@ -927,6 +956,7 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= @@ -1203,8 +1233,9 @@ golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d h1:62NvYBuaanGXR2ZOfwDFkhhl6X1DUgf8qg3GuQvxZsE= +golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1257,6 +1288,7 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1340,9 +1372,11 @@ golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1360,12 +1394,14 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -1381,6 +1417,7 @@ golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1410,12 +1447,14 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -1505,6 +1544,7 @@ google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -1544,8 +1584,9 @@ google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368 h1:Et6SkiuvnBn+SgrSYXs/BrUpGB4mbdwt4R3vaPIlicA= +google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -1576,8 +1617,9 @@ google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM= +google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1670,6 +1712,7 @@ k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= k8s.io/client-go v0.23.1 h1:Ma4Fhf/p07Nmj9yAB1H7UwbFHEBrSPg8lviR24U2GiQ= k8s.io/client-go v0.23.1/go.mod h1:6QSI8fEuqD4zgFK0xbdwfB/PthBsIxCJMa3s17WlcO0= +k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0= k8s.io/code-generator v0.23.1/go.mod h1:V7yn6VNTCWW8GqodYCESVo95fuiEg713S8B7WacWZDA= k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= @@ -1682,12 +1725,15 @@ k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw= k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4= @@ -1700,8 +1746,8 @@ k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/ k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b h1:wxEMGetGMur3J1xuGLQY7GEQYg9bZxKn3tKo5k/eYcs= k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -oras.land/oras-go v1.0.0 h1:R5+g6OYqsOPGcdwHZkMpT0tpKvTiIB8zAer0Nv+WF3c= -oras.land/oras-go v1.0.0/go.mod h1:MZN6VbUUZjfWRF1EJKPbAWhJtE+R8JVicRmeYZp8qDg= +oras.land/oras-go v1.1.0-rc2 h1:NVMIdNfgRp2TR6oIEmu3w0NTIje2FUav3e7dKjYrrX0= +oras.land/oras-go v1.1.0-rc2/go.mod h1:1A7vR/0KknT2UkJVWh+xMi95I/AhK8ZrxrnUSmXN0bQ= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= @@ -1716,6 +1762,7 @@ sigs.k8s.io/kustomize/cmd/config v0.10.2/go.mod h1:K2aW7nXJ0AaT+VA/eO0/dzFLxmpFc sigs.k8s.io/kustomize/kustomize/v4 v4.4.1/go.mod h1:qOKJMMz2mBP+vcS7vK+mNz4HBLjaQSWRY22EF6Tb7Io= sigs.k8s.io/kustomize/kyaml v0.13.0 h1:9c+ETyNfSrVhxvphs+K2dzT3dh5oVPPEqPOE/cUpScY= sigs.k8s.io/kustomize/kyaml v0.13.0/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= diff --git a/internal/experimental/registry/client.go b/internal/experimental/registry/client.go index ef70ea8b5..220b2048c 100644 --- a/internal/experimental/registry/client.go +++ b/internal/experimental/registry/client.go @@ -213,11 +213,11 @@ type ( ) // Pull downloads a chart from a registry -func (c *Client) Pull(ref string, options ...PullOption) (*PullResult, error) { - // Convert plus (+) to underscore (_) in request string before pull - // This must remain right at the top of client.Pull() - // See https://github.com/helm/helm/issues/10166 - ref = strings.ReplaceAll(ref, "+", "_") +func (c *Client) Pull(rawRef string, options ...PullOption) (*PullResult, error) { + ref, err := parseReference(rawRef) + if err != nil { + return nil, err + } operation := &pullOperation{ withChart: true, // By default, always download the chart layer @@ -248,14 +248,13 @@ func (c *Client) Pull(ref string, options ...PullOption) (*PullResult, error) { var descriptors, layers []ocispec.Descriptor registryStore := content.Registry{Resolver: c.resolver} - manifest, err := oras.Copy(ctx(c.out, c.debug), registryStore, ref, memoryStore, "", + manifest, err := oras.Copy(ctx(c.out, c.debug), registryStore, ref.String(), memoryStore, "", oras.WithPullEmptyNameAllowed(), oras.WithAllowedMediaTypes(allowedMediaTypes), oras.WithLayerDescriptors(func(l []ocispec.Descriptor) { layers = l })) if err != nil { - fmt.Println(err) return nil, err } @@ -315,7 +314,7 @@ func (c *Client) Pull(ref string, options ...PullOption) (*PullResult, error) { }, Chart: &descriptorPullSummaryWithMeta{}, Prov: &descriptorPullSummary{}, - Ref: ref, + Ref: ref.String(), } var getManifestErr error if _, manifestData, ok := memoryStore.Get(manifest); !ok { @@ -429,11 +428,11 @@ type ( ) // Push uploads a chart to a registry. -func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResult, error) { - // Convert plus (+) to underscore (_) before push, so OCI doesn't choke - // See https://github.com/helm/helm/issues/10166 - origRef := ref - ref = strings.ReplaceAll(ref, "+", "_") +func (c *Client) Push(data []byte, rawRef string, options ...PushOption) (*PushResult, error) { + ref, err := parseReference(rawRef) + if err != nil { + return nil, err + } operation := &pushOperation{ strictMode: true, // By default, enable strict mode @@ -446,7 +445,7 @@ func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResu return nil, err } if operation.strictMode { - if !strings.HasSuffix(origRef, fmt.Sprintf("/%s:%s", meta.Name, meta.Version)) { + if !strings.HasSuffix(rawRef, fmt.Sprintf("/%s:%s", meta.Name, meta.Version)) { return nil, errors.New( "strict mode enabled, ref basename and tag must match the chart name and version") } @@ -483,12 +482,12 @@ func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResu return nil, err } - if err := memoryStore.StoreManifest(ref, manifest, manifestData); err != nil { + if err := memoryStore.StoreManifest(ref.String(), manifest, manifestData); err != nil { return nil, err } registryStore := content.Registry{Resolver: c.resolver} - _, err = oras.Copy(ctx(c.out, c.debug), memoryStore, ref, registryStore, "", + _, err = oras.Copy(ctx(c.out, c.debug), memoryStore, ref.String(), registryStore, "", oras.WithNameValidation(nil)) if err != nil { return nil, err @@ -509,7 +508,7 @@ func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResu }, Chart: chartSummary, Prov: &descriptorPushSummary{}, // prevent nil references - Ref: ref, + Ref: ref.String(), } if operation.provData != nil { result.Prov = &descriptorPushSummary{ diff --git a/internal/experimental/registry/util.go b/internal/experimental/registry/util.go index 257e7af87..0e68d70aa 100644 --- a/internal/experimental/registry/util.go +++ b/internal/experimental/registry/util.go @@ -25,6 +25,7 @@ import ( "github.com/sirupsen/logrus" orascontext "oras.land/oras-go/pkg/context" + "oras.land/oras-go/pkg/registry" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" @@ -54,3 +55,25 @@ func ctx(out io.Writer, debug bool) context.Context { orascontext.GetLogger(ctx).Logger.SetLevel(logrus.DebugLevel) return ctx } + +// parseReference will parse and validate the reference, and clean tags when applicable +// tags are only cleaned when plus (+) signs are present, and are converted to underscores (_) before pushing +// See https://github.com/helm/helm/issues/10166 +func parseReference(raw string) (registry.Reference, error) { + // The sole possible reference modification is replacing plus (+) signs present in tags with underscores (_) + // To do this properly, we first need to identify a tag, and then pass it on to the reference parser + // NOTE: Passing immediately to the reference parser will fail since (+) signs are an invalid tag character, and + // simply replacing all plus (+) occurances could invalidate other portions of the URI + parts := strings.Split(raw, ":") + if len(parts) > 1 && !strings.Contains(parts[len(parts)-1], "/") { + tag := parts[len(parts)-1] + + if tag != "" { + // Replace any plus (+) signs with known underscore (_) conversion + newTag := strings.ReplaceAll(tag, "+", "_") + raw = strings.ReplaceAll(raw, tag, newTag) + } + } + + return registry.ParseReference(raw) +} From 157ac85ab72827062b963a99ab7990c31804c5dd Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Mon, 10 Jan 2022 13:22:28 -0500 Subject: [PATCH 17/48] Fix typo. Thanks buildbot. Also comments at 80 chars Signed-off-by: Scott Rigby --- internal/experimental/registry/util.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/internal/experimental/registry/util.go b/internal/experimental/registry/util.go index 0e68d70aa..c421e5639 100644 --- a/internal/experimental/registry/util.go +++ b/internal/experimental/registry/util.go @@ -56,14 +56,17 @@ func ctx(out io.Writer, debug bool) context.Context { return ctx } -// parseReference will parse and validate the reference, and clean tags when applicable -// tags are only cleaned when plus (+) signs are present, and are converted to underscores (_) before pushing -// See https://github.com/helm/helm/issues/10166 +// parseReference will parse and validate the reference, and clean tags when +// applicable tags are only cleaned when plus (+) signs are present, and are +// converted to underscores (_) before pushing +// See https://github.com/helm/helm/issues/10166 func parseReference(raw string) (registry.Reference, error) { - // The sole possible reference modification is replacing plus (+) signs present in tags with underscores (_) - // To do this properly, we first need to identify a tag, and then pass it on to the reference parser - // NOTE: Passing immediately to the reference parser will fail since (+) signs are an invalid tag character, and - // simply replacing all plus (+) occurances could invalidate other portions of the URI + // The sole possible reference modification is replacing plus (+) signs + // present in tags with underscores (_). To do this properly, we first + // need to identify a tag, and then pass it on to the reference parser + // NOTE: Passing immediately to the reference parser will fail since (+) + // signs are an invalid tag character, and simply replacing all plus (+) + // occurrences could invalidate other portions of the URI parts := strings.Split(raw, ":") if len(parts) > 1 && !strings.Contains(parts[len(parts)-1], "/") { tag := parts[len(parts)-1] From fed0d31bf5ea07515acb8f766a9a205fb8c84d46 Mon Sep 17 00:00:00 2001 From: Josh Wolf Date: Mon, 10 Jan 2022 15:06:18 -0700 Subject: [PATCH 18/48] ensure consistency in registry client Push/Pull function signatures. ensure message is only printed when tags contain a replaced character Signed-off-by: Josh Wolf --- internal/experimental/registry/client.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/internal/experimental/registry/client.go b/internal/experimental/registry/client.go index 220b2048c..78116f60f 100644 --- a/internal/experimental/registry/client.go +++ b/internal/experimental/registry/client.go @@ -213,8 +213,8 @@ type ( ) // Pull downloads a chart from a registry -func (c *Client) Pull(rawRef string, options ...PullOption) (*PullResult, error) { - ref, err := parseReference(rawRef) +func (c *Client) Pull(ref string, options ...PullOption) (*PullResult, error) { + parsedRef, err := parseReference(ref) if err != nil { return nil, err } @@ -248,7 +248,7 @@ func (c *Client) Pull(rawRef string, options ...PullOption) (*PullResult, error) var descriptors, layers []ocispec.Descriptor registryStore := content.Registry{Resolver: c.resolver} - manifest, err := oras.Copy(ctx(c.out, c.debug), registryStore, ref.String(), memoryStore, "", + manifest, err := oras.Copy(ctx(c.out, c.debug), registryStore, parsedRef.String(), memoryStore, "", oras.WithPullEmptyNameAllowed(), oras.WithAllowedMediaTypes(allowedMediaTypes), oras.WithLayerDescriptors(func(l []ocispec.Descriptor) { @@ -314,7 +314,7 @@ func (c *Client) Pull(rawRef string, options ...PullOption) (*PullResult, error) }, Chart: &descriptorPullSummaryWithMeta{}, Prov: &descriptorPullSummary{}, - Ref: ref.String(), + Ref: parsedRef.String(), } var getManifestErr error if _, manifestData, ok := memoryStore.Get(manifest); !ok { @@ -428,8 +428,8 @@ type ( ) // Push uploads a chart to a registry. -func (c *Client) Push(data []byte, rawRef string, options ...PushOption) (*PushResult, error) { - ref, err := parseReference(rawRef) +func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResult, error) { + parsedRef, err := parseReference(ref) if err != nil { return nil, err } @@ -445,7 +445,7 @@ func (c *Client) Push(data []byte, rawRef string, options ...PushOption) (*PushR return nil, err } if operation.strictMode { - if !strings.HasSuffix(rawRef, fmt.Sprintf("/%s:%s", meta.Name, meta.Version)) { + if !strings.HasSuffix(ref, fmt.Sprintf("/%s:%s", meta.Name, meta.Version)) { return nil, errors.New( "strict mode enabled, ref basename and tag must match the chart name and version") } @@ -482,12 +482,12 @@ func (c *Client) Push(data []byte, rawRef string, options ...PushOption) (*PushR return nil, err } - if err := memoryStore.StoreManifest(ref.String(), manifest, manifestData); err != nil { + if err := memoryStore.StoreManifest(parsedRef.String(), manifest, manifestData); err != nil { return nil, err } registryStore := content.Registry{Resolver: c.resolver} - _, err = oras.Copy(ctx(c.out, c.debug), memoryStore, ref.String(), registryStore, "", + _, err = oras.Copy(ctx(c.out, c.debug), memoryStore, parsedRef.String(), registryStore, "", oras.WithNameValidation(nil)) if err != nil { return nil, err @@ -508,7 +508,7 @@ func (c *Client) Push(data []byte, rawRef string, options ...PushOption) (*PushR }, Chart: chartSummary, Prov: &descriptorPushSummary{}, // prevent nil references - Ref: ref.String(), + Ref: parsedRef.String(), } if operation.provData != nil { result.Prov = &descriptorPushSummary{ @@ -518,7 +518,7 @@ func (c *Client) Push(data []byte, rawRef string, options ...PushOption) (*PushR } fmt.Fprintf(c.out, "Pushed: %s\n", result.Ref) fmt.Fprintf(c.out, "Digest: %s\n", result.Manifest.Digest) - if strings.Contains(result.Ref, "_") { + if strings.Contains(parsedRef.Reference, "_") { fmt.Fprintf(c.out, "%s contains an underscore.\n", result.Ref) fmt.Fprint(c.out, registryUnderscoreMessage+"\n") } From e08a9270be1b3be83397c73e7635fd2ecd8f043d Mon Sep 17 00:00:00 2001 From: Allen Bai Date: Mon, 10 Jan 2022 13:42:45 -0500 Subject: [PATCH 19/48] HELM_REGISTRY_CONFIG: change default file of registry config to config.json Changes default registry config file from `registry.json` to `config.json`. This aligns with the `config.json` that is widely used in docker. Closes: https://github.com/helm/helm/issues/10156 Related: https://github.com/helm/helm/issues/10122 Signed-off-by: Allen Bai --- internal/experimental/registry/constants.go | 2 +- pkg/cli/environment.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/experimental/registry/constants.go b/internal/experimental/registry/constants.go index 876e4dc13..9babcdfce 100644 --- a/internal/experimental/registry/constants.go +++ b/internal/experimental/registry/constants.go @@ -21,7 +21,7 @@ const ( OCIScheme = "oci" // CredentialsFileBasename is the filename for auth credentials file - CredentialsFileBasename = "registry.json" + CredentialsFileBasename = "registry/config.json" // ConfigMediaType is the reserved media type for the Helm chart manifest config ConfigMediaType = "application/vnd.cncf.helm.config.v1+json" diff --git a/pkg/cli/environment.go b/pkg/cli/environment.go index 7e3933cc6..d5b208015 100644 --- a/pkg/cli/environment.go +++ b/pkg/cli/environment.go @@ -81,7 +81,7 @@ func New() *EnvSettings { KubeAPIServer: os.Getenv("HELM_KUBEAPISERVER"), KubeCaFile: os.Getenv("HELM_KUBECAFILE"), PluginsDirectory: envOr("HELM_PLUGINS", helmpath.DataPath("plugins")), - RegistryConfig: envOr("HELM_REGISTRY_CONFIG", helmpath.ConfigPath("registry.json")), + RegistryConfig: envOr("HELM_REGISTRY_CONFIG", helmpath.ConfigPath("registry/config.json")), RepositoryConfig: envOr("HELM_REPOSITORY_CONFIG", helmpath.ConfigPath("repositories.yaml")), RepositoryCache: envOr("HELM_REPOSITORY_CACHE", helmpath.CachePath("repository")), } From e3897ad6b10ba2bf02b7505fb2baa63e74039b6f Mon Sep 17 00:00:00 2001 From: Allen Bai Date: Tue, 11 Jan 2022 13:20:56 -0500 Subject: [PATCH 20/48] registry/client: use NewClientWithDockerFallback from oras v1.1.0-rc3 Uses NewClientWithDockerFallback to always use Docker config and modifies go.mod to use oras v1.1.0-rc3. Ref: - https://github.com/helm/helm/pull/10536#issuecomment-1010144075 - https://github.com/oras-project/oras-go/pull/92 Signed-off-by: Allen Bai --- go.mod | 2 +- go.sum | 4 ++-- internal/experimental/registry/client.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 38885ecf8..d328ad8bb 100644 --- a/go.mod +++ b/go.mod @@ -42,6 +42,6 @@ require ( k8s.io/client-go v0.23.1 k8s.io/klog/v2 v2.30.0 k8s.io/kubectl v0.23.1 - oras.land/oras-go v1.1.0-rc2 + oras.land/oras-go v1.1.0-rc3 sigs.k8s.io/yaml v1.3.0 ) diff --git a/go.sum b/go.sum index d2367febf..c56a45885 100644 --- a/go.sum +++ b/go.sum @@ -1746,8 +1746,8 @@ k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/ k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b h1:wxEMGetGMur3J1xuGLQY7GEQYg9bZxKn3tKo5k/eYcs= k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -oras.land/oras-go v1.1.0-rc2 h1:NVMIdNfgRp2TR6oIEmu3w0NTIje2FUav3e7dKjYrrX0= -oras.land/oras-go v1.1.0-rc2/go.mod h1:1A7vR/0KknT2UkJVWh+xMi95I/AhK8ZrxrnUSmXN0bQ= +oras.land/oras-go v1.1.0-rc3 h1:+HdHR0Lgm/0jmjF4SqUif8Ky2XNWhrcP4hxGVvtKIUI= +oras.land/oras-go v1.1.0-rc3/go.mod h1:1A7vR/0KknT2UkJVWh+xMi95I/AhK8ZrxrnUSmXN0bQ= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/internal/experimental/registry/client.go b/internal/experimental/registry/client.go index 78116f60f..3bdfac20b 100644 --- a/internal/experimental/registry/client.go +++ b/internal/experimental/registry/client.go @@ -72,7 +72,7 @@ func NewClient(options ...ClientOption) (*Client, error) { client.credentialsFile = helmpath.ConfigPath(CredentialsFileBasename) } if client.authorizer == nil { - authClient, err := dockerauth.NewClient(client.credentialsFile) + authClient, err := dockerauth.NewClientWithDockerFallback(client.credentialsFile) if err != nil { return nil, err } From 0d2f0116eac616d9b3a3b8836a8d854bbe40be74 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Wed, 5 Jan 2022 18:41:02 -0500 Subject: [PATCH 21/48] hack in progress Signed-off-by: Scott Rigby --- internal/resolver/resolver.go | 68 +++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/internal/resolver/resolver.go b/internal/resolver/resolver.go index 70ce6a55b..6df33fd68 100644 --- a/internal/resolver/resolver.go +++ b/internal/resolver/resolver.go @@ -17,7 +17,9 @@ package resolver import ( "bytes" + "context" "encoding/json" + "net/http" "os" "path/filepath" "strings" @@ -33,6 +35,10 @@ import ( "helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v3/pkg/provenance" "helm.sh/helm/v3/pkg/repo" + + orasregistry "oras.land/oras-go/pkg/registry" + orasremote "oras.land/oras-go/pkg/registry/remote" + orasauth "oras.land/oras-go/pkg/registry/remote/auth" ) const FeatureGateOCI = gates.Gate("HELM_EXPERIMENTAL_OCI") @@ -52,6 +58,7 @@ func New(chartpath, cachepath string) *Resolver { } // Resolve resolves dependencies and returns a lock file with the resolution. +// To-do: clarify that we use "Repository" in struct as URL for registrytoo, even though strictly speaking it's not a helm "repository" func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string) (*chart.Lock, error) { // Now we clone the dependencies, locking as we go. @@ -139,6 +146,67 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string return nil, errors.Wrapf(FeatureGateOCI.Error(), "repository %s is an OCI registry", d.Repository) } + + // Call ORAS tag API + // See https://github.com/oras-project/oras-go/pull/89 + // - using string: concat d.Repository + d.Name + // - does latest version exist, find out how Masterminds/semver checks this given contstraint string, and get the version + // To-do: use registry.ctx() + // How to get the opts though without context from a *Client? + ctx := context.Background() + // Do we need to extract something from this string in order to work? + ociRepository := d.Repository + parsedRepository, err := orasregistry.ParseReference(ociRepository) + if err != nil { + return nil, errors.Wrapf(err, "no cached repository for %s found. (try 'helm repo update')", repoName) + } + + // To:do: Can we get client values from registry.NewClient()? + // If so how to pass client ops without an existing *Client? + // Example code for this: + // client, err := registry.NewClient() + // if err != nil { + // return nil, err + // } + client := &orasauth.Client{ + Header: http.Header{ + "User-Agent": {"oras-go"}, + }, + Cache: orasauth.DefaultCache, + } + + repository := orasremote.Repository{ + Reference: parsedRepository, + Client: client, + } + + // Get tags from ORAS tag API + // To-do: The block farther below comment says + // "The version are already sorted and hence the first one to satisfy the constraint is used" + // So how do we ensure these are sorted? + tags, err := orasregistry.Tags(ctx, &repository) + if err != nil { + return nil, err + } + + // Mock chart version objects + vs = make(repo.ChartVersions, len(tags)) + for i, tag := range tags { + // Change underscore (_) back to plus (+) for Helm + // See https://github.com/helm/helm/issues/10166 + tag = strings.ReplaceAll(tag, "_", "+") + + // Then add those on what comes from equivalent of tags + // To-do: do we need anything here other than Version and Name? + vs[i].Version = tag + vs[i].Name = d.Name + } + + // Ultimately either here before continue, or below, we want to accomplish: + // 1. if there's a reference that matches the version (did it work or not? could it locate image? 401 or 403 etc) + // 2. if so, proceed + // But below, if `len(ver.URLs) == 0` it's not considered valid, so we continue + // what is the equivalent of this for OCI? There is no tarball URL(s), right? } locked[i] = &chart.Dependency{ From 042e13d0d10dda30eadbc7f9069417a33bffd919 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Wed, 5 Jan 2022 18:46:13 -0500 Subject: [PATCH 22/48] Temp use Andy's fork PR branch Signed-off-by: Scott Rigby --- go.mod | 2 ++ go.sum | 2 ++ 2 files changed, 4 insertions(+) diff --git a/go.mod b/go.mod index d328ad8bb..427cbc04a 100644 --- a/go.mod +++ b/go.mod @@ -45,3 +45,5 @@ require ( oras.land/oras-go v1.1.0-rc3 sigs.k8s.io/yaml v1.3.0 ) + +replace oras.land/oras-go => github.com/sabre1041/oras-go v1.0.1-0.20220105042547-7ebb8809edae diff --git a/go.sum b/go.sum index c56a45885..19662166d 100644 --- a/go.sum +++ b/go.sum @@ -953,6 +953,8 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sabre1041/oras-go v1.0.1-0.20220105042547-7ebb8809edae h1:ZhMHqeREElljvMEkMcIak/rRWxWe7ut0x1jb0yFQ8CI= +github.com/sabre1041/oras-go v1.0.1-0.20220105042547-7ebb8809edae/go.mod h1:MZN6VbUUZjfWRF1EJKPbAWhJtE+R8JVicRmeYZp8qDg= github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= From 16453c372c41a82e676ba95a18b88890060f16b0 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Wed, 5 Jan 2022 18:46:57 -0500 Subject: [PATCH 23/48] It appears we never got to this block below. Quick rec by Farina. Untested if necessary Signed-off-by: Scott Rigby --- pkg/downloader/manager.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index fc6c7a432..c85b0b707 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -594,6 +594,8 @@ func (m *Manager) resolveRepoNames(deps []*chart.Dependency) (map[string]string, continue } + // See https://helm.sh/docs/topics/registries/#specifying-dependencies + // See createTestingMetadataForOCI() if registry.IsOCI(dd.Repository) { reposMap[dd.Name] = dd.Repository continue From 3dc9930488aeaf2fb6a15c266255ae9691167f8f Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Thu, 6 Jan 2022 19:08:46 -0500 Subject: [PATCH 24/48] Revert "hack in progress" This reverts commit c0be414e4b8d2928018504c010cb04b1b2450bf3. Taking a different approach, but keep this work in git history for now until we know the new approach works. Signed-off-by: Scott Rigby --- internal/resolver/resolver.go | 68 ----------------------------------- 1 file changed, 68 deletions(-) diff --git a/internal/resolver/resolver.go b/internal/resolver/resolver.go index 6df33fd68..70ce6a55b 100644 --- a/internal/resolver/resolver.go +++ b/internal/resolver/resolver.go @@ -17,9 +17,7 @@ package resolver import ( "bytes" - "context" "encoding/json" - "net/http" "os" "path/filepath" "strings" @@ -35,10 +33,6 @@ import ( "helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v3/pkg/provenance" "helm.sh/helm/v3/pkg/repo" - - orasregistry "oras.land/oras-go/pkg/registry" - orasremote "oras.land/oras-go/pkg/registry/remote" - orasauth "oras.land/oras-go/pkg/registry/remote/auth" ) const FeatureGateOCI = gates.Gate("HELM_EXPERIMENTAL_OCI") @@ -58,7 +52,6 @@ func New(chartpath, cachepath string) *Resolver { } // Resolve resolves dependencies and returns a lock file with the resolution. -// To-do: clarify that we use "Repository" in struct as URL for registrytoo, even though strictly speaking it's not a helm "repository" func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string) (*chart.Lock, error) { // Now we clone the dependencies, locking as we go. @@ -146,67 +139,6 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string return nil, errors.Wrapf(FeatureGateOCI.Error(), "repository %s is an OCI registry", d.Repository) } - - // Call ORAS tag API - // See https://github.com/oras-project/oras-go/pull/89 - // - using string: concat d.Repository + d.Name - // - does latest version exist, find out how Masterminds/semver checks this given contstraint string, and get the version - // To-do: use registry.ctx() - // How to get the opts though without context from a *Client? - ctx := context.Background() - // Do we need to extract something from this string in order to work? - ociRepository := d.Repository - parsedRepository, err := orasregistry.ParseReference(ociRepository) - if err != nil { - return nil, errors.Wrapf(err, "no cached repository for %s found. (try 'helm repo update')", repoName) - } - - // To:do: Can we get client values from registry.NewClient()? - // If so how to pass client ops without an existing *Client? - // Example code for this: - // client, err := registry.NewClient() - // if err != nil { - // return nil, err - // } - client := &orasauth.Client{ - Header: http.Header{ - "User-Agent": {"oras-go"}, - }, - Cache: orasauth.DefaultCache, - } - - repository := orasremote.Repository{ - Reference: parsedRepository, - Client: client, - } - - // Get tags from ORAS tag API - // To-do: The block farther below comment says - // "The version are already sorted and hence the first one to satisfy the constraint is used" - // So how do we ensure these are sorted? - tags, err := orasregistry.Tags(ctx, &repository) - if err != nil { - return nil, err - } - - // Mock chart version objects - vs = make(repo.ChartVersions, len(tags)) - for i, tag := range tags { - // Change underscore (_) back to plus (+) for Helm - // See https://github.com/helm/helm/issues/10166 - tag = strings.ReplaceAll(tag, "_", "+") - - // Then add those on what comes from equivalent of tags - // To-do: do we need anything here other than Version and Name? - vs[i].Version = tag - vs[i].Name = d.Name - } - - // Ultimately either here before continue, or below, we want to accomplish: - // 1. if there's a reference that matches the version (did it work or not? could it locate image? 401 or 403 etc) - // 2. if so, proceed - // But below, if `len(ver.URLs) == 0` it's not considered valid, so we continue - // what is the equivalent of this for OCI? There is no tarball URL(s), right? } locked[i] = &chart.Dependency{ From 39792b5ad004a99b3ef649a649a0f1834b07a0f6 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Thu, 6 Jan 2022 19:10:15 -0500 Subject: [PATCH 25/48] Revert "It appears we never got to this block below. Quick rec by Farina. Untested if necessary" This reverts commit f616a01808da3428c6191e5196f32ca72eb22254. Removing for now until we know we need it. Signed-off-by: Scott Rigby --- pkg/downloader/manager.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index c85b0b707..52f1a1312 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -578,7 +578,8 @@ func (m *Manager) resolveRepoNames(deps []*chart.Dependency) (map[string]string, missing := []string{} for _, dd := range deps { // Don't map the repository, we don't need to download chart from charts directory - if dd.Repository == "" { + // When OCI is used there is no Helm repository + if dd.Repository == "" || registry.IsOCI(dd.Repository) { continue } // if dep chart is from local path, verify the path is valid @@ -594,8 +595,6 @@ func (m *Manager) resolveRepoNames(deps []*chart.Dependency) (map[string]string, continue } - // See https://helm.sh/docs/topics/registries/#specifying-dependencies - // See createTestingMetadataForOCI() if registry.IsOCI(dd.Repository) { reposMap[dd.Name] = dd.Repository continue From 9a7c362dd115431f9f5c17606113769ec036530c Mon Sep 17 00:00:00 2001 From: Andrew Block Date: Thu, 6 Jan 2022 22:31:32 -0600 Subject: [PATCH 26/48] Initial tag listing support Signed-off-by: Andrew Block --- internal/experimental/registry/client.go | 36 +++++++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/internal/experimental/registry/client.go b/internal/experimental/registry/client.go index 3bdfac20b..fdfab76f4 100644 --- a/internal/experimental/registry/client.go +++ b/internal/experimental/registry/client.go @@ -31,6 +31,9 @@ import ( dockerauth "oras.land/oras-go/pkg/auth/docker" "oras.land/oras-go/pkg/content" "oras.land/oras-go/pkg/oras" + "oras.land/oras-go/pkg/registry" + registrremote "oras.land/oras-go/pkg/registry/remote" + registryauth "oras.land/oras-go/pkg/registry/remote/auth" "helm.sh/helm/v3/internal/version" "helm.sh/helm/v3/pkg/chart" @@ -49,10 +52,11 @@ type ( Client struct { debug bool // path to repository config file e.g. ~/.docker/config.json - credentialsFile string - out io.Writer - authorizer auth.Client - resolver remotes.Resolver + credentialsFile string + out io.Writer + authorizer auth.Client + registryAuthorizer *registryauth.Client + resolver remotes.Resolver } // ClientOption allows specifying various settings configurable by the user for overriding the defaults @@ -88,6 +92,15 @@ func NewClient(options ...ClientOption) (*Client, error) { } client.resolver = resolver } + if client.registryAuthorizer == nil { + client.registryAuthorizer = ®istryauth.Client{ + Header: http.Header{ + "User-Agent": {version.GetUserAgent()}, + }, + Cache: registryauth.DefaultCache, + } + + } return client, nil } @@ -539,3 +552,18 @@ func PushOptStrictMode(strictMode bool) PushOption { operation.strictMode = strictMode } } + +// Tags lists all tags for a given repository +func (c *Client) Tags(ref string) ([]string, error) { + parsedReference, err := registry.ParseReference(ref) + if err != nil { + return nil, err + } + + repository := registrremote.Repository{ + Reference: parsedReference, + Client: c.registryAuthorizer, + } + + return registry.Tags(ctx(c.out, c.debug), &repository) +} From e3f2fb42357fbe67257b0eeacd82cb6cba98c7c1 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Fri, 7 Jan 2022 03:51:52 -0500 Subject: [PATCH 27/48] Add OCI tag verions to the Dependency object before Resolve. TODO: fix HTTP HTTPS error for local registries Signed-off-by: Scott Rigby --- internal/resolver/resolver.go | 17 ++++++++++++++++- pkg/chart/dependency.go | 4 ++++ pkg/downloader/manager.go | 20 ++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/internal/resolver/resolver.go b/internal/resolver/resolver.go index 70ce6a55b..7fc27acac 100644 --- a/internal/resolver/resolver.go +++ b/internal/resolver/resolver.go @@ -139,6 +139,20 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string return nil, errors.Wrapf(FeatureGateOCI.Error(), "repository %s is an OCI registry", d.Repository) } + + // This works, fake it to test mocking the version + // tags := []string{"0.1.0", "0.1.1", "0.2.0"} + tags := d.OCITagVersions + vs = make(repo.ChartVersions, len(tags)) + for ti, t := range tags { + // Mock chart version objects + version := &repo.ChartVersion{ + Metadata: &chart.Metadata{ + Version: t, + }, + } + vs[ti] = version + } } locked[i] = &chart.Dependency{ @@ -149,7 +163,8 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string // The version are already sorted and hence the first one to satisfy the constraint is used for _, ver := range vs { v, err := semver.NewVersion(ver.Version) - if err != nil || len(ver.URLs) == 0 { + // OCI does not need URLs + if err != nil || (!registry.IsOCI(d.Repository) && len(ver.URLs) == 0) { // Not a legit entry. continue } diff --git a/pkg/chart/dependency.go b/pkg/chart/dependency.go index b2819f373..890fa971f 100644 --- a/pkg/chart/dependency.go +++ b/pkg/chart/dependency.go @@ -47,6 +47,10 @@ type Dependency struct { ImportValues []interface{} `json:"import-values,omitempty"` // Alias usable alias to be used for the chart Alias string `json:"alias,omitempty"` + // OCI tag versions available to check against the constraint when Version + // contains a semantic version range. + // See (*Manager).resolve. + OCITagVersions []string `json:"-"` } // Validate checks for common problems with the dependency datastructure in diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 52f1a1312..d8c0eeb9c 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -233,6 +233,26 @@ func (m *Manager) loadChartDir() (*chart.Chart, error) { // This returns a lock file, which has all of the dependencies normalized to a specific version. func (m *Manager) resolve(req []*chart.Dependency, repoNames map[string]string) (*chart.Lock, error) { res := resolver.New(m.ChartPath, m.RepositoryCache) + // NOTE: When OCI dependencies specify a semver range in Version, + // (*Resolver).Resolve must somehow get the list of OCI tag versions + // available to check against this constraint. However for backward + // compatibility we can not change that function signature to pass a + // *registry.Client required to get tags from the ORAS tag listing API. + // However we can add a new backward compatible struct field to + // *chart.Dependency, so that we can pass these along to + // (*Resolver).resolve from here through reqs []*chart.Dependency. + for i, d := range req { + if registry.IsOCI(d.Repository) { + // TODO(scottrigby): fix HTTP error + // > Error: Get "https://localhost:5000/v2/helm-charts/tags/list": http: server gave HTTP response to HTTPS client + ref := strings.Trim(d.Repository, "oci://") + tags, err := m.RegistryClient.Tags(ref) + if err != nil { + return nil, err + } + req[i].OCITagVersions = tags + } + } return res.Resolve(req, repoNames) } From a8df413c4116fde82c00ba72563ff5ff5d1b8300 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Fri, 7 Jan 2022 15:38:41 -0500 Subject: [PATCH 28/48] Update ORAS to v1.1.0-rc1 Now that https://github.com/oras-project/oras-go/pull/89 is merged and released Signed-off-by: Scott Rigby --- go.mod | 2 -- go.sum | 2 -- 2 files changed, 4 deletions(-) diff --git a/go.mod b/go.mod index 427cbc04a..d328ad8bb 100644 --- a/go.mod +++ b/go.mod @@ -45,5 +45,3 @@ require ( oras.land/oras-go v1.1.0-rc3 sigs.k8s.io/yaml v1.3.0 ) - -replace oras.land/oras-go => github.com/sabre1041/oras-go v1.0.1-0.20220105042547-7ebb8809edae diff --git a/go.sum b/go.sum index 19662166d..c56a45885 100644 --- a/go.sum +++ b/go.sum @@ -953,8 +953,6 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sabre1041/oras-go v1.0.1-0.20220105042547-7ebb8809edae h1:ZhMHqeREElljvMEkMcIak/rRWxWe7ut0x1jb0yFQ8CI= -github.com/sabre1041/oras-go v1.0.1-0.20220105042547-7ebb8809edae/go.mod h1:MZN6VbUUZjfWRF1EJKPbAWhJtE+R8JVicRmeYZp8qDg= github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= From 1fabbabae9fd0c76fccf2a6658de867d8cf96ab9 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Fri, 7 Jan 2022 15:47:30 -0500 Subject: [PATCH 29/48] Fix Trim to TrimPrefix Signed-off-by: Scott Rigby --- pkg/downloader/manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index d8c0eeb9c..8fd17fa14 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -245,7 +245,7 @@ func (m *Manager) resolve(req []*chart.Dependency, repoNames map[string]string) if registry.IsOCI(d.Repository) { // TODO(scottrigby): fix HTTP error // > Error: Get "https://localhost:5000/v2/helm-charts/tags/list": http: server gave HTTP response to HTTPS client - ref := strings.Trim(d.Repository, "oci://") + ref := strings.TrimPrefix(d.Repository, "oci://") tags, err := m.RegistryClient.Tags(ref) if err != nil { return nil, err From 834a11db567b1e154ed976c03a7556c336ad4c7b Mon Sep 17 00:00:00 2001 From: Andrew Block Date: Sat, 8 Jan 2022 22:10:21 -0600 Subject: [PATCH 30/48] Added registryClient to resolver Signed-off-by: Andrew Block --- internal/resolver/resolver.go | 14 ++++++++------ internal/resolver/resolver_test.go | 4 +++- pkg/downloader/manager.go | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/internal/resolver/resolver.go b/internal/resolver/resolver.go index 7fc27acac..634b351a6 100644 --- a/internal/resolver/resolver.go +++ b/internal/resolver/resolver.go @@ -39,15 +39,17 @@ const FeatureGateOCI = gates.Gate("HELM_EXPERIMENTAL_OCI") // Resolver resolves dependencies from semantic version ranges to a particular version. type Resolver struct { - chartpath string - cachepath string + chartpath string + cachepath string + registryClient *registry.Client } -// New creates a new resolver for a given chart and a given helm home. -func New(chartpath, cachepath string) *Resolver { +// New creates a new resolver for a given chart, helm home and registry client. +func New(chartpath, cachepath string, registryClient *registry.Client) *Resolver { return &Resolver{ - chartpath: chartpath, - cachepath: cachepath, + chartpath: chartpath, + cachepath: cachepath, + registryClient: registryClient, } } diff --git a/internal/resolver/resolver_test.go b/internal/resolver/resolver_test.go index 419f8f316..6fbc2e86a 100644 --- a/internal/resolver/resolver_test.go +++ b/internal/resolver/resolver_test.go @@ -19,6 +19,7 @@ import ( "runtime" "testing" + "helm.sh/helm/v3/internal/experimental/registry" "helm.sh/helm/v3/pkg/chart" ) @@ -139,7 +140,8 @@ func TestResolve(t *testing.T) { } repoNames := map[string]string{"alpine": "kubernetes-charts", "redis": "kubernetes-charts"} - r := New("testdata/chartpath", "testdata/repository") + registryClient, _ := registry.NewClient() + r := New("testdata/chartpath", "testdata/repository", registryClient) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { l, err := r.Resolve(tt.req, repoNames) diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 8fd17fa14..74286b3fd 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -232,7 +232,7 @@ func (m *Manager) loadChartDir() (*chart.Chart, error) { // // This returns a lock file, which has all of the dependencies normalized to a specific version. func (m *Manager) resolve(req []*chart.Dependency, repoNames map[string]string) (*chart.Lock, error) { - res := resolver.New(m.ChartPath, m.RepositoryCache) + res := resolver.New(m.ChartPath, m.RepositoryCache, m.RegistryClient) // NOTE: When OCI dependencies specify a semver range in Version, // (*Resolver).Resolve must somehow get the list of OCI tag versions // available to check against this constraint. However for backward From 0fae7f5008b4dc64dc5f830b819094c78a313d06 Mon Sep 17 00:00:00 2001 From: Andrew Block Date: Sun, 9 Jan 2022 14:47:08 -0600 Subject: [PATCH 31/48] Updated tag resolver logic Signed-off-by: Andrew Block --- internal/experimental/registry/client.go | 28 ++++++++++++++++++++++-- internal/resolver/resolver.go | 11 +++++++--- pkg/chart/dependency.go | 4 ---- pkg/downloader/manager.go | 20 ----------------- 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/internal/experimental/registry/client.go b/internal/experimental/registry/client.go index fdfab76f4..a9badb9d5 100644 --- a/internal/experimental/registry/client.go +++ b/internal/experimental/registry/client.go @@ -22,8 +22,10 @@ import ( "io" "io/ioutil" "net/http" + "sort" "strings" + "github.com/Masterminds/semver/v3" "github.com/containerd/containerd/remotes" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" @@ -553,7 +555,7 @@ func PushOptStrictMode(strictMode bool) PushOption { } } -// Tags lists all tags for a given repository +// Tags provides an all semver compliant tags for a given repository func (c *Client) Tags(ref string) ([]string, error) { parsedReference, err := registry.ParseReference(ref) if err != nil { @@ -565,5 +567,27 @@ func (c *Client) Tags(ref string) ([]string, error) { Client: c.registryAuthorizer, } - return registry.Tags(ctx(c.out, c.debug), &repository) + registrtyTags, err := registry.Tags(ctx(c.out, c.debug), &repository) + if err != nil { + return nil, err + } + + var tagVersions []*semver.Version + for _, tag := range registrtyTags { + tagVersion, err := semver.StrictNewVersion(tag) + if err != nil { + tagVersions = append(tagVersions, tagVersion) + } + } + + sort.Sort(semver.Collection(tagVersions)) + + tags := make([]string, len(tagVersions)) + + for iTv, tv := range tagVersions { + tags[iTv] = tv.String() + } + + return tags, nil + } diff --git a/internal/resolver/resolver.go b/internal/resolver/resolver.go index 634b351a6..27ca9929d 100644 --- a/internal/resolver/resolver.go +++ b/internal/resolver/resolver.go @@ -18,6 +18,7 @@ package resolver import ( "bytes" "encoding/json" + "fmt" "os" "path/filepath" "strings" @@ -136,15 +137,19 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string } found = false } else { + fmt.Println("Entering OCI block") version = d.Version if !FeatureGateOCI.IsEnabled() { return nil, errors.Wrapf(FeatureGateOCI.Error(), "repository %s is an OCI registry", d.Repository) } - // This works, fake it to test mocking the version - // tags := []string{"0.1.0", "0.1.1", "0.2.0"} - tags := d.OCITagVersions + // Retrive list of tags for repository + tags, err := r.registryClient.Tags(d.Repository) + if err != nil { + return nil, errors.Wrapf(err, "could not retrieve list of tags for repository", d.Repository) + } + vs = make(repo.ChartVersions, len(tags)) for ti, t := range tags { // Mock chart version objects diff --git a/pkg/chart/dependency.go b/pkg/chart/dependency.go index 890fa971f..b2819f373 100644 --- a/pkg/chart/dependency.go +++ b/pkg/chart/dependency.go @@ -47,10 +47,6 @@ type Dependency struct { ImportValues []interface{} `json:"import-values,omitempty"` // Alias usable alias to be used for the chart Alias string `json:"alias,omitempty"` - // OCI tag versions available to check against the constraint when Version - // contains a semantic version range. - // See (*Manager).resolve. - OCITagVersions []string `json:"-"` } // Validate checks for common problems with the dependency datastructure in diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 74286b3fd..d26dfd845 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -233,26 +233,6 @@ func (m *Manager) loadChartDir() (*chart.Chart, error) { // This returns a lock file, which has all of the dependencies normalized to a specific version. func (m *Manager) resolve(req []*chart.Dependency, repoNames map[string]string) (*chart.Lock, error) { res := resolver.New(m.ChartPath, m.RepositoryCache, m.RegistryClient) - // NOTE: When OCI dependencies specify a semver range in Version, - // (*Resolver).Resolve must somehow get the list of OCI tag versions - // available to check against this constraint. However for backward - // compatibility we can not change that function signature to pass a - // *registry.Client required to get tags from the ORAS tag listing API. - // However we can add a new backward compatible struct field to - // *chart.Dependency, so that we can pass these along to - // (*Resolver).resolve from here through reqs []*chart.Dependency. - for i, d := range req { - if registry.IsOCI(d.Repository) { - // TODO(scottrigby): fix HTTP error - // > Error: Get "https://localhost:5000/v2/helm-charts/tags/list": http: server gave HTTP response to HTTPS client - ref := strings.TrimPrefix(d.Repository, "oci://") - tags, err := m.RegistryClient.Tags(ref) - if err != nil { - return nil, err - } - req[i].OCITagVersions = tags - } - } return res.Resolve(req, repoNames) } From df98e18eb73cd08feee1c9e7ddf0e629ad510ee7 Mon Sep 17 00:00:00 2001 From: Andrew Block Date: Sun, 9 Jan 2022 18:47:31 -0600 Subject: [PATCH 32/48] Working oci code without providing versions Signed-off-by: Andrew Block --- internal/experimental/registry/client.go | 9 +++++---- internal/experimental/registry/util.go | 10 ++++++++++ internal/resolver/resolver.go | 4 ++-- pkg/action/install.go | 5 ++--- pkg/getter/ocigetter.go | 25 ++++++++++++++++++++++-- 5 files changed, 42 insertions(+), 11 deletions(-) diff --git a/internal/experimental/registry/client.go b/internal/experimental/registry/client.go index a9badb9d5..b3bc49612 100644 --- a/internal/experimental/registry/client.go +++ b/internal/experimental/registry/client.go @@ -567,20 +567,21 @@ func (c *Client) Tags(ref string) ([]string, error) { Client: c.registryAuthorizer, } - registrtyTags, err := registry.Tags(ctx(c.out, c.debug), &repository) + registryTags, err := registry.Tags(ctx(c.out, c.debug), &repository) if err != nil { return nil, err } var tagVersions []*semver.Version - for _, tag := range registrtyTags { + for _, tag := range registryTags { tagVersion, err := semver.StrictNewVersion(tag) - if err != nil { + if err == nil { tagVersions = append(tagVersions, tagVersion) } } - sort.Sort(semver.Collection(tagVersions)) + // Sort the collection + sort.Sort(sort.Reverse(semver.Collection(tagVersions))) tags := make([]string, len(tagVersions)) diff --git a/internal/experimental/registry/util.go b/internal/experimental/registry/util.go index c421e5639..909a803a3 100644 --- a/internal/experimental/registry/util.go +++ b/internal/experimental/registry/util.go @@ -36,6 +36,16 @@ func IsOCI(url string) bool { return strings.HasPrefix(url, fmt.Sprintf("%s://", OCIScheme)) } +// ContainsTag determines whether a tag is found in a provided list of tags +func ContainsTag(tags []string, tag string) bool { + for _, t := range tags { + if tag == t { + return true + } + } + return false +} + // extractChartMeta is used to extract a chart metadata from a byte array func extractChartMeta(chartData []byte) (*chart.Metadata, error) { ch, err := loader.LoadArchive(bytes.NewReader(chartData)) diff --git a/internal/resolver/resolver.go b/internal/resolver/resolver.go index 27ca9929d..36a4803e1 100644 --- a/internal/resolver/resolver.go +++ b/internal/resolver/resolver.go @@ -144,10 +144,10 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string "repository %s is an OCI registry", d.Repository) } - // Retrive list of tags for repository + // Retrieve list of tags for repository tags, err := r.registryClient.Tags(d.Repository) if err != nil { - return nil, errors.Wrapf(err, "could not retrieve list of tags for repository", d.Repository) + return nil, errors.Wrapf(err, "could not retrieve list of tags for repository %s", d.Repository) } vs = make(repo.ChartVersions, len(tags)) diff --git a/pkg/action/install.go b/pkg/action/install.go index 922f728b0..250dfae95 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -695,10 +695,9 @@ func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) ( } if registry.IsOCI(name) { - if version == "" { - return "", errors.New("version is explicitly required for OCI registries") + if version != "" { + dl.Options = append(dl.Options, getter.WithTagName(version)) } - dl.Options = append(dl.Options, getter.WithTagName(version)) } if c.Verify { diff --git a/pkg/getter/ocigetter.go b/pkg/getter/ocigetter.go index 45c92749c..fbfcf7133 100644 --- a/pkg/getter/ocigetter.go +++ b/pkg/getter/ocigetter.go @@ -20,6 +20,8 @@ import ( "fmt" "strings" + "github.com/pkg/errors" + "helm.sh/helm/v3/internal/experimental/registry" ) @@ -50,10 +52,29 @@ func (g *OCIGetter) get(href string) (*bytes.Buffer, error) { registry.PullOptWithProv(true)) } - if version := g.opts.version; version != "" { - ref = fmt.Sprintf("%s:%s", ref, version) + // Retrieve list of repository tags + tags, err := client.Tags(ref) + if err != nil { + return nil, err + } + + //Determine if version provided. If not + providedVersion := g.opts.version + if g.opts.version == "" { + if len(tags) > 0 { + providedVersion = tags[0] + } else { + return nil, errors.Errorf("Unable to locate any tags in provided repository: %s", ref) + } + + } else { + if !registry.ContainsTag(tags, providedVersion) { + return nil, errors.Errorf("Could not located provided version %s in repository %s", providedVersion, ref) + } } + ref = fmt.Sprintf("%s:%s", ref, providedVersion) + result, err := client.Pull(ref, pullOpts...) if err != nil { return nil, err From 4f62d3dc1b8b95246eb345f8e9117adee6d52f91 Mon Sep 17 00:00:00 2001 From: Andrew Block Date: Sun, 9 Jan 2022 19:51:03 -0600 Subject: [PATCH 33/48] Started work on 'helm pull' Signed-off-by: Andrew Block --- internal/resolver/resolver.go | 2 -- pkg/action/pull.go | 12 ++++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/internal/resolver/resolver.go b/internal/resolver/resolver.go index 36a4803e1..5afb439e3 100644 --- a/internal/resolver/resolver.go +++ b/internal/resolver/resolver.go @@ -18,7 +18,6 @@ package resolver import ( "bytes" "encoding/json" - "fmt" "os" "path/filepath" "strings" @@ -137,7 +136,6 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string } found = false } else { - fmt.Println("Entering OCI block") version = d.Version if !FeatureGateOCI.IsEnabled() { return nil, errors.Wrapf(FeatureGateOCI.Error(), diff --git a/pkg/action/pull.go b/pkg/action/pull.go index 2f5127ea9..f09da82d0 100644 --- a/pkg/action/pull.go +++ b/pkg/action/pull.go @@ -92,13 +92,13 @@ func (p *Pull) Run(chartRef string) (string, error) { } if registry.IsOCI(chartRef) { - if p.Version == "" { - return out.String(), errors.Errorf("--version flag is explicitly required for OCI registries") - } - c.Options = append(c.Options, - getter.WithRegistryClient(p.cfg.RegistryClient), - getter.WithTagName(p.Version)) + getter.WithRegistryClient(p.cfg.RegistryClient)) + + if p.Version != "" { + c.Options = append(c.Options, + getter.WithTagName(p.Version)) + } } if p.Verify { From b6bf3905f37b13863efc5c5309bb154853ac6daa Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Mon, 10 Jan 2022 14:47:45 -0500 Subject: [PATCH 34/48] Implement reusable GetTagMatchingVersionOrConstraint Largely borrowed from (IndexFile).Get. However there is not currently a nice way to make this code also usable to the repo package, as IndexFile depends on a list of index Entries containing a nexted version. We could refactor this later to somehow use the same shared function, but for now keeping separate. Signed-off-by: Scott Rigby --- internal/experimental/registry/util.go | 31 ++++++++++++++++++++++++++ pkg/getter/ocigetter.go | 27 +++++++++++----------- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/internal/experimental/registry/util.go b/internal/experimental/registry/util.go index 909a803a3..36713676a 100644 --- a/internal/experimental/registry/util.go +++ b/internal/experimental/registry/util.go @@ -23,6 +23,8 @@ import ( "io" "strings" + "github.com/Masterminds/semver" + "github.com/pkg/errors" "github.com/sirupsen/logrus" orascontext "oras.land/oras-go/pkg/context" "oras.land/oras-go/pkg/registry" @@ -46,6 +48,35 @@ func ContainsTag(tags []string, tag string) bool { return false } +func GetTagMatchingVersionOrConstraint(tags []string, versionString string) (string, error) { + var constraint *semver.Constraints + if versionString == "" { + // If string is empty, set wildcard constraint + constraint, _ = semver.NewConstraint("*") + } else { + // Otherwise set constraint to the string given + var err error + constraint, err = semver.NewConstraint(versionString) + if err != nil { + return "", err + } + } + + // Otherwise try to find the first available version matching the string, + // in case it is a constraint + for _, v := range tags { + test, err := semver.NewVersion(v) + if err != nil { + continue + } + if constraint.Check(test) { + return v, nil + } + } + + return "", errors.Errorf("Could not locate a version matching provided version string %s", versionString) +} + // extractChartMeta is used to extract a chart metadata from a byte array func extractChartMeta(chartData []byte) (*chart.Metadata, error) { ch, err := loader.LoadArchive(bytes.NewReader(chartData)) diff --git a/pkg/getter/ocigetter.go b/pkg/getter/ocigetter.go index fbfcf7133..0de5987db 100644 --- a/pkg/getter/ocigetter.go +++ b/pkg/getter/ocigetter.go @@ -30,7 +30,7 @@ type OCIGetter struct { opts options } -//Get performs a Get from repo.Getter and returns the body. +// Get performs a Get from repo.Getter and returns the body. func (g *OCIGetter) Get(href string, options ...Option) (*bytes.Buffer, error) { for _, opt := range options { opt(&g.opts) @@ -57,23 +57,22 @@ func (g *OCIGetter) get(href string) (*bytes.Buffer, error) { if err != nil { return nil, err } + if len(tags) == 0 { + return nil, errors.Errorf("Unable to locate any tags in provided repository: %s", ref) + } - //Determine if version provided. If not + // Determine if version provided + // If empty, try to get the highest available tag + // If exact version, try to find it + // If semver constraint string, try to find a match providedVersion := g.opts.version - if g.opts.version == "" { - if len(tags) > 0 { - providedVersion = tags[0] - } else { - return nil, errors.Errorf("Unable to locate any tags in provided repository: %s", ref) - } - - } else { - if !registry.ContainsTag(tags, providedVersion) { - return nil, errors.Errorf("Could not located provided version %s in repository %s", providedVersion, ref) - } + + tag, err := registry.GetTagMatchingVersionOrConstraint(tags, providedVersion) + if err != nil { + return nil, err } - ref = fmt.Sprintf("%s:%s", ref, providedVersion) + ref = fmt.Sprintf("%s:%s", ref, tag) result, err := client.Pull(ref, pullOpts...) if err != nil { From 4c8a3faaa28e67316297d68fcb1cca0a54a8ae56 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Mon, 10 Jan 2022 17:54:46 -0500 Subject: [PATCH 35/48] Fix import Signed-off-by: Scott Rigby --- internal/experimental/registry/util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/experimental/registry/util.go b/internal/experimental/registry/util.go index 36713676a..dc4133ac1 100644 --- a/internal/experimental/registry/util.go +++ b/internal/experimental/registry/util.go @@ -23,7 +23,7 @@ import ( "io" "strings" - "github.com/Masterminds/semver" + "github.com/Masterminds/semver/v3" "github.com/pkg/errors" "github.com/sirupsen/logrus" orascontext "oras.land/oras-go/pkg/context" From 291c17fcc5627c85a0c378e0ba83eb0c5ae6dffc Mon Sep 17 00:00:00 2001 From: Andrew Block Date: Tue, 11 Jan 2022 19:13:08 -0600 Subject: [PATCH 36/48] Enabled auth and support http registries for OCI Signed-off-by: Andrew Block --- internal/experimental/registry/client.go | 42 ++++++++++++++++--- internal/experimental/registry/client_test.go | 20 ++++++++- 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/internal/experimental/registry/client.go b/internal/experimental/registry/client.go index b3bc49612..2de348ccd 100644 --- a/internal/experimental/registry/client.go +++ b/internal/experimental/registry/client.go @@ -17,6 +17,7 @@ limitations under the License. package registry // import "helm.sh/helm/v3/internal/experimental/registry" import ( + "context" "encoding/json" "fmt" "io" @@ -34,7 +35,7 @@ import ( "oras.land/oras-go/pkg/content" "oras.land/oras-go/pkg/oras" "oras.land/oras-go/pkg/registry" - registrremote "oras.land/oras-go/pkg/registry/remote" + registryremote "oras.land/oras-go/pkg/registry/remote" registryauth "oras.land/oras-go/pkg/registry/remote/auth" "helm.sh/helm/v3/internal/version" @@ -100,6 +101,23 @@ func NewClient(options ...ClientOption) (*Client, error) { "User-Agent": {version.GetUserAgent()}, }, Cache: registryauth.DefaultCache, + Credential: func(ctx context.Context, reg string) (registryauth.Credential, error) { + dockerClient, ok := client.authorizer.(*dockerauth.Client) + if !ok { + return registryauth.EmptyCredential, errors.New("unable to obtain docker client") + } + + username, password, err := dockerClient.Credential(reg) + if err != nil { + return registryauth.EmptyCredential, errors.New("unable to retrieve credentials") + } + + return registryauth.Credential{ + Username: username, + Password: password, + }, nil + + }, } } @@ -555,21 +573,33 @@ func PushOptStrictMode(strictMode bool) PushOption { } } -// Tags provides an all semver compliant tags for a given repository +// Tags provides a sorted list all semver compliant tags for a given repository func (c *Client) Tags(ref string) ([]string, error) { parsedReference, err := registry.ParseReference(ref) if err != nil { return nil, err } - repository := registrremote.Repository{ + repository := registryremote.Repository{ Reference: parsedReference, Client: c.registryAuthorizer, } - registryTags, err := registry.Tags(ctx(c.out, c.debug), &repository) - if err != nil { - return nil, err + var registryTags []string + + for { + registryTags, err = registry.Tags(ctx(c.out, c.debug), &repository) + if err != nil { + // Fallback to http based request + if !repository.PlainHTTP && strings.Contains(err.Error(), "server gave HTTP response") { + repository.PlainHTTP = true + continue + } + return nil, err + } + + break + } var tagVersions []*semver.Version diff --git a/internal/experimental/registry/client_test.go b/internal/experimental/registry/client_test.go index 356f3eaba..baf9b4291 100644 --- a/internal/experimental/registry/client_test.go +++ b/internal/experimental/registry/client_test.go @@ -294,7 +294,23 @@ func (suite *RegistryClientTestSuite) Test_2_Pull() { suite.Equal(provData, result.Prov.Data) } -func (suite *RegistryClientTestSuite) Test_3_Logout() { +func (suite *RegistryClientTestSuite) Test_3_Tags() { + + // Load test chart (to build ref pushed in previous test) + chartData, err := ioutil.ReadFile("../../../pkg/downloader/testdata/local-subchart-0.1.0.tgz") + suite.Nil(err, "no error loading test chart") + meta, err := extractChartMeta(chartData) + suite.Nil(err, "no error extracting chart meta") + ref := fmt.Sprintf("%s/testrepo/%s", suite.DockerRegistryHost, meta.Name) + + // Query for tags and validate length + tags, err := suite.RegistryClient.Tags(ref) + suite.Nil(err, "no error retrieving tags") + suite.Equal(1, len(tags)) + +} + +func (suite *RegistryClientTestSuite) Test_4_Logout() { err := suite.RegistryClient.Logout("this-host-aint-real:5000") suite.NotNil(err, "error logging out of registry that has no entry") @@ -302,7 +318,7 @@ func (suite *RegistryClientTestSuite) Test_3_Logout() { suite.Nil(err, "no error logging out of registry") } -func (suite *RegistryClientTestSuite) Test_4_ManInTheMiddle() { +func (suite *RegistryClientTestSuite) Test_5_ManInTheMiddle() { ref := fmt.Sprintf("%s/testrepo/supposedlysafechart:9.9.9", suite.CompromisedRegistryHost) // returns content that does not match the expected digest From 828941b273e1c6393bec6723ae2cc394c0536db4 Mon Sep 17 00:00:00 2001 From: Andrew Block Date: Tue, 11 Jan 2022 20:54:47 -0600 Subject: [PATCH 37/48] Readded resolver OCI logic Signed-off-by: Andrew Block --- internal/resolver/resolver.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/resolver/resolver.go b/internal/resolver/resolver.go index 5afb439e3..79d72917d 100644 --- a/internal/resolver/resolver.go +++ b/internal/resolver/resolver.go @@ -143,8 +143,8 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string } // Retrieve list of tags for repository - tags, err := r.registryClient.Tags(d.Repository) - if err != nil { + ref := fmt.Sprintf("%s/%s", strings.TrimPrefix(d.Repository, fmt.Sprintf("%s://", registry.OCIScheme)), d.Name) + tags, err := r.registryClient.Tags(ref) if err != nil { return nil, errors.Wrapf(err, "could not retrieve list of tags for repository %s", d.Repository) } From 9c3b0008896d840237617bae8cc9823b77b536d4 Mon Sep 17 00:00:00 2001 From: Andrew Block Date: Tue, 11 Jan 2022 21:05:28 -0600 Subject: [PATCH 38/48] Fixed bad commit Signed-off-by: Andrew Block --- internal/resolver/resolver.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/resolver/resolver.go b/internal/resolver/resolver.go index 79d72917d..cf370e927 100644 --- a/internal/resolver/resolver.go +++ b/internal/resolver/resolver.go @@ -18,6 +18,7 @@ package resolver import ( "bytes" "encoding/json" + "fmt" "os" "path/filepath" "strings" @@ -144,7 +145,8 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string // Retrieve list of tags for repository ref := fmt.Sprintf("%s/%s", strings.TrimPrefix(d.Repository, fmt.Sprintf("%s://", registry.OCIScheme)), d.Name) - tags, err := r.registryClient.Tags(ref) if err != nil { + tags, err := r.registryClient.Tags(ref) + if err != nil { return nil, errors.Wrapf(err, "could not retrieve list of tags for repository %s", d.Repository) } From 1b3e0bc46a3e22cfa8f0adce08a18c8436152b30 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Wed, 12 Jan 2022 12:38:32 -0500 Subject: [PATCH 39/48] Update oras-go to v1.1.0 Signed-off-by: Scott Rigby --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d328ad8bb..49f96ea97 100644 --- a/go.mod +++ b/go.mod @@ -42,6 +42,6 @@ require ( k8s.io/client-go v0.23.1 k8s.io/klog/v2 v2.30.0 k8s.io/kubectl v0.23.1 - oras.land/oras-go v1.1.0-rc3 + oras.land/oras-go v1.1.0 sigs.k8s.io/yaml v1.3.0 ) diff --git a/go.sum b/go.sum index c56a45885..88da64deb 100644 --- a/go.sum +++ b/go.sum @@ -1746,8 +1746,8 @@ k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/ k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b h1:wxEMGetGMur3J1xuGLQY7GEQYg9bZxKn3tKo5k/eYcs= k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -oras.land/oras-go v1.1.0-rc3 h1:+HdHR0Lgm/0jmjF4SqUif8Ky2XNWhrcP4hxGVvtKIUI= -oras.land/oras-go v1.1.0-rc3/go.mod h1:1A7vR/0KknT2UkJVWh+xMi95I/AhK8ZrxrnUSmXN0bQ= +oras.land/oras-go v1.1.0 h1:tfWM1RT7PzUwWphqHU6ptPU3ZhwVnSw/9nEGf519rYg= +oras.land/oras-go v1.1.0/go.mod h1:1A7vR/0KknT2UkJVWh+xMi95I/AhK8ZrxrnUSmXN0bQ= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= From c7b2a9d48795e1191b80a1f94acca5b4f084d612 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Mon, 10 Jan 2022 11:20:50 -0500 Subject: [PATCH 40/48] Fixing issue where OCI handling early causes a bad message Note, there is OCI handling later in the funtion that should handle the situation instead. Closes #10534 Signed-off-by: Matt Farina --- pkg/downloader/manager.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index d26dfd845..aa2c4a2f4 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -578,8 +578,7 @@ func (m *Manager) resolveRepoNames(deps []*chart.Dependency) (map[string]string, missing := []string{} for _, dd := range deps { // Don't map the repository, we don't need to download chart from charts directory - // When OCI is used there is no Helm repository - if dd.Repository == "" || registry.IsOCI(dd.Repository) { + if dd.Repository == "" { continue } // if dep chart is from local path, verify the path is valid From 4d50526a2bcf788d2518cb42dd468863bd3f0332 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Wed, 12 Jan 2022 14:36:54 -0500 Subject: [PATCH 41/48] Move OCI tag semver range logic from OCIGetter to ChartDownloader Signed-off-by: Scott Rigby --- pkg/action/pull.go | 5 ----- pkg/downloader/chart_downloader.go | 35 +++++++++++++++++++++++++++++- pkg/getter/ocigetter.go | 24 -------------------- 3 files changed, 34 insertions(+), 30 deletions(-) diff --git a/pkg/action/pull.go b/pkg/action/pull.go index f09da82d0..6de08a6da 100644 --- a/pkg/action/pull.go +++ b/pkg/action/pull.go @@ -94,11 +94,6 @@ func (p *Pull) Run(chartRef string) (string, error) { if registry.IsOCI(chartRef) { c.Options = append(c.Options, getter.WithRegistryClient(p.cfg.RegistryClient)) - - if p.Version != "" { - c.Options = append(c.Options, - getter.WithTagName(p.Version)) - } } if p.Verify { diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index 93afb1461..cd5a5d83d 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -139,12 +139,41 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven return destfile, ver, nil } +func (c *ChartDownloader) getOciUri(ref, version string, u *url.URL) (*url.URL, error) { + // Retrieve list of repository tags + tags, err := c.RegistryClient.Tags(ref) + if err != nil { + return nil, err + } + if len(tags) == 0 { + return nil, errors.Errorf("Unable to locate any tags in provided repository: %s", ref) + } + + // Determine if version provided + // If empty, try to get the highest available tag + // If exact version, try to find it + // If semver constraint string, try to find a match + providedVersion := version + + tag, err := registry.GetTagMatchingVersionOrConstraint(tags, providedVersion) + if err != nil { + return nil, err + } + + // TODO Find a net/url equivalent of this + //ref = fmt.Sprintf("%s:%s", ref, tag) + u.Path = fmt.Sprintf("%s:%s", u.Path, tag) + + return u, err +} + // ResolveChartVersion resolves a chart reference to a URL. // // It returns the URL and sets the ChartDownloader's Options that can fetch // the URL using the appropriate Getter. // -// A reference may be an HTTP URL, a 'reponame/chartname' reference, or a local path. +// A reference may be an HTTP URL, an oci reference URL, a 'reponame/chartname' +// reference, or a local path. // // A version is a SemVer string (1.2.3-beta.1+f334a6789). // @@ -159,6 +188,10 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er return nil, errors.Errorf("invalid chart URL format: %s", ref) } + if registry.IsOCI(u.Path) { + return c.getOciUri(ref, version, u) + } + rf, err := loadRepoConfig(c.RepositoryConfig) if err != nil { return u, err diff --git a/pkg/getter/ocigetter.go b/pkg/getter/ocigetter.go index 0de5987db..dbf382102 100644 --- a/pkg/getter/ocigetter.go +++ b/pkg/getter/ocigetter.go @@ -20,8 +20,6 @@ import ( "fmt" "strings" - "github.com/pkg/errors" - "helm.sh/helm/v3/internal/experimental/registry" ) @@ -52,28 +50,6 @@ func (g *OCIGetter) get(href string) (*bytes.Buffer, error) { registry.PullOptWithProv(true)) } - // Retrieve list of repository tags - tags, err := client.Tags(ref) - if err != nil { - return nil, err - } - if len(tags) == 0 { - return nil, errors.Errorf("Unable to locate any tags in provided repository: %s", ref) - } - - // Determine if version provided - // If empty, try to get the highest available tag - // If exact version, try to find it - // If semver constraint string, try to find a match - providedVersion := g.opts.version - - tag, err := registry.GetTagMatchingVersionOrConstraint(tags, providedVersion) - if err != nil { - return nil, err - } - - ref = fmt.Sprintf("%s:%s", ref, tag) - result, err := client.Pull(ref, pullOpts...) if err != nil { return nil, err From ba4020770ec21286dbf9cb4b6c6c82b42ee8d4d3 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Wed, 12 Jan 2022 14:45:10 -0500 Subject: [PATCH 42/48] Fix linting Signed-off-by: Scott Rigby --- pkg/downloader/chart_downloader.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index cd5a5d83d..879c36d36 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -139,7 +139,7 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven return destfile, ver, nil } -func (c *ChartDownloader) getOciUri(ref, version string, u *url.URL) (*url.URL, error) { +func (c *ChartDownloader) getOciURI(ref, version string, u *url.URL) (*url.URL, error) { // Retrieve list of repository tags tags, err := c.RegistryClient.Tags(ref) if err != nil { @@ -189,7 +189,7 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er } if registry.IsOCI(u.Path) { - return c.getOciUri(ref, version, u) + return c.getOciURI(ref, version, u) } rf, err := loadRepoConfig(c.RepositoryConfig) From 23989f9e2411aa603066356076f43840bcd2d212 Mon Sep 17 00:00:00 2001 From: Andrew Block Date: Wed, 12 Jan 2022 14:32:42 -0600 Subject: [PATCH 43/48] Updates to chart downloader Signed-off-by: Andrew Block --- pkg/downloader/chart_downloader.go | 6 ++---- pkg/downloader/manager.go | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index 879c36d36..b8853a1a6 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -141,7 +141,7 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven func (c *ChartDownloader) getOciURI(ref, version string, u *url.URL) (*url.URL, error) { // Retrieve list of repository tags - tags, err := c.RegistryClient.Tags(ref) + tags, err := c.RegistryClient.Tags(strings.TrimPrefix(ref, fmt.Sprintf("%s://", registry.OCIScheme))) if err != nil { return nil, err } @@ -160,8 +160,6 @@ func (c *ChartDownloader) getOciURI(ref, version string, u *url.URL) (*url.URL, return nil, err } - // TODO Find a net/url equivalent of this - //ref = fmt.Sprintf("%s:%s", ref, tag) u.Path = fmt.Sprintf("%s:%s", u.Path, tag) return u, err @@ -188,7 +186,7 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er return nil, errors.Errorf("invalid chart URL format: %s", ref) } - if registry.IsOCI(u.Path) { + if registry.IsOCI(u.String()) { return c.getOciURI(ref, version, u) } diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index aa2c4a2f4..cc59ae864 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -332,6 +332,7 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error { Keyring: m.Keyring, RepositoryConfig: m.RepositoryConfig, RepositoryCache: m.RepositoryCache, + RegistryClient: m.RegistryClient, Getters: m.Getters, Options: []getter.Option{ getter.WithBasicAuth(username, password), From 1a9cb93551dd112ab91c0dd0982819979787e637 Mon Sep 17 00:00:00 2001 From: Andrew Block Date: Wed, 12 Jan 2022 15:49:12 -0600 Subject: [PATCH 44/48] Handling name of OCI file Signed-off-by: Andrew Block --- pkg/action/pull.go | 1 + pkg/downloader/chart_downloader.go | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/action/pull.go b/pkg/action/pull.go index 6de08a6da..55a127d4d 100644 --- a/pkg/action/pull.go +++ b/pkg/action/pull.go @@ -87,6 +87,7 @@ func (p *Pull) Run(chartRef string) (string, error) { getter.WithTLSClientConfig(p.CertFile, p.KeyFile, p.CaFile), getter.WithInsecureSkipVerifyTLS(p.InsecureSkipTLSverify), }, + RegistryClient: p.cfg.RegistryClient, RepositoryConfig: p.Settings.RepositoryConfig, RepositoryCache: p.Settings.RepositoryCache, } diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index b8853a1a6..8bcd76395 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -103,7 +103,8 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven name := filepath.Base(u.Path) if u.Scheme == registry.OCIScheme { - name = fmt.Sprintf("%s-%s.tgz", name, version) + idx := strings.LastIndexByte(name, ':') + name = fmt.Sprintf("%s-%s.tgz", name[:idx], name[idx+1:]) } destfile := filepath.Join(dest, name) From bd754a054c73a6c6dc4d342cda0a0ecdd4ce96d0 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Wed, 12 Jan 2022 17:42:52 -0500 Subject: [PATCH 45/48] Bring exact version check logic from IndexFile.Get into registry tag check Signed-off-by: Scott Rigby --- internal/experimental/registry/util.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/internal/experimental/registry/util.go b/internal/experimental/registry/util.go index dc4133ac1..8c6eb1958 100644 --- a/internal/experimental/registry/util.go +++ b/internal/experimental/registry/util.go @@ -54,6 +54,14 @@ func GetTagMatchingVersionOrConstraint(tags []string, versionString string) (str // If string is empty, set wildcard constraint constraint, _ = semver.NewConstraint("*") } else { + // when customer input exact version, check whether have exact match + // one first + for _, v := range tags { + if versionString == v { + return v, nil + } + } + // Otherwise set constraint to the string given var err error constraint, err = semver.NewConstraint(versionString) From ee382eb169bab70a3b44571ce5c363b80f1399e1 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Wed, 12 Jan 2022 17:43:10 -0500 Subject: [PATCH 46/48] Remove unneeded assignment Signed-off-by: Scott Rigby --- pkg/downloader/chart_downloader.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index 8bcd76395..8ca5cacb6 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -154,9 +154,7 @@ func (c *ChartDownloader) getOciURI(ref, version string, u *url.URL) (*url.URL, // If empty, try to get the highest available tag // If exact version, try to find it // If semver constraint string, try to find a match - providedVersion := version - - tag, err := registry.GetTagMatchingVersionOrConstraint(tags, providedVersion) + tag, err := registry.GetTagMatchingVersionOrConstraint(tags, version) if err != nil { return nil, err } From 808a2d1908088137a16d086dd86802ece7bd13b3 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Wed, 12 Jan 2022 17:59:56 -0500 Subject: [PATCH 47/48] Change underscore (_) back to plus (+) for Helm Signed-off-by: Scott Rigby --- internal/experimental/registry/client.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/experimental/registry/client.go b/internal/experimental/registry/client.go index 2de348ccd..1b686b8ba 100644 --- a/internal/experimental/registry/client.go +++ b/internal/experimental/registry/client.go @@ -604,7 +604,9 @@ func (c *Client) Tags(ref string) ([]string, error) { var tagVersions []*semver.Version for _, tag := range registryTags { - tagVersion, err := semver.StrictNewVersion(tag) + // Change underscore (_) back to plus (+) for Helm + // See https://github.com/helm/helm/issues/10166 + tagVersion, err := semver.StrictNewVersion(strings.ReplaceAll(tag, "_", "+")) if err == nil { tagVersions = append(tagVersions, tagVersion) } From 548ec55cf9ee54f8563c2848b9f9fd33b8753936 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Wed, 12 Jan 2022 21:26:41 -0500 Subject: [PATCH 48/48] Fix panic with OCI for install, upgrade, and show When range support for OCI went in via #10527 it created a situation where some lookups for a chart could cause a panic. This change makes sure the registry client is available to lookup OCI charts Signed-off-by: Matt Farina --- cmd/helm/root.go | 2 +- cmd/helm/show.go | 4 ++-- pkg/action/install.go | 22 +++++++++++++++------- pkg/action/show.go | 12 ++++++++++++ pkg/action/show_test.go | 3 ++- pkg/action/upgrade.go | 5 ++++- 6 files changed, 36 insertions(+), 12 deletions(-) diff --git a/cmd/helm/root.go b/cmd/helm/root.go index be72bbb84..2888d14e2 100644 --- a/cmd/helm/root.go +++ b/cmd/helm/root.go @@ -165,7 +165,7 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string newCreateCmd(out), newDependencyCmd(actionConfig, out), newPullCmd(actionConfig, out), - newShowCmd(out), + newShowCmd(actionConfig, out), newLintCmd(out), newPackageCmd(out), newRepoCmd(out), diff --git a/cmd/helm/show.go b/cmd/helm/show.go index 4640b3ccf..a479ccda5 100644 --- a/cmd/helm/show.go +++ b/cmd/helm/show.go @@ -56,8 +56,8 @@ This command inspects a chart (directory, file, or URL) and displays the content of the CustomResourceDefinition files ` -func newShowCmd(out io.Writer) *cobra.Command { - client := action.NewShow(action.ShowAll) +func newShowCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { + client := action.NewShowWithConfig(action.ShowAll, cfg) showCommand := &cobra.Command{ Use: "show", diff --git a/pkg/action/install.go b/pkg/action/install.go index 250dfae95..f0bbb5cb0 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -117,13 +117,20 @@ type ChartPathOptions struct { Username string // --username Verify bool // --verify Version string // --version + + // registryClient provides a registry client but is not added with + // options from a flag + registryClient *registry.Client } // NewInstall creates a new Install object with the given configuration. func NewInstall(cfg *Configuration) *Install { - return &Install{ + in := &Install{ cfg: cfg, } + in.ChartPathOptions.registryClient = cfg.RegistryClient + + return in } func (i *Install) installCRDs(crds []chart.CRD) error { @@ -662,6 +669,12 @@ OUTER: // // If 'verify' was set on ChartPathOptions, this will attempt to also verify the chart. func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) (string, error) { + // If there is no registry client and the name is in an OCI registry return + // an error and a lookup will not occur. + if registry.IsOCI(name) && c.registryClient == nil { + return "", fmt.Errorf("unable to lookup chart %q, missing registry client", name) + } + name = strings.TrimSpace(name) version := strings.TrimSpace(c.Version) @@ -692,12 +705,7 @@ func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) ( }, RepositoryConfig: settings.RepositoryConfig, RepositoryCache: settings.RepositoryCache, - } - - if registry.IsOCI(name) { - if version != "" { - dl.Options = append(dl.Options, getter.WithTagName(version)) - } + RegistryClient: c.registryClient, } if c.Verify { diff --git a/pkg/action/show.go b/pkg/action/show.go index 1e3da3bdc..9ba85234d 100644 --- a/pkg/action/show.go +++ b/pkg/action/show.go @@ -64,12 +64,24 @@ type Show struct { } // NewShow creates a new Show object with the given configuration. +// Deprecated: Use NewShowWithConfig +// TODO Helm 4: Fold NewShowWithConfig back into NewShow func NewShow(output ShowOutputFormat) *Show { return &Show{ OutputFormat: output, } } +// NewShowWithConfig creates a new Show object with the given configuration. +func NewShowWithConfig(output ShowOutputFormat, cfg *Configuration) *Show { + sh := &Show{ + OutputFormat: output, + } + sh.ChartPathOptions.registryClient = cfg.RegistryClient + + return sh +} + // Run executes 'helm show' against the given release. func (s *Show) Run(chartpath string) (string, error) { if s.chart == nil { diff --git a/pkg/action/show_test.go b/pkg/action/show_test.go index 983bcfe05..8b617ea85 100644 --- a/pkg/action/show_test.go +++ b/pkg/action/show_test.go @@ -23,7 +23,8 @@ import ( ) func TestShow(t *testing.T) { - client := NewShow(ShowAll) + config := actionConfigFixture(t) + client := NewShowWithConfig(ShowAll, config) client.chart = &chart.Chart{ Metadata: &chart.Metadata{Name: "alpine"}, Files: []*chart.File{ diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go index 1e7054118..e228f52dc 100644 --- a/pkg/action/upgrade.go +++ b/pkg/action/upgrade.go @@ -112,9 +112,12 @@ type resultMessage struct { // NewUpgrade creates a new Upgrade object with the given configuration. func NewUpgrade(cfg *Configuration) *Upgrade { - return &Upgrade{ + up := &Upgrade{ cfg: cfg, } + up.ChartPathOptions.registryClient = cfg.RegistryClient + + return up } // Run executes the upgrade on the given release.