ref(cmd): consistent naming of cmd variables

pull/4027/head
Adam Reese 7 years ago
parent c30637b8a1
commit 57e288a88d
No known key found for this signature in database
GPG Key ID: 06F35E60A7A18DD6

@ -37,16 +37,11 @@ For example, 'helm create foo' will create a directory structure that looks
something like this: something like this:
foo/ foo/
| .helmignore # Contains patterns to ignore when packaging Helm charts.
|- .helmignore # Contains patterns to ignore when packaging Helm charts. Chart.yaml # Information about your chart
| values.yaml # The default values for your templates
|- Chart.yaml # Information about your chart charts/ # Charts that this chart depends on
| templates/ # The template files
|- values.yaml # The default values for your templates
|
|- charts/ # Charts that this chart depends on
|
|- templates/ # The template files
'helm create' takes a path for an argument. If directories in the given path 'helm create' takes a path for an argument. If directories in the given path
do not exist, Helm will attempt to create them as it goes. If the given do not exist, Helm will attempt to create them as it goes. If the given
@ -54,37 +49,40 @@ destination exists and there are files in that directory, conflicting files
will be overwritten, but other files will be left alone. will be overwritten, but other files will be left alone.
` `
type createCmd struct { type createOptions struct {
home helmpath.Home starter string // --starter
name string
starter string // args
name string
home helmpath.Home
} }
func newCreateCmd(out io.Writer) *cobra.Command { func newCreateCmd(out io.Writer) *cobra.Command {
cc := &createCmd{} o := &createOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "create NAME", Use: "create NAME",
Short: "create a new chart with the given name", Short: "create a new chart with the given name",
Long: createDesc, Long: createDesc,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cc.home = settings.Home o.home = settings.Home
if len(args) == 0 { if len(args) == 0 {
return errors.New("the name of the new chart is required") return errors.New("the name of the new chart is required")
} }
cc.name = args[0] o.name = args[0]
return cc.run(out) return o.run(out)
}, },
} }
cmd.Flags().StringVarP(&cc.starter, "starter", "p", "", "the named Helm starter scaffold") cmd.Flags().StringVarP(&o.starter, "starter", "p", "", "the named Helm starter scaffold")
return cmd return cmd
} }
func (c *createCmd) run(out io.Writer) error { func (o *createOptions) run(out io.Writer) error {
fmt.Fprintf(out, "Creating %s\n", c.name) fmt.Fprintf(out, "Creating %s\n", o.name)
chartname := filepath.Base(c.name) chartname := filepath.Base(o.name)
cfile := &chart.Metadata{ cfile := &chart.Metadata{
Name: chartname, Name: chartname,
Description: "A Helm chart for Kubernetes", Description: "A Helm chart for Kubernetes",
@ -93,12 +91,12 @@ func (c *createCmd) run(out io.Writer) error {
APIVersion: chartutil.APIVersionv1, APIVersion: chartutil.APIVersionv1,
} }
if c.starter != "" { if o.starter != "" {
// Create from the starter // Create from the starter
lstarter := filepath.Join(c.home.Starters(), c.starter) lstarter := filepath.Join(o.home.Starters(), o.starter)
return chartutil.CreateFrom(cfile, filepath.Dir(c.name), lstarter) return chartutil.CreateFrom(cfile, filepath.Dir(o.name), lstarter)
} }
_, err := chartutil.Create(cfile, filepath.Dir(c.name)) _, err := chartutil.Create(cfile, filepath.Dir(o.name))
return err return err
} }

@ -34,18 +34,20 @@ Use the '--dry-run' flag to see which releases will be deleted without actually
deleting them. deleting them.
` `
type deleteCmd struct { type deleteOptions struct {
name string disableHooks bool // --no-hooks
dryRun bool dryRun bool // --dry-run
disableHooks bool purge bool // --purge
purge bool timeout int64 // --timeout
timeout int64
// args
name string
client helm.Interface client helm.Interface
} }
func newDeleteCmd(c helm.Interface, out io.Writer) *cobra.Command { func newDeleteCmd(c helm.Interface, out io.Writer) *cobra.Command {
del := &deleteCmd{client: c} o := &deleteOptions{client: c}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "delete [flags] RELEASE_NAME [...]", Use: "delete [flags] RELEASE_NAME [...]",
@ -57,37 +59,37 @@ func newDeleteCmd(c helm.Interface, out io.Writer) *cobra.Command {
if len(args) == 0 { if len(args) == 0 {
return errors.New("command 'delete' requires a release name") return errors.New("command 'delete' requires a release name")
} }
del.client = ensureHelmClient(del.client, false) o.client = ensureHelmClient(o.client, false)
for i := 0; i < len(args); i++ { for i := 0; i < len(args); i++ {
del.name = args[i] o.name = args[i]
if err := del.run(out); err != nil { if err := o.run(out); err != nil {
return err return err
} }
fmt.Fprintf(out, "release \"%s\" deleted\n", del.name) fmt.Fprintf(out, "release \"%s\" deleted\n", o.name)
} }
return nil return nil
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.BoolVar(&del.dryRun, "dry-run", false, "simulate a delete") f.BoolVar(&o.dryRun, "dry-run", false, "simulate a delete")
f.BoolVar(&del.disableHooks, "no-hooks", false, "prevent hooks from running during deletion") f.BoolVar(&o.disableHooks, "no-hooks", false, "prevent hooks from running during deletion")
f.BoolVar(&del.purge, "purge", false, "remove the release from the store and make its name free for later use") f.BoolVar(&o.purge, "purge", false, "remove the release from the store and make its name free for later use")
f.Int64Var(&del.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)") f.Int64Var(&o.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)")
return cmd return cmd
} }
func (d *deleteCmd) run(out io.Writer) error { func (o *deleteOptions) run(out io.Writer) error {
opts := []helm.DeleteOption{ opts := []helm.DeleteOption{
helm.DeleteDryRun(d.dryRun), helm.DeleteDryRun(o.dryRun),
helm.DeleteDisableHooks(d.disableHooks), helm.DeleteDisableHooks(o.disableHooks),
helm.DeletePurge(d.purge), helm.DeletePurge(o.purge),
helm.DeleteTimeout(d.timeout), helm.DeleteTimeout(o.timeout),
} }
res, err := d.client.DeleteRelease(d.name, opts...) res, err := o.client.DeleteRelease(o.name, opts...)
if res != nil && res.Info != "" { if res != nil && res.Info != "" {
fmt.Fprintln(out, res.Info) fmt.Fprintln(out, res.Info)
} }

@ -102,12 +102,14 @@ func newDependencyCmd(out io.Writer) *cobra.Command {
return cmd return cmd
} }
type dependencyListCmd struct { type dependencyLisOptions struct {
chartpath string chartpath string
} }
func newDependencyListCmd(out io.Writer) *cobra.Command { func newDependencyListCmd(out io.Writer) *cobra.Command {
dlc := &dependencyListCmd{} o := &dependencyLisOptions{
chartpath: ".",
}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "list [flags] CHART", Use: "list [flags] CHART",
@ -115,20 +117,17 @@ func newDependencyListCmd(out io.Writer) *cobra.Command {
Short: "list the dependencies for the given chart", Short: "list the dependencies for the given chart",
Long: dependencyListDesc, Long: dependencyListDesc,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cp := "."
if len(args) > 0 { if len(args) > 0 {
cp = args[0] o.chartpath = filepath.Clean(args[0])
} }
return o.run(out)
dlc.chartpath = filepath.Clean(cp)
return dlc.run()
}, },
} }
return cmd return cmd
} }
func (l *dependencyListCmd) run(out io.Writer) error { func (o *dependencyLisOptions) run(out io.Writer) error {
c, err := chartutil.Load(l.chartpath) c, err := chartutil.Load(o.chartpath)
if err != nil { if err != nil {
return err return err
} }
@ -136,21 +135,21 @@ func (l *dependencyListCmd) run(out io.Writer) error {
r, err := chartutil.LoadRequirements(c) r, err := chartutil.LoadRequirements(c)
if err != nil { if err != nil {
if err == chartutil.ErrRequirementsNotFound { if err == chartutil.ErrRequirementsNotFound {
fmt.Fprintf(out, "WARNING: no requirements at %s/charts\n", l.chartpath) fmt.Fprintf(out, "WARNING: no requirements at %s/charts\n", o.chartpath)
return nil return nil
} }
return err return err
} }
l.printRequirements(out, r) o.printRequirements(out, r)
fmt.Fprintln(out) fmt.Fprintln(out)
l.printMissing(out, r) o.printMissing(out, r)
return nil return nil
} }
func (l *dependencyListCmd) dependencyStatus(dep *chartutil.Dependency) string { func (o *dependencyLisOptions) dependencyStatus(dep *chartutil.Dependency) string {
filename := fmt.Sprintf("%s-%s.tgz", dep.Name, "*") filename := fmt.Sprintf("%s-%s.tgz", dep.Name, "*")
archives, err := filepath.Glob(filepath.Join(l.chartpath, "charts", filename)) archives, err := filepath.Glob(filepath.Join(o.chartpath, "charts", filename))
if err != nil { if err != nil {
return "bad pattern" return "bad pattern"
} else if len(archives) > 1 { } else if len(archives) > 1 {
@ -186,7 +185,7 @@ func (l *dependencyListCmd) dependencyStatus(dep *chartutil.Dependency) string {
} }
} }
folder := filepath.Join(l.chartpath, "charts", dep.Name) folder := filepath.Join(o.chartpath, "charts", dep.Name)
if fi, err := os.Stat(folder); err != nil { if fi, err := os.Stat(folder); err != nil {
return "missing" return "missing"
} else if !fi.IsDir() { } else if !fi.IsDir() {
@ -223,19 +222,19 @@ func (l *dependencyListCmd) dependencyStatus(dep *chartutil.Dependency) string {
} }
// printRequirements prints all of the requirements in the yaml file. // printRequirements prints all of the requirements in the yaml file.
func (l *dependencyListCmd) printRequirements(out io.Writer, reqs *chartutil.Requirements) { func (o *dependencyLisOptions) printRequirements(out io.Writer, reqs *chartutil.Requirements) {
table := uitable.New() table := uitable.New()
table.MaxColWidth = 80 table.MaxColWidth = 80
table.AddRow("NAME", "VERSION", "REPOSITORY", "STATUS") table.AddRow("NAME", "VERSION", "REPOSITORY", "STATUS")
for _, row := range reqs.Dependencies { for _, row := range reqs.Dependencies {
table.AddRow(row.Name, row.Version, row.Repository, l.dependencyStatus(row)) table.AddRow(row.Name, row.Version, row.Repository, o.dependencyStatus(row))
} }
fmt.Fprintln(out, table) fmt.Fprintln(out, table)
} }
// printMissing prints warnings about charts that are present on disk, but are not in the requirements. // printMissing prints warnings about charts that are present on disk, but are not in the requirements.
func (l *dependencyListCmd) printMissing(out io.Writer, reqs *chartutil.Requirements) { func (o *dependencyLisOptions) printMissing(out io.Writer, reqs *chartutil.Requirements) {
folder := filepath.Join(l.chartpath, "charts/*") folder := filepath.Join(o.chartpath, "charts/*")
files, err := filepath.Glob(folder) files, err := filepath.Glob(folder)
if err != nil { if err != nil {
fmt.Fprintln(out, err) fmt.Fprintln(out, err)

@ -36,47 +36,50 @@ If no lock file is found, 'helm dependency build' will mirror the behavior
of 'helm dependency update'. of 'helm dependency update'.
` `
type dependencyBuildCmd struct { type dependencyBuildOptions struct {
keyring string // --keyring
verify bool // --verify
// args
chartpath string chartpath string
verify bool
keyring string helmhome helmpath.Home
helmhome helmpath.Home
} }
func newDependencyBuildCmd(out io.Writer) *cobra.Command { func newDependencyBuildCmd(out io.Writer) *cobra.Command {
dbc := &dependencyBuildCmd{} o := &dependencyBuildOptions{
chartpath: ".",
}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "build [flags] CHART", Use: "build [flags] CHART",
Short: "rebuild the charts/ directory based on the requirements.lock file", Short: "rebuild the charts/ directory based on the requirements.lock file",
Long: dependencyBuildDesc, Long: dependencyBuildDesc,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
dbc.helmhome = settings.Home o.helmhome = settings.Home
dbc.chartpath = "."
if len(args) > 0 { if len(args) > 0 {
dbc.chartpath = args[0] o.chartpath = args[0]
} }
return dbc.run(out) return o.run(out)
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.BoolVar(&dbc.verify, "verify", false, "verify the packages against signatures") f.BoolVar(&o.verify, "verify", false, "verify the packages against signatures")
f.StringVar(&dbc.keyring, "keyring", defaultKeyring(), "keyring containing public keys") f.StringVar(&o.keyring, "keyring", defaultKeyring(), "keyring containing public keys")
return cmd return cmd
} }
func (d *dependencyBuildCmd) run(out io.Writer) error { func (o *dependencyBuildOptions) run(out io.Writer) error {
man := &downloader.Manager{ man := &downloader.Manager{
Out: out, Out: out,
ChartPath: d.chartpath, ChartPath: o.chartpath,
HelmHome: d.helmhome, HelmHome: o.helmhome,
Keyring: d.keyring, Keyring: o.keyring,
Getters: getter.All(settings), Getters: getter.All(settings),
} }
if d.verify { if o.verify {
man.Verify = downloader.VerifyIfPossible man.Verify = downloader.VerifyIfPossible
} }

@ -41,18 +41,23 @@ reason, an update command will not remove charts unless they are (a) present
in the requirements.yaml file, but (b) at the wrong version. in the requirements.yaml file, but (b) at the wrong version.
` `
// dependencyUpdateCmd describes a 'helm dependency update' // dependencyUpdateOptions describes a 'helm dependency update'
type dependencyUpdateCmd struct { type dependencyUpdateOptions struct {
chartpath string keyring string // --keyring
helmhome helmpath.Home skipRefresh bool // --skip-refresh
verify bool verify bool // --verify
keyring string
skipRefresh bool // args
chartpath string
helmhome helmpath.Home
} }
// newDependencyUpdateCmd creates a new dependency update command. // newDependencyUpdateCmd creates a new dependency update command.
func newDependencyUpdateCmd(out io.Writer) *cobra.Command { func newDependencyUpdateCmd(out io.Writer) *cobra.Command {
duc := &dependencyUpdateCmd{} o := &dependencyUpdateOptions{
chartpath: ".",
}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "update [flags] CHART", Use: "update [flags] CHART",
@ -60,42 +65,33 @@ func newDependencyUpdateCmd(out io.Writer) *cobra.Command {
Short: "update charts/ based on the contents of requirements.yaml", Short: "update charts/ based on the contents of requirements.yaml",
Long: dependencyUpDesc, Long: dependencyUpDesc,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cp := "."
if len(args) > 0 { if len(args) > 0 {
cp = args[0] o.chartpath = filepath.Clean(args[0])
} }
o.helmhome = settings.Home
var err error return o.run(out)
duc.chartpath, err = filepath.Abs(cp)
if err != nil {
return err
}
duc.helmhome = settings.Home
return duc.run(out)
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.BoolVar(&duc.verify, "verify", false, "verify the packages against signatures") f.BoolVar(&o.verify, "verify", false, "verify the packages against signatures")
f.StringVar(&duc.keyring, "keyring", defaultKeyring(), "keyring containing public keys") f.StringVar(&o.keyring, "keyring", defaultKeyring(), "keyring containing public keys")
f.BoolVar(&duc.skipRefresh, "skip-refresh", false, "do not refresh the local repository cache") f.BoolVar(&o.skipRefresh, "skip-refresh", false, "do not refresh the local repository cache")
return cmd return cmd
} }
// run runs the full dependency update process. // run runs the full dependency update process.
func (d *dependencyUpdateCmd) run(out io.Writer) error { func (o *dependencyUpdateOptions) run(out io.Writer) error {
man := &downloader.Manager{ man := &downloader.Manager{
Out: out, Out: out,
ChartPath: d.chartpath, ChartPath: o.chartpath,
HelmHome: d.helmhome, HelmHome: o.helmhome,
Keyring: d.keyring, Keyring: o.keyring,
SkipUpdate: d.skipRefresh, SkipUpdate: o.skipRefresh,
Getters: getter.All(settings), Getters: getter.All(settings),
} }
if d.verify { if o.verify {
man.Verify = downloader.VerifyAlways man.Verify = downloader.VerifyAlways
} }
if settings.Debug { if settings.Debug {

@ -190,11 +190,11 @@ func TestDependencyUpdateCmd_DontDeleteOldChartsOnError(t *testing.T) {
} }
out := bytes.NewBuffer(nil) out := bytes.NewBuffer(nil)
duc := &dependencyUpdateCmd{} o := &dependencyUpdateOptions{}
duc.helmhome = helmpath.Home(hh) o.helmhome = helmpath.Home(hh)
duc.chartpath = hh.Path(chartname) o.chartpath = hh.Path(chartname)
if err := duc.run(out); err != nil { if err := o.run(out); err != nil {
output := out.String() output := out.String()
t.Logf("Output: %s", output) t.Logf("Output: %s", output)
t.Fatal(err) t.Fatal(err)
@ -203,14 +203,14 @@ func TestDependencyUpdateCmd_DontDeleteOldChartsOnError(t *testing.T) {
// Chart repo is down // Chart repo is down
srv.Stop() srv.Stop()
if err := duc.run(out); err == nil { if err := o.run(out); err == nil {
output := out.String() output := out.String()
t.Logf("Output: %s", output) t.Logf("Output: %s", output)
t.Fatal("Expected error, got nil") t.Fatal("Expected error, got nil")
} }
// Make sure charts dir still has dependencies // Make sure charts dir still has dependencies
files, err := ioutil.ReadDir(filepath.Join(duc.chartpath, "charts")) files, err := ioutil.ReadDir(filepath.Join(o.chartpath, "charts"))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -226,7 +226,7 @@ func TestDependencyUpdateCmd_DontDeleteOldChartsOnError(t *testing.T) {
} }
// Make sure tmpcharts is deleted // Make sure tmpcharts is deleted
if _, err := os.Stat(filepath.Join(duc.chartpath, "tmpcharts")); !os.IsNotExist(err) { if _, err := os.Stat(filepath.Join(o.chartpath, "tmpcharts")); !os.IsNotExist(err) {
t.Fatalf("tmpcharts dir still exists") t.Fatalf("tmpcharts dir still exists")
} }
} }

@ -37,15 +37,14 @@ It can also generate bash autocompletions.
$ helm docs markdown -dir mydocs/ $ helm docs markdown -dir mydocs/
` `
type docsCmd struct { type docsOptions struct {
out io.Writer
dest string dest string
docTypeString string docTypeString string
topCmd *cobra.Command topCmd *cobra.Command
} }
func newDocsCmd(out io.Writer) *cobra.Command { func newDocsCmd(out io.Writer) *cobra.Command {
dc := &docsCmd{out: out} o := &docsOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "docs", Use: "docs",
@ -53,28 +52,28 @@ func newDocsCmd(out io.Writer) *cobra.Command {
Long: docsDesc, Long: docsDesc,
Hidden: true, Hidden: true,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
dc.topCmd = cmd.Root() o.topCmd = cmd.Root()
return dc.run() return o.run(out)
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.StringVar(&dc.dest, "dir", "./", "directory to which documentation is written") f.StringVar(&o.dest, "dir", "./", "directory to which documentation is written")
f.StringVar(&dc.docTypeString, "type", "markdown", "the type of documentation to generate (markdown, man, bash)") f.StringVar(&o.docTypeString, "type", "markdown", "the type of documentation to generate (markdown, man, bash)")
return cmd return cmd
} }
func (d *docsCmd) run() error { func (o *docsOptions) run(out io.Writer) error {
switch d.docTypeString { switch o.docTypeString {
case "markdown", "mdown", "md": case "markdown", "mdown", "md":
return doc.GenMarkdownTree(d.topCmd, d.dest) return doc.GenMarkdownTree(o.topCmd, o.dest)
case "man": case "man":
manHdr := &doc.GenManHeader{Title: "HELM", Section: "1"} manHdr := &doc.GenManHeader{Title: "HELM", Section: "1"}
return doc.GenManTree(d.topCmd, manHdr, d.dest) return doc.GenManTree(o.topCmd, manHdr, o.dest)
case "bash": case "bash":
return d.topCmd.GenBashCompletionFile(filepath.Join(d.dest, "completions.bash")) return o.topCmd.GenBashCompletionFile(filepath.Join(o.dest, "completions.bash"))
default: default:
return fmt.Errorf("unknown doc type %q. Try 'markdown' or 'man'", d.docTypeString) return fmt.Errorf("unknown doc type %q. Try 'markdown' or 'man'", o.docTypeString)
} }
} }

@ -46,29 +46,27 @@ file, and MUST pass the verification process. Failure in any part of this will
result in an error, and the chart will not be saved locally. result in an error, and the chart will not be saved locally.
` `
type fetchCmd struct { type fetchOptions struct {
untar bool caFile string // --ca-file
untardir string certFile string // --cert-file
chartRef string destdir string // --destination
destdir string devel bool // --devel
version string keyFile string // --key-file
repoURL string keyring string // --keyring
username string password string // --password
password string repoURL string // --repo
untar bool // --untar
verify bool untardir string // --untardir
verifyLater bool username string // --username
keyring string verify bool // --verify
verifyLater bool // --prov
version string // --version
certFile string chartRef string
keyFile string
caFile string
devel bool
} }
func newFetchCmd(out io.Writer) *cobra.Command { func newFetchCmd(out io.Writer) *cobra.Command {
fch := &fetchCmd{} o := &fetchOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "fetch [flags] [chart URL | repo/chartname] [...]", Use: "fetch [flags] [chart URL | repo/chartname] [...]",
@ -79,14 +77,14 @@ func newFetchCmd(out io.Writer) *cobra.Command {
return fmt.Errorf("need at least one argument, url or repo/name of the chart") return fmt.Errorf("need at least one argument, url or repo/name of the chart")
} }
if fch.version == "" && fch.devel { if o.version == "" && o.devel {
debug("setting version to >0.0.0-0") debug("setting version to >0.0.0-0")
fch.version = ">0.0.0-0" o.version = ">0.0.0-0"
} }
for i := 0; i < len(args); i++ { for i := 0; i < len(args); i++ {
fch.chartRef = args[i] o.chartRef = args[i]
if err := fch.run(out); err != nil { if err := o.run(out); err != nil {
return err return err
} }
} }
@ -95,45 +93,45 @@ func newFetchCmd(out io.Writer) *cobra.Command {
} }
f := cmd.Flags() f := cmd.Flags()
f.BoolVar(&fch.untar, "untar", false, "if set to true, will untar the chart after downloading it") f.BoolVar(&o.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.")
f.StringVar(&fch.untardir, "untardir", ".", "if untar is specified, this flag specifies the name of the directory into which the chart is expanded") f.BoolVar(&o.untar, "untar", false, "if set to true, will untar the chart after downloading it")
f.BoolVar(&fch.verify, "verify", false, "verify the package against its signature") f.BoolVar(&o.verify, "verify", false, "verify the package against its signature")
f.BoolVar(&fch.verifyLater, "prov", false, "fetch the provenance file, but don't perform verification") f.BoolVar(&o.verifyLater, "prov", false, "fetch the provenance file, but don't perform verification")
f.StringVar(&fch.version, "version", "", "specific version of a chart. Without this, the latest version is fetched") f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
f.StringVar(&fch.keyring, "keyring", defaultKeyring(), "keyring containing public keys") f.StringVar(&o.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
f.StringVarP(&fch.destdir, "destination", "d", ".", "location to write the chart. If this and tardir are specified, tardir is appended to this") f.StringVar(&o.keyFile, "key-file", "", "identify HTTPS client using this SSL key file")
f.StringVar(&fch.repoURL, "repo", "", "chart repository url where to locate the requested chart") f.StringVar(&o.keyring, "keyring", defaultKeyring(), "keyring containing public keys")
f.StringVar(&fch.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file") f.StringVar(&o.password, "password", "", "chart repository password")
f.StringVar(&fch.keyFile, "key-file", "", "identify HTTPS client using this SSL key file") f.StringVar(&o.repoURL, "repo", "", "chart repository url where to locate the requested chart")
f.StringVar(&fch.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") f.StringVar(&o.untardir, "untardir", ".", "if untar is specified, this flag specifies the name of the directory into which the chart is expanded")
f.BoolVar(&fch.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.") f.StringVar(&o.username, "username", "", "chart repository username")
f.StringVar(&fch.username, "username", "", "chart repository username") f.StringVar(&o.version, "version", "", "specific version of a chart. Without this, the latest version is fetched")
f.StringVar(&fch.password, "password", "", "chart repository password") f.StringVarP(&o.destdir, "destination", "d", ".", "location to write the chart. If this and tardir are specified, tardir is appended to this")
return cmd return cmd
} }
func (f *fetchCmd) run(out io.Writer) error { func (o *fetchOptions) run(out io.Writer) error {
c := downloader.ChartDownloader{ c := downloader.ChartDownloader{
HelmHome: settings.Home, HelmHome: settings.Home,
Out: out, Out: out,
Keyring: f.keyring, Keyring: o.keyring,
Verify: downloader.VerifyNever, Verify: downloader.VerifyNever,
Getters: getter.All(settings), Getters: getter.All(settings),
Username: f.username, Username: o.username,
Password: f.password, Password: o.password,
} }
if f.verify { if o.verify {
c.Verify = downloader.VerifyAlways c.Verify = downloader.VerifyAlways
} else if f.verifyLater { } else if o.verifyLater {
c.Verify = downloader.VerifyLater c.Verify = downloader.VerifyLater
} }
// If untar is set, we fetch to a tempdir, then untar and copy after // If untar is set, we fetch to a tempdir, then untar and copy after
// verification. // verification.
dest := f.destdir dest := o.destdir
if f.untar { if o.untar {
var err error var err error
dest, err = ioutil.TempDir("", "helm-") dest, err = ioutil.TempDir("", "helm-")
if err != nil { if err != nil {
@ -142,28 +140,28 @@ func (f *fetchCmd) run(out io.Writer) error {
defer os.RemoveAll(dest) defer os.RemoveAll(dest)
} }
if f.repoURL != "" { if o.repoURL != "" {
chartURL, err := repo.FindChartInAuthRepoURL(f.repoURL, f.username, f.password, f.chartRef, f.version, f.certFile, f.keyFile, f.caFile, getter.All(settings)) chartURL, err := repo.FindChartInAuthRepoURL(o.repoURL, o.username, o.password, o.chartRef, o.version, o.certFile, o.keyFile, o.caFile, getter.All(settings))
if err != nil { if err != nil {
return err return err
} }
f.chartRef = chartURL o.chartRef = chartURL
} }
saved, v, err := c.DownloadTo(f.chartRef, f.version, dest) saved, v, err := c.DownloadTo(o.chartRef, o.version, dest)
if err != nil { if err != nil {
return err return err
} }
if f.verify { if o.verify {
fmt.Fprintf(out, "Verification: %v\n", v) fmt.Fprintf(out, "Verification: %v\n", v)
} }
// After verification, untar the chart into the requested directory. // After verification, untar the chart into the requested directory.
if f.untar { if o.untar {
ud := f.untardir ud := o.untardir
if !filepath.IsAbs(ud) { if !filepath.IsAbs(ud) {
ud = filepath.Join(f.destdir, ud) ud = filepath.Join(o.destdir, ud)
} }
if fi, err := os.Stat(ud); err != nil { if fi, err := os.Stat(ud); err != nil {
if err := os.MkdirAll(ud, 0755); err != nil { if err := os.MkdirAll(ud, 0755); err != nil {

@ -40,15 +40,16 @@ chart, the supplied values, and the generated manifest file.
var errReleaseRequired = errors.New("release name is required") var errReleaseRequired = errors.New("release name is required")
type getCmd struct { type getOptions struct {
version int // --revision
release string release string
version int
client helm.Interface client helm.Interface
} }
func newGetCmd(client helm.Interface, out io.Writer) *cobra.Command { func newGetCmd(client helm.Interface, out io.Writer) *cobra.Command {
get := &getCmd{client: client} o := &getOptions{client: client}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "get [flags] RELEASE_NAME", Use: "get [flags] RELEASE_NAME",
@ -58,13 +59,13 @@ func newGetCmd(client helm.Interface, out io.Writer) *cobra.Command {
if len(args) == 0 { if len(args) == 0 {
return errReleaseRequired return errReleaseRequired
} }
get.release = args[0] o.release = args[0]
get.client = ensureHelmClient(get.client, false) o.client = ensureHelmClient(o.client, false)
return get.run(out) return o.run(out)
}, },
} }
cmd.Flags().IntVar(&get.version, "revision", 0, "get the named release with revision") cmd.Flags().IntVar(&o.version, "revision", 0, "get the named release with revision")
cmd.AddCommand(newGetValuesCmd(client, out)) cmd.AddCommand(newGetValuesCmd(client, out))
cmd.AddCommand(newGetManifestCmd(client, out)) cmd.AddCommand(newGetManifestCmd(client, out))
@ -73,8 +74,7 @@ func newGetCmd(client helm.Interface, out io.Writer) *cobra.Command {
return cmd return cmd
} }
// getCmd is the command that implements 'helm get' func (g *getOptions) run(out io.Writer) error {
func (g *getCmd) run(out io.Writer) error {
res, err := g.client.ReleaseContent(g.release, g.version) res, err := g.client.ReleaseContent(g.release, g.version)
if err != nil { if err != nil {
return err return err

@ -31,14 +31,14 @@ This command downloads hooks for a given release.
Hooks are formatted in YAML and separated by the YAML '---\n' separator. Hooks are formatted in YAML and separated by the YAML '---\n' separator.
` `
type getHooksCmd struct { type getHooksOptions struct {
release string release string
client helm.Interface client helm.Interface
version int version int
} }
func newGetHooksCmd(client helm.Interface, out io.Writer) *cobra.Command { func newGetHooksCmd(client helm.Interface, out io.Writer) *cobra.Command {
ghc := &getHooksCmd{client: client} o := &getHooksOptions{client: client}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "hooks [flags] RELEASE_NAME", Use: "hooks [flags] RELEASE_NAME",
@ -48,19 +48,19 @@ func newGetHooksCmd(client helm.Interface, out io.Writer) *cobra.Command {
if len(args) == 0 { if len(args) == 0 {
return errReleaseRequired return errReleaseRequired
} }
ghc.release = args[0] o.release = args[0]
ghc.client = ensureHelmClient(ghc.client, false) o.client = ensureHelmClient(o.client, false)
return ghc.run(out) return o.run(out)
}, },
} }
cmd.Flags().IntVar(&ghc.version, "revision", 0, "get the named release with revision") cmd.Flags().IntVar(&o.version, "revision", 0, "get the named release with revision")
return cmd return cmd
} }
func (g *getHooksCmd) run(out io.Writer) error { func (o *getHooksOptions) run(out io.Writer) error {
res, err := g.client.ReleaseContent(g.release, g.version) res, err := o.client.ReleaseContent(o.release, o.version)
if err != nil { if err != nil {
fmt.Fprintln(out, g.release) fmt.Fprintln(out, o.release)
return err return err
} }

@ -33,14 +33,16 @@ were generated from this release's chart(s). If a chart is dependent on other
charts, those resources will also be included in the manifest. charts, those resources will also be included in the manifest.
` `
type getManifestCmd struct { type getManifestOptions struct {
version int // --revision
release string release string
client helm.Interface
version int client helm.Interface
} }
func newGetManifestCmd(client helm.Interface, out io.Writer) *cobra.Command { func newGetManifestCmd(client helm.Interface, out io.Writer) *cobra.Command {
get := &getManifestCmd{client: client} o := &getManifestOptions{client: client}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "manifest [flags] RELEASE_NAME", Use: "manifest [flags] RELEASE_NAME",
@ -50,19 +52,19 @@ func newGetManifestCmd(client helm.Interface, out io.Writer) *cobra.Command {
if len(args) == 0 { if len(args) == 0 {
return errReleaseRequired return errReleaseRequired
} }
get.release = args[0] o.release = args[0]
get.client = ensureHelmClient(get.client, false) o.client = ensureHelmClient(o.client, false)
return get.run(out) return o.run(out)
}, },
} }
cmd.Flags().IntVar(&get.version, "revision", 0, "get the named release with revision") cmd.Flags().IntVar(&o.version, "revision", 0, "get the named release with revision")
return cmd return cmd
} }
// getManifest implements 'helm get manifest' // getManifest implements 'helm get manifest'
func (g *getManifestCmd) run(out io.Writer) error { func (o *getManifestOptions) run(out io.Writer) error {
res, err := g.client.ReleaseContent(g.release, g.version) res, err := o.client.ReleaseContent(o.release, o.version)
if err != nil { if err != nil {
return err return err
} }

@ -30,15 +30,17 @@ var getValuesHelp = `
This command downloads a values file for a given release. This command downloads a values file for a given release.
` `
type getValuesCmd struct { type getValuesOptions struct {
release string allValues bool // --all
allValues bool version int // --revision
client helm.Interface
version int release string
client helm.Interface
} }
func newGetValuesCmd(client helm.Interface, out io.Writer) *cobra.Command { func newGetValuesCmd(client helm.Interface, out io.Writer) *cobra.Command {
get := &getValuesCmd{client: client} o := &getValuesOptions{client: client}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "values [flags] RELEASE_NAME", Use: "values [flags] RELEASE_NAME",
@ -48,26 +50,26 @@ func newGetValuesCmd(client helm.Interface, out io.Writer) *cobra.Command {
if len(args) == 0 { if len(args) == 0 {
return errReleaseRequired return errReleaseRequired
} }
get.release = args[0] o.release = args[0]
get.client = ensureHelmClient(get.client, false) o.client = ensureHelmClient(o.client, false)
return get.run(out) return o.run(out)
}, },
} }
cmd.Flags().IntVar(&get.version, "revision", 0, "get the named release with revision") cmd.Flags().BoolVarP(&o.allValues, "all", "a", false, "dump all (computed) values")
cmd.Flags().BoolVarP(&get.allValues, "all", "a", false, "dump all (computed) values") cmd.Flags().IntVar(&o.version, "revision", 0, "get the named release with revision")
return cmd return cmd
} }
// getValues implements 'helm get values' // getValues implements 'helm get values'
func (g *getValuesCmd) run(out io.Writer) error { func (o *getValuesOptions) run(out io.Writer) error {
res, err := g.client.ReleaseContent(g.release, g.version) res, err := o.client.ReleaseContent(o.release, o.version)
if err != nil { if err != nil {
return err return err
} }
// If the user wants all values, compute the values and return. // If the user wants all values, compute the values and return.
if g.allValues { if o.allValues {
cfg, err := chartutil.CoalesceValues(res.Chart, res.Config) cfg, err := chartutil.CoalesceValues(res.Chart, res.Config)
if err != nil { if err != nil {
return err return err

@ -30,13 +30,13 @@ import (
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
"k8s.io/helm/pkg/helm" "k8s.io/helm/pkg/helm"
helm_env "k8s.io/helm/pkg/helm/environment" "k8s.io/helm/pkg/helm/environment"
"k8s.io/helm/pkg/kube" "k8s.io/helm/pkg/kube"
"k8s.io/helm/pkg/storage/driver" "k8s.io/helm/pkg/storage/driver"
) )
var ( var (
settings helm_env.EnvSettings settings environment.EnvSettings
config clientcmd.ClientConfig config clientcmd.ClientConfig
configOnce sync.Once configOnce sync.Once
) )

@ -56,16 +56,18 @@ The historical release set is printed as a formatted table, e.g:
4 Mon Oct 3 10:15:13 2016 deployed alpine-0.1.0 Upgraded successfully 4 Mon Oct 3 10:15:13 2016 deployed alpine-0.1.0 Upgraded successfully
` `
type historyCmd struct { type historyOptions struct {
max int colWidth uint // --col-width
rls string max int // --max
helmc helm.Interface outputFormat string // --output
colWidth uint
outputFormat string release string
client helm.Interface
} }
func newHistoryCmd(c helm.Interface, out io.Writer) *cobra.Command { func newHistoryCmd(c helm.Interface, out io.Writer) *cobra.Command {
his := &historyCmd{helmc: c} o := &historyOptions{client: c}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "history [flags] RELEASE_NAME", Use: "history [flags] RELEASE_NAME",
@ -76,22 +78,22 @@ func newHistoryCmd(c helm.Interface, out io.Writer) *cobra.Command {
if len(args) == 0 { if len(args) == 0 {
return errReleaseRequired return errReleaseRequired
} }
his.helmc = ensureHelmClient(his.helmc, false) o.client = ensureHelmClient(o.client, false)
his.rls = args[0] o.release = args[0]
return his.run(out) return o.run(out)
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.IntVar(&his.max, "max", 256, "maximum number of revision to include in history") f.IntVar(&o.max, "max", 256, "maximum number of revision to include in history")
f.UintVar(&his.colWidth, "col-width", 60, "specifies the max column width of output") f.UintVar(&o.colWidth, "col-width", 60, "specifies the max column width of output")
f.StringVarP(&his.outputFormat, "output", "o", "table", "prints the output in the specified format (json|table|yaml)") f.StringVarP(&o.outputFormat, "output", "o", "table", "prints the output in the specified format (json|table|yaml)")
return cmd return cmd
} }
func (cmd *historyCmd) run(out io.Writer) error { func (o *historyOptions) run(out io.Writer) error {
rels, err := cmd.helmc.ReleaseHistory(cmd.rls, cmd.max) rels, err := o.client.ReleaseHistory(o.release, o.max)
if err != nil { if err != nil {
return err return err
} }
@ -104,15 +106,15 @@ func (cmd *historyCmd) run(out io.Writer) error {
var history []byte var history []byte
var formattingError error var formattingError error
switch cmd.outputFormat { switch o.outputFormat {
case "yaml": case "yaml":
history, formattingError = yaml.Marshal(releaseHistory) history, formattingError = yaml.Marshal(releaseHistory)
case "json": case "json":
history, formattingError = json.Marshal(releaseHistory) history, formattingError = json.Marshal(releaseHistory)
case "table": case "table":
history = formatAsTable(releaseHistory, cmd.colWidth) history = formatAsTable(releaseHistory, o.colWidth)
default: default:
return fmt.Errorf("unknown output format %q", cmd.outputFormat) return fmt.Errorf("unknown output format %q", o.outputFormat)
} }
if formattingError != nil { if formattingError != nil {

@ -33,17 +33,20 @@ const initDesc = `
This command sets up local configuration in $HELM_HOME (default ~/.helm/). This command sets up local configuration in $HELM_HOME (default ~/.helm/).
` `
const stableRepository = "stable" const (
stableRepository = "stable"
defaultStableRepositoryURL = "https://kubernetes-charts.storage.googleapis.com"
)
var stableRepositoryURL = "https://kubernetes-charts.storage.googleapis.com" type initOptions struct {
skipRefresh bool // --skip-refresh
stableRepositoryURL string // --stable-repo-url
type initCmd struct { home helmpath.Home
skipRefresh bool
home helmpath.Home
} }
func newInitCmd(out io.Writer) *cobra.Command { func newInitCmd(out io.Writer) *cobra.Command {
i := &initCmd{} o := &initOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "init", Use: "init",
@ -53,27 +56,27 @@ func newInitCmd(out io.Writer) *cobra.Command {
if len(args) != 0 { if len(args) != 0 {
return errors.New("This command does not accept arguments") return errors.New("This command does not accept arguments")
} }
i.home = settings.Home o.home = settings.Home
return i.run(out) return o.run(out)
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.BoolVar(&i.skipRefresh, "skip-refresh", false, "do not refresh (download) the local repository cache") f.BoolVar(&o.skipRefresh, "skip-refresh", false, "do not refresh (download) the local repository cache")
f.StringVar(&stableRepositoryURL, "stable-repo-url", stableRepositoryURL, "URL for stable repository") f.StringVar(&o.stableRepositoryURL, "stable-repo-url", defaultStableRepositoryURL, "URL for stable repository")
return cmd return cmd
} }
// run initializes local config and installs Tiller to Kubernetes cluster. // run initializes local config.
func (i *initCmd) run(out io.Writer) error { func (o *initOptions) run(out io.Writer) error {
if err := ensureDirectories(i.home, out); err != nil { if err := ensureDirectories(o.home, out); err != nil {
return err return err
} }
if err := ensureDefaultRepos(i.home, out, i.skipRefresh); err != nil { if err := ensureDefaultRepos(o.home, out, o.skipRefresh, o.stableRepositoryURL); err != nil {
return err return err
} }
if err := ensureRepoFileFormat(i.home.RepositoryFile(), out); err != nil { if err := ensureRepoFileFormat(o.home.RepositoryFile(), out); err != nil {
return err return err
} }
fmt.Fprintf(out, "$HELM_HOME has been configured at %s.\n", settings.Home) fmt.Fprintf(out, "$HELM_HOME has been configured at %s.\n", settings.Home)
@ -107,12 +110,12 @@ func ensureDirectories(home helmpath.Home, out io.Writer) error {
return nil return nil
} }
func ensureDefaultRepos(home helmpath.Home, out io.Writer, skipRefresh bool) error { func ensureDefaultRepos(home helmpath.Home, out io.Writer, skipRefresh bool, url string) error {
repoFile := home.RepositoryFile() repoFile := home.RepositoryFile()
if fi, err := os.Stat(repoFile); err != nil { if fi, err := os.Stat(repoFile); err != nil {
fmt.Fprintf(out, "Creating %s \n", repoFile) fmt.Fprintf(out, "Creating %s \n", repoFile)
f := repo.NewRepoFile() f := repo.NewRepoFile()
sr, err := initStableRepo(home.CacheIndex(stableRepository), out, skipRefresh, home) sr, err := initRepo(url, home.CacheIndex(stableRepository), out, skipRefresh, home)
if err != nil { if err != nil {
return err return err
} }
@ -126,11 +129,11 @@ func ensureDefaultRepos(home helmpath.Home, out io.Writer, skipRefresh bool) err
return nil return nil
} }
func initStableRepo(cacheFile string, out io.Writer, skipRefresh bool, home helmpath.Home) (*repo.Entry, error) { func initRepo(url, cacheFile string, out io.Writer, skipRefresh bool, home helmpath.Home) (*repo.Entry, error) {
fmt.Fprintf(out, "Adding %s repo with URL: %s \n", stableRepository, stableRepositoryURL) fmt.Fprintf(out, "Adding %s repo with URL: %s \n", stableRepository, url)
c := repo.Entry{ c := repo.Entry{
Name: stableRepository, Name: stableRepository,
URL: stableRepositoryURL, URL: url,
Cache: cacheFile, Cache: cacheFile,
} }
r, err := repo.NewChartRepository(&c, getter.All(settings)) r, err := repo.NewChartRepository(&c, getter.All(settings))
@ -145,7 +148,7 @@ func initStableRepo(cacheFile string, out io.Writer, skipRefresh bool, home helm
// In this case, the cacheFile is always absolute. So passing empty string // In this case, the cacheFile is always absolute. So passing empty string
// is safe. // is safe.
if err := r.DownloadIndexFile(""); err != nil { if err := r.DownloadIndexFile(""); err != nil {
return nil, fmt.Errorf("Looks like %q is not a valid chart repository or cannot be reached: %s", stableRepositoryURL, err.Error()) return nil, fmt.Errorf("Looks like %q is not a valid chart repository or cannot be reached: %s", url, err.Error())
} }
return &c, nil return &c, nil

@ -38,10 +38,10 @@ func TestEnsureHome(t *testing.T) {
if err := ensureDirectories(hh, b); err != nil { if err := ensureDirectories(hh, b); err != nil {
t.Error(err) t.Error(err)
} }
if err := ensureDefaultRepos(hh, b, false); err != nil { if err := ensureDefaultRepos(hh, b, false, defaultStableRepositoryURL); err != nil {
t.Error(err) t.Error(err)
} }
if err := ensureDefaultRepos(hh, b, true); err != nil { if err := ensureDefaultRepos(hh, b, true, defaultStableRepositoryURL); err != nil {
t.Error(err) t.Error(err)
} }
if err := ensureRepoFileFormat(hh.RepositoryFile(), b); err != nil { if err := ensureRepoFileFormat(hh.RepositoryFile(), b); err != nil {

@ -50,7 +50,7 @@ This command inspects a chart (directory, file, or URL) and displays the content
of the README file of the README file
` `
type inspectCmd struct { type inspectOptions struct {
chartpath string chartpath string
output string output string
verify bool verify bool
@ -59,10 +59,9 @@ type inspectCmd struct {
repoURL string repoURL string
username string username string
password string password string
certFile string
certFile string keyFile string
keyFile string caFile string
caFile string
} }
const ( const (
@ -75,7 +74,7 @@ const (
var readmeFileNames = []string{"readme.md", "readme.txt", "readme"} var readmeFileNames = []string{"readme.md", "readme.txt", "readme"}
func newInspectCmd(out io.Writer) *cobra.Command { func newInspectCmd(out io.Writer) *cobra.Command {
insp := &inspectCmd{output: all} o := &inspectOptions{output: all}
inspectCommand := &cobra.Command{ inspectCommand := &cobra.Command{
Use: "inspect [CHART]", Use: "inspect [CHART]",
@ -85,13 +84,13 @@ func newInspectCmd(out io.Writer) *cobra.Command {
if err := checkArgsLength(len(args), "chart name"); err != nil { if err := checkArgsLength(len(args), "chart name"); err != nil {
return err return err
} }
cp, err := locateChartPath(insp.repoURL, insp.username, insp.password, args[0], insp.version, insp.verify, insp.keyring, cp, err := locateChartPath(o.repoURL, o.username, o.password, args[0], o.version, o.verify, o.keyring,
insp.certFile, insp.keyFile, insp.caFile) o.certFile, o.keyFile, o.caFile)
if err != nil { if err != nil {
return err return err
} }
insp.chartpath = cp o.chartpath = cp
return insp.run(out) return o.run(out)
}, },
} }
@ -100,17 +99,17 @@ func newInspectCmd(out io.Writer) *cobra.Command {
Short: "shows inspect values", Short: "shows inspect values",
Long: inspectValuesDesc, Long: inspectValuesDesc,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
insp.output = valuesOnly o.output = valuesOnly
if err := checkArgsLength(len(args), "chart name"); err != nil { if err := checkArgsLength(len(args), "chart name"); err != nil {
return err return err
} }
cp, err := locateChartPath(insp.repoURL, insp.username, insp.password, args[0], insp.version, insp.verify, insp.keyring, cp, err := locateChartPath(o.repoURL, o.username, o.password, args[0], o.version, o.verify, o.keyring,
insp.certFile, insp.keyFile, insp.caFile) o.certFile, o.keyFile, o.caFile)
if err != nil { if err != nil {
return err return err
} }
insp.chartpath = cp o.chartpath = cp
return insp.run(out) return o.run(out)
}, },
} }
@ -119,17 +118,17 @@ func newInspectCmd(out io.Writer) *cobra.Command {
Short: "shows inspect chart", Short: "shows inspect chart",
Long: inspectChartDesc, Long: inspectChartDesc,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
insp.output = chartOnly o.output = chartOnly
if err := checkArgsLength(len(args), "chart name"); err != nil { if err := checkArgsLength(len(args), "chart name"); err != nil {
return err return err
} }
cp, err := locateChartPath(insp.repoURL, insp.username, insp.password, args[0], insp.version, insp.verify, insp.keyring, cp, err := locateChartPath(o.repoURL, o.username, o.password, args[0], o.version, o.verify, o.keyring,
insp.certFile, insp.keyFile, insp.caFile) o.certFile, o.keyFile, o.caFile)
if err != nil { if err != nil {
return err return err
} }
insp.chartpath = cp o.chartpath = cp
return insp.run(out) return o.run(out)
}, },
} }
@ -138,17 +137,17 @@ func newInspectCmd(out io.Writer) *cobra.Command {
Short: "shows inspect readme", Short: "shows inspect readme",
Long: readmeChartDesc, Long: readmeChartDesc,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
insp.output = readmeOnly o.output = readmeOnly
if err := checkArgsLength(len(args), "chart name"); err != nil { if err := checkArgsLength(len(args), "chart name"); err != nil {
return err return err
} }
cp, err := locateChartPath(insp.repoURL, insp.username, insp.password, args[0], insp.version, insp.verify, insp.keyring, cp, err := locateChartPath(o.repoURL, o.username, o.password, args[0], o.version, o.verify, o.keyring,
insp.certFile, insp.keyFile, insp.caFile) o.certFile, o.keyFile, o.caFile)
if err != nil { if err != nil {
return err return err
} }
insp.chartpath = cp o.chartpath = cp
return insp.run(out) return o.run(out)
}, },
} }
@ -156,56 +155,56 @@ func newInspectCmd(out io.Writer) *cobra.Command {
vflag := "verify" vflag := "verify"
vdesc := "verify the provenance data for this chart" vdesc := "verify the provenance data for this chart"
for _, subCmd := range cmds { for _, subCmd := range cmds {
subCmd.Flags().BoolVar(&insp.verify, vflag, false, vdesc) subCmd.Flags().BoolVar(&o.verify, vflag, false, vdesc)
} }
kflag := "keyring" kflag := "keyring"
kdesc := "path to the keyring containing public verification keys" kdesc := "path to the keyring containing public verification keys"
kdefault := defaultKeyring() kdefault := defaultKeyring()
for _, subCmd := range cmds { for _, subCmd := range cmds {
subCmd.Flags().StringVar(&insp.keyring, kflag, kdefault, kdesc) subCmd.Flags().StringVar(&o.keyring, kflag, kdefault, kdesc)
} }
verflag := "version" verflag := "version"
verdesc := "version of the chart. By default, the newest chart is shown" verdesc := "version of the chart. By default, the newest chart is shown"
for _, subCmd := range cmds { for _, subCmd := range cmds {
subCmd.Flags().StringVar(&insp.version, verflag, "", verdesc) subCmd.Flags().StringVar(&o.version, verflag, "", verdesc)
} }
repoURL := "repo" repoURL := "repo"
repoURLdesc := "chart repository url where to locate the requested chart" repoURLdesc := "chart repository url where to locate the requested chart"
for _, subCmd := range cmds { for _, subCmd := range cmds {
subCmd.Flags().StringVar(&insp.repoURL, repoURL, "", repoURLdesc) subCmd.Flags().StringVar(&o.repoURL, repoURL, "", repoURLdesc)
} }
username := "username" username := "username"
usernamedesc := "chart repository username where to locate the requested chart" usernamedesc := "chart repository username where to locate the requested chart"
inspectCommand.Flags().StringVar(&insp.username, username, "", usernamedesc) inspectCommand.Flags().StringVar(&o.username, username, "", usernamedesc)
valuesSubCmd.Flags().StringVar(&insp.username, username, "", usernamedesc) valuesSubCmd.Flags().StringVar(&o.username, username, "", usernamedesc)
chartSubCmd.Flags().StringVar(&insp.username, username, "", usernamedesc) chartSubCmd.Flags().StringVar(&o.username, username, "", usernamedesc)
password := "password" password := "password"
passworddesc := "chart repository password where to locate the requested chart" passworddesc := "chart repository password where to locate the requested chart"
inspectCommand.Flags().StringVar(&insp.password, password, "", passworddesc) inspectCommand.Flags().StringVar(&o.password, password, "", passworddesc)
valuesSubCmd.Flags().StringVar(&insp.password, password, "", passworddesc) valuesSubCmd.Flags().StringVar(&o.password, password, "", passworddesc)
chartSubCmd.Flags().StringVar(&insp.password, password, "", passworddesc) chartSubCmd.Flags().StringVar(&o.password, password, "", passworddesc)
certFile := "cert-file" certFile := "cert-file"
certFiledesc := "verify certificates of HTTPS-enabled servers using this CA bundle" certFiledesc := "verify certificates of HTTPS-enabled servers using this CA bundle"
for _, subCmd := range cmds { for _, subCmd := range cmds {
subCmd.Flags().StringVar(&insp.certFile, certFile, "", certFiledesc) subCmd.Flags().StringVar(&o.certFile, certFile, "", certFiledesc)
} }
keyFile := "key-file" keyFile := "key-file"
keyFiledesc := "identify HTTPS client using this SSL key file" keyFiledesc := "identify HTTPS client using this SSL key file"
for _, subCmd := range cmds { for _, subCmd := range cmds {
subCmd.Flags().StringVar(&insp.keyFile, keyFile, "", keyFiledesc) subCmd.Flags().StringVar(&o.keyFile, keyFile, "", keyFiledesc)
} }
caFile := "ca-file" caFile := "ca-file"
caFiledesc := "chart repository url where to locate the requested chart" caFiledesc := "chart repository url where to locate the requested chart"
for _, subCmd := range cmds { for _, subCmd := range cmds {
subCmd.Flags().StringVar(&insp.caFile, caFile, "", caFiledesc) subCmd.Flags().StringVar(&o.caFile, caFile, "", caFiledesc)
} }
for _, subCmd := range cmds[1:] { for _, subCmd := range cmds[1:] {
@ -215,7 +214,7 @@ func newInspectCmd(out io.Writer) *cobra.Command {
return inspectCommand return inspectCommand
} }
func (i *inspectCmd) run(out io.Writer) error { func (i *inspectOptions) run(out io.Writer) error {
chrt, err := chartutil.Load(i.chartpath) chrt, err := chartutil.Load(i.chartpath)
if err != nil { if err != nil {
return err return err

@ -26,11 +26,11 @@ import (
func TestInspect(t *testing.T) { func TestInspect(t *testing.T) {
b := bytes.NewBuffer(nil) b := bytes.NewBuffer(nil)
insp := &inspectCmd{ o := &inspectOptions{
chartpath: "testdata/testcharts/alpine", chartpath: "testdata/testcharts/alpine",
output: all, output: all,
} }
insp.run(b) o.run(b)
// Load the data from the textfixture directly. // Load the data from the textfixture directly.
cdata, err := ioutil.ReadFile("testdata/testcharts/alpine/Chart.yaml") cdata, err := ioutil.ReadFile("testdata/testcharts/alpine/Chart.yaml")
@ -67,11 +67,11 @@ func TestInspect(t *testing.T) {
// Regression tests for missing values. See issue #1024. // Regression tests for missing values. See issue #1024.
b.Reset() b.Reset()
insp = &inspectCmd{ o = &inspectOptions{
chartpath: "testdata/testcharts/novals", chartpath: "testdata/testcharts/novals",
output: "values", output: "values",
} }
insp.run(b) o.run(b)
if b.Len() != 0 { if b.Len() != 0 {
t.Errorf("expected empty values buffer, got %q", b.String()) t.Errorf("expected empty values buffer, got %q", b.String())
} }

@ -104,7 +104,7 @@ To see the list of chart repositories, use 'helm repo list'. To search for
charts in a repository, use 'helm search'. charts in a repository, use 'helm search'.
` `
type installCmd struct { type installOptions struct {
name string // --name name string // --name
valueFiles valueFiles // --values valueFiles valueFiles // --values
dryRun bool // --dry-run dryRun bool // --dry-run
@ -149,7 +149,7 @@ func (v *valueFiles) Set(value string) error {
} }
func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command { func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
inst := &installCmd{client: c} o := &installOptions{client: c}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "install [CHART]", Use: "install [CHART]",
@ -160,69 +160,69 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
return err return err
} }
debug("Original chart version: %q", inst.version) debug("Original chart version: %q", o.version)
if inst.version == "" && inst.devel { if o.version == "" && o.devel {
debug("setting version to >0.0.0-0") debug("setting version to >0.0.0-0")
inst.version = ">0.0.0-0" o.version = ">0.0.0-0"
} }
cp, err := locateChartPath(inst.repoURL, inst.username, inst.password, args[0], inst.version, inst.verify, inst.keyring, cp, err := locateChartPath(o.repoURL, o.username, o.password, args[0], o.version, o.verify, o.keyring,
inst.certFile, inst.keyFile, inst.caFile) o.certFile, o.keyFile, o.caFile)
if err != nil { if err != nil {
return err return err
} }
inst.chartPath = cp o.chartPath = cp
inst.client = ensureHelmClient(inst.client, false) o.client = ensureHelmClient(o.client, false)
return inst.run(out) return o.run(out)
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.VarP(&inst.valueFiles, "values", "f", "specify values in a YAML file or a URL(can specify multiple)") f.VarP(&o.valueFiles, "values", "f", "specify values in a YAML file or a URL(can specify multiple)")
f.StringVarP(&inst.name, "name", "", "", "release name. If unspecified, it will autogenerate one for you") f.StringVarP(&o.name, "name", "", "", "release name. If unspecified, it will autogenerate one for you")
f.BoolVar(&inst.dryRun, "dry-run", false, "simulate an install") f.BoolVar(&o.dryRun, "dry-run", false, "simulate an install")
f.BoolVar(&inst.disableHooks, "no-hooks", false, "prevent hooks from running during install") f.BoolVar(&o.disableHooks, "no-hooks", false, "prevent hooks from running during install")
f.BoolVar(&inst.replace, "replace", false, "re-use the given name, even if that name is already used. This is unsafe in production") f.BoolVar(&o.replace, "replace", false, "re-use the given name, even if that name is already used. This is unsafe in production")
f.StringArrayVar(&inst.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") f.StringArrayVar(&o.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
f.StringArrayVar(&inst.stringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") f.StringArrayVar(&o.stringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
f.StringVar(&inst.nameTemplate, "name-template", "", "specify template used to name the release") f.StringVar(&o.nameTemplate, "name-template", "", "specify template used to name the release")
f.BoolVar(&inst.verify, "verify", false, "verify the package before installing it") f.BoolVar(&o.verify, "verify", false, "verify the package before installing it")
f.StringVar(&inst.keyring, "keyring", defaultKeyring(), "location of public keys used for verification") f.StringVar(&o.keyring, "keyring", defaultKeyring(), "location of public keys used for verification")
f.StringVar(&inst.version, "version", "", "specify the exact chart version to install. If this is not specified, the latest version is installed") f.StringVar(&o.version, "version", "", "specify the exact chart version to install. If this is not specified, the latest version is installed")
f.Int64Var(&inst.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)") f.Int64Var(&o.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)")
f.BoolVar(&inst.wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout") f.BoolVar(&o.wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout")
f.StringVar(&inst.repoURL, "repo", "", "chart repository url where to locate the requested chart") f.StringVar(&o.repoURL, "repo", "", "chart repository url where to locate the requested chart")
f.StringVar(&inst.username, "username", "", "chart repository username where to locate the requested chart") f.StringVar(&o.username, "username", "", "chart repository username where to locate the requested chart")
f.StringVar(&inst.password, "password", "", "chart repository password where to locate the requested chart") f.StringVar(&o.password, "password", "", "chart repository password where to locate the requested chart")
f.StringVar(&inst.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file") f.StringVar(&o.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
f.StringVar(&inst.keyFile, "key-file", "", "identify HTTPS client using this SSL key file") f.StringVar(&o.keyFile, "key-file", "", "identify HTTPS client using this SSL key file")
f.StringVar(&inst.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
f.BoolVar(&inst.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.") f.BoolVar(&o.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.")
f.BoolVar(&inst.depUp, "dep-up", false, "run helm dependency update before installing the chart") f.BoolVar(&o.depUp, "dep-up", false, "run helm dependency update before installing the chart")
return cmd return cmd
} }
func (i *installCmd) run(out io.Writer) error { func (o *installOptions) run(out io.Writer) error {
debug("CHART PATH: %s\n", i.chartPath) debug("CHART PATH: %s\n", o.chartPath)
rawVals, err := vals(i.valueFiles, i.values, i.stringValues) rawVals, err := vals(o.valueFiles, o.values, o.stringValues)
if err != nil { if err != nil {
return err return err
} }
// If template is specified, try to run the template. // If template is specified, try to run the template.
if i.nameTemplate != "" { if o.nameTemplate != "" {
i.name, err = generateName(i.nameTemplate) o.name, err = generateName(o.nameTemplate)
if err != nil { if err != nil {
return err return err
} }
// Print the final name so the user knows what the final name of the release is. // Print the final name so the user knows what the final name of the release is.
fmt.Printf("FINAL NAME: %s\n", i.name) fmt.Printf("FINAL NAME: %s\n", o.name)
} }
// Check chart requirements to make sure all dependencies are present in /charts // Check chart requirements to make sure all dependencies are present in /charts
chartRequested, err := chartutil.Load(i.chartPath) chartRequested, err := chartutil.Load(o.chartPath)
if err != nil { if err != nil {
return err return err
} }
@ -232,10 +232,10 @@ func (i *installCmd) run(out io.Writer) error {
// As of Helm 2.4.0, this is treated as a stopping condition: // As of Helm 2.4.0, this is treated as a stopping condition:
// https://github.com/kubernetes/helm/issues/2209 // https://github.com/kubernetes/helm/issues/2209
if err := checkDependencies(chartRequested, req); err != nil { if err := checkDependencies(chartRequested, req); err != nil {
if i.depUp { if o.depUp {
man := &downloader.Manager{ man := &downloader.Manager{
Out: out, Out: out,
ChartPath: i.chartPath, ChartPath: o.chartPath,
HelmHome: settings.Home, HelmHome: settings.Home,
Keyring: defaultKeyring(), Keyring: defaultKeyring(),
SkipUpdate: false, SkipUpdate: false,
@ -253,16 +253,16 @@ func (i *installCmd) run(out io.Writer) error {
return fmt.Errorf("cannot load requirements: %v", err) return fmt.Errorf("cannot load requirements: %v", err)
} }
rel, err := i.client.InstallReleaseFromChart( rel, err := o.client.InstallReleaseFromChart(
chartRequested, chartRequested,
getNamespace(), getNamespace(),
helm.ValueOverrides(rawVals), helm.ValueOverrides(rawVals),
helm.ReleaseName(i.name), helm.ReleaseName(o.name),
helm.InstallDryRun(i.dryRun), helm.InstallDryRun(o.dryRun),
helm.InstallReuseName(i.replace), helm.InstallReuseName(o.replace),
helm.InstallDisableHooks(i.disableHooks), helm.InstallDisableHooks(o.disableHooks),
helm.InstallTimeout(i.timeout), helm.InstallTimeout(o.timeout),
helm.InstallWait(i.wait)) helm.InstallWait(o.wait))
if err != nil { if err != nil {
return err return err
} }
@ -270,15 +270,15 @@ func (i *installCmd) run(out io.Writer) error {
if rel == nil { if rel == nil {
return nil return nil
} }
i.printRelease(out, rel) o.printRelease(out, rel)
// If this is a dry run, we can't display status. // If this is a dry run, we can't display status.
if i.dryRun { if o.dryRun {
return nil return nil
} }
// Print the status like status command does // Print the status like status command does
status, err := i.client.ReleaseStatus(rel.Name, 0) status, err := o.client.ReleaseStatus(rel.Name, 0)
if err != nil { if err != nil {
return err return err
} }
@ -359,7 +359,7 @@ func vals(valueFiles valueFiles, values []string, stringValues []string) ([]byte
} }
// printRelease prints info about a release if the Debug is true. // printRelease prints info about a release if the Debug is true.
func (i *installCmd) printRelease(out io.Writer, rel *release.Release) { func (o *installOptions) printRelease(out io.Writer, rel *release.Release) {
if rel == nil { if rel == nil {
return return
} }

@ -43,7 +43,7 @@ it will emit [ERROR] messages. If it encounters issues that break with conventio
or recommendation, it will emit [WARNING] messages. or recommendation, it will emit [WARNING] messages.
` `
type lintCmd struct { type lintOptions struct {
valueFiles valueFiles valueFiles valueFiles
values []string values []string
sValues []string sValues []string
@ -52,7 +52,7 @@ type lintCmd struct {
} }
func newLintCmd(out io.Writer) *cobra.Command { func newLintCmd(out io.Writer) *cobra.Command {
l := &lintCmd{paths: []string{"."}} o := &lintOptions{paths: []string{"."}}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "lint [flags] PATH", Use: "lint [flags] PATH",
@ -60,40 +60,40 @@ func newLintCmd(out io.Writer) *cobra.Command {
Long: longLintHelp, Long: longLintHelp,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 { if len(args) > 0 {
l.paths = args o.paths = args
} }
return l.run(out) return o.run(out)
}, },
} }
cmd.Flags().VarP(&l.valueFiles, "values", "f", "specify values in a YAML file (can specify multiple)") cmd.Flags().VarP(&o.valueFiles, "values", "f", "specify values in a YAML file (can specify multiple)")
cmd.Flags().StringArrayVar(&l.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") cmd.Flags().StringArrayVar(&o.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
cmd.Flags().StringArrayVar(&l.sValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") cmd.Flags().StringArrayVar(&o.sValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
cmd.Flags().BoolVar(&l.strict, "strict", false, "fail on lint warnings") cmd.Flags().BoolVar(&o.strict, "strict", false, "fail on lint warnings")
return cmd return cmd
} }
var errLintNoChart = errors.New("No chart found for linting (missing Chart.yaml)") var errLintNoChart = errors.New("No chart found for linting (missing Chart.yaml)")
func (l *lintCmd) run(out io.Writer) error { func (o *lintOptions) run(out io.Writer) error {
var lowestTolerance int var lowestTolerance int
if l.strict { if o.strict {
lowestTolerance = support.WarningSev lowestTolerance = support.WarningSev
} else { } else {
lowestTolerance = support.ErrorSev lowestTolerance = support.ErrorSev
} }
// Get the raw values // Get the raw values
rvals, err := l.vals() rvals, err := o.vals()
if err != nil { if err != nil {
return err return err
} }
var total int var total int
var failures int var failures int
for _, path := range l.paths { for _, path := range o.paths {
if linter, err := lintChart(path, rvals, getNamespace(), l.strict); err != nil { if linter, err := lintChart(path, rvals, getNamespace(), o.strict); err != nil {
fmt.Println("==> Skipping", path) fmt.Println("==> Skipping", path)
fmt.Println(err) fmt.Println(err)
if err == errLintNoChart { if err == errLintNoChart {
@ -167,11 +167,11 @@ func lintChart(path string, vals []byte, namespace string, strict bool) (support
return lint.All(chartPath, vals, namespace, strict), nil return lint.All(chartPath, vals, namespace, strict), nil
} }
func (l *lintCmd) vals() ([]byte, error) { func (o *lintOptions) vals() ([]byte, error) {
base := map[string]interface{}{} base := map[string]interface{}{}
// User specified a values files via -f/--values // User specified a values files via -f/--values
for _, filePath := range l.valueFiles { for _, filePath := range o.valueFiles {
currentMap := map[string]interface{}{} currentMap := map[string]interface{}{}
bytes, err := ioutil.ReadFile(filePath) bytes, err := ioutil.ReadFile(filePath)
if err != nil { if err != nil {
@ -186,14 +186,14 @@ func (l *lintCmd) vals() ([]byte, error) {
} }
// User specified a value via --set // User specified a value via --set
for _, value := range l.values { for _, value := range o.values {
if err := strvals.ParseInto(value, base); err != nil { if err := strvals.ParseInto(value, base); err != nil {
return []byte{}, fmt.Errorf("failed parsing --set data: %s", err) return []byte{}, fmt.Errorf("failed parsing --set data: %s", err)
} }
} }
// User specified a value via --set-string // User specified a value via --set-string
for _, value := range l.sValues { for _, value := range o.sValues {
if err := strvals.ParseIntoString(value, base); err != nil { if err := strvals.ParseIntoString(value, base); err != nil {
return []byte{}, fmt.Errorf("failed parsing --set-string data: %s", err) return []byte{}, fmt.Errorf("failed parsing --set-string data: %s", err)
} }

@ -56,27 +56,31 @@ server's default, which may be much higher than 256. Pairing the '--max'
flag with the '--offset' flag allows you to page through results. flag with the '--offset' flag allows you to page through results.
` `
type listCmd struct { type listOptions struct {
filter string // flags
short bool all bool // --all
limit int allNamespaces bool // --all-namespaces
offset string byDate bool // --date
byDate bool colWidth uint // --col-width
sortDesc bool deleted bool // --deleted
all bool deleting bool // --deleting
deleted bool deployed bool // --deployed
deleting bool failed bool // --failed
deployed bool limit int // --max
failed bool offset string // --offset
superseded bool pending bool // --pending
pending bool short bool // --short
client helm.Interface sortDesc bool // --reverse
colWidth uint superseded bool // --superseded
allNamespaces bool
// args
filter string
client helm.Interface
} }
func newListCmd(client helm.Interface, out io.Writer) *cobra.Command { func newListCmd(client helm.Interface, out io.Writer) *cobra.Command {
list := &listCmd{client: client} o := &listOptions{client: client}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "list [flags] [FILTER]", Use: "list [flags] [FILTER]",
@ -85,48 +89,49 @@ func newListCmd(client helm.Interface, out io.Writer) *cobra.Command {
Aliases: []string{"ls"}, Aliases: []string{"ls"},
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 { if len(args) > 0 {
list.filter = strings.Join(args, " ") o.filter = strings.Join(args, " ")
} }
list.client = ensureHelmClient(list.client, list.allNamespaces) o.client = ensureHelmClient(o.client, o.allNamespaces)
return list.run(out) return o.run(out)
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.BoolVarP(&list.short, "short", "q", false, "output short (quiet) listing format") f.BoolVarP(&o.short, "short", "q", false, "output short (quiet) listing format")
f.BoolVarP(&list.byDate, "date", "d", false, "sort by release date") f.BoolVarP(&o.byDate, "date", "d", false, "sort by release date")
f.BoolVarP(&list.sortDesc, "reverse", "r", false, "reverse the sort order") f.BoolVarP(&o.sortDesc, "reverse", "r", false, "reverse the sort order")
f.IntVarP(&list.limit, "max", "m", 256, "maximum number of releases to fetch") f.IntVarP(&o.limit, "max", "m", 256, "maximum number of releases to fetch")
f.StringVarP(&list.offset, "offset", "o", "", "next release name in the list, used to offset from start value") f.StringVarP(&o.offset, "offset", "o", "", "next release name in the list, used to offset from start value")
f.BoolVarP(&list.all, "all", "a", false, "show all releases, not just the ones marked deployed") f.BoolVarP(&o.all, "all", "a", false, "show all releases, not just the ones marked deployed")
f.BoolVar(&list.deleted, "deleted", false, "show deleted releases") f.BoolVar(&o.deleted, "deleted", false, "show deleted releases")
f.BoolVar(&list.deleting, "deleting", false, "show releases that are currently being deleted") f.BoolVar(&o.superseded, "superseded", false, "show superseded releases")
f.BoolVar(&list.deployed, "deployed", false, "show deployed releases. If no other is specified, this will be automatically enabled") f.BoolVar(&o.deleting, "deleting", false, "show releases that are currently being deleted")
f.BoolVar(&list.failed, "failed", false, "show failed releases") f.BoolVar(&o.deployed, "deployed", false, "show deployed releases. If no other is specified, this will be automatically enabled")
f.BoolVar(&list.pending, "pending", false, "show pending releases") f.BoolVar(&o.failed, "failed", false, "show failed releases")
f.UintVar(&list.colWidth, "col-width", 60, "specifies the max column width of output") f.BoolVar(&o.pending, "pending", false, "show pending releases")
f.BoolVar(&list.allNamespaces, "all-namespaces", false, "list releases across all namespaces") f.UintVar(&o.colWidth, "col-width", 60, "specifies the max column width of output")
f.BoolVar(&o.allNamespaces, "all-namespaces", false, "list releases across all namespaces")
return cmd return cmd
} }
func (l *listCmd) run(out io.Writer) error { func (o *listOptions) run(out io.Writer) error {
sortBy := hapi.SortByName sortBy := hapi.SortByName
if l.byDate { if o.byDate {
sortBy = hapi.SortByLastReleased sortBy = hapi.SortByLastReleased
} }
sortOrder := hapi.SortAsc sortOrder := hapi.SortAsc
if l.sortDesc { if o.sortDesc {
sortOrder = hapi.SortDesc sortOrder = hapi.SortDesc
} }
stats := l.statusCodes() stats := o.statusCodes()
res, err := l.client.ListReleases( res, err := o.client.ListReleases(
helm.ReleaseListLimit(l.limit), helm.ReleaseListLimit(o.limit),
helm.ReleaseListOffset(l.offset), helm.ReleaseListOffset(o.offset),
helm.ReleaseListFilter(l.filter), helm.ReleaseListFilter(o.filter),
helm.ReleaseListSort(sortBy), helm.ReleaseListSort(sortBy),
helm.ReleaseListOrder(sortOrder), helm.ReleaseListOrder(sortOrder),
helm.ReleaseListStatuses(stats), helm.ReleaseListStatuses(stats),
@ -142,13 +147,13 @@ func (l *listCmd) run(out io.Writer) error {
rels := filterList(res) rels := filterList(res)
if l.short { if o.short {
for _, r := range rels { for _, r := range rels {
fmt.Fprintln(out, r.Name) fmt.Fprintln(out, r.Name)
} }
return nil return nil
} }
fmt.Fprintln(out, formatList(rels, l.colWidth)) fmt.Fprintln(out, formatList(rels, o.colWidth))
return nil return nil
} }
@ -177,8 +182,8 @@ func filterList(rels []*release.Release) []*release.Release {
} }
// statusCodes gets the list of status codes that are to be included in the results. // statusCodes gets the list of status codes that are to be included in the results.
func (l *listCmd) statusCodes() []release.ReleaseStatus { func (o *listOptions) statusCodes() []release.ReleaseStatus {
if l.all { if o.all {
return []release.ReleaseStatus{ return []release.ReleaseStatus{
release.StatusUnknown, release.StatusUnknown,
release.StatusDeployed, release.StatusDeployed,
@ -191,22 +196,22 @@ func (l *listCmd) statusCodes() []release.ReleaseStatus {
} }
} }
status := []release.ReleaseStatus{} status := []release.ReleaseStatus{}
if l.deployed { if o.deployed {
status = append(status, release.StatusDeployed) status = append(status, release.StatusDeployed)
} }
if l.deleted { if o.deleted {
status = append(status, release.StatusDeleted) status = append(status, release.StatusDeleted)
} }
if l.deleting { if o.deleting {
status = append(status, release.StatusDeleting) status = append(status, release.StatusDeleting)
} }
if l.failed { if o.failed {
status = append(status, release.StatusFailed) status = append(status, release.StatusFailed)
} }
if l.superseded { if o.superseded {
status = append(status, release.StatusSuperseded) status = append(status, release.StatusSuperseded)
} }
if l.pending { if o.pending {
status = append(status, release.StatusPendingInstall, release.StatusPendingUpgrade, release.StatusPendingRollback) status = append(status, release.StatusPendingInstall, release.StatusPendingUpgrade, release.StatusPendingRollback)
} }

@ -49,45 +49,47 @@ Chart.yaml file, and (if found) build the current directory into a chart.
Versioned chart archives are used by Helm package repositories. Versioned chart archives are used by Helm package repositories.
` `
type packageCmd struct { type packageOptions struct {
sign bool appVersion string // --app-version
path string dependencyUpdate bool // --dependency-update
valueFiles valueFiles destination string // --destination
values []string key string // --key
stringValues []string keyring string // --keyring
key string sign bool // --sign
keyring string stringValues []string // --set-string
version string valueFiles valueFiles // --values
appVersion string values []string // --set
destination string version string // --version
dependencyUpdate bool
// args
path string
home helmpath.Home home helmpath.Home
} }
func newPackageCmd(out io.Writer) *cobra.Command { func newPackageCmd(out io.Writer) *cobra.Command {
pkg := &packageCmd{} o := &packageOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "package [flags] [CHART_PATH] [...]", Use: "package [flags] [CHART_PATH] [...]",
Short: "package a chart directory into a chart archive", Short: "package a chart directory into a chart archive",
Long: packageDesc, Long: packageDesc,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
pkg.home = settings.Home o.home = settings.Home
if len(args) == 0 { if len(args) == 0 {
return fmt.Errorf("need at least one argument, the path to the chart") return fmt.Errorf("need at least one argument, the path to the chart")
} }
if pkg.sign { if o.sign {
if pkg.key == "" { if o.key == "" {
return errors.New("--key is required for signing a package") return errors.New("--key is required for signing a package")
} }
if pkg.keyring == "" { if o.keyring == "" {
return errors.New("--keyring is required for signing a package") return errors.New("--keyring is required for signing a package")
} }
} }
for i := 0; i < len(args); i++ { for i := 0; i < len(args); i++ {
pkg.path = args[i] o.path = args[i]
if err := pkg.run(out); err != nil { if err := o.run(out); err != nil {
return err return err
} }
} }
@ -96,32 +98,32 @@ func newPackageCmd(out io.Writer) *cobra.Command {
} }
f := cmd.Flags() f := cmd.Flags()
f.VarP(&pkg.valueFiles, "values", "f", "specify values in a YAML file or a URL(can specify multiple)") f.VarP(&o.valueFiles, "values", "f", "specify values in a YAML file or a URL(can specify multiple)")
f.StringArrayVar(&pkg.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") f.StringArrayVar(&o.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
f.StringArrayVar(&pkg.stringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") f.StringArrayVar(&o.stringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
f.BoolVar(&pkg.sign, "sign", false, "use a PGP private key to sign this package") f.BoolVar(&o.sign, "sign", false, "use a PGP private key to sign this package")
f.StringVar(&pkg.key, "key", "", "name of the key to use when signing. Used if --sign is true") f.StringVar(&o.key, "key", "", "name of the key to use when signing. Used if --sign is true")
f.StringVar(&pkg.keyring, "keyring", defaultKeyring(), "location of a public keyring") f.StringVar(&o.keyring, "keyring", defaultKeyring(), "location of a public keyring")
f.StringVar(&pkg.version, "version", "", "set the version on the chart to this semver version") f.StringVar(&o.version, "version", "", "set the version on the chart to this semver version")
f.StringVar(&pkg.appVersion, "app-version", "", "set the appVersion on the chart to this version") f.StringVar(&o.appVersion, "app-version", "", "set the appVersion on the chart to this version")
f.StringVarP(&pkg.destination, "destination", "d", ".", "location to write the chart.") f.StringVarP(&o.destination, "destination", "d", ".", "location to write the chart.")
f.BoolVarP(&pkg.dependencyUpdate, "dependency-update", "u", false, `update dependencies from "requirements.yaml" to dir "charts/" before packaging`) f.BoolVarP(&o.dependencyUpdate, "dependency-update", "u", false, `update dependencies from "requirements.yaml" to dir "charts/" before packaging`)
return cmd return cmd
} }
func (p *packageCmd) run(out io.Writer) error { func (o *packageOptions) run(out io.Writer) error {
path, err := filepath.Abs(p.path) path, err := filepath.Abs(o.path)
if err != nil { if err != nil {
return err return err
} }
if p.dependencyUpdate { if o.dependencyUpdate {
downloadManager := &downloader.Manager{ downloadManager := &downloader.Manager{
Out: out, Out: out,
ChartPath: path, ChartPath: path,
HelmHome: settings.Home, HelmHome: settings.Home,
Keyring: p.keyring, Keyring: o.keyring,
Getters: getter.All(settings), Getters: getter.All(settings),
Debug: settings.Debug, Debug: settings.Debug,
} }
@ -136,7 +138,7 @@ func (p *packageCmd) run(out io.Writer) error {
return err return err
} }
overrideVals, err := vals(p.valueFiles, p.values, p.stringValues) overrideVals, err := vals(o.valueFiles, o.values, o.stringValues)
if err != nil { if err != nil {
return err return err
} }
@ -151,16 +153,16 @@ func (p *packageCmd) run(out io.Writer) error {
ch.Values = newVals ch.Values = newVals
// If version is set, modify the version. // If version is set, modify the version.
if len(p.version) != 0 { if len(o.version) != 0 {
if err := setVersion(ch, p.version); err != nil { if err := setVersion(ch, o.version); err != nil {
return err return err
} }
debug("Setting version to %s", p.version) debug("Setting version to %s", o.version)
} }
if p.appVersion != "" { if o.appVersion != "" {
ch.Metadata.AppVersion = p.appVersion ch.Metadata.AppVersion = o.appVersion
debug("Setting appVersion to %s", p.appVersion) debug("Setting appVersion to %s", o.appVersion)
} }
if filepath.Base(path) != ch.Metadata.Name { if filepath.Base(path) != ch.Metadata.Name {
@ -178,7 +180,7 @@ func (p *packageCmd) run(out io.Writer) error {
} }
var dest string var dest string
if p.destination == "." { if o.destination == "." {
// Save to the current working directory. // Save to the current working directory.
dest, err = os.Getwd() dest, err = os.Getwd()
if err != nil { if err != nil {
@ -186,7 +188,7 @@ func (p *packageCmd) run(out io.Writer) error {
} }
} else { } else {
// Otherwise save to set destination // Otherwise save to set destination
dest = p.destination dest = o.destination
} }
name, err := chartutil.Save(ch, dest) name, err := chartutil.Save(ch, dest)
@ -196,8 +198,8 @@ func (p *packageCmd) run(out io.Writer) error {
return fmt.Errorf("Failed to save: %s", err) return fmt.Errorf("Failed to save: %s", err)
} }
if p.sign { if o.sign {
err = p.clearsign(name) err = o.clearsign(name)
} }
return err return err
@ -214,9 +216,9 @@ func setVersion(ch *chart.Chart, ver string) error {
return nil return nil
} }
func (p *packageCmd) clearsign(filename string) error { func (o *packageOptions) clearsign(filename string) error {
// Load keyring // Load keyring
signer, err := provenance.NewFromKeyring(p.keyring, p.key) signer, err := provenance.NewFromKeyring(o.keyring, o.key)
if err != nil { if err != nil {
return err return err
} }

@ -26,11 +26,10 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
type pluginInstallCmd struct { type pluginInstallOptions struct {
source string source string
version string version string
home helmpath.Home home helmpath.Home
out io.Writer
} }
const pluginInstallDesc = ` const pluginInstallDesc = `
@ -41,35 +40,35 @@ Example usage:
` `
func newPluginInstallCmd(out io.Writer) *cobra.Command { func newPluginInstallCmd(out io.Writer) *cobra.Command {
pcmd := &pluginInstallCmd{out: out} o := &pluginInstallOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "install [options] <path|url>...", Use: "install [options] <path|url>...",
Short: "install one or more Helm plugins", Short: "install one or more Helm plugins",
Long: pluginInstallDesc, Long: pluginInstallDesc,
PreRunE: func(cmd *cobra.Command, args []string) error { PreRunE: func(cmd *cobra.Command, args []string) error {
return pcmd.complete(args) return o.complete(args)
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return pcmd.run() return o.run(out)
}, },
} }
cmd.Flags().StringVar(&pcmd.version, "version", "", "specify a version constraint. If this is not specified, the latest version is installed") cmd.Flags().StringVar(&o.version, "version", "", "specify a version constraint. If this is not specified, the latest version is installed")
return cmd return cmd
} }
func (pcmd *pluginInstallCmd) complete(args []string) error { func (o *pluginInstallOptions) complete(args []string) error {
if err := checkArgsLength(len(args), "plugin"); err != nil { if err := checkArgsLength(len(args), "plugin"); err != nil {
return err return err
} }
pcmd.source = args[0] o.source = args[0]
pcmd.home = settings.Home o.home = settings.Home
return nil return nil
} }
func (pcmd *pluginInstallCmd) run() error { func (o *pluginInstallOptions) run(out io.Writer) error {
installer.Debug = settings.Debug installer.Debug = settings.Debug
i, err := installer.NewForSource(pcmd.source, pcmd.version, pcmd.home) i, err := installer.NewForSource(o.source, o.version, o.home)
if err != nil { if err != nil {
return err return err
} }
@ -87,6 +86,6 @@ func (pcmd *pluginInstallCmd) run() error {
return err return err
} }
fmt.Fprintf(pcmd.out, "Installed plugin: %s\n", p.Metadata.Name) fmt.Fprintf(out, "Installed plugin: %s\n", p.Metadata.Name)
return nil return nil
} }

@ -25,24 +25,24 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
type pluginListCmd struct { type pluginListOptions struct {
home helmpath.Home home helmpath.Home
} }
func newPluginListCmd(out io.Writer) *cobra.Command { func newPluginListCmd(out io.Writer) *cobra.Command {
pcmd := &pluginListCmd{} o := &pluginListOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "list", Use: "list",
Short: "list installed Helm plugins", Short: "list installed Helm plugins",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
pcmd.home = settings.Home o.home = settings.Home
return pcmd.run(out) return o.run(out)
}, },
} }
return cmd return cmd
} }
func (pcmd *pluginListCmd) run(out io.Writer) error { func (o *pluginListOptions) run(out io.Writer) error {
debug("pluginDirs: %s", settings.PluginDirs()) debug("pluginDirs: %s", settings.PluginDirs())
plugins, err := findPlugins(settings.PluginDirs()) plugins, err := findPlugins(settings.PluginDirs())
if err != nil { if err != nil {

@ -28,43 +28,43 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
type pluginRemoveCmd struct { type pluginRemoveOptions struct {
names []string names []string
home helmpath.Home home helmpath.Home
} }
func newPluginRemoveCmd(out io.Writer) *cobra.Command { func newPluginRemoveCmd(out io.Writer) *cobra.Command {
pcmd := &pluginRemoveCmd{} o := &pluginRemoveOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "remove <plugin>...", Use: "remove <plugin>...",
Short: "remove one or more Helm plugins", Short: "remove one or more Helm plugins",
PreRunE: func(cmd *cobra.Command, args []string) error { PreRunE: func(cmd *cobra.Command, args []string) error {
return pcmd.complete(args) return o.complete(args)
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return pcmd.run(out) return o.run(out)
}, },
} }
return cmd return cmd
} }
func (pcmd *pluginRemoveCmd) complete(args []string) error { func (o *pluginRemoveOptions) complete(args []string) error {
if len(args) == 0 { if len(args) == 0 {
return errors.New("please provide plugin name to remove") return errors.New("please provide plugin name to remove")
} }
pcmd.names = args o.names = args
pcmd.home = settings.Home o.home = settings.Home
return nil return nil
} }
func (pcmd *pluginRemoveCmd) run(out io.Writer) error { func (o *pluginRemoveOptions) run(out io.Writer) error {
debug("loading installed plugins from %s", settings.PluginDirs()) debug("loading installed plugins from %s", settings.PluginDirs())
plugins, err := findPlugins(settings.PluginDirs()) plugins, err := findPlugins(settings.PluginDirs())
if err != nil { if err != nil {
return err return err
} }
var errorPlugins []string var errorPlugins []string
for _, name := range pcmd.names { for _, name := range o.names {
if found := findPlugin(plugins, name); found != nil { if found := findPlugin(plugins, name); found != nil {
if err := removePlugin(found); err != nil { if err := removePlugin(found); err != nil {
errorPlugins = append(errorPlugins, fmt.Sprintf("Failed to remove plugin %s, got error (%v)", name, err)) errorPlugins = append(errorPlugins, fmt.Sprintf("Failed to remove plugin %s, got error (%v)", name, err))

@ -29,36 +29,36 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
type pluginUpdateCmd struct { type pluginUpdateOptions struct {
names []string names []string
home helmpath.Home home helmpath.Home
} }
func newPluginUpdateCmd(out io.Writer) *cobra.Command { func newPluginUpdateCmd(out io.Writer) *cobra.Command {
pcmd := &pluginUpdateCmd{} o := &pluginUpdateOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "update <plugin>...", Use: "update <plugin>...",
Short: "update one or more Helm plugins", Short: "update one or more Helm plugins",
PreRunE: func(cmd *cobra.Command, args []string) error { PreRunE: func(cmd *cobra.Command, args []string) error {
return pcmd.complete(args) return o.complete(args)
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return pcmd.run(out) return o.run(out)
}, },
} }
return cmd return cmd
} }
func (pcmd *pluginUpdateCmd) complete(args []string) error { func (o *pluginUpdateOptions) complete(args []string) error {
if len(args) == 0 { if len(args) == 0 {
return errors.New("please provide plugin name to update") return errors.New("please provide plugin name to update")
} }
pcmd.names = args o.names = args
pcmd.home = settings.Home o.home = settings.Home
return nil return nil
} }
func (pcmd *pluginUpdateCmd) run(out io.Writer) error { func (o *pluginUpdateOptions) run(out io.Writer) error {
installer.Debug = settings.Debug installer.Debug = settings.Debug
debug("loading installed plugins from %s", settings.PluginDirs()) debug("loading installed plugins from %s", settings.PluginDirs())
plugins, err := findPlugins(settings.PluginDirs()) plugins, err := findPlugins(settings.PluginDirs())
@ -67,9 +67,9 @@ func (pcmd *pluginUpdateCmd) run(out io.Writer) error {
} }
var errorPlugins []string var errorPlugins []string
for _, name := range pcmd.names { for _, name := range o.names {
if found := findPlugin(plugins, name); found != nil { if found := findPlugin(plugins, name); found != nil {
if err := updatePlugin(found, pcmd.home); err != nil { if err := updatePlugin(found, o.home); err != nil {
errorPlugins = append(errorPlugins, fmt.Sprintf("Failed to update plugin %s, got error (%v)", name, err)) errorPlugins = append(errorPlugins, fmt.Sprintf("Failed to update plugin %s, got error (%v)", name, err))
} else { } else {
fmt.Fprintf(out, "Updated plugin: %s\n", name) fmt.Fprintf(out, "Updated plugin: %s\n", name)

@ -33,7 +33,7 @@ The argument this command takes is the name of a deployed release.
The tests to be run are defined in the chart that was installed. The tests to be run are defined in the chart that was installed.
` `
type releaseTestCmd struct { type releaseTestOptions struct {
name string name string
client helm.Interface client helm.Interface
timeout int64 timeout int64
@ -41,7 +41,7 @@ type releaseTestCmd struct {
} }
func newReleaseTestCmd(c helm.Interface, out io.Writer) *cobra.Command { func newReleaseTestCmd(c helm.Interface, out io.Writer) *cobra.Command {
rlsTest := &releaseTestCmd{client: c} o := &releaseTestOptions{client: c}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "test [RELEASE]", Use: "test [RELEASE]",
@ -52,24 +52,24 @@ func newReleaseTestCmd(c helm.Interface, out io.Writer) *cobra.Command {
return err return err
} }
rlsTest.name = args[0] o.name = args[0]
rlsTest.client = ensureHelmClient(rlsTest.client, false) o.client = ensureHelmClient(o.client, false)
return rlsTest.run(out) return o.run(out)
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.Int64Var(&rlsTest.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)") f.Int64Var(&o.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)")
f.BoolVar(&rlsTest.cleanup, "cleanup", false, "delete test pods upon completion") f.BoolVar(&o.cleanup, "cleanup", false, "delete test pods upon completion")
return cmd return cmd
} }
func (t *releaseTestCmd) run(out io.Writer) (err error) { func (o *releaseTestOptions) run(out io.Writer) (err error) {
c, errc := t.client.RunReleaseTest( c, errc := o.client.RunReleaseTest(
t.name, o.name,
helm.ReleaseTestTimeout(t.timeout), helm.ReleaseTestTimeout(o.timeout),
helm.ReleaseTestCleanup(t.cleanup), helm.ReleaseTestCleanup(o.cleanup),
) )
testErr := &testErr{} testErr := &testErr{}

@ -27,7 +27,7 @@ import (
"k8s.io/helm/pkg/repo" "k8s.io/helm/pkg/repo"
) )
type repoAddCmd struct { type repoAddOptions struct {
name string name string
url string url string
username string username string
@ -41,7 +41,7 @@ type repoAddCmd struct {
} }
func newRepoAddCmd(out io.Writer) *cobra.Command { func newRepoAddCmd(out io.Writer) *cobra.Command {
add := &repoAddCmd{} o := &repoAddOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "add [flags] [NAME] [URL]", Use: "add [flags] [NAME] [URL]",
@ -51,30 +51,30 @@ func newRepoAddCmd(out io.Writer) *cobra.Command {
return err return err
} }
add.name = args[0] o.name = args[0]
add.url = args[1] o.url = args[1]
add.home = settings.Home o.home = settings.Home
return add.run(out) return o.run(out)
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.StringVar(&add.username, "username", "", "chart repository username") f.StringVar(&o.username, "username", "", "chart repository username")
f.StringVar(&add.password, "password", "", "chart repository password") f.StringVar(&o.password, "password", "", "chart repository password")
f.BoolVar(&add.noupdate, "no-update", false, "raise error if repo is already registered") f.BoolVar(&o.noupdate, "no-update", false, "raise error if repo is already registered")
f.StringVar(&add.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file") f.StringVar(&o.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
f.StringVar(&add.keyFile, "key-file", "", "identify HTTPS client using this SSL key file") f.StringVar(&o.keyFile, "key-file", "", "identify HTTPS client using this SSL key file")
f.StringVar(&add.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
return cmd return cmd
} }
func (a *repoAddCmd) run(out io.Writer) error { func (o *repoAddOptions) run(out io.Writer) error {
if err := addRepository(a.name, a.url, a.username, a.password, a.home, a.certFile, a.keyFile, a.caFile, a.noupdate); err != nil { if err := addRepository(o.name, o.url, o.username, o.password, o.home, o.certFile, o.keyFile, o.caFile, o.noupdate); err != nil {
return err return err
} }
fmt.Fprintf(out, "%q has been added to your repositories\n", a.name) fmt.Fprintf(out, "%q has been added to your repositories\n", o.name)
return nil return nil
} }

@ -38,14 +38,14 @@ flag. In this case, the charts found in the current directory will be merged
into the existing index, with local charts taking priority over existing charts. into the existing index, with local charts taking priority over existing charts.
` `
type repoIndexCmd struct { type repoIndexOptions struct {
dir string dir string
url string url string
merge string merge string
} }
func newRepoIndexCmd(out io.Writer) *cobra.Command { func newRepoIndexCmd(out io.Writer) *cobra.Command {
index := &repoIndexCmd{} o := &repoIndexOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "index [flags] [DIR]", Use: "index [flags] [DIR]",
@ -56,20 +56,20 @@ func newRepoIndexCmd(out io.Writer) *cobra.Command {
return err return err
} }
index.dir = args[0] o.dir = args[0]
return index.run(out) return o.run(out)
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.StringVar(&index.url, "url", "", "url of chart repository") f.StringVar(&o.url, "url", "", "url of chart repository")
f.StringVar(&index.merge, "merge", "", "merge the generated index into the given index") f.StringVar(&o.merge, "merge", "", "merge the generated index into the given index")
return cmd return cmd
} }
func (i *repoIndexCmd) run(out io.Writer) error { func (i *repoIndexOptions) run(out io.Writer) error {
path, err := filepath.Abs(i.dir) path, err := filepath.Abs(i.dir)
if err != nil { if err != nil {
return err return err

@ -28,27 +28,27 @@ import (
"k8s.io/helm/pkg/repo" "k8s.io/helm/pkg/repo"
) )
type repoListCmd struct { type repoListOptions struct {
home helmpath.Home home helmpath.Home
} }
func newRepoListCmd(out io.Writer) *cobra.Command { func newRepoListCmd(out io.Writer) *cobra.Command {
list := &repoListCmd{} o := &repoListOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "list [flags]", Use: "list [flags]",
Short: "list chart repositories", Short: "list chart repositories",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
list.home = settings.Home o.home = settings.Home
return list.run(out) return o.run(out)
}, },
} }
return cmd return cmd
} }
func (a *repoListCmd) run(out io.Writer) error { func (o *repoListOptions) run(out io.Writer) error {
f, err := repo.LoadRepositoriesFile(a.home.RepositoryFile()) f, err := repo.LoadRepositoriesFile(o.home.RepositoryFile())
if err != nil { if err != nil {
return err return err
} }

@ -27,13 +27,13 @@ import (
"k8s.io/helm/pkg/repo" "k8s.io/helm/pkg/repo"
) )
type repoRemoveCmd struct { type repoRemoveOptions struct {
name string name string
home helmpath.Home home helmpath.Home
} }
func newRepoRemoveCmd(out io.Writer) *cobra.Command { func newRepoRemoveCmd(out io.Writer) *cobra.Command {
remove := &repoRemoveCmd{} o := &repoRemoveOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "remove [flags] [NAME]", Use: "remove [flags] [NAME]",
@ -43,17 +43,17 @@ func newRepoRemoveCmd(out io.Writer) *cobra.Command {
if err := checkArgsLength(len(args), "name of chart repository"); err != nil { if err := checkArgsLength(len(args), "name of chart repository"); err != nil {
return err return err
} }
remove.name = args[0] o.name = args[0]
remove.home = settings.Home o.home = settings.Home
return remove.run(out) return o.run(out)
}, },
} }
return cmd return cmd
} }
func (r *repoRemoveCmd) run(out io.Writer) error { func (r *repoRemoveOptions) run(out io.Writer) error {
return removeRepoLine(out, r.name, r.home) return removeRepoLine(out, r.name, r.home)
} }

@ -39,13 +39,13 @@ future releases.
var errNoRepositories = errors.New("no repositories found. You must add one before updating") var errNoRepositories = errors.New("no repositories found. You must add one before updating")
type repoUpdateCmd struct { type repoUpdateOptions struct {
update func([]*repo.ChartRepository, io.Writer, helmpath.Home) update func([]*repo.ChartRepository, io.Writer, helmpath.Home)
home helmpath.Home home helmpath.Home
} }
func newRepoUpdateCmd(out io.Writer) *cobra.Command { func newRepoUpdateCmd(out io.Writer) *cobra.Command {
u := &repoUpdateCmd{update: updateCharts} o := &repoUpdateOptions{update: updateCharts}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "update", Use: "update",
@ -53,15 +53,15 @@ func newRepoUpdateCmd(out io.Writer) *cobra.Command {
Short: "update information of available charts locally from chart repositories", Short: "update information of available charts locally from chart repositories",
Long: updateDesc, Long: updateDesc,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
u.home = settings.Home o.home = settings.Home
return u.run(out) return o.run(out)
}, },
} }
return cmd return cmd
} }
func (u *repoUpdateCmd) run(out io.Writer) error { func (o *repoUpdateOptions) run(out io.Writer) error {
f, err := repo.LoadRepositoriesFile(u.home.RepositoryFile()) f, err := repo.LoadRepositoriesFile(o.home.RepositoryFile())
if err != nil { if err != nil {
return err return err
} }
@ -78,7 +78,7 @@ func (u *repoUpdateCmd) run(out io.Writer) error {
repos = append(repos, r) repos = append(repos, r)
} }
u.update(repos, out, u.home) o.update(repos, out, o.home)
return nil return nil
} }

@ -51,11 +51,11 @@ func TestUpdateCmd(t *testing.T) {
fmt.Fprintln(out, re.Config.Name) fmt.Fprintln(out, re.Config.Name)
} }
} }
uc := &repoUpdateCmd{ o := &repoUpdateOptions{
update: updater, update: updater,
home: helmpath.Home(thome), home: helmpath.Home(thome),
} }
if err := uc.run(out); err != nil { if err := o.run(out); err != nil {
t.Fatal(err) t.Fatal(err)
} }

@ -34,7 +34,7 @@ second is a revision (version) number. To see revision numbers, run
'helm history RELEASE'. 'helm history RELEASE'.
` `
type rollbackCmd struct { type rollbackOptions struct {
name string name string
revision int revision int
dryRun bool dryRun bool
@ -47,7 +47,7 @@ type rollbackCmd struct {
} }
func newRollbackCmd(c helm.Interface, out io.Writer) *cobra.Command { func newRollbackCmd(c helm.Interface, out io.Writer) *cobra.Command {
rollback := &rollbackCmd{client: c} o := &rollbackOptions{client: c}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "rollback [flags] [RELEASE] [REVISION]", Use: "rollback [flags] [RELEASE] [REVISION]",
@ -58,40 +58,40 @@ func newRollbackCmd(c helm.Interface, out io.Writer) *cobra.Command {
return err return err
} }
rollback.name = args[0] o.name = args[0]
v64, err := strconv.ParseInt(args[1], 10, 32) v64, err := strconv.ParseInt(args[1], 10, 32)
if err != nil { if err != nil {
return fmt.Errorf("invalid revision number '%q': %s", args[1], err) return fmt.Errorf("invalid revision number '%q': %s", args[1], err)
} }
rollback.revision = int(v64) o.revision = int(v64)
rollback.client = ensureHelmClient(rollback.client, false) o.client = ensureHelmClient(o.client, false)
return rollback.run(out) return o.run(out)
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.BoolVar(&rollback.dryRun, "dry-run", false, "simulate a rollback") f.BoolVar(&o.dryRun, "dry-run", false, "simulate a rollback")
f.BoolVar(&rollback.recreate, "recreate-pods", false, "performs pods restart for the resource if applicable") f.BoolVar(&o.recreate, "recreate-pods", false, "performs pods restart for the resource if applicable")
f.BoolVar(&rollback.force, "force", false, "force resource update through delete/recreate if needed") f.BoolVar(&o.force, "force", false, "force resource update through delete/recreate if needed")
f.BoolVar(&rollback.disableHooks, "no-hooks", false, "prevent hooks from running during rollback") f.BoolVar(&o.disableHooks, "no-hooks", false, "prevent hooks from running during rollback")
f.Int64Var(&rollback.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)") f.Int64Var(&o.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)")
f.BoolVar(&rollback.wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout") f.BoolVar(&o.wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout")
return cmd return cmd
} }
func (r *rollbackCmd) run(out io.Writer) error { func (o *rollbackOptions) run(out io.Writer) error {
_, err := r.client.RollbackRelease( _, err := o.client.RollbackRelease(
r.name, o.name,
helm.RollbackDryRun(r.dryRun), helm.RollbackDryRun(o.dryRun),
helm.RollbackRecreate(r.recreate), helm.RollbackRecreate(o.recreate),
helm.RollbackForce(r.force), helm.RollbackForce(o.force),
helm.RollbackDisableHooks(r.disableHooks), helm.RollbackDisableHooks(o.disableHooks),
helm.RollbackVersion(r.revision), helm.RollbackVersion(o.revision),
helm.RollbackTimeout(r.timeout), helm.RollbackTimeout(o.timeout),
helm.RollbackWait(r.wait)) helm.RollbackWait(o.wait))
if err != nil { if err != nil {
return err return err
} }

@ -40,7 +40,7 @@ Repositories are managed with 'helm repo' commands.
// searchMaxScore suggests that any score higher than this is not considered a match. // searchMaxScore suggests that any score higher than this is not considered a match.
const searchMaxScore = 25 const searchMaxScore = 25
type searchCmd struct { type searchOptions struct {
helmhome helmpath.Home helmhome helmpath.Home
versions bool versions bool
@ -49,28 +49,28 @@ type searchCmd struct {
} }
func newSearchCmd(out io.Writer) *cobra.Command { func newSearchCmd(out io.Writer) *cobra.Command {
sc := &searchCmd{} o := &searchOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "search [keyword]", Use: "search [keyword]",
Short: "search for a keyword in charts", Short: "search for a keyword in charts",
Long: searchDesc, Long: searchDesc,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
sc.helmhome = settings.Home o.helmhome = settings.Home
return sc.run(out, args) return o.run(out, args)
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.BoolVarP(&sc.regexp, "regexp", "r", false, "use regular expressions for searching") f.BoolVarP(&o.regexp, "regexp", "r", false, "use regular expressions for searching")
f.BoolVarP(&sc.versions, "versions", "l", false, "show the long listing, with each version of each chart on its own line") f.BoolVarP(&o.versions, "versions", "l", false, "show the long listing, with each version of each chart on its own line")
f.StringVarP(&sc.version, "version", "v", "", "search using semantic versioning constraints") f.StringVarP(&o.version, "version", "v", "", "search using semantic versioning constraints")
return cmd return cmd
} }
func (s *searchCmd) run(out io.Writer, args []string) error { func (o *searchOptions) run(out io.Writer, args []string) error {
index, err := s.buildIndex(out) index, err := o.buildIndex(out)
if err != nil { if err != nil {
return err return err
} }
@ -80,29 +80,29 @@ func (s *searchCmd) run(out io.Writer, args []string) error {
res = index.All() res = index.All()
} else { } else {
q := strings.Join(args, " ") q := strings.Join(args, " ")
res, err = index.Search(q, searchMaxScore, s.regexp) res, err = index.Search(q, searchMaxScore, o.regexp)
if err != nil { if err != nil {
return err return err
} }
} }
search.SortScore(res) search.SortScore(res)
data, err := s.applyConstraint(res) data, err := o.applyConstraint(res)
if err != nil { if err != nil {
return err return err
} }
fmt.Fprintln(out, s.formatSearchResults(data)) fmt.Fprintln(out, o.formatSearchResults(data))
return nil return nil
} }
func (s *searchCmd) applyConstraint(res []*search.Result) ([]*search.Result, error) { func (o *searchOptions) applyConstraint(res []*search.Result) ([]*search.Result, error) {
if len(s.version) == 0 { if len(o.version) == 0 {
return res, nil return res, nil
} }
constraint, err := semver.NewConstraint(s.version) constraint, err := semver.NewConstraint(o.version)
if err != nil { if err != nil {
return res, fmt.Errorf("an invalid version/constraint format: %s", err) return res, fmt.Errorf("an invalid version/constraint format: %s", err)
} }
@ -116,7 +116,7 @@ func (s *searchCmd) applyConstraint(res []*search.Result) ([]*search.Result, err
v, err := semver.NewVersion(r.Chart.Version) v, err := semver.NewVersion(r.Chart.Version)
if err != nil || constraint.Check(v) { if err != nil || constraint.Check(v) {
data = append(data, r) data = append(data, r)
if !s.versions { if !o.versions {
foundNames[r.Name] = true // If user hasn't requested all versions, only show the latest that matches foundNames[r.Name] = true // If user hasn't requested all versions, only show the latest that matches
} }
} }
@ -125,7 +125,7 @@ func (s *searchCmd) applyConstraint(res []*search.Result) ([]*search.Result, err
return data, nil return data, nil
} }
func (s *searchCmd) formatSearchResults(res []*search.Result) string { func (o *searchOptions) formatSearchResults(res []*search.Result) string {
if len(res) == 0 { if len(res) == 0 {
return "No results found" return "No results found"
} }
@ -138,9 +138,9 @@ func (s *searchCmd) formatSearchResults(res []*search.Result) string {
return table.String() return table.String()
} }
func (s *searchCmd) buildIndex(out io.Writer) (*search.Index, error) { func (o *searchOptions) buildIndex(out io.Writer) (*search.Index, error) {
// Load the repositories.yaml // Load the repositories.yaml
rf, err := repo.LoadRepositoriesFile(s.helmhome.RepositoryFile()) rf, err := repo.LoadRepositoriesFile(o.helmhome.RepositoryFile())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -148,7 +148,7 @@ func (s *searchCmd) buildIndex(out io.Writer) (*search.Index, error) {
i := search.NewIndex() i := search.NewIndex()
for _, re := range rf.Repositories { for _, re := range rf.Repositories {
n := re.Name n := re.Name
f := s.helmhome.CacheIndex(n) f := o.helmhome.CacheIndex(n)
ind, err := repo.LoadIndexFile(f) ind, err := repo.LoadIndexFile(f)
if err != nil { if err != nil {
// TODO should print to stderr // TODO should print to stderr
@ -156,7 +156,7 @@ func (s *searchCmd) buildIndex(out io.Writer) (*search.Index, error) {
continue continue
} }
i.AddRepo(n, ind, s.versions || len(s.version) > 0) i.AddRepo(n, ind, o.versions || len(o.version) > 0)
} }
return i, nil return i, nil
} }

@ -44,7 +44,7 @@ The status consists of:
- additional notes provided by the chart - additional notes provided by the chart
` `
type statusCmd struct { type statusOptions struct {
release string release string
client helm.Interface client helm.Interface
version int version int
@ -52,7 +52,7 @@ type statusCmd struct {
} }
func newStatusCmd(client helm.Interface, out io.Writer) *cobra.Command { func newStatusCmd(client helm.Interface, out io.Writer) *cobra.Command {
status := &statusCmd{client: client} o := &statusOptions{client: client}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "status [flags] RELEASE_NAME", Use: "status [flags] RELEASE_NAME",
@ -62,25 +62,25 @@ func newStatusCmd(client helm.Interface, out io.Writer) *cobra.Command {
if len(args) == 0 { if len(args) == 0 {
return errReleaseRequired return errReleaseRequired
} }
status.release = args[0] o.release = args[0]
status.client = ensureHelmClient(status.client, false) o.client = ensureHelmClient(o.client, false)
return status.run(out) return o.run(out)
}, },
} }
cmd.PersistentFlags().IntVar(&status.version, "revision", 0, "if set, display the status of the named release with revision") cmd.PersistentFlags().IntVar(&o.version, "revision", 0, "if set, display the status of the named release with revision")
cmd.PersistentFlags().StringVarP(&status.outfmt, "output", "o", "", "output the status in the specified format (json or yaml)") cmd.PersistentFlags().StringVarP(&o.outfmt, "output", "o", "", "output the status in the specified format (json or yaml)")
return cmd return cmd
} }
func (s *statusCmd) run(out io.Writer) error { func (o *statusOptions) run(out io.Writer) error {
res, err := s.client.ReleaseStatus(s.release, s.version) res, err := o.client.ReleaseStatus(o.release, o.version)
if err != nil { if err != nil {
return err return err
} }
switch s.outfmt { switch o.outfmt {
case "": case "":
PrintStatus(out, res) PrintStatus(out, res)
return nil return nil
@ -100,7 +100,7 @@ func (s *statusCmd) run(out io.Writer) error {
return nil return nil
} }
return fmt.Errorf("Unknown output format %q", s.outfmt) return fmt.Errorf("Unknown output format %q", o.outfmt)
} }
// PrintStatus prints out the status of a release. Shared because also used by // PrintStatus prints out the status of a release. Shared because also used by

@ -60,7 +60,7 @@ To render just one template in a chart, use '-x':
$ helm template mychart -x templates/deployment.yaml $ helm template mychart -x templates/deployment.yaml
` `
type templateCmd struct { type templateOptions struct {
valueFiles valueFiles valueFiles valueFiles
chartPath string chartPath string
values []string values []string
@ -74,7 +74,7 @@ type templateCmd struct {
} }
func newTemplateCmd(out io.Writer) *cobra.Command { func newTemplateCmd(out io.Writer) *cobra.Command {
t := &templateCmd{} o := &templateOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "template [flags] CHART", Use: "template [flags] CHART",
@ -86,39 +86,39 @@ func newTemplateCmd(out io.Writer) *cobra.Command {
} }
// verify chart path exists // verify chart path exists
if _, err := os.Stat(args[0]); err == nil { if _, err := os.Stat(args[0]); err == nil {
if t.chartPath, err = filepath.Abs(args[0]); err != nil { if o.chartPath, err = filepath.Abs(args[0]); err != nil {
return err return err
} }
} else { } else {
return err return err
} }
return t.run(out) return o.run(out)
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.BoolVar(&t.showNotes, "notes", false, "show the computed NOTES.txt file as well") f.BoolVar(&o.showNotes, "notes", false, "show the computed NOTES.txt file as well")
f.StringVarP(&t.releaseName, "name", "", "RELEASE-NAME", "release name") f.StringVarP(&o.releaseName, "name", "", "RELEASE-NAME", "release name")
f.StringArrayVarP(&t.renderFiles, "execute", "x", []string{}, "only execute the given templates") f.StringArrayVarP(&o.renderFiles, "execute", "x", []string{}, "only execute the given templates")
f.VarP(&t.valueFiles, "values", "f", "specify values in a YAML file (can specify multiple)") f.VarP(&o.valueFiles, "values", "f", "specify values in a YAML file (can specify multiple)")
f.StringArrayVar(&t.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") f.StringArrayVar(&o.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
f.StringArrayVar(&t.stringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") f.StringArrayVar(&o.stringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
f.StringVar(&t.nameTemplate, "name-template", "", "specify template used to name the release") f.StringVar(&o.nameTemplate, "name-template", "", "specify template used to name the release")
f.StringVar(&t.kubeVersion, "kube-version", defaultKubeVersion, "kubernetes version used as Capabilities.KubeVersion.Major/Minor") f.StringVar(&o.kubeVersion, "kube-version", defaultKubeVersion, "kubernetes version used as Capabilities.KubeVersion.Major/Minor")
f.StringVar(&t.outputDir, "output-dir", "", "writes the executed templates to files in output-dir instead of stdout") f.StringVar(&o.outputDir, "output-dir", "", "writes the executed templates to files in output-dir instead of stdout")
return cmd return cmd
} }
func (t *templateCmd) run(out io.Writer) error { func (o *templateOptions) run(out io.Writer) error {
// verify specified templates exist relative to chart // verify specified templates exist relative to chart
rf := []string{} rf := []string{}
var af string var af string
var err error var err error
if len(t.renderFiles) > 0 { if len(o.renderFiles) > 0 {
for _, f := range t.renderFiles { for _, f := range o.renderFiles {
if !filepath.IsAbs(f) { if !filepath.IsAbs(f) {
af, err = filepath.Abs(filepath.Join(t.chartPath, f)) af, err = filepath.Abs(filepath.Join(o.chartPath, f))
if err != nil { if err != nil {
return fmt.Errorf("could not resolve template path: %s", err) return fmt.Errorf("could not resolve template path: %s", err)
} }
@ -134,29 +134,29 @@ func (t *templateCmd) run(out io.Writer) error {
} }
// verify that output-dir exists if provided // verify that output-dir exists if provided
if t.outputDir != "" { if o.outputDir != "" {
_, err = os.Stat(t.outputDir) _, err = os.Stat(o.outputDir)
if os.IsNotExist(err) { if os.IsNotExist(err) {
return fmt.Errorf("output-dir '%s' does not exist", t.outputDir) return fmt.Errorf("output-dir '%s' does not exist", o.outputDir)
} }
} }
// get combined values and create config // get combined values and create config
config, err := vals(t.valueFiles, t.values, t.stringValues) config, err := vals(o.valueFiles, o.values, o.stringValues)
if err != nil { if err != nil {
return err return err
} }
// If template is specified, try to run the template. // If template is specified, try to run the template.
if t.nameTemplate != "" { if o.nameTemplate != "" {
t.releaseName, err = generateName(t.nameTemplate) o.releaseName, err = generateName(o.nameTemplate)
if err != nil { if err != nil {
return err return err
} }
} }
// Check chart requirements to make sure all dependencies are present in /charts // Check chart requirements to make sure all dependencies are present in /charts
c, err := chartutil.Load(t.chartPath) c, err := chartutil.Load(o.chartPath)
if err != nil { if err != nil {
return err return err
} }
@ -169,7 +169,7 @@ func (t *templateCmd) run(out io.Writer) error {
return fmt.Errorf("cannot load requirements: %v", err) return fmt.Errorf("cannot load requirements: %v", err)
} }
options := chartutil.ReleaseOptions{ options := chartutil.ReleaseOptions{
Name: t.releaseName, Name: o.releaseName,
Time: time.Now(), Time: time.Now(),
Namespace: getNamespace(), Namespace: getNamespace(),
} }
@ -193,7 +193,7 @@ func (t *templateCmd) run(out io.Writer) error {
} }
// kubernetes version // kubernetes version
kv, err := semver.NewVersion(t.kubeVersion) kv, err := semver.NewVersion(o.kubeVersion)
if err != nil { if err != nil {
return fmt.Errorf("could not parse a kubernetes version: %v", err) return fmt.Errorf("could not parse a kubernetes version: %v", err)
} }
@ -226,7 +226,7 @@ func (t *templateCmd) run(out io.Writer) error {
// make needle path absolute // make needle path absolute
d := strings.Split(needle, string(os.PathSeparator)) d := strings.Split(needle, string(os.PathSeparator))
dd := d[1:] dd := d[1:]
an := filepath.Join(t.chartPath, strings.Join(dd, string(os.PathSeparator))) an := filepath.Join(o.chartPath, strings.Join(dd, string(os.PathSeparator)))
for _, h := range haystack { for _, h := range haystack {
if h == an { if h == an {
@ -237,7 +237,7 @@ func (t *templateCmd) run(out io.Writer) error {
} }
if settings.Debug { if settings.Debug {
rel := &release.Release{ rel := &release.Release{
Name: t.releaseName, Name: o.releaseName,
Chart: c, Chart: c,
Config: config, Config: config,
Version: 1, Version: 1,
@ -247,24 +247,24 @@ func (t *templateCmd) run(out io.Writer) error {
} }
for _, m := range tiller.SortByKind(listManifests) { for _, m := range tiller.SortByKind(listManifests) {
if len(t.renderFiles) > 0 && !in(m.Name, rf) { if len(o.renderFiles) > 0 && !in(m.Name, rf) {
continue continue
} }
data := m.Content data := m.Content
b := filepath.Base(m.Name) b := filepath.Base(m.Name)
if !t.showNotes && b == "NOTES.txt" { if !o.showNotes && b == "NOTES.txt" {
continue continue
} }
if strings.HasPrefix(b, "_") { if strings.HasPrefix(b, "_") {
continue continue
} }
if t.outputDir != "" { if o.outputDir != "" {
// blank template after execution // blank template after execution
if whitespaceRegex.MatchString(data) { if whitespaceRegex.MatchString(data) {
continue continue
} }
err = writeToFile(t.outputDir, m.Name, data) err = writeToFile(o.outputDir, m.Name, data)
if err != nil { if err != nil {
return err return err
} }

@ -53,7 +53,7 @@ set for a key called 'foo', the 'newbar' value would take precedence:
$ helm upgrade --set foo=bar --set foo=newbar redis ./redis $ helm upgrade --set foo=bar --set foo=newbar redis ./redis
` `
type upgradeCmd struct { type upgradeOptions struct {
release string release string
chart string chart string
client helm.Interface client helm.Interface
@ -83,7 +83,7 @@ type upgradeCmd struct {
} }
func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
upgrade := &upgradeCmd{client: client} o := &upgradeOptions{client: client}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "upgrade [RELEASE] [CHART]", Use: "upgrade [RELEASE] [CHART]",
@ -94,81 +94,81 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
return err return err
} }
if upgrade.version == "" && upgrade.devel { if o.version == "" && o.devel {
debug("setting version to >0.0.0-0") debug("setting version to >0.0.0-0")
upgrade.version = ">0.0.0-0" o.version = ">0.0.0-0"
} }
upgrade.release = args[0] o.release = args[0]
upgrade.chart = args[1] o.chart = args[1]
upgrade.client = ensureHelmClient(upgrade.client, false) o.client = ensureHelmClient(o.client, false)
return upgrade.run(out) return o.run(out)
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.VarP(&upgrade.valueFiles, "values", "f", "specify values in a YAML file or a URL(can specify multiple)") f.VarP(&o.valueFiles, "values", "f", "specify values in a YAML file or a URL(can specify multiple)")
f.BoolVar(&upgrade.dryRun, "dry-run", false, "simulate an upgrade") f.BoolVar(&o.dryRun, "dry-run", false, "simulate an upgrade")
f.BoolVar(&upgrade.recreate, "recreate-pods", false, "performs pods restart for the resource if applicable") f.BoolVar(&o.recreate, "recreate-pods", false, "performs pods restart for the resource if applicable")
f.BoolVar(&upgrade.force, "force", false, "force resource update through delete/recreate if needed") f.BoolVar(&o.force, "force", false, "force resource update through delete/recreate if needed")
f.StringArrayVar(&upgrade.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") f.StringArrayVar(&o.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
f.StringArrayVar(&upgrade.stringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") f.StringArrayVar(&o.stringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
f.BoolVar(&upgrade.disableHooks, "disable-hooks", false, "disable pre/post upgrade hooks. DEPRECATED. Use no-hooks") f.BoolVar(&o.disableHooks, "disable-hooks", false, "disable pre/post upgrade hooks. DEPRECATED. Use no-hooks")
f.BoolVar(&upgrade.disableHooks, "no-hooks", false, "disable pre/post upgrade hooks") f.BoolVar(&o.disableHooks, "no-hooks", false, "disable pre/post upgrade hooks")
f.BoolVar(&upgrade.verify, "verify", false, "verify the provenance of the chart before upgrading") f.BoolVar(&o.verify, "verify", false, "verify the provenance of the chart before upgrading")
f.StringVar(&upgrade.keyring, "keyring", defaultKeyring(), "path to the keyring that contains public signing keys") f.StringVar(&o.keyring, "keyring", defaultKeyring(), "path to the keyring that contains public signing keys")
f.BoolVarP(&upgrade.install, "install", "i", false, "if a release by this name doesn't already exist, run an install") f.BoolVarP(&o.install, "install", "i", false, "if a release by this name doesn't already exist, run an install")
f.StringVar(&upgrade.version, "version", "", "specify the exact chart version to use. If this is not specified, the latest version is used") f.StringVar(&o.version, "version", "", "specify the exact chart version to use. If this is not specified, the latest version is used")
f.Int64Var(&upgrade.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)") f.Int64Var(&o.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)")
f.BoolVar(&upgrade.resetValues, "reset-values", false, "when upgrading, reset the values to the ones built into the chart") f.BoolVar(&o.resetValues, "reset-values", false, "when upgrading, reset the values to the ones built into the chart")
f.BoolVar(&upgrade.reuseValues, "reuse-values", false, "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.") f.BoolVar(&o.reuseValues, "reuse-values", false, "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.")
f.BoolVar(&upgrade.wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout") f.BoolVar(&o.wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout")
f.StringVar(&upgrade.repoURL, "repo", "", "chart repository url where to locate the requested chart") f.StringVar(&o.repoURL, "repo", "", "chart repository url where to locate the requested chart")
f.StringVar(&upgrade.username, "username", "", "chart repository username where to locate the requested chart") f.StringVar(&o.username, "username", "", "chart repository username where to locate the requested chart")
f.StringVar(&upgrade.password, "password", "", "chart repository password where to locate the requested chart") f.StringVar(&o.password, "password", "", "chart repository password where to locate the requested chart")
f.StringVar(&upgrade.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file") f.StringVar(&o.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
f.StringVar(&upgrade.keyFile, "key-file", "", "identify HTTPS client using this SSL key file") f.StringVar(&o.keyFile, "key-file", "", "identify HTTPS client using this SSL key file")
f.StringVar(&upgrade.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
f.BoolVar(&upgrade.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.") f.BoolVar(&o.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.")
f.MarkDeprecated("disable-hooks", "use --no-hooks instead") f.MarkDeprecated("disable-hooks", "use --no-hooks instead")
return cmd return cmd
} }
func (u *upgradeCmd) run(out io.Writer) error { func (o *upgradeOptions) run(out io.Writer) error {
chartPath, err := locateChartPath(u.repoURL, u.username, u.password, u.chart, u.version, u.verify, u.keyring, u.certFile, u.keyFile, u.caFile) chartPath, err := locateChartPath(o.repoURL, o.username, o.password, o.chart, o.version, o.verify, o.keyring, o.certFile, o.keyFile, o.caFile)
if err != nil { if err != nil {
return err return err
} }
if u.install { if o.install {
// If a release does not exist, install it. If another error occurs during // If a release does not exist, install it. If another error occurs during
// the check, ignore the error and continue with the upgrade. // the check, ignore the error and continue with the upgrade.
_, err := u.client.ReleaseHistory(u.release, 1) _, err := o.client.ReleaseHistory(o.release, 1)
if err != nil && strings.Contains(err.Error(), driver.ErrReleaseNotFound(u.release).Error()) { if err != nil && strings.Contains(err.Error(), driver.ErrReleaseNotFound(o.release).Error()) {
fmt.Fprintf(out, "Release %q does not exist. Installing it now.\n", u.release) fmt.Fprintf(out, "Release %q does not exist. Installing it now.\n", o.release)
ic := &installCmd{ io := &installOptions{
chartPath: chartPath, chartPath: chartPath,
client: u.client, client: o.client,
name: u.release, name: o.release,
valueFiles: u.valueFiles, valueFiles: o.valueFiles,
dryRun: u.dryRun, dryRun: o.dryRun,
verify: u.verify, verify: o.verify,
disableHooks: u.disableHooks, disableHooks: o.disableHooks,
keyring: u.keyring, keyring: o.keyring,
values: u.values, values: o.values,
stringValues: u.stringValues, stringValues: o.stringValues,
timeout: u.timeout, timeout: o.timeout,
wait: u.wait, wait: o.wait,
} }
return ic.run(out) return io.run(out)
} }
} }
rawVals, err := vals(u.valueFiles, u.values, u.stringValues) rawVals, err := vals(o.valueFiles, o.values, o.stringValues)
if err != nil { if err != nil {
return err return err
} }
@ -186,18 +186,18 @@ func (u *upgradeCmd) run(out io.Writer) error {
return err return err
} }
resp, err := u.client.UpdateRelease( resp, err := o.client.UpdateRelease(
u.release, o.release,
chartPath, chartPath,
helm.UpdateValueOverrides(rawVals), helm.UpdateValueOverrides(rawVals),
helm.UpgradeDryRun(u.dryRun), helm.UpgradeDryRun(o.dryRun),
helm.UpgradeRecreate(u.recreate), helm.UpgradeRecreate(o.recreate),
helm.UpgradeForce(u.force), helm.UpgradeForce(o.force),
helm.UpgradeDisableHooks(u.disableHooks), helm.UpgradeDisableHooks(o.disableHooks),
helm.UpgradeTimeout(u.timeout), helm.UpgradeTimeout(o.timeout),
helm.ResetValues(u.resetValues), helm.ResetValues(o.resetValues),
helm.ReuseValues(u.reuseValues), helm.ReuseValues(o.reuseValues),
helm.UpgradeWait(u.wait)) helm.UpgradeWait(o.wait))
if err != nil { if err != nil {
return fmt.Errorf("UPGRADE FAILED: %v", err) return fmt.Errorf("UPGRADE FAILED: %v", err)
} }
@ -206,10 +206,10 @@ func (u *upgradeCmd) run(out io.Writer) error {
printRelease(out, resp) printRelease(out, resp)
} }
fmt.Fprintf(out, "Release %q has been upgraded. Happy Helming!\n", u.release) fmt.Fprintf(out, "Release %q has been upgraded. Happy Helming!\n", o.release)
// Print the status like status command does // Print the status like status command does
status, err := u.client.ReleaseStatus(u.release, 0) status, err := o.client.ReleaseStatus(o.release, 0)
if err != nil { if err != nil {
return err return err
} }

@ -35,13 +35,13 @@ This command can be used to verify a local chart. Several other commands provide
the 'helm package --sign' command. the 'helm package --sign' command.
` `
type verifyCmd struct { type verifyOptions struct {
keyring string keyring string
chartfile string chartfile string
} }
func newVerifyCmd(out io.Writer) *cobra.Command { func newVerifyCmd(out io.Writer) *cobra.Command {
vc := &verifyCmd{} o := &verifyOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "verify [flags] PATH", Use: "verify [flags] PATH",
@ -51,18 +51,18 @@ func newVerifyCmd(out io.Writer) *cobra.Command {
if len(args) == 0 { if len(args) == 0 {
return errors.New("a path to a package file is required") return errors.New("a path to a package file is required")
} }
vc.chartfile = args[0] o.chartfile = args[0]
return vc.run(out) return o.run(out)
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.StringVar(&vc.keyring, "keyring", defaultKeyring(), "keyring containing public keys") f.StringVar(&o.keyring, "keyring", defaultKeyring(), "keyring containing public keys")
return cmd return cmd
} }
func (v *verifyCmd) run(out io.Writer) error { func (o *verifyOptions) run(out io.Writer) error {
_, err := downloader.VerifyChart(v.chartfile, v.keyring) _, err := downloader.VerifyChart(o.chartfile, o.keyring)
return err return err
} }

@ -40,38 +40,38 @@ version.BuildInfo{Version:"v2.0.0", GitCommit:"ff52399e51bb880526e9cd0ed8386f643
built, and "dirty" if the binary was built from locally modified code. built, and "dirty" if the binary was built from locally modified code.
` `
type versionCmd struct { type versionOptions struct {
short bool short bool
template string template string
} }
func newVersionCmd(out io.Writer) *cobra.Command { func newVersionCmd(out io.Writer) *cobra.Command {
version := &versionCmd{} o := &versionOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "version", Use: "version",
Short: "print the client version information", Short: "print the client version information",
Long: versionDesc, Long: versionDesc,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return version.run(out) return o.run(out)
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.BoolVar(&version.short, "short", false, "print the version number") f.BoolVar(&o.short, "short", false, "print the version number")
f.StringVar(&version.template, "template", "", "template for version string format") f.StringVar(&o.template, "template", "", "template for version string format")
return cmd return cmd
} }
func (v *versionCmd) run(out io.Writer) error { func (o *versionOptions) run(out io.Writer) error {
if v.template != "" { if o.template != "" {
tt, err := template.New("_").Parse(v.template) tt, err := template.New("_").Parse(o.template)
if err != nil { if err != nil {
return err return err
} }
return tt.Execute(out, version.GetBuildInfo()) return tt.Execute(out, version.GetBuildInfo())
} }
fmt.Fprintln(out, formatVersion(v.short)) fmt.Fprintln(out, formatVersion(o.short))
return nil return nil
} }

Loading…
Cancel
Save