diff --git a/cmd/helm/create.go b/cmd/helm/create.go index 0d6e9f100..d4efcde1b 100644 --- a/cmd/helm/create.go +++ b/cmd/helm/create.go @@ -18,6 +18,7 @@ package main import ( "fmt" + "helm.sh/helm/v3/pkg/chart" "io" "path/filepath" @@ -50,9 +51,10 @@ will be overwritten, but other files will be left alone. ` type createOptions struct { - starter string // --starter - name string - starterDir string + starter string // --starter + name string + starterDir string + originalMeta bool } func newCreateCmd(out io.Writer) *cobra.Command { @@ -80,6 +82,7 @@ func newCreateCmd(out io.Writer) *cobra.Command { } cmd.Flags().StringVarP(&o.starter, "starter", "p", "", "the name or absolute path to Helm starter scaffold") + cmd.Flags().BoolVar(&o.originalMeta, "original-meta", false, "use Chart.yaml from the starter template") return cmd } @@ -87,18 +90,37 @@ func (o *createOptions) run(out io.Writer) error { fmt.Fprintf(out, "Creating %s\n", o.name) chartname := filepath.Base(o.name) + // No starter chart path is given, creating from default template + if o.starter == "" { + chartutil.Stderr = out + _, err := chartutil.Create(chartname, filepath.Dir(o.name)) + return err + } + + // Create from the starter + lstarter := filepath.Join(o.starterDir, o.starter) + // If path is absolute, we don't want to prefix it with helm starters folder + if filepath.IsAbs(o.starter) { + lstarter = o.starter + } - if o.starter != "" { - // Create from the starter - lstarter := filepath.Join(o.starterDir, o.starter) - // If path is absolute, we don't want to prefix it with helm starters folder - if filepath.IsAbs(o.starter) { - lstarter = o.starter + cfile := &chart.Metadata{ + Name: chartname, + Description: "A Helm chart for Kubernetes", + Type: "application", + Version: "0.1.0", + AppVersion: "0.1.0", + APIVersion: chart.APIVersionV2, + } + if o.originalMeta { + chartYamlPath := filepath.Join(lstarter, "Chart.yaml") + originalChartfile, err := chartutil.LoadChartfile(chartYamlPath) + if err != nil { + return err } - return chartutil.CreateFrom(chartname, filepath.Dir(o.name), lstarter) + originalChartfile.Name = chartname + cfile = originalChartfile } - chartutil.Stderr = out - _, err := chartutil.Create(chartname, filepath.Dir(o.name)) - return err + return chartutil.CreateFrom(cfile, filepath.Dir(o.name), lstarter) } diff --git a/cmd/helm/create_test.go b/cmd/helm/create_test.go index 1db6bed52..cbf03d095 100644 --- a/cmd/helm/create_test.go +++ b/cmd/helm/create_test.go @@ -193,6 +193,76 @@ func TestCreateStarterAbsoluteCmd(t *testing.T) { } } +func TestCreateStarterAbsoluteCmdOriginalMeta(t *testing.T) { + defer resetEnv()() + defer ensure.HelmHome(t)() + cname := "testchart" + + // Create a starter. + starterchart := helmpath.DataPath("starters") + os.MkdirAll(starterchart, 0755) + starterChartPath, err := chartutil.Create("starterchart", starterchart) + if err != nil { + t.Fatalf("Could not create chart: %s", err) + } else { + t.Logf("Created %s", starterChartPath) + } + + chartYamlPath := filepath.Join(starterChartPath, "Chart.yaml") + meta, err := chartutil.LoadChartfile(chartYamlPath) + if err != nil { + t.Fatalf("Could not read Chart.yaml of the template: %s", err) + } + meta.Dependencies = []*chart.Dependency{ + { + Name: "some-dependency", + Version: "1.0.1", + Repository: "@repo", + }, + } + err = chartutil.SaveChartfile(chartYamlPath, meta) + if err != nil { + t.Fatalf("Could not save Chart.yaml of the template: %s", err) + } + os.MkdirAll(helmpath.CachePath(), 0755) + defer testChdir(t, helmpath.CachePath())() + + // Run a create + if _, _, err := executeActionCommand(fmt.Sprintf("create --starter=%s %s --original-meta", starterChartPath, cname)); err != nil { + t.Errorf("Failed to run create: %s", err) + return + } + + // Test that the chart is there + if fi, err := os.Stat(cname); err != nil { + t.Fatalf("no chart directory: %s", err) + } else if !fi.IsDir() { + t.Fatalf("chart is not directory") + } + + c, err := loader.LoadDir(cname) + if err != nil { + t.Fatal(err) + } + + if c.Name() != cname { + t.Errorf("Expected %q name, got %q", cname, c.Name()) + } + if c.Metadata.APIVersion != chart.APIVersionV2 { + t.Errorf("Wrong API version: %q", c.Metadata.APIVersion) + } + + if len(c.Metadata.Dependencies) == 0 { + t.Errorf("Chart.yaml of the created chart does not match the template") + } + + expectedNumberOfTemplates := 8 + if l := len(c.Templates); l != expectedNumberOfTemplates { + t.Errorf("Expected %d templates, got %d", expectedNumberOfTemplates, l) + } + +} + func TestCreateFileCompletion(t *testing.T) { checkFileCompletion(t, "create", true) checkFileCompletion(t, "create myname", false) diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go index ce6724348..ca79e7ab2 100644 --- a/pkg/chartutil/create.go +++ b/pkg/chartutil/create.go @@ -511,12 +511,13 @@ spec: var Stderr io.Writer = os.Stderr // CreateFrom creates a new chart, but scaffolds it from the src chart. -func CreateFrom(chartname, dest, src string) error { +func CreateFrom(chartfile *chart.Metadata, dest, src string) error { schart, err := loader.Load(src) if err != nil { return errors.Wrapf(err, "could not load %s", src) } - schart.Metadata.Name = chartname + + schart.Metadata = chartfile var updatedTemplates []*chart.File diff --git a/pkg/chartutil/create_test.go b/pkg/chartutil/create_test.go index e2edd1a56..9a473fc59 100644 --- a/pkg/chartutil/create_test.go +++ b/pkg/chartutil/create_test.go @@ -23,6 +23,7 @@ import ( "path/filepath" "testing" + "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" ) @@ -75,21 +76,25 @@ func TestCreateFrom(t *testing.T) { } defer os.RemoveAll(tdir) - chartname := "foo" + cf := &chart.Metadata{ + APIVersion: chart.APIVersionV1, + Name: "foo", + Version: "0.1.0", + } srcdir := "./testdata/frobnitz/charts/mariner" - if err := CreateFrom(chartname, tdir, srcdir); err != nil { + if err := CreateFrom(cf, tdir, srcdir); err != nil { t.Fatal(err) } - dir := filepath.Join(tdir, chartname) - c := filepath.Join(tdir, chartname) + dir := filepath.Join(tdir, "foo") + c := filepath.Join(tdir, cf.Name) mychart, err := loader.LoadDir(c) if err != nil { t.Fatalf("Failed to load newly created chart %q: %s", c, err) } - if mychart.Name() != chartname { + if mychart.Name() != "foo" { t.Errorf("Expected name to be 'foo', got %q", mychart.Name()) }