feat(template): Add --notes flag

Added flag `--notes` to `helm template` command
with default set to `false`. If enabled, it will
print the rendered `NOTES.txt` at the end of the
manifests. If `--render-subchart-notes` (flag
already exists on `template` command as it is part
of `install` command's flags that `template` uses)
is also enabled, the output will include the
subchart's notes also.

Updated the `install` command's
`--render-subchart-notes` flag's description to
include additional information (that it is only
valid when `--notes` flag is enabled) in case of
`template` command. Note: `template` command uses
most of the `install` command's flags, including
`--render-subchart-notes`.

Updated `action.renderResources()` to format root
chart's notes, and subcharts' notes if
`--render-subchart-notes` flag is enabled, and
return as a string based on whether it is:
- Dry run, the notes are prefixed with the source
  filename and `---` separator. For helm install/
  upgrade commands, the  `--dry-run` flag can be
  used to enable dry run. The helm template
  command is considered a dry run by default.
  Note: The `template` command is considered a dry
  run by default. For eg:
  ```
  foo NOTES HERE

  bar NOTES HERE

  baz NOTES HERE

  qux NOTES HERE
  ```
- Not a dry run, render the root chart's notes. If
  the `--render-subchart-notes` flag is enabled,
  since the subcharts' notes are also included,
  separate each note with a newline at the end.
  For eg:
  ```
  ---
  # Source: foo/templates/NOTES.txt
  foo NOTES HERE
  ---
  # Source: foo/charts/bar/templates/NOTES.txt
  bar NOTES HERE
  ---
  # Source: foo/charts/baz/templates/NOTES.txt
  baz NOTES HERE
  ---
  # Source: foo/charts/bar/charts/qux/templates/NOTES.txt
  qux NOTES HERE
  ```
The notes in both cases are sorted based on the
following 2 conditions:
 1. Depth
 2. Alphabetical (since the notes file's name will
    be the same for any chart/subchart, the order
    gets applied to the chart/subchart's name).

Added tests for the following scenarios:
 - helm template:
   1. On the chart without notes or subcharts
   2. `--notes` on chart without notes or
      subcharts
   3. `--render-subchart-notes` on chart without
      notes or subcharts
   4. `--notes --render-subchart-notes` on chart
      without notes or subcharts
   5. On the chart with notes without subcharts
   6. `--notes` on chart with notes without
      subcharts
   7. `--render-subchart-notes` on chart with
      notes without subcharts
   8. `--notes --render-subchart-notes` on chart
      with notes without subcharts
   9. On the chart with notes and subchart
   10. `--notes` on chart with notes and subchart
   11. `--render-subchart-notes` on the chart with
       notes and subchart
   12. `--notes --render-subchart-notes` on chart
       with notes and subchart
   13. `--help`
 - helm install:
   1. On the chart without notes or subcharts
   2. `--dry-run` on chart without notes or
      subcharts
   3. `--render-subchart-notes` on chart without
      notes or subcharts
   4. `--dry-run --render-subchart-notes` on chart
      without notes or subcharts
   5. On the chart with notes without subcharts
   6. `--dry-run` on chart with notes without
      subcharts
   7. `--render-subchart-notes` on chart with
      notes without subcharts
   8. `--dry-run --render-subchart-notes` on chart
      with notes without subcharts
   9. On a chart with notes and subcharts
   10. `--dry-run` on chart with notes and
       subcharts
   11. `--render-subchart-notes` on chart with
       notes and subcharts
   12. `--dry-run --render-subchart-notes` on chart
       with notes and subcharts
   13. `--help`
 - helm upgrade:
   1. On the chart without notes or subcharts
   2. `--dry-run` on chart without notes or
      subcharts
   3. `--render-subchart-notes` on chart without
      notes or subcharts
   4. `--dry-run --render-subchart-notes` on chart
      without notes or subcharts
   5. On the chart with notes without subcharts
   6. `--dry-run` on chart with notes without
      subcharts
   7. `--render-subchart-notes` on chart with
      notes without subcharts
   8. `--dry-run --render-subchart-notes` on chart
      with notes without subcharts
   9. On the chart with notes and subcharts
   10. `--dry-run` on chart with notes and
       subcharts
   11. `--render-subchart-notes` on chart with
       notes and subcharts
   12. `--dry-run --render-subchart-notes` on
       chart with notes and subcharts
   13. `--help`

Related to #6901

Signed-off-by: Bhargav Ravuri <bhargav.ravuri@infracloud.io>
pull/31097/head
Bhargav Ravuri 2 months ago
parent b0fcbc5487
commit df9811b15f
No known key found for this signature in database
GPG Key ID: 78CAC07D8471333F

@ -162,7 +162,7 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
}, },
} }
addInstallFlags(cmd, cmd.Flags(), client, valueOpts) addInstallFlags(cmd, cmd.Flags(), client, valueOpts, false)
// hide-secret is not available in all places the install flags are used so // hide-secret is not available in all places the install flags are used so
// it is added separately // it is added separately
f := cmd.Flags() f := cmd.Flags()
@ -173,7 +173,8 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
return cmd return cmd
} }
func addInstallFlags(cmd *cobra.Command, f *pflag.FlagSet, client *action.Install, valueOpts *values.Options) { func addInstallFlags(cmd *cobra.Command, f *pflag.FlagSet, client *action.Install, valueOpts *values.Options,
isTemplateCommand bool) {
f.BoolVar(&client.CreateNamespace, "create-namespace", false, "create the release namespace if not present") f.BoolVar(&client.CreateNamespace, "create-namespace", false, "create the release namespace if not present")
// --dry-run options with expected outcome: // --dry-run options with expected outcome:
// - Not set means no dry run and server is contacted. // - Not set means no dry run and server is contacted.
@ -196,12 +197,21 @@ func addInstallFlags(cmd *cobra.Command, f *pflag.FlagSet, client *action.Instal
f.BoolVar(&client.DisableOpenAPIValidation, "disable-openapi-validation", false, "if set, the installation process will not validate rendered templates against the Kubernetes OpenAPI Schema") f.BoolVar(&client.DisableOpenAPIValidation, "disable-openapi-validation", false, "if set, the installation process will not validate rendered templates against the Kubernetes OpenAPI Schema")
f.BoolVar(&client.Atomic, "atomic", false, "if set, the installation process deletes the installation on failure. The --wait flag will be set automatically if --atomic is used") f.BoolVar(&client.Atomic, "atomic", false, "if set, the installation process deletes the installation on failure. The --wait flag will be set automatically if --atomic is used")
f.BoolVar(&client.SkipCRDs, "skip-crds", false, "if set, no CRDs will be installed. By default, CRDs are installed if not already present") f.BoolVar(&client.SkipCRDs, "skip-crds", false, "if set, no CRDs will be installed. By default, CRDs are installed if not already present")
f.BoolVar(&client.SubNotes, "render-subchart-notes", false, "if set, render subchart notes along with the parent")
f.BoolVar(&client.SkipSchemaValidation, "skip-schema-validation", false, "if set, disables JSON schema validation") f.BoolVar(&client.SkipSchemaValidation, "skip-schema-validation", false, "if set, disables JSON schema validation")
f.StringToStringVarP(&client.Labels, "labels", "l", nil, "Labels that would be added to release metadata. Should be divided by comma.") f.StringToStringVarP(&client.Labels, "labels", "l", nil, "Labels that would be added to release metadata. Should be divided by comma.")
f.BoolVar(&client.EnableDNS, "enable-dns", false, "enable DNS lookups when rendering templates") f.BoolVar(&client.EnableDNS, "enable-dns", false, "enable DNS lookups when rendering templates")
f.BoolVar(&client.HideNotes, "hide-notes", false, "if set, do not show notes in install output. Does not affect presence in chart metadata") f.BoolVar(&client.HideNotes, "hide-notes", false, "if set, do not show notes in install output. Does not affect presence in chart metadata")
f.BoolVar(&client.TakeOwnership, "take-ownership", false, "if set, install will ignore the check for helm annotations and take ownership of the existing resources") f.BoolVar(&client.TakeOwnership, "take-ownership", false, "if set, install will ignore the check for helm annotations and take ownership of the existing resources")
// Set the --render-subchart-notes flag description based on the command. The template command requires some
// additional information than the install/upgrade commands.
renderSubchartNotesFlagDesc := "if set, render subchart notes along with the parent"
if isTemplateCommand {
renderSubchartNotesFlagDesc = fmt.Sprintf("%s. Note: This will only work if --notes flag is enabled.",
renderSubchartNotesFlagDesc)
}
f.BoolVar(&client.SubNotes, "render-subchart-notes", false, renderSubchartNotesFlagDesc)
addValueOptionsFlags(f, valueOpts) addValueOptionsFlags(f, valueOpts)
addChartPathOptionsFlags(f, &client.ChartPathOptions) addChartPathOptionsFlags(f, &client.ChartPathOptions)

@ -20,10 +20,13 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"os"
"path/filepath" "path/filepath"
"testing" "testing"
"helm.sh/helm/v3/pkg/repo/repotest" "helm.sh/helm/v3/pkg/repo/repotest"
"github.com/stretchr/testify/assert"
) )
func TestInstall(t *testing.T) { func TestInstall(t *testing.T) {
@ -280,11 +283,139 @@ func TestInstall(t *testing.T) {
wantError: true, wantError: true,
golden: "output/install-hide-secret.txt", golden: "output/install-hide-secret.txt",
}, },
{
// Running `helm install` on a chart that doesn't have notes or subcharts should print the install command's
// output without notes.
name: "helm install on chart without notes or subcharts",
cmd: fmt.Sprintf("install luffy '%s' --namespace default", emptyChart),
golden: "output/install-without-notes-or-subcharts.txt",
},
{
// Running `helm install --dry-run` on a chart that doesn't have notes or subcharts should print the install
// command's dry-run output without notes.
name: "helm install --dry-run on chart without notes or subcharts",
cmd: fmt.Sprintf("install luffy '%s' --namespace default --dry-run", emptyChart),
golden: "output/install-without-notes-or-subcharts-with-flag-dry-run-enabled.txt",
},
{
// Running `helm install --render-subchart-notes` on a chart that doesn't have notes or subcharts should
// print the install command's output without any notes.
name: "helm install --render-subchart-notes on chart without notes or subcharts",
cmd: fmt.Sprintf("install luffy '%s' --namespace default --render-subchart-notes", emptyChart),
golden: "output/install-without-notes-or-subcharts.txt",
},
{
// Running `helm install --dry-run --render-subchart-notes` on a chart that doesn't have notes or subcharts
// should print the install command's dry-run output without any notes.
name: "helm install --dry-run --render-subchart-notes on chart without notes or subcharts",
cmd: fmt.Sprintf("install luffy '%s' --namespace default --dry-run --render-subchart-notes", emptyChart),
golden: "output/install-without-notes-or-subcharts-with-flag-dry-run-enabled.txt",
},
{
// Running `helm install` on a chart that has notes but no subcharts should print the install command's
// output with (current chart's) notes.
name: "helm install on chart with notes without subcharts",
cmd: fmt.Sprintf("install luffy '%s' --namespace default", chartWithNotes),
golden: "output/install-with-notes.txt",
},
{
// Running `helm install --dry-run` on a chart that has notes but no subcharts should print the install
// command's dry-run output with (current chart's) notes. Note: The notes in dry-run output include the
// source filename and separator "---".
name: "helm install --dry-run on chart with notes without subcharts",
cmd: fmt.Sprintf("install luffy '%s' --namespace default --dry-run", chartWithNotes),
golden: "output/install-with-notes-with-flag-dry-run-enabled.txt",
},
{
// Running `helm install --render-subchart-notes` on a chart that has notes but no subcharts should print
// the install command's output with (current chart's) notes, i.e., no subchart's notes as no subchart.
name: "helm install --render-subchart-notes on chart with notes without subcharts",
cmd: fmt.Sprintf("install luffy '%s' --namespace default --render-subchart-notes", chartWithNotes),
golden: "output/install-with-notes.txt",
},
{
// Running `helm install --dry-run --render-subchart-notes` on a chart that has notes but no subcharts
// should print the install command's dry-run output (current chart's) notes, i.e., no subchart's notes as
// no subchart. Note: The notes in dry-run output include the source filename and separator "---".
name: "helm install --dry-run --render-subchart-notes on chart with notes without subcharts",
cmd: fmt.Sprintf("install luffy '%s' --namespace default --dry-run --render-subchart-notes",
chartWithNotes),
golden: "output/install-with-notes-with-flag-dry-run-enabled.txt",
},
{
// Running `helm install` on a chart that has notes and 2 levels of subcharts should print install command's
// output with just root chart's notes, i.e., without subchart's notes.
name: "helm install on chart with notes and subcharts",
cmd: fmt.Sprintf("install luffy '%s' --namespace default", chartWithNotesAnd2LevelsOfSubCharts),
golden: "output/install-with-notes-and-subcharts.txt",
},
{
// Running `helm install --dry-run` on a chart that has notes and 2 levels of subcharts should print the
// install command's dry-run output with just the root chart's notes, i.e., without the subchart's notes.
// sNote: The notes in dry-run output include the source filename and separator "---".
name: "helm install --dry-run on chart with notes and subcharts",
cmd: fmt.Sprintf("install luffy '%s' --namespace default --dry-run",
chartWithNotesAnd2LevelsOfSubCharts),
golden: "output/install-with-notes-and-subcharts-with-flag-dry-run-enabled.txt",
},
{
// Running `helm install --render-subchart-notes` on a chart that has notes and 2 levels of subcharts should
// print the install command's output with both the root chart and the subcharts' notes.
name: "helm install --render-subchart-notes on chart with notes and subcharts",
cmd: fmt.Sprintf("install luffy '%s' --namespace default --render-subchart-notes",
chartWithNotesAnd2LevelsOfSubCharts),
golden: "output/install-with-notes-and-subcharts-with-flag-render-subchart-notes-enabled.txt",
},
{
// Running `helm install --dry-run --render-subchart-notes` on a chart that has notes and 2 levels of
// subcharts should print the install command's dry-run output with both the root chart and the subcharts'
// notes. Note: The notes in dry-run output include the source filename and separator "---".
name: "helm install --dry-run --render-subchart-notes on chart with notes and subcharts",
cmd: fmt.Sprintf("install luffy '%s' --namespace default --dry-run --render-subchart-notes",
chartWithNotesAnd2LevelsOfSubCharts),
golden: "output/" +
"install-with-notes-and-subcharts-with-both-flags-dry-run-and-render-subchart-notes-enabled.txt",
},
} }
runTestCmd(t, tests) runTestCmd(t, tests)
} }
// TestInstallHelpOutput tests the `helm install --help` command's output text. This is required because the
// --render-subchart-notes flag's description is different for the template command from that of install/upgrade
// commands.
func TestInstallHelpOutput(t *testing.T) {
const (
outputFilePath = "testdata/output/install-help.txt"
testNamespace = "test-namespace"
repositoryCache = "test-repository-cache-dir"
repositoryConfig = "test-repository-config.yaml"
registryConfig = "test-registry-config.json"
gnupgHome = "test-gpg"
commandText = "install --help"
)
// Reset the envs and the configs at the end of this test so that the updates wouldnt affect other tests.
defer resetEnv()()
// Read the expected output file.
expectedOutput, err := os.ReadFile(outputFilePath)
assert.NoError(t, err, "unexpected error while reading expected output's file %q", outputFilePath)
// Set the configs that might otherwise change based on the local environment if not explicitly set. Note: These
// configs are not related to the current test.
settings.RepositoryCache = repositoryCache
settings.RepositoryConfig = repositoryConfig
settings.RegistryConfig = registryConfig
settings.SetNamespace(testNamespace)
t.Setenv("GNUPGHOME", gnupgHome)
// Run the `helm install --help` command and compare the help text.
_, actualOutput, err := executeActionCommandC(storageFixture(), commandText)
assert.NoError(t, err, "unexpected error running command %q", commandText)
assert.Equal(t, string(expectedOutput), actualOutput, "mismatch of output")
}
func TestInstallOutputCompletion(t *testing.T) { func TestInstallOutputCompletion(t *testing.T) {
outputFlagCompletionTest(t, "install") outputFlagCompletionTest(t, "install")
} }

