From 8c283e8706ce19c0f19226344854906596414fcf Mon Sep 17 00:00:00 2001 From: "Paul \"TBBle\" Hampson" Date: Thu, 12 Dec 2019 04:07:05 +1100 Subject: [PATCH] fix(*): Helm v3 handling of APIVersion v1 charts dependencies (#7009) * Include requirements.* as Files in APIVersionV1 Fixes #6974. This ensures that when reading a Chart marked with APIVersion v1, we maintain the behaviour of Helm v2 and include the requirements.yaml and requirements.lock in the Files collection, and hence produce charts that work correctly with Helm v2. Signed-off-by: Paul "Hampy" Hampson * Write out requirements.lock for APIVersion1 Charts This keeps the on-disk format consistent after `helm dependency update` of an APIVersion1 Chart. Signed-off-by: Paul "Hampy" Hampson * Exclude 'dependencies' from APVersion1 Chart.yaml This fixes `helm lint` against an APIVersion1 chart packaged with Helm v3. Signed-off-by: Paul "Hampy" Hampson * Generate APIVersion v2 charts for dependency tests As the generated chart contains no requirements.yaml in its files list, but has dependencies in its metadata, it is not a valid APIVersion v1 chart. Signed-off-by: Paul "Hampy" Hampson * Generate APIVersion v2 charts for manager tests Specifically for the charts that have dependencies, the generated chart contains no requirements.yaml in its files but has dependencies in its metadata. Hence it is not a valid APIVersion v1 chart. Signed-off-by: Paul "Hampy" Hampson --- cmd/helm/dependency_update_test.go | 2 +- pkg/chart/loader/load.go | 6 ++++++ pkg/chartutil/chartfile.go | 9 +++++++++ pkg/chartutil/save.go | 9 +++++++++ pkg/downloader/manager.go | 10 +++++++--- pkg/downloader/manager_test.go | 4 ++-- 6 files changed, 34 insertions(+), 6 deletions(-) diff --git a/cmd/helm/dependency_update_test.go b/cmd/helm/dependency_update_test.go index 53d67ef59..9afc04f8d 100644 --- a/cmd/helm/dependency_update_test.go +++ b/cmd/helm/dependency_update_test.go @@ -182,7 +182,7 @@ func TestDependencyUpdateCmd_DontDeleteOldChartsOnError(t *testing.T) { func createTestingMetadata(name, baseURL string) *chart.Chart { return &chart.Chart{ Metadata: &chart.Metadata{ - APIVersion: chart.APIVersionV1, + APIVersion: chart.APIVersionV2, Name: name, Version: "1.2.3", Dependencies: []*chart.Dependency{ diff --git a/pkg/chart/loader/load.go b/pkg/chart/loader/load.go index 3c38519bc..dd4fd2dff 100644 --- a/pkg/chart/loader/load.go +++ b/pkg/chart/loader/load.go @@ -114,12 +114,18 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) { if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil { return c, errors.Wrap(err, "cannot load requirements.yaml") } + if c.Metadata.APIVersion == chart.APIVersionV1 { + c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data}) + } // Deprecated: requirements.lock is deprecated use Chart.lock. case f.Name == "requirements.lock": c.Lock = new(chart.Lock) if err := yaml.Unmarshal(f.Data, &c.Lock); err != nil { return c, errors.Wrap(err, "cannot load requirements.lock") } + if c.Metadata.APIVersion == chart.APIVersionV1 { + c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data}) + } case strings.HasPrefix(f.Name, "templates/"): c.Templates = append(c.Templates, &chart.File{Name: f.Name, Data: f.Data}) diff --git a/pkg/chartutil/chartfile.go b/pkg/chartutil/chartfile.go index 68176ed5d..756b87cfb 100644 --- a/pkg/chartutil/chartfile.go +++ b/pkg/chartutil/chartfile.go @@ -42,7 +42,16 @@ func LoadChartfile(filename string) (*chart.Metadata, error) { // // 'filename' should be the complete path and filename ('foo/Chart.yaml') func SaveChartfile(filename string, cf *chart.Metadata) error { + // Pull out the dependencies of a v1 Chart, since there's no way + // to tell the serialiser to skip a field for just this use case + savedDependencies := cf.Dependencies + if cf.APIVersion == chart.APIVersionV1 { + cf.Dependencies = nil + } out, err := yaml.Marshal(cf) + if cf.APIVersion == chart.APIVersionV1 { + cf.Dependencies = savedDependencies + } if err != nil { return err } diff --git a/pkg/chartutil/save.go b/pkg/chartutil/save.go index bc8f5bdd9..e264c4391 100644 --- a/pkg/chartutil/save.go +++ b/pkg/chartutil/save.go @@ -141,8 +141,17 @@ func Save(c *chart.Chart, outDir string) (string, error) { func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error { base := filepath.Join(prefix, c.Name()) + // Pull out the dependencies of a v1 Chart, since there's no way + // to tell the serialiser to skip a field for just this use case + savedDependencies := c.Metadata.Dependencies + if c.Metadata.APIVersion == chart.APIVersionV1 { + c.Metadata.Dependencies = nil + } // Save Chart.yaml cdata, err := yaml.Marshal(c.Metadata) + if c.Metadata.APIVersion == chart.APIVersionV1 { + c.Metadata.Dependencies = savedDependencies + } if err != nil { return err } diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 81dd53614..e46af6944 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -163,7 +163,7 @@ func (m *Manager) Update() error { } // Finally, we need to write the lockfile. - return writeLock(m.ChartPath, lock) + return writeLock(m.ChartPath, lock, c.Metadata.APIVersion == chart.APIVersionV1) } func (m *Manager) loadChartDir() (*chart.Chart, error) { @@ -634,12 +634,16 @@ func (m *Manager) loadChartRepositories() (map[string]*repo.ChartRepository, err } // writeLock writes a lockfile to disk -func writeLock(chartpath string, lock *chart.Lock) error { +func writeLock(chartpath string, lock *chart.Lock, legacyLockfile bool) error { data, err := yaml.Marshal(lock) if err != nil { return err } - dest := filepath.Join(chartpath, "Chart.lock") + lockfileName := "Chart.lock" + if legacyLockfile { + lockfileName = "requirements.lock" + } + dest := filepath.Join(chartpath, lockfileName) return ioutil.WriteFile(dest, data, 0644) } diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go index dd83c3dc2..ea235c13f 100644 --- a/pkg/downloader/manager_test.go +++ b/pkg/downloader/manager_test.go @@ -211,7 +211,7 @@ func TestUpdateBeforeBuild(t *testing.T) { Metadata: &chart.Metadata{ Name: "with-dependency", Version: "0.1.0", - APIVersion: "v1", + APIVersion: "v2", Dependencies: []*chart.Dependency{{ Name: d.Metadata.Name, Version: ">=0.1.0", @@ -285,7 +285,7 @@ func checkBuildWithOptionalFields(t *testing.T, chartName string, dep chart.Depe Metadata: &chart.Metadata{ Name: chartName, Version: "0.1.0", - APIVersion: "v1", + APIVersion: "v2", Dependencies: []*chart.Dependency{&dep}, }, }