@ -55,6 +55,7 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
var kubeVersion string var kubeVersion string
var extraAPIs []string var extraAPIs []string
var showFiles []string var showFiles []string
var renderNotes bool
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "template [NAME] [CHART]", Use: "template [NAME] [CHART]",
@ -133,6 +134,38 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
} }
} }
// If --notes flag is enabled, add the rendered notes file (templates/NOTES.txt) content to the output.
// Since the template command is considered a dry run, the rendered notes include the source file name
// and the separator as follows:
//
// ---
// # Source: foo/templates/NOTES.txt
// foo NOTES HERE
//
// If --render-subchart-notes flag is also enabled, the rendered notes will include notes from subcharts
// as follows:
//
// ---
// # Source: foo/templates/NOTES.txt
// foo NOTES HERE
// ---
// # Source: foo/charts/bar/templates/NOTES.txt
// bar NOTES HERE
// ---
// # Source: foo/charts/baz/templates/NOTES.txt
// baz NOTES HERE
// ---
// # Source: foo/charts/bar/charts/qux/templates/NOTES.txt
// qux NOTES HERE
//
// Note: The order of the notes files above is based on depth first, and then in alphabetical order.
//
// If just --render-subchart-notes flag is enabled and --notes flag is not, skip adding any notes to
// output.
if renderNotes {
fmt.Fprint(&manifests, rel.Info.Notes)
}
// if we have a list of files to render, then check that each of the // if we have a list of files to render, then check that each of the
// provided files exists in the chart. // provided files exists in the chart.
if len(showFiles) > 0 { if len(showFiles) > 0 {
@ -190,7 +223,7 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
} }
f := cmd.Flags() f := cmd.Flags()
addInstallFlags(cmd, f, client, valueOpts) addInstallFlags(cmd, f, client, valueOpts, true)
f.StringArrayVarP(&showFiles, "show-only", "s", []string{}, "only show manifests rendered from the given templates") f.StringArrayVarP(&showFiles, "show-only", "s", []string{}, "only show manifests rendered from the given templates")
f.StringVar(&client.OutputDir, "output-dir", "", "writes the executed templates to files in output-dir instead of stdout") f.StringVar(&client.OutputDir, "output-dir", "", "writes the executed templates to files in output-dir instead of stdout")
f.BoolVar(&validate, "validate", false, "validate your manifests against the Kubernetes cluster you are currently pointing at. This is the same validation performed on an install") f.BoolVar(&validate, "validate", false, "validate your manifests against the Kubernetes cluster you are currently pointing at. This is the same validation performed on an install")
@ -200,6 +233,7 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
f.StringVar(&kubeVersion, "kube-version", "", "Kubernetes version used for Capabilities.KubeVersion") f.StringVar(&kubeVersion, "kube-version", "", "Kubernetes version used for Capabilities.KubeVersion")
f.StringSliceVarP(&extraAPIs, "api-versions", "a", []string{}, "Kubernetes api versions used for Capabilities.APIVersions") f.StringSliceVarP(&extraAPIs, "api-versions", "a", []string{}, "Kubernetes api versions used for Capabilities.APIVersions")
f.BoolVar(&client.UseReleaseName, "release-name", false, "use release name in the output-dir path.") f.BoolVar(&client.UseReleaseName, "release-name", false, "use release name in the output-dir path.")
f.BoolVar(&renderNotes, "notes", false, "if set, render the current chart's notes file")
bindPostRenderFlag(cmd, &client.PostRenderer) bindPostRenderFlag(cmd, &client.PostRenderer)
return cmd return cmd

@ -18,11 +18,19 @@ package main
import ( import (
"fmt" "fmt"
"os"
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
var chartPath = "testdata/testcharts/subchart" var (
emptyChart = "testdata/testcharts/empty"
chartPath = "testdata/testcharts/subchart"
chartWithNotes = "testdata/testcharts/chart-with-notes"
chartWithNotesAnd2LevelsOfSubCharts = "testdata/testcharts/chart-with-notes-and-2-levels-of-subcharts"
)
func TestTemplateCmd(t *testing.T) { func TestTemplateCmd(t *testing.T) {
deletevalchart := "testdata/testcharts/issue-9027" deletevalchart := "testdata/testcharts/issue-9027"
@ -161,10 +169,133 @@ func TestTemplateCmd(t *testing.T) {
cmd: fmt.Sprintf("template '%s' -f %s/extra_values.yaml", chartPath, chartPath), cmd: fmt.Sprintf("template '%s' -f %s/extra_values.yaml", chartPath, chartPath),
golden: "output/template-subchart-cm-set-file.txt", golden: "output/template-subchart-cm-set-file.txt",
}, },
{
// Running `helm template` on a chart that doesn't have notes or subcharts should print the template
// command's output without notes.
name: "helm template on chart without notes or subcharts",
cmd: fmt.Sprintf("template luffy '%s' --namespace default", emptyChart),
golden: "output/template-without-notes-or-subcharts.txt",
},
{
// Running `helm template --notes` on a chart that doesn't have notes or subcharts should print template
// command's output without notes.
name: "helm template --notes on chart without notes or subcharts",
cmd: fmt.Sprintf("template luffy '%s' --namespace default --notes", emptyChart),
golden: "output/template-without-notes-or-subcharts.txt",
},
{
// Running `helm template --render-subchart-notes` on a chart that doesn't have notes or subcharts should
// print the template command's output without notes.
name: "helm template --render-subchart-notes on chart without notes or subcharts",
cmd: fmt.Sprintf("template luffy '%s' --namespace default --render-subchart-notes", emptyChart),
golden: "output/template-without-notes-or-subcharts.txt",
},
{
// Running `helm template --notes --render-subchart-notes` on a chart that doesn't have notes or subcharts
// should print the template command's output without notes.
name: "helm template --notes --render-subchart-notes on chart without notes or subcharts",
cmd: fmt.Sprintf("template luffy '%s' --namespace default --notes --render-subchart-notes", emptyChart),
golden: "output/template-without-notes-or-subcharts.txt",
},
{
// Running `helm template` on a chart that has notes but no subcharts should print the template command's
// output without notes, since --notes flag is not enabled.
name: "helm template on chart with notes without subcharts",
cmd: fmt.Sprintf("template luffy '%s' --namespace default", chartWithNotes),
golden: "output/template-with-notes.txt",
},
{
// Running `helm template --notes` on a chart that has notes but no subcharts should print the template
// command's output with (current chart's) notes.
name: "helm template --notes on chart with notes without subcharts",
cmd: fmt.Sprintf("template luffy '%s' --namespace default --notes", chartWithNotes),
golden: "output/template-with-notes-with-flag-notes-enabled.txt",
},
{
// Running `helm template --render-subchart-notes` on a chart that has notes but no subcharts should print
// the template command's output without notes, since --notes flag is not enabled.
name: "helm template --render-subchart-notes on chart with notes without subcharts",
cmd: fmt.Sprintf("template luffy '%s' --namespace default --render-subchart-notes", chartWithNotes),
golden: "output/template-with-notes.txt",
},
{
// Running `helm template --notes --render-subchart-notes` on a chart that has notes but no subcharts should
// print the template command's output (current chart's) notes, i.e., no subchart's notes as no subcharts.
name: "helm template --notes --render-subchart-notes on chart with notes without subcharts",
cmd: fmt.Sprintf("template luffy '%s' --namespace default --notes --render-subchart-notes",
chartWithNotes),
golden: "output/template-with-notes-with-flag-notes-enabled.txt",
},
{
// Running `helm template` on a chart that has notes and 2 levels of subcharts should print template
// command's output without notes, since --notes flag is not enabled.
name: "helm template on chart with notes and subcharts",
cmd: fmt.Sprintf("template luffy '%s' --namespace default", chartWithNotesAnd2LevelsOfSubCharts),
golden: "output/template-with-notes-and-subcharts.txt",
},
{
// Running `helm template --notes` on a chart that has notes and 2 levels of subcharts should print template
// command's output with just root chart's notes, i.e., no subchart's notes as no --render-subchart-notes.
name: "helm template --notes on chart with notes and subcharts",
cmd: fmt.Sprintf("template luffy '%s' --namespace default --notes", chartWithNotesAnd2LevelsOfSubCharts),
golden: "output/template-with-notes-and-subcharts-with-flag-notes-enabled.txt",
},
{
// Running `helm template --render-subchart-notes` on a chart that has notes and 2 levels of subcharts
// should print the template command's output without notes, since --notes flag is not enabled.
name: "helm template --render-subchart-notes on chart with notes and subcharts",
cmd: fmt.Sprintf("template luffy '%s' --namespace default --render-subchart-notes",
chartWithNotesAnd2LevelsOfSubCharts),
golden: "output/template-with-notes-and-subcharts.txt",
},
{
// Running `helm template --notes --render-subchart-notes` on a chart that has notes and 2 levels of
// subcharts should print the template command's output with both the root chart and the subchart's notes.
name: "helm template --notes --render-subchart-notes on chart with notes and subcharts",
cmd: fmt.Sprintf("template luffy '%s' --namespace default --notes --render-subchart-notes",
chartWithNotesAnd2LevelsOfSubCharts),
golden: "output/" +
"template-with-notes-and-subcharts-with-both-flags-notes-and-render-subchart-notes-enabled.txt",
},
} }
runTestCmd(t, tests) runTestCmd(t, tests)
} }
// TestTemplateHelpOutput tests the `helm template --help` command's output text. This is required because the
// --render-subchart-notes flag's description is different for the template command from that of install/upgrade
// commands.
func TestTemplateHelpOutput(t *testing.T) {
const (
outputFilePath = "testdata/output/template-help.txt"
testNamespace = "test-namespace"
repositoryCache = "test-repository-cache-dir"
repositoryConfig = "test-repository-config.yaml"
registryConfig = "test-registry-config.json"
gnupgHome = "test-gpg"
commandText = "template --help"
)
// Reset the envs and the configs at the end of this test so that the updates wouldnt affect other tests.
defer resetEnv()()
// Read the expected output file.
expectedOutput, err := os.ReadFile(outputFilePath)
assert.NoError(t, err, "unexpected error while reading expected output's file %q", outputFilePath)
// Set the configs that might otherwise change based on the local environment if not explicitly set. Note: These
// configs are not related to the current test.
settings.RepositoryCache = repositoryCache
settings.RepositoryConfig = repositoryConfig
settings.RegistryConfig = registryConfig
settings.SetNamespace(testNamespace)
t.Setenv("GNUPGHOME", gnupgHome)
// Run the `helm template --help` command and compare the help text.
_, actualOutput, err := executeActionCommandC(storageFixture(), commandText)
assert.NoError(t, err, "unexpected error running command %q", commandText)
assert.Equal(t, string(expectedOutput), actualOutput, "mismatch of output")
}
func TestTemplateVersionCompletion(t *testing.T) { func TestTemplateVersionCompletion(t *testing.T) {
repoFile := "testdata/helmhome/helm/repositories.yaml" repoFile := "testdata/helmhome/helm/repositories.yaml"
repoCache := "testdata/helmhome/helm/repository" repoCache := "testdata/helmhome/helm/repository"

@ -0,0 +1,151 @@
This command installs a chart archive.
The install argument must be a chart reference, a path to a packaged chart,
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'. 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 also use '--set-json' to set json values
(scalars/objects/arrays) from the command line.
$ helm install -f myvalues.yaml myredis ./redis
or
$ helm install --set name=prod myredis ./redis
or
$ helm install --set-string long_int=1234567890 myredis ./redis
or
$ helm install --set-file my_script=dothings.sh myredis ./redis
or
$ helm install --set-json 'master.sidecars=[{"name":"sidecar","image":"myImage","imagePullPolicy":"Always","ports":[{"name":"portname","containerPort":1234}]}]' myredis ./redis
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
contained a key called 'Test', the value set in override.yaml would take precedence:
$ helm install -f myvalues.yaml -f override.yaml myredis ./redis
You can specify the '--set' flag multiple times. The priority will be given to the
last (right-most) set specified. For example, if both 'bar' and 'newbar' values are
set for a key called 'foo', the 'newbar' value would take precedence:
$ helm install --set foo=bar --set foo=newbar myredis ./redis
Similarly, in the following example 'foo' is set to '["four"]':
$ helm install --set-json='foo=["one", "two", "three"]' --set-json='foo=["four"]' myredis ./redis
And in the following example, 'foo' is set to '{"key1":"value1","key2":"bar"}':
$ helm install --set-json='foo={"key1":"value1","key2":"value2"}' --set-json='foo.key2="bar"' myredis ./redis
To check the generated manifests of a release without installing the chart,
the --debug and --dry-run flags can be combined.
The --dry-run flag will output all generated chart manifests, including Secrets
which can contain sensitive values. To hide Kubernetes Secrets use the
--hide-secret flag. Please carefully consider how and when these flags are used.
If --verify is set, the chart MUST have a provenance file, and the provenance
file MUST pass all verification steps.
There are six different ways you can express the chart you want to install:
1. By chart reference: helm install mymaria example/mariadb
2. By path to a packaged chart: helm install mynginx ./nginx-1.2.3.tgz
3. By path to an unpacked chart directory: helm install mynginx ./nginx
4. By absolute URL: helm install mynginx https://example.com/charts/nginx-1.2.3.tgz
5. By chart reference and repo url: helm install --repo https://example.com/charts/ mynginx nginx
6. By OCI registries: helm install mynginx --version 1.2.3 oci://example.com/charts/nginx
CHART REFERENCES
A chart reference is a convenient way of referencing a chart in a chart repository.
When you use a chart reference with a repo prefix ('example/mariadb'), Helm will look in the local
configuration for a chart repository named 'example', and will then look for a
chart in that repository whose name is 'mariadb'. It will install the latest stable version of that chart
until you specify '--devel' flag to also include development version (alpha, beta, and release candidate releases), or
supply a version number with the '--version' flag.
To see the list of chart repositories, use 'helm repo list'. To search for
charts in a repository, use 'helm search'.
Usage:
helm install [NAME] [CHART] [flags]
Flags:
--atomic if set, the installation process deletes the installation on failure. The --wait flag will be set automatically if --atomic is used
--ca-file string verify certificates of HTTPS-enabled servers using this CA bundle
--cert-file string identify HTTPS client using this SSL certificate file
--create-namespace create the release namespace if not present
--dependency-update update dependencies if they are missing before installing the chart
--description string add a custom description
--devel use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored
--disable-openapi-validation if set, the installation process will not validate rendered templates against the Kubernetes OpenAPI Schema
--dry-run string[="client"] simulate an install. If --dry-run is set with no option being specified or as '--dry-run=client', it will not attempt cluster connections. Setting '--dry-run=server' allows attempting cluster connections.
--enable-dns enable DNS lookups when rendering templates
--force force resource updates through a replacement strategy
-g, --generate-name generate the name (and omit the NAME parameter)
-h, --help help for install
--hide-notes if set, do not show notes in install output. Does not affect presence in chart metadata
--hide-secret hide Kubernetes Secrets when also using the --dry-run flag
--insecure-skip-tls-verify skip tls certificate checks for the chart download
--key-file string identify HTTPS client using this SSL key file
--keyring string location of public keys used for verification (default "test-gpg/pubring.gpg")
-l, --labels stringToString Labels that would be added to release metadata. Should be divided by comma. (default [])
--name-template string specify template used to name the release
--no-hooks prevent hooks from running during install
-o, --output format prints the output in the specified format. Allowed values: table, json, yaml (default table)
--pass-credentials pass credentials to all domains
--password string chart repository password where to locate the requested chart
--plain-http use insecure HTTP connections for the chart download
--post-renderer postRendererString the path to an executable to be used for post rendering. If it exists in $PATH, the binary will be used, otherwise it will try to look for the executable at the given path
--post-renderer-args postRendererArgsSlice an argument to the post-renderer (can specify multiple) (default [])
--render-subchart-notes if set, render subchart notes along with the parent
--replace re-use the given name, only if that name is a deleted release which remains in the history. This is unsafe in production
--repo string chart repository url where to locate the requested chart
--set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--set-file stringArray set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)
--set-json stringArray set JSON values on the command line (can specify multiple or separate values with commas: key1=jsonval1,key2=jsonval2)
--set-literal stringArray set a literal STRING value on the command line
--set-string stringArray set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--skip-crds if set, no CRDs will be installed. By default, CRDs are installed if not already present
--skip-schema-validation if set, disables JSON schema validation
--take-ownership if set, install will ignore the check for helm annotations and take ownership of the existing resources
--timeout duration time to wait for any individual Kubernetes operation (like Jobs for hooks) (default 5m0s)
--username string chart repository username where to locate the requested chart
-f, --values strings specify values in a YAML file or a URL (can specify multiple)
--verify verify the package before using it
--version string specify a version constraint for the chart version to use. This constraint can be a specific tag (e.g. 1.1.1) or it may reference a valid range (e.g. ^2.0.0). If this is not specified, the latest version is used
--wait if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment, StatefulSet, or ReplicaSet are in a ready state before marking the release as successful. It will wait for as long as --timeout
--wait-for-jobs if set and --wait enabled, will wait until all Jobs have been completed before marking the release as successful. It will wait for as long as --timeout
Global Flags:
--burst-limit int client-side default throttling limit (default 100)
--debug enable verbose output
--kube-apiserver string the address and the port for the Kubernetes API server
--kube-as-group stringArray group to impersonate for the operation, this flag can be repeated to specify multiple groups.
--kube-as-user string username to impersonate for the operation
--kube-ca-file string the certificate authority file for the Kubernetes API server connection
--kube-context string name of the kubeconfig context to use
--kube-insecure-skip-tls-verify if true, the Kubernetes API server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kube-tls-server-name string server name to use for Kubernetes API server certificate validation. If it is not provided, the hostname used to contact the server is used
--kube-token string bearer token used for authentication
--kubeconfig string path to the kubeconfig file
-n, --namespace string namespace scope for this request (default "test-namespace")
--qps float32 queries per second used when communicating with the Kubernetes API, not including bursting
--registry-config string path to the registry config file (default "test-registry-config.json")
--repository-cache string path to the directory containing cached repository indexes (default "test-repository-cache-dir")
--repository-config string path to the file containing repository names and URLs (default "test-repository-config.yaml")

@ -0,0 +1,152 @@
NAME: luffy
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: pending-install
REVISION: 1
HOOKS:
---
# Source: foo/templates/tests/test-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: "luffy-testconfig"
annotations:
"helm.sh/hook": test
data:
message: Hello World
---
# Source: foo/templates/tests/test-nothing.yaml
apiVersion: v1
kind: Pod
metadata:
name: "luffy-test"
annotations:
"helm.sh/hook": test
spec:
containers:
- name: test
image: "alpine:latest"
envFrom:
- configMapRef:
name: "luffy-testconfig"
command:
- echo
- "$message"
restartPolicy: Never
MANIFEST:
---
# Source: foo/templates/rbac/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: foo-sa
---
# Source: foo/templates/rbac/role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: foo-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]
---
# Source: foo/templates/rbac/rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: foo-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: foo-role
subjects:
- kind: ServiceAccount
name: foo-sa
namespace: default
---
# Source: foo/charts/bar/charts/qux/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: qux
labels:
helm.sh/chart: "qux-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: usopp
selector:
app.kubernetes.io/name: qux
---
# Source: foo/charts/bar/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: bar
labels:
helm.sh/chart: "bar-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: zoro
selector:
app.kubernetes.io/name: bar
---
# Source: foo/charts/baz/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: baz
labels:
helm.sh/chart: "baz-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nami
selector:
app.kubernetes.io/name: baz
---
# Source: foo/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: foo
labels:
helm.sh/chart: "foo-0.1.0"
app.kubernetes.io/instance: "luffy"
kube-version/major: "1"
kube-version/minor: "20"
kube-version/version: "v1.20.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: luffy
selector:
app.kubernetes.io/name: foo
NOTES:
---
# Source: foo/templates/NOTES.txt
Sample notes for foo
---
# Source: foo/charts/bar/templates/NOTES.txt
Sample notes for bar
---
# Source: foo/charts/baz/templates/NOTES.txt
Sample notes for baz
---
# Source: foo/charts/bar/charts/qux/templates/NOTES.txt
Sample notes for qux

@ -0,0 +1,143 @@
NAME: luffy
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: pending-install
REVISION: 1
HOOKS:
---
# Source: foo/templates/tests/test-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: "luffy-testconfig"
annotations:
"helm.sh/hook": test
data:
message: Hello World
---
# Source: foo/templates/tests/test-nothing.yaml
apiVersion: v1
kind: Pod
metadata:
name: "luffy-test"
annotations:
"helm.sh/hook": test
spec:
containers:
- name: test
image: "alpine:latest"
envFrom:
- configMapRef:
name: "luffy-testconfig"
command:
- echo
- "$message"
restartPolicy: Never
MANIFEST:
---
# Source: foo/templates/rbac/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: foo-sa
---
# Source: foo/templates/rbac/role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: foo-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]
---
# Source: foo/templates/rbac/rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: foo-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: foo-role
subjects:
- kind: ServiceAccount
name: foo-sa
namespace: default
---
# Source: foo/charts/bar/charts/qux/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: qux
labels:
helm.sh/chart: "qux-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: usopp
selector:
app.kubernetes.io/name: qux
---
# Source: foo/charts/bar/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: bar
labels:
helm.sh/chart: "bar-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: zoro
selector:
app.kubernetes.io/name: bar
---
# Source: foo/charts/baz/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: baz
labels:
helm.sh/chart: "baz-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nami
selector:
app.kubernetes.io/name: baz
---
# Source: foo/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: foo
labels:
helm.sh/chart: "foo-0.1.0"
app.kubernetes.io/instance: "luffy"
kube-version/major: "1"
kube-version/minor: "20"
kube-version/version: "v1.20.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: luffy
selector:
app.kubernetes.io/name: foo
NOTES:
---
# Source: foo/templates/NOTES.txt
Sample notes for foo

@ -0,0 +1,13 @@
NAME: luffy
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
Sample notes for foo
Sample notes for bar
Sample notes for baz
Sample notes for qux

@ -0,0 +1,7 @@
NAME: luffy
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
Sample notes for foo

@ -0,0 +1,92 @@
NAME: luffy
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: pending-install
REVISION: 1
HOOKS:
---
# Source: foo/templates/tests/test-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: "luffy-testconfig"
annotations:
"helm.sh/hook": test
data:
message: Hello World
---
# Source: foo/templates/tests/test-nothing.yaml
apiVersion: v1
kind: Pod
metadata:
name: "luffy-test"
annotations:
"helm.sh/hook": test
spec:
containers:
- name: test
image: "alpine:latest"
envFrom:
- configMapRef:
name: "luffy-testconfig"
command:
- echo
- "$message"
restartPolicy: Never
MANIFEST:
---
# Source: foo/templates/rbac/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: foo-sa
---
# Source: foo/templates/rbac/role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: foo-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]
---
# Source: foo/templates/rbac/rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: foo-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: foo-role
subjects:
- kind: ServiceAccount
name: foo-sa
namespace: default
---
# Source: foo/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: foo
labels:
helm.sh/chart: "foo-0.1.0"
app.kubernetes.io/instance: "luffy"
kube-version/major: "1"
kube-version/minor: "20"
kube-version/version: "v1.20.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: sanji
selector:
app.kubernetes.io/name: foo
NOTES:
---
# Source: foo/templates/NOTES.txt
Sample notes for foo

@ -0,0 +1,7 @@
NAME: luffy
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
Sample notes for foo

@ -0,0 +1,12 @@
NAME: luffy
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: empty/templates/empty.yaml
# This file is intentionally blank

@ -0,0 +1,6 @@
NAME: luffy
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

@ -0,0 +1,82 @@
Render chart templates locally and display the output.
Any values that would normally be looked up or retrieved in-cluster will be
faked locally. Additionally, none of the server-side testing of chart validity
(e.g. whether an API is supported) is done.
Usage:
helm template [NAME] [CHART] [flags]
Flags:
-a, --api-versions strings Kubernetes api versions used for Capabilities.APIVersions
--atomic if set, the installation process deletes the installation on failure. The --wait flag will be set automatically if --atomic is used
--ca-file string verify certificates of HTTPS-enabled servers using this CA bundle
--cert-file string identify HTTPS client using this SSL certificate file
--create-namespace create the release namespace if not present
--dependency-update update dependencies if they are missing before installing the chart
--description string add a custom description
--devel use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored
--disable-openapi-validation if set, the installation process will not validate rendered templates against the Kubernetes OpenAPI Schema
--dry-run string[="client"] simulate an install. If --dry-run is set with no option being specified or as '--dry-run=client', it will not attempt cluster connections. Setting '--dry-run=server' allows attempting cluster connections.
--enable-dns enable DNS lookups when rendering templates
--force force resource updates through a replacement strategy
-g, --generate-name generate the name (and omit the NAME parameter)
-h, --help help for template
--hide-notes if set, do not show notes in install output. Does not affect presence in chart metadata
--include-crds include CRDs in the templated output
--insecure-skip-tls-verify skip tls certificate checks for the chart download
--is-upgrade set .Release.IsUpgrade instead of .Release.IsInstall
--key-file string identify HTTPS client using this SSL key file
--keyring string location of public keys used for verification (default "test-gpg/pubring.gpg")
--kube-version string Kubernetes version used for Capabilities.KubeVersion
-l, --labels stringToString Labels that would be added to release metadata. Should be divided by comma. (default [])
--name-template string specify template used to name the release
--no-hooks prevent hooks from running during install
--notes if set, render the current chart's notes file
--output-dir string writes the executed templates to files in output-dir instead of stdout
--pass-credentials pass credentials to all domains
--password string chart repository password where to locate the requested chart
--plain-http use insecure HTTP connections for the chart download
--post-renderer postRendererString the path to an executable to be used for post rendering. If it exists in $PATH, the binary will be used, otherwise it will try to look for the executable at the given path
--post-renderer-args postRendererArgsSlice an argument to the post-renderer (can specify multiple) (default [])
--release-name use release name in the output-dir path.
--render-subchart-notes if set, render subchart notes along with the parent. Note: This will only work if --notes flag is enabled.
--replace re-use the given name, only if that name is a deleted release which remains in the history. This is unsafe in production
--repo string chart repository url where to locate the requested chart
--set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--set-file stringArray set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)
--set-json stringArray set JSON values on the command line (can specify multiple or separate values with commas: key1=jsonval1,key2=jsonval2)
--set-literal stringArray set a literal STRING value on the command line
--set-string stringArray set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
-s, --show-only stringArray only show manifests rendered from the given templates
--skip-crds if set, no CRDs will be installed. By default, CRDs are installed if not already present
--skip-schema-validation if set, disables JSON schema validation
--skip-tests skip tests from templated output
--take-ownership if set, install will ignore the check for helm annotations and take ownership of the existing resources
--timeout duration time to wait for any individual Kubernetes operation (like Jobs for hooks) (default 5m0s)
--username string chart repository username where to locate the requested chart
--validate validate your manifests against the Kubernetes cluster you are currently pointing at. This is the same validation performed on an install
-f, --values strings specify values in a YAML file or a URL (can specify multiple)
--verify verify the package before using it
--version string specify a version constraint for the chart version to use. This constraint can be a specific tag (e.g. 1.1.1) or it may reference a valid range (e.g. ^2.0.0). If this is not specified, the latest version is used
--wait if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment, StatefulSet, or ReplicaSet are in a ready state before marking the release as successful. It will wait for as long as --timeout
--wait-for-jobs if set and --wait enabled, will wait until all Jobs have been completed before marking the release as successful. It will wait for as long as --timeout
Global Flags:
--burst-limit int client-side default throttling limit (default 100)
--debug enable verbose output
--kube-apiserver string the address and the port for the Kubernetes API server
--kube-as-group stringArray group to impersonate for the operation, this flag can be repeated to specify multiple groups.
--kube-as-user string username to impersonate for the operation
--kube-ca-file string the certificate authority file for the Kubernetes API server connection
--kube-context string name of the kubeconfig context to use
--kube-insecure-skip-tls-verify if true, the Kubernetes API server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kube-tls-server-name string server name to use for Kubernetes API server certificate validation. If it is not provided, the hostname used to contact the server is used
--kube-token string bearer token used for authentication
--kubeconfig string path to the kubeconfig file
-n, --namespace string namespace scope for this request (default "test-namespace")
--qps float32 queries per second used when communicating with the Kubernetes API, not including bursting
--registry-config string path to the registry config file (default "test-registry-config.json")
--repository-cache string path to the directory containing cached repository indexes (default "test-repository-cache-dir")
--repository-config string path to the file containing repository names and URLs (default "test-repository-config.yaml")

@ -0,0 +1,143 @@
---
# Source: foo/templates/rbac/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: foo-sa
---
# Source: foo/templates/rbac/role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: foo-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]
---
# Source: foo/templates/rbac/rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: foo-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: foo-role
subjects:
- kind: ServiceAccount
name: foo-sa
namespace: default
---
# Source: foo/charts/bar/charts/qux/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: qux
labels:
helm.sh/chart: "qux-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: usopp
selector:
app.kubernetes.io/name: qux
---
# Source: foo/charts/bar/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: bar
labels:
helm.sh/chart: "bar-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: zoro
selector:
app.kubernetes.io/name: bar
---
# Source: foo/charts/baz/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: baz
labels:
helm.sh/chart: "baz-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nami
selector:
app.kubernetes.io/name: baz
---
# Source: foo/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: foo
labels:
helm.sh/chart: "foo-0.1.0"
app.kubernetes.io/instance: "luffy"
kube-version/major: "1"
kube-version/minor: "20"
kube-version/version: "v1.20.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: luffy
selector:
app.kubernetes.io/name: foo
---
# Source: foo/templates/tests/test-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: "luffy-testconfig"
annotations:
"helm.sh/hook": test
data:
message: Hello World
---
# Source: foo/templates/tests/test-nothing.yaml
apiVersion: v1
kind: Pod
metadata:
name: "luffy-test"
annotations:
"helm.sh/hook": test
spec:
containers:
- name: test
image: "alpine:latest"
envFrom:
- configMapRef:
name: "luffy-testconfig"
command:
- echo
- "$message"
restartPolicy: Never
---
# Source: foo/templates/NOTES.txt
Sample notes for foo
---
# Source: foo/charts/bar/templates/NOTES.txt
Sample notes for bar
---
# Source: foo/charts/baz/templates/NOTES.txt
Sample notes for baz
---
# Source: foo/charts/bar/charts/qux/templates/NOTES.txt
Sample notes for qux

@ -0,0 +1,134 @@
---
# Source: foo/templates/rbac/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: foo-sa
---
# Source: foo/templates/rbac/role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: foo-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]
---
# Source: foo/templates/rbac/rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: foo-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: foo-role
subjects:
- kind: ServiceAccount
name: foo-sa
namespace: default
---
# Source: foo/charts/bar/charts/qux/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: qux
labels:
helm.sh/chart: "qux-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: usopp
selector:
app.kubernetes.io/name: qux
---
# Source: foo/charts/bar/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: bar
labels:
helm.sh/chart: "bar-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: zoro
selector:
app.kubernetes.io/name: bar
---
# Source: foo/charts/baz/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: baz
labels:
helm.sh/chart: "baz-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nami
selector:
app.kubernetes.io/name: baz
---
# Source: foo/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: foo
labels:
helm.sh/chart: "foo-0.1.0"
app.kubernetes.io/instance: "luffy"
kube-version/major: "1"
kube-version/minor: "20"
kube-version/version: "v1.20.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: luffy
selector:
app.kubernetes.io/name: foo
---
# Source: foo/templates/tests/test-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: "luffy-testconfig"
annotations:
"helm.sh/hook": test
data:
message: Hello World
---
# Source: foo/templates/tests/test-nothing.yaml
apiVersion: v1
kind: Pod
metadata:
name: "luffy-test"
annotations:
"helm.sh/hook": test
spec:
containers:
- name: test
image: "alpine:latest"
envFrom:
- configMapRef:
name: "luffy-testconfig"
command:
- echo
- "$message"
restartPolicy: Never
---
# Source: foo/templates/NOTES.txt
Sample notes for foo

@ -0,0 +1,131 @@
---
# Source: foo/templates/rbac/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: foo-sa
---
# Source: foo/templates/rbac/role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: foo-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]
---
# Source: foo/templates/rbac/rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: foo-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: foo-role
subjects:
- kind: ServiceAccount
name: foo-sa
namespace: default
---
# Source: foo/charts/bar/charts/qux/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: qux
labels:
helm.sh/chart: "qux-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: usopp
selector:
app.kubernetes.io/name: qux
---
# Source: foo/charts/bar/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: bar
labels:
helm.sh/chart: "bar-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: zoro
selector:
app.kubernetes.io/name: bar
---
# Source: foo/charts/baz/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: baz
labels:
helm.sh/chart: "baz-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nami
selector:
app.kubernetes.io/name: baz
---
# Source: foo/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: foo
labels:
helm.sh/chart: "foo-0.1.0"
app.kubernetes.io/instance: "luffy"
kube-version/major: "1"
kube-version/minor: "20"
kube-version/version: "v1.20.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: luffy
selector:
app.kubernetes.io/name: foo
---
# Source: foo/templates/tests/test-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: "luffy-testconfig"
annotations:
"helm.sh/hook": test
data:
message: Hello World
---
# Source: foo/templates/tests/test-nothing.yaml
apiVersion: v1
kind: Pod
metadata:
name: "luffy-test"
annotations:
"helm.sh/hook": test
spec:
containers:
- name: test
image: "alpine:latest"
envFrom:
- configMapRef:
name: "luffy-testconfig"
command:
- echo
- "$message"
restartPolicy: Never

@ -0,0 +1,83 @@
---
# Source: foo/templates/rbac/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: foo-sa
---
# Source: foo/templates/rbac/role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: foo-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]
---
# Source: foo/templates/rbac/rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: foo-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: foo-role
subjects:
- kind: ServiceAccount
name: foo-sa
namespace: default
---
# Source: foo/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: foo
labels:
helm.sh/chart: "foo-0.1.0"
app.kubernetes.io/instance: "luffy"
kube-version/major: "1"
kube-version/minor: "20"
kube-version/version: "v1.20.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: sanji
selector:
app.kubernetes.io/name: foo
---
# Source: foo/templates/tests/test-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: "luffy-testconfig"
annotations:
"helm.sh/hook": test
data:
message: Hello World
---
# Source: foo/templates/tests/test-nothing.yaml
apiVersion: v1
kind: Pod
metadata:
name: "luffy-test"
annotations:
"helm.sh/hook": test
spec:
containers:
- name: test
image: "alpine:latest"
envFrom:
- configMapRef:
name: "luffy-testconfig"
command:
- echo
- "$message"
restartPolicy: Never
---
# Source: foo/templates/NOTES.txt
Sample notes for foo

@ -0,0 +1,80 @@
---
# Source: foo/templates/rbac/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: foo-sa
---
# Source: foo/templates/rbac/role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: foo-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]
---
# Source: foo/templates/rbac/rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: foo-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: foo-role
subjects:
- kind: ServiceAccount
name: foo-sa
namespace: default
---
# Source: foo/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: foo
labels:
helm.sh/chart: "foo-0.1.0"
app.kubernetes.io/instance: "luffy"
kube-version/major: "1"
kube-version/minor: "20"
kube-version/version: "v1.20.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: sanji
selector:
app.kubernetes.io/name: foo
---
# Source: foo/templates/tests/test-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: "luffy-testconfig"
annotations:
"helm.sh/hook": test
data:
message: Hello World
---
# Source: foo/templates/tests/test-nothing.yaml
apiVersion: v1
kind: Pod
metadata:
name: "luffy-test"
annotations:
"helm.sh/hook": test
spec:
containers:
- name: test
image: "alpine:latest"
envFrom:
- configMapRef:
name: "luffy-testconfig"
command:
- echo
- "$message"
restartPolicy: Never

@ -0,0 +1,3 @@
---
# Source: empty/templates/empty.yaml
# This file is intentionally blank

@ -0,0 +1,108 @@
This command upgrades a release to a new version of a chart.
The upgrade arguments must be a release and chart. The chart
argument can be either: a chart reference('example/mariadb'), a path to a chart directory,
a packaged chart, or a fully qualified URL. For chart references, the latest
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'. 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 also use '--set-json' to set json values
(scalars/objects/arrays) from the command line.
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
contained a key called 'Test', the value set in override.yaml would take precedence:
$ helm upgrade -f myvalues.yaml -f override.yaml redis ./redis
You can specify the '--set' flag multiple times. The priority will be given to the
last (right-most) set specified. For example, if both 'bar' and 'newbar' values are
set for a key called 'foo', the 'newbar' value would take precedence:
$ helm upgrade --set foo=bar --set foo=newbar redis ./redis
You can update the values for an existing release with this command as well via the
'--reuse-values' flag. The 'RELEASE' and 'CHART' arguments should be set to the original
parameters, and existing values will be merged with any values set via '--values'/'-f'
or '--set' flags. Priority is given to new values.
$ helm upgrade --reuse-values --set foo=bar --set foo=newbar redis ./redis
The --dry-run flag will output all generated chart manifests, including Secrets
which can contain sensitive values. To hide Kubernetes Secrets use the
--hide-secret flag. Please carefully consider how and when these flags are used.
Usage:
helm upgrade [RELEASE] [CHART] [flags]
Flags:
--atomic if set, upgrade process rolls back changes made in case of failed upgrade. The --wait flag will be set automatically if --atomic is used
--ca-file string verify certificates of HTTPS-enabled servers using this CA bundle
--cert-file string identify HTTPS client using this SSL certificate file
--cleanup-on-fail allow deletion of new resources created in this upgrade when upgrade fails
--create-namespace if --install is set, create the release namespace if not present
--dependency-update update dependencies if they are missing before installing the chart
--description string add a custom description
--devel use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored
--disable-openapi-validation if set, the upgrade process will not validate rendered templates against the Kubernetes OpenAPI Schema
--dry-run string[="client"] simulate an install. If --dry-run is set with no option being specified or as '--dry-run=client', it will not attempt cluster connections. Setting '--dry-run=server' allows attempting cluster connections.
--enable-dns enable DNS lookups when rendering templates
--force force resource updates through a replacement strategy
-h, --help help for upgrade
--hide-notes if set, do not show notes in upgrade output. Does not affect presence in chart metadata
--hide-secret hide Kubernetes Secrets when also using the --dry-run flag
--history-max int limit the maximum number of revisions saved per release. Use 0 for no limit (default 10)
--insecure-skip-tls-verify skip tls certificate checks for the chart download
-i, --install if a release by this name doesn't already exist, run an install
--key-file string identify HTTPS client using this SSL key file
--keyring string location of public keys used for verification (default "test-gpg/pubring.gpg")
-l, --labels stringToString Labels that would be added to release metadata. Should be separated by comma. Original release labels will be merged with upgrade labels. You can unset label using null. (default [])
--no-hooks disable pre/post upgrade hooks
-o, --output format prints the output in the specified format. Allowed values: table, json, yaml (default table)
--pass-credentials pass credentials to all domains
--password string chart repository password where to locate the requested chart
--plain-http use insecure HTTP connections for the chart download
--post-renderer postRendererString the path to an executable to be used for post rendering. If it exists in $PATH, the binary will be used, otherwise it will try to look for the executable at the given path
--post-renderer-args postRendererArgsSlice an argument to the post-renderer (can specify multiple) (default [])
--render-subchart-notes if set, render subchart notes along with the parent
--repo string chart repository url where to locate the requested chart
--reset-then-reuse-values when upgrading, reset the values to the ones built into the chart, apply the last release's values and merge in any overrides from the command line via --set and -f. If '--reset-values' or '--reuse-values' is specified, this is ignored
--reset-values when upgrading, reset the values to the ones built into the chart
--reuse-values when upgrading, reuse the last release's values and merge in any overrides from the command line via --set and -f. If '--reset-values' is specified, this is ignored
--set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--set-file stringArray set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)
--set-json stringArray set JSON values on the command line (can specify multiple or separate values with commas: key1=jsonval1,key2=jsonval2)
--set-literal stringArray set a literal STRING value on the command line
--set-string stringArray set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--skip-crds if set, no CRDs will be installed when an upgrade is performed with install flag enabled. By default, CRDs are installed if not already present, when an upgrade is performed with install flag enabled
--skip-schema-validation if set, disables JSON schema validation
--take-ownership if set, upgrade will ignore the check for helm annotations and take ownership of the existing resources
--timeout duration time to wait for any individual Kubernetes operation (like Jobs for hooks) (default 5m0s)
--username string chart repository username where to locate the requested chart
-f, --values strings specify values in a YAML file or a URL (can specify multiple)
--verify verify the package before using it
--version string specify a version constraint for the chart version to use. This constraint can be a specific tag (e.g. 1.1.1) or it may reference a valid range (e.g. ^2.0.0). If this is not specified, the latest version is used
--wait if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment, StatefulSet, or ReplicaSet are in a ready state before marking the release as successful. It will wait for as long as --timeout
--wait-for-jobs if set and --wait enabled, will wait until all Jobs have been completed before marking the release as successful. It will wait for as long as --timeout
Global Flags:
--burst-limit int client-side default throttling limit (default 100)
--debug enable verbose output
--kube-apiserver string the address and the port for the Kubernetes API server
--kube-as-group stringArray group to impersonate for the operation, this flag can be repeated to specify multiple groups.
--kube-as-user string username to impersonate for the operation
--kube-ca-file string the certificate authority file for the Kubernetes API server connection
--kube-context string name of the kubeconfig context to use
--kube-insecure-skip-tls-verify if true, the Kubernetes API server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kube-tls-server-name string server name to use for Kubernetes API server certificate validation. If it is not provided, the hostname used to contact the server is used
--kube-token string bearer token used for authentication
--kubeconfig string path to the kubeconfig file
-n, --namespace string namespace scope for this request (default "test-namespace")
--qps float32 queries per second used when communicating with the Kubernetes API, not including bursting
--registry-config string path to the registry config file (default "test-registry-config.json")
--repository-cache string path to the directory containing cached repository indexes (default "test-repository-cache-dir")
--repository-config string path to the file containing repository names and URLs (default "test-repository-config.yaml")

@ -0,0 +1,153 @@
Release "luffy" has been upgraded. Happy Helming!
NAME: luffy
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: pending-upgrade
REVISION: 2
HOOKS:
---
# Source: foo/templates/tests/test-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: "luffy-testconfig"
annotations:
"helm.sh/hook": test
data:
message: Hello World
---
# Source: foo/templates/tests/test-nothing.yaml
apiVersion: v1
kind: Pod
metadata:
name: "luffy-test"
annotations:
"helm.sh/hook": test
spec:
containers:
- name: test
image: "alpine:latest"
envFrom:
- configMapRef:
name: "luffy-testconfig"
command:
- echo
- "$message"
restartPolicy: Never
MANIFEST:
---
# Source: foo/templates/rbac/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: foo-sa
---
# Source: foo/templates/rbac/role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: foo-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]
---
# Source: foo/templates/rbac/rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: foo-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: foo-role
subjects:
- kind: ServiceAccount
name: foo-sa
namespace: default
---
# Source: foo/charts/bar/charts/qux/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: qux
labels:
helm.sh/chart: "qux-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: usopp
selector:
app.kubernetes.io/name: qux
---
# Source: foo/charts/bar/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: bar
labels:
helm.sh/chart: "bar-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: zoro
selector:
app.kubernetes.io/name: bar
---
# Source: foo/charts/baz/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: baz
labels:
helm.sh/chart: "baz-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nami
selector:
app.kubernetes.io/name: baz
---
# Source: foo/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: foo
labels:
helm.sh/chart: "foo-0.1.0"
app.kubernetes.io/instance: "luffy"
kube-version/major: "1"
kube-version/minor: "20"
kube-version/version: "v1.20.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: luffy
selector:
app.kubernetes.io/name: foo
NOTES:
---
# Source: foo/templates/NOTES.txt
Sample notes for foo
---
# Source: foo/charts/bar/templates/NOTES.txt
Sample notes for bar
---
# Source: foo/charts/baz/templates/NOTES.txt
Sample notes for baz
---
# Source: foo/charts/bar/charts/qux/templates/NOTES.txt
Sample notes for qux

@ -0,0 +1,144 @@
Release "luffy" has been upgraded. Happy Helming!
NAME: luffy
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: pending-upgrade
REVISION: 2
HOOKS:
---
# Source: foo/templates/tests/test-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: "luffy-testconfig"
annotations:
"helm.sh/hook": test
data:
message: Hello World
---
# Source: foo/templates/tests/test-nothing.yaml
apiVersion: v1
kind: Pod
metadata:
name: "luffy-test"
annotations:
"helm.sh/hook": test
spec:
containers:
- name: test
image: "alpine:latest"
envFrom:
- configMapRef:
name: "luffy-testconfig"
command:
- echo
- "$message"
restartPolicy: Never
MANIFEST:
---
# Source: foo/templates/rbac/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: foo-sa
---
# Source: foo/templates/rbac/role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: foo-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]
---
# Source: foo/templates/rbac/rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: foo-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: foo-role
subjects:
- kind: ServiceAccount
name: foo-sa
namespace: default
---
# Source: foo/charts/bar/charts/qux/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: qux
labels:
helm.sh/chart: "qux-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: usopp
selector:
app.kubernetes.io/name: qux
---
# Source: foo/charts/bar/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: bar
labels:
helm.sh/chart: "bar-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: zoro
selector:
app.kubernetes.io/name: bar
---
# Source: foo/charts/baz/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: baz
labels:
helm.sh/chart: "baz-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nami
selector:
app.kubernetes.io/name: baz
---
# Source: foo/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: foo
labels:
helm.sh/chart: "foo-0.1.0"
app.kubernetes.io/instance: "luffy"
kube-version/major: "1"
kube-version/minor: "20"
kube-version/version: "v1.20.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: luffy
selector:
app.kubernetes.io/name: foo
NOTES:
---
# Source: foo/templates/NOTES.txt
Sample notes for foo

@ -0,0 +1,14 @@
Release "luffy" has been upgraded. Happy Helming!
NAME: luffy
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 2
NOTES:
Sample notes for foo
Sample notes for bar
Sample notes for baz
Sample notes for qux

@ -0,0 +1,8 @@
Release "luffy" has been upgraded. Happy Helming!
NAME: luffy
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 2
NOTES:
Sample notes for foo

@ -0,0 +1,93 @@
Release "luffy" has been upgraded. Happy Helming!
NAME: luffy
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: pending-upgrade
REVISION: 2
HOOKS:
---
# Source: foo/templates/tests/test-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: "luffy-testconfig"
annotations:
"helm.sh/hook": test
data:
message: Hello World
---
# Source: foo/templates/tests/test-nothing.yaml
apiVersion: v1
kind: Pod
metadata:
name: "luffy-test"
annotations:
"helm.sh/hook": test
spec:
containers:
- name: test
image: "alpine:latest"
envFrom:
- configMapRef:
name: "luffy-testconfig"
command:
- echo
- "$message"
restartPolicy: Never
MANIFEST:
---
# Source: foo/templates/rbac/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: foo-sa
---
# Source: foo/templates/rbac/role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: foo-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]
---
# Source: foo/templates/rbac/rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: foo-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: foo-role
subjects:
- kind: ServiceAccount
name: foo-sa
namespace: default
---
# Source: foo/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: foo
labels:
helm.sh/chart: "foo-0.1.0"
app.kubernetes.io/instance: "luffy"
kube-version/major: "1"
kube-version/minor: "20"
kube-version/version: "v1.20.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: sanji
selector:
app.kubernetes.io/name: foo
NOTES:
---
# Source: foo/templates/NOTES.txt
Sample notes for foo

@ -0,0 +1,8 @@
Release "luffy" has been upgraded. Happy Helming!
NAME: luffy
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 2
NOTES:
Sample notes for foo

@ -0,0 +1,13 @@
Release "luffy" has been upgraded. Happy Helming!
NAME: luffy
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: pending-upgrade
REVISION: 2
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: empty/templates/empty.yaml
# This file is intentionally blank

@ -0,0 +1,7 @@
Release "luffy" has been upgraded. Happy Helming!
NAME: luffy
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None

@ -0,0 +1,20 @@
apiVersion: v1
description: A Helm chart 'foo' for Kubernetes
name: foo
version: 0.1.0
dependencies:
- name: bar
repository: http://localhost:8080
version: 0.1.0
condition: bar.enabled
tags:
- strawhats
- bar
- name: baz
repository: http://localhost:8080
version: 0.1.0
condition: baz.enabled
tags:
- strawhats
- baz

@ -0,0 +1,4 @@
apiVersion: v1
description: A Helm chart 'bar' for Kubernetes
name: bar
version: 0.1.0

@ -0,0 +1,4 @@
apiVersion: v1
description: A Helm chart 'qux' for Kubernetes
name: qux
version: 0.1.0

@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ .Chart.Name }}
labels:
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.externalPort }}
targetPort: {{ .Values.service.internalPort }}
protocol: TCP
name: {{ .Values.service.name }}
selector:
app.kubernetes.io/name: {{ .Chart.Name }}

@ -0,0 +1,5 @@
service:
name: usopp
type: ClusterIP
externalPort: 80
internalPort: 80

@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ .Chart.Name }}
labels:
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.externalPort }}
targetPort: {{ .Values.service.internalPort }}
protocol: TCP
name: {{ .Values.service.name }}
selector:
app.kubernetes.io/name: {{ .Chart.Name }}

@ -0,0 +1,5 @@
service:
name: zoro
type: ClusterIP
externalPort: 80
internalPort: 80

@ -0,0 +1,4 @@
apiVersion: v1
description: A Helm chart 'baz' for Kubernetes
name: baz
version: 0.1.0

@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ .Chart.Name }}
labels:
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.externalPort }}
targetPort: {{ .Values.service.internalPort }}
protocol: TCP
name: {{ .Values.service.name }}
selector:
app.kubernetes.io/name: {{ .Chart.Name }}

@ -0,0 +1,5 @@
service:
name: nami
type: ClusterIP
externalPort: 80
internalPort: 80

@ -0,0 +1,8 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ .Chart.Name }}-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]

@ -0,0 +1,12 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ .Chart.Name }}-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ .Chart.Name }}-role
subjects:
- kind: ServiceAccount
name: {{ .Chart.Name }}-sa
namespace: default

@ -0,0 +1,4 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ .Chart.Name }}-sa

@ -0,0 +1,22 @@
apiVersion: v1
kind: Service
metadata:
name: {{ .Chart.Name }}
labels:
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
app.kubernetes.io/instance: "{{ .Release.Name }}"
kube-version/major: "{{ .Capabilities.KubeVersion.Major }}"
kube-version/minor: "{{ .Capabilities.KubeVersion.Minor }}"
kube-version/version: "v{{ .Capabilities.KubeVersion.Major }}.{{ .Capabilities.KubeVersion.Minor }}.0"
{{- if .Capabilities.APIVersions.Has "helm.k8s.io/test" }}
kube-api-version/test: v1
{{- end }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.externalPort }}
targetPort: {{ .Values.service.internalPort }}
protocol: TCP
name: {{ .Values.service.name }}
selector:
app.kubernetes.io/name: {{ .Chart.Name }}

@ -0,0 +1,8 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: "{{ .Release.Name }}-testconfig"
annotations:
"helm.sh/hook": test
data:
message: Hello World

@ -0,0 +1,17 @@
apiVersion: v1
kind: Pod
metadata:
name: "{{ .Release.Name }}-test"
annotations:
"helm.sh/hook": test
spec:
containers:
- name: test
image: "alpine:latest"
envFrom:
- configMapRef:
name: "{{ .Release.Name }}-testconfig"
command:
- echo
- "$message"
restartPolicy: Never

@ -0,0 +1,5 @@
service:
name: luffy
type: ClusterIP
externalPort: 80
internalPort: 80

@ -0,0 +1,4 @@
apiVersion: v1
description: A Helm chart 'foo' for Kubernetes
name: foo
version: 0.1.0

@ -0,0 +1 @@
Sample notes for {{ .Chart.Name }}

@ -0,0 +1,8 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ .Chart.Name }}-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]

@ -0,0 +1,12 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ .Chart.Name }}-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ .Chart.Name }}-role
subjects:
- kind: ServiceAccount
name: {{ .Chart.Name }}-sa
namespace: default

@ -0,0 +1,4 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ .Chart.Name }}-sa

@ -0,0 +1,22 @@
apiVersion: v1
kind: Service
metadata:
name: {{ .Chart.Name }}
labels:
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
app.kubernetes.io/instance: "{{ .Release.Name }}"
kube-version/major: "{{ .Capabilities.KubeVersion.Major }}"
kube-version/minor: "{{ .Capabilities.KubeVersion.Minor }}"
kube-version/version: "v{{ .Capabilities.KubeVersion.Major }}.{{ .Capabilities.KubeVersion.Minor }}.0"
{{- if .Capabilities.APIVersions.Has "helm.k8s.io/test" }}
kube-api-version/test: v1
{{- end }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.externalPort }}
targetPort: {{ .Values.service.internalPort }}
protocol: TCP
name: {{ .Values.service.name }}
selector:
app.kubernetes.io/name: {{ .Chart.Name }}

@ -0,0 +1,8 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: "{{ .Release.Name }}-testconfig"
annotations:
"helm.sh/hook": test
data:
message: Hello World

@ -0,0 +1,17 @@
apiVersion: v1
kind: Pod
metadata:
name: "{{ .Release.Name }}-test"
annotations:
"helm.sh/hook": test
spec:
containers:
- name: test
image: "alpine:latest"
envFrom:
- configMapRef:
name: "{{ .Release.Name }}-testconfig"
command:
- echo
- "$message"
restartPolicy: Never

@ -0,0 +1,5 @@
service:
name: sanji
type: ClusterIP
externalPort: 80
internalPort: 80

@ -28,6 +28,8 @@ import (
"helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/chartutil"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v3/pkg/release"
"github.com/stretchr/testify/assert"
) )
func TestUpgradeCmd(t *testing.T) { func TestUpgradeCmd(t *testing.T) {
@ -187,10 +189,150 @@ func TestUpgradeCmd(t *testing.T) {
golden: "output/upgrade-uninstalled-with-keep-history.txt", golden: "output/upgrade-uninstalled-with-keep-history.txt",
rels: []*release.Release{relWithStatusMock("funny-bunny", 2, ch, release.StatusUninstalled)}, rels: []*release.Release{relWithStatusMock("funny-bunny", 2, ch, release.StatusUninstalled)},
}, },
{
// Running `helm upgrade` on a chart that doesn't have notes or subcharts should print the upgrade command's
// output without notes.
name: "helm upgrade on chart without notes or subcharts",
cmd: fmt.Sprintf("upgrade luffy '%s' --namespace default", emptyChart),
golden: "output/upgrade-without-notes-or-subcharts.txt",
rels: []*release.Release{relMock("luffy", 1, ch)},
},
{
// Running `helm upgrade --dry-run` on a chart that doesn't have notes or subcharts should print upgrade
// command's dry-run output without notes.
name: "helm upgrade --dry-run on chart without notes or subcharts",
cmd: fmt.Sprintf("upgrade luffy '%s' --namespace default --dry-run", emptyChart),
golden: "output/upgrade-without-notes-or-subcharts-with-flag-dry-run-enabled.txt",
rels: []*release.Release{relMock("luffy", 1, ch)},
},
{
// Running `helm upgrade --render-subchart-notes` on a chart that doesn't have notes or subcharts should
// print the upgrade command's output without any notes.
name: "helm upgrade --render-subchart-notes on chart without notes or subcharts",
cmd: fmt.Sprintf("upgrade luffy '%s' --namespace default --render-subchart-notes", emptyChart),
golden: "output/upgrade-without-notes-or-subcharts.txt",
rels: []*release.Release{relMock("luffy", 1, ch)},
},
{
// Running `helm upgrade --dry-run --render-subchart-notes` on a chart that doesn't have notes or subcharts
// should print the upgrade command's dry-run output without any notes.
name: "helm upgrade --dry-run --render-subchart-notes on chart without notes or subcharts",
cmd: fmt.Sprintf("upgrade luffy '%s' --namespace default --dry-run --render-subchart-notes", emptyChart),
golden: "output/upgrade-without-notes-or-subcharts-with-flag-dry-run-enabled.txt",
rels: []*release.Release{relMock("luffy", 1, ch)},
},
{
// Running `helm upgrade` on a chart that has notes but no subcharts should print the upgrade command's
// output with (current chart's) notes.
name: "helm upgrade on chart with notes without subcharts",
cmd: fmt.Sprintf("upgrade luffy '%s' --namespace default", chartWithNotes),
golden: "output/upgrade-with-notes.txt",
rels: []*release.Release{relMock("luffy", 1, ch)},
},
{
// Running `helm upgrade --dry-run` on a chart that has notes but no subcharts should print the upgrade
// command's dry-run output with (current chart's) notes. Note: The notes in dry-run output include the
// source filename and separator "---".
name: "helm upgrade --dry-run on chart with notes without subcharts",
cmd: fmt.Sprintf("upgrade luffy '%s' --namespace default --dry-run", chartWithNotes),
golden: "output/upgrade-with-notes-with-flag-dry-run-enabled.txt",
rels: []*release.Release{relMock("luffy", 1, ch)},
},
{
// Running `helm upgrade --render-subchart-notes` on a chart that has notes but no subcharts should print
// the upgrade command's output with (current chart's) notes, i.e., no subchart's notes as no subchart.
name: "helm upgrade --render-subchart-notes on chart with notes without subcharts",
cmd: fmt.Sprintf("upgrade luffy '%s' --namespace default --render-subchart-notes", chartWithNotes),
golden: "output/upgrade-with-notes.txt",
rels: []*release.Release{relMock("luffy", 1, ch)},
},
{
// Running `helm upgrade --dry-run --render-subchart-notes` on a chart that has notes but no subcharts
// should print the upgrade command's dry-run output (current chart's) notes, i.e., no subchart's notes as
// no subchart. Note: The notes in dry-run output include the source filename and separator "---".
name: "helm upgrade --dry-run --render-subchart-notes on chart with notes without subcharts",
cmd: fmt.Sprintf("upgrade luffy '%s' --namespace default --dry-run --render-subchart-notes",
chartWithNotes),
golden: "output/upgrade-with-notes-with-flag-dry-run-enabled.txt",
rels: []*release.Release{relMock("luffy", 1, ch)},
},
{
// Running `helm upgrade` on a chart that has notes and 2 levels of subcharts should print upgrade command's
// output with just root chart's notes, i.e., without subchart's notes.
name: "helm upgrade on chart with notes and subcharts",
cmd: fmt.Sprintf("upgrade luffy '%s' --namespace default", chartWithNotesAnd2LevelsOfSubCharts),
golden: "output/upgrade-with-notes-and-subcharts.txt",
rels: []*release.Release{relMock("luffy", 1, ch)},
},
{
// Running `helm upgrade --dry-run` on a chart that has notes and 2 levels of subcharts should print the
// upgrade command's dry-run output with just the root chart's notes, i.e., without subcharts' notes. Note:
// The notes in dry-run output include the source filename and separator "---".
name: "helm upgrade --dry-run on chart with notes and subcharts",
cmd: fmt.Sprintf("upgrade luffy '%s' --namespace default --dry-run",
chartWithNotesAnd2LevelsOfSubCharts),
golden: "output/upgrade-with-notes-and-subcharts-with-flag-dry-run-enabled.txt",
rels: []*release.Release{relMock("luffy", 1, ch)},
},
{
// Running `helm upgrade --render-subchart-notes` on a chart that has notes and 2 levels of subcharts should
// print the upgrade command's output with both the root chart and the subcharts' notes.
name: "helm upgrade --render-subchart-notes on chart with notes and subcharts",
cmd: fmt.Sprintf("upgrade luffy '%s' --namespace default --render-subchart-notes",
chartWithNotesAnd2LevelsOfSubCharts),
golden: "output/upgrade-with-notes-and-subcharts-with-flag-render-subchart-notes-enabled.txt",
rels: []*release.Release{relMock("luffy", 1, ch)},
},
{
// Running `helm upgrade --dry-run --render-subchart-notes` on a chart that has notes and 2 levels of
// subcharts should print the upgrade command's dry-run output with both the root chart and the subcharts'
// notes. Note: The notes in dry-run output include the source filename and separator "---".
name: "helm upgrade --dry-run --render-subchart-notes on chart with notes and subcharts",
cmd: fmt.Sprintf("upgrade luffy '%s' --namespace default --dry-run --render-subchart-notes",
chartWithNotesAnd2LevelsOfSubCharts),
golden: "output/" +
"upgrade-with-notes-and-subcharts-with-both-flags-dry-run-and-render-subchart-notes-enabled.txt",
rels: []*release.Release{relMock("luffy", 1, ch)},
},
} }
runTestCmd(t, tests) runTestCmd(t, tests)
} }
// TestUpgradeHelpOutput tests the `helm upgrade --help` command's output text. This is required because the
// --render-subchart-notes flag's description is different for the template command from that of install/upgrade
// commands.
func TestUpgradeHelpOutput(t *testing.T) {
const (
outputFilePath = "testdata/output/upgrade-help.txt"
testNamespace = "test-namespace"
repositoryCache = "test-repository-cache-dir"
repositoryConfig = "test-repository-config.yaml"
registryConfig = "test-registry-config.json"
gnupgHome = "test-gpg"
commandText = "upgrade --help"
)
// Reset the envs and the configs at the end of this test so that the updates wouldnt affect other tests.
defer resetEnv()()
// Read the expected output file.
expectedOutput, err := os.ReadFile(outputFilePath)
assert.NoError(t, err, "unexpected error while reading expected output's file %q", outputFilePath)
// Set the configs that might otherwise change based on the local environment if not explicitly set. Note: These
// configs are not related to the current test.
settings.RepositoryCache = repositoryCache
settings.RepositoryConfig = repositoryConfig
settings.RegistryConfig = registryConfig
settings.SetNamespace(testNamespace)
t.Setenv("GNUPGHOME", gnupgHome)
// Run the `helm upgrade --help` command and compare the help text.
_, actualOutput, err := executeActionCommandC(storageFixture(), commandText)
assert.NoError(t, err, "unexpected error running command %q", commandText)
assert.Equal(t, string(expectedOutput), actualOutput, "mismatch of output")
}
func TestUpgradeWithValue(t *testing.T) { func TestUpgradeWithValue(t *testing.T) {
releaseName := "funny-bunny-v2" releaseName := "funny-bunny-v2"
relMock, ch, chartPath := prepareMockRelease(releaseName, t) relMock, ch, chartPath := prepareMockRelease(releaseName, t)

@ -24,6 +24,7 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"regexp" "regexp"
"sort"
"strings" "strings"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -107,7 +108,9 @@ type Configuration struct {
// TODO: As part of the refactor the duplicate code in cmd/helm/template.go should be removed // TODO: As part of the refactor the duplicate code in cmd/helm/template.go should be removed
// //
// This code has to do with writing files to disk. // This code has to do with writing files to disk.
func (cfg *Configuration) renderResources(ch *chart.Chart, values chartutil.Values, releaseName, outputDir string, subNotes, useReleaseName, includeCrds bool, pr postrender.PostRenderer, interactWithRemote, enableDNS, hideSecret bool) ([]*release.Hook, *bytes.Buffer, string, error) { func (cfg *Configuration) renderResources(ch *chart.Chart, values chartutil.Values, releaseName, outputDir string,
renderSubchartNotes, useReleaseName, includeCrds bool, pr postrender.PostRenderer, interactWithRemote, enableDNS,
hideSecret, isDryRun bool) ([]*release.Hook, *bytes.Buffer, string, error) {
hs := []*release.Hook{} hs := []*release.Hook{}
b := bytes.NewBuffer(nil) b := bytes.NewBuffer(nil)
@ -151,20 +154,71 @@ func (cfg *Configuration) renderResources(ch *chart.Chart, values chartutil.Valu
// text file. We have to spin through this map because the file contains path information, so we // text file. We have to spin through this map because the file contains path information, so we
// look for terminating NOTES.txt. We also remove it from the files so that we don't have to skip // look for terminating NOTES.txt. We also remove it from the files so that we don't have to skip
// it in the sortHooks. // it in the sortHooks.
var notesBuffer bytes.Buffer //
for k, v := range files { // If --render-subchart-notes flag is enabled, the NOTES.txt files from the subcharts are also included by rendering
if strings.HasSuffix(k, notesFileSuffix) { // engine.
if subNotes || (k == path.Join(ch.Name(), "templates", notesFileSuffix)) { notesFilePathToContent := make(map[string]string)
// If buffer contains data, add newline before adding more notesFilePaths := make([]string, 0)
if notesBuffer.Len() > 0 { for filePath, fileContent := range files {
notesBuffer.WriteString("\n") // Filter the notes filepath(s), i.e., filepaths that end with "NOTES.txt", from all files. Note: Depending on
// the --render-subchart-notes flag, there may be more than one notes file.
if strings.HasSuffix(filePath, notesFileSuffix) {
// If --render-subchart-notes flag is enabled, add all the notes files, i.e., notes from the root chart, and
// subcharts, if any.
//
// If not enabled, select just the root chart's notes file, which will be in the format:
// <chart-name>/templates/NOTES.txt
if renderSubchartNotes || (filePath == path.Join(ch.Name(), "templates", notesFileSuffix)) {
// Store the notes file's (path -> content) pairs. In a dry run, the notes file names will be useful as
// the source details in the output.
//
// Since the filepaths are of already existing files, they will be unique. No checks needed.
notesFilePathToContent[filePath] = fileContent
// Store the list of notes filepaths. The list will be used for ordering and will be sorted in the next
// steps.
notesFilePaths = append(notesFilePaths, filePath)
}
// Remove the notes files from the manifest files list. Rendered notes will be returned separately.
delete(files, filePath)
} }
notesBuffer.WriteString(v)
} }
delete(files, k)
// Sort the notes filepaths based on depth first, and then in alphabetical order. Since the notes file's names are
// the same for all charts, the ordering is based on the chart names and notes filepaths.
//
// For example, for a chart and its subcharts in the hierarchy as follows:
//
// foo
// └── charts
// ├── bar
// │ └── charts
// │ └── qux
// └── baz
//
// The notes files must be sorted as follows:
// 1. foo/templates/NOTES.txt
// 2. foo/charts/bar/templates/NOTES.txt
// 3. foo/charts/baz/templates/NOTES.txt
// 4. foo/charts/bar/charts/qux/templates/NOTES.txt
sort.Slice(notesFilePaths, func(notesI, notesJ int) bool {
// Count the number of occurrences of the string "/charts/" for depth.
depth := func(s string) int {
return strings.Count(s, "/charts/")
} }
// When the depth of both charts is not the same, the smaller depth one goes first. In the above example, foo
// goes before bar and baz, and bar goes before qux.
depthI := depth(notesFilePaths[notesI])
depthJ := depth(notesFilePaths[notesJ])
if depthI != depthJ {
return depthI < depthJ
} }
notes := notesBuffer.String()
// When both charts have the same depth, like bar and baz in the above example, use alphabetical order.
return notesFilePaths[notesI] < notesFilePaths[notesJ]
})
// Sort hooks, manifests, and partials. Only hooks and manifests are returned, // Sort hooks, manifests, and partials. Only hooks and manifests are returned,
// as partials are not used after renderer.Render. Empty manifests are also // as partials are not used after renderer.Render. Empty manifests are also
@ -229,11 +283,66 @@ func (cfg *Configuration) renderResources(ch *chart.Chart, values chartutil.Valu
if pr != nil { if pr != nil {
b, err = pr.Run(b) b, err = pr.Run(b)
if err != nil { if err != nil {
return hs, b, notes, errors.Wrap(err, "error while running post render on files") return hs, b, "", errors.Wrap(err, "error while running post render on files")
}
}
// The rendered notes are returned as a string, which can be used in the output of the calling command. If
// --render-subchart-notes is enabled, the notes from the subcharts are also included in the output in an ordered
// manner, separated by empty lines.
//
// foo NOTES HERE
//
// bar NOTES HERE
//
// baz NOTES HERE
//
// qux NOTES HERE
//
// In a dry run, the notes are prefixed with the source file name and separator instead of an empty line as follows.
// For helm install/upgrade commands, dry run can be enabled by using the `--dry-run` flag. The helm template
// command is considered a dry run by default. However, to include notes in the helm template, the `--notes` flag
// must be enabled.
//
// ---
// # Source: foo/templates/NOTES.txt
// foo NOTES HERE
//
// If --render-subchart-notes is enabled on dry run with any of those commands, the notes from the subcharts are
// also included in the output.
//
// ---
// # Source: foo/templates/NOTES.txt
// foo NOTES HERE
// ---
// # Source: foo/charts/bar/templates/NOTES.txt
// bar NOTES HERE
// ---
// # Source: foo/charts/baz/templates/NOTES.txt
// baz NOTES HERE
// ---
// # Source: foo/charts/bar/charts/qux/templates/NOTES.txt
// qux NOTES HERE
//
// Note: The order of the notes files above is based on depth first, and then in alphabetical order.
var renderedNotes bytes.Buffer
for _, noteFilePath := range notesFilePaths {
// When dry run is enabled, add the notes file name and separator to the notes and write to the buffer.
if isDryRun {
fmt.Fprintf(&renderedNotes, "---\n# Source: %s\n%s", noteFilePath, notesFilePathToContent[noteFilePath])
continue
}
// When dry run is disabled, write rendered notes to the buffer. If the buffer contains data, add a newline to
// separate from the next note.
if renderedNotes.Len() > 0 {
renderedNotes.WriteString("\n")
} }
renderedNotes.WriteString(notesFilePathToContent[noteFilePath])
} }
return hs, b, notes, nil return hs, b, renderedNotes.String(), nil
} }
// RESTClientGetter gets the rest client // RESTClientGetter gets the rest client

@ -314,7 +314,9 @@ func (i *Install) RunWithContext(ctx context.Context, chrt *chart.Chart, vals ma
rel := i.createRelease(chrt, vals, i.Labels) rel := i.createRelease(chrt, vals, i.Labels)
var manifestDoc *bytes.Buffer var manifestDoc *bytes.Buffer
rel.Hooks, manifestDoc, rel.Info.Notes, err = i.cfg.renderResources(chrt, valuesToRender, i.ReleaseName, i.OutputDir, i.SubNotes, i.UseReleaseName, i.IncludeCRDs, i.PostRenderer, interactWithRemote, i.EnableDNS, i.HideSecret) rel.Hooks, manifestDoc, rel.Info.Notes, err = i.cfg.renderResources(chrt, valuesToRender, i.ReleaseName,
i.OutputDir, i.SubNotes, i.UseReleaseName, i.IncludeCRDs, i.PostRenderer, interactWithRemote, i.EnableDNS,
i.HideSecret, i.isDryRun())
// Even for errors, attach this if available // Even for errors, attach this if available
if manifestDoc != nil { if manifestDoc != nil {
rel.Manifest = manifestDoc.String() rel.Manifest = manifestDoc.String()

@ -273,7 +273,8 @@ func (u *Upgrade) prepareUpgrade(name string, chart *chart.Chart, vals map[strin
interactWithRemote = true interactWithRemote = true
} }
hooks, manifestDoc, notesTxt, err := u.cfg.renderResources(chart, valuesToRender, "", "", u.SubNotes, false, false, u.PostRenderer, interactWithRemote, u.EnableDNS, u.HideSecret) hooks, manifestDoc, notesTxt, err := u.cfg.renderResources(chart, valuesToRender, "", "", u.SubNotes, false, false,
u.PostRenderer, interactWithRemote, u.EnableDNS, u.HideSecret, u.isDryRun())
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

Loading…
Cancel
Save