diff --git a/cmd/helm/get.go b/cmd/helm/get.go index 2ec9217c7..784bd6084 100644 --- a/cmd/helm/get.go +++ b/cmd/helm/get.go @@ -19,6 +19,7 @@ package main import ( "errors" "fmt" + "io" "time" "github.com/spf13/cobra" @@ -41,60 +42,43 @@ By default, this prints a human readable collection of information about the chart, the supplied values, and the generated manifest file. ` -var getValuesHelp = ` -This command downloads a values file for a given release. -` - -var getManifestHelp = ` -This command fetches the generated manifest for a given release. - -A manifest is a YAML-encoded representation of the Kubernetes resources that -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. -` - -var allValues = false - var errReleaseRequired = errors.New("release name is required") -var getCommand = &cobra.Command{ - Use: "get [flags] RELEASE_NAME", - Short: "download a named release", - Long: getHelp, - RunE: getCmd, - PersistentPreRunE: setupConnection, -} - -var getValuesCommand = &cobra.Command{ - Use: "values [flags] RELEASE_NAME", - Short: "download the values file for a named release", - Long: getValuesHelp, - RunE: getValues, +type getCmd struct { + release string + out io.Writer + client helm.Interface } -var getManifestCommand = &cobra.Command{ - Use: "manifest [flags] RELEASE_NAME", - Short: "download the manifest for a named release", - Long: getManifestHelp, - RunE: getManifest, -} - -func init() { - // 'get values' flags. - getValuesCommand.PersistentFlags().BoolVarP(&allValues, "all", "a", false, "dump all (computed) values") - - getCommand.AddCommand(getValuesCommand) - getCommand.AddCommand(getManifestCommand) - RootCommand.AddCommand(getCommand) +func newGetCmd(client helm.Interface, out io.Writer) *cobra.Command { + get := &getCmd{ + out: out, + client: client, + } + cmd := &cobra.Command{ + Use: "get [flags] RELEASE_NAME", + Short: "download a named release", + Long: getHelp, + PersistentPreRunE: setupConnection, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + return errReleaseRequired + } + get.release = args[0] + if get.client == nil { + get.client = helm.NewClient(helm.HelmHost(helm.Config.ServAddr)) + } + return get.run() + }, + } + cmd.AddCommand(newGetValuesCmd(nil, out)) + cmd.AddCommand(newGetManifestCmd(nil, out)) + return cmd } // getCmd is the command that implements 'helm get' -func getCmd(cmd *cobra.Command, args []string) error { - if len(args) == 0 { - return errReleaseRequired - } - - res, err := helm.GetReleaseContent(args[0]) +func (g *getCmd) run() error { + res, err := g.client.ReleaseContent(g.release) if err != nil { return prettyError(err) } @@ -108,56 +92,13 @@ func getCmd(cmd *cobra.Command, args []string) error { return err } - fmt.Printf("CHART: %s-%s\n", res.Release.Chart.Metadata.Name, res.Release.Chart.Metadata.Version) - fmt.Printf("RELEASED: %s\n", timeconv.Format(res.Release.Info.LastDeployed, time.ANSIC)) - fmt.Println("USER-SUPPLIED VALUES:") - fmt.Println(res.Release.Config.Raw) - fmt.Println("COMPUTED VALUES:") - fmt.Println(cfgStr) - fmt.Println("MANIFEST:") - fmt.Println(res.Release.Manifest) - return nil -} - -// getValues implements 'helm get values' -func getValues(cmd *cobra.Command, args []string) error { - if len(args) == 0 { - return errReleaseRequired - } - - res, err := helm.GetReleaseContent(args[0]) - if err != nil { - return prettyError(err) - } - - // If the user wants all values, compute the values and return. - if allValues { - cfg, err := chartutil.CoalesceValues(res.Release.Chart, res.Release.Config, nil) - if err != nil { - return err - } - cfgStr, err := cfg.YAML() - if err != nil { - return err - } - fmt.Println(cfgStr) - return nil - } - - fmt.Println(res.Release.Config.Raw) - return nil -} - -// getManifest implements 'helm get manifest' -func getManifest(cmd *cobra.Command, args []string) error { - if len(args) == 0 { - return errReleaseRequired - } - - res, err := helm.GetReleaseContent(args[0]) - if err != nil { - return prettyError(err) - } - fmt.Println(res.Release.Manifest) + fmt.Fprintf(g.out, "CHART: %s-%s\n", res.Release.Chart.Metadata.Name, res.Release.Chart.Metadata.Version) + fmt.Fprintf(g.out, "RELEASED: %s\n", timeconv.Format(res.Release.Info.LastDeployed, time.ANSIC)) + fmt.Fprintln(g.out, "USER-SUPPLIED VALUES:") + fmt.Fprintln(g.out, res.Release.Config.Raw) + fmt.Fprintln(g.out, "COMPUTED VALUES:") + fmt.Fprintln(g.out, cfgStr) + fmt.Fprintln(g.out, "MANIFEST:") + fmt.Fprintln(g.out, res.Release.Manifest) return nil } diff --git a/cmd/helm/get_manifest.go b/cmd/helm/get_manifest.go new file mode 100644 index 000000000..20f61443e --- /dev/null +++ b/cmd/helm/get_manifest.go @@ -0,0 +1,73 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + "io" + + "github.com/spf13/cobra" + + "k8s.io/helm/pkg/helm" +) + +var getManifestHelp = ` +This command fetches the generated manifest for a given release. + +A manifest is a YAML-encoded representation of the Kubernetes resources that +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. +` + +type getManifestCmd struct { + release string + out io.Writer + client helm.Interface +} + +func newGetManifestCmd(client helm.Interface, out io.Writer) *cobra.Command { + get := &getManifestCmd{ + out: out, + client: client, + } + cmd := &cobra.Command{ + Use: "manifest [flags] RELEASE_NAME", + Short: "download the manifest for a named release", + Long: getManifestHelp, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + return errReleaseRequired + } + get.release = args[0] + if get.client == nil { + get.client = helm.NewClient(helm.HelmHost(helm.Config.ServAddr)) + } + return get.run() + }, + } + return cmd +} + +// getManifest implements 'helm get manifest' +func (g *getManifestCmd) run() error { + res, err := g.client.ReleaseContent(g.release) + if err != nil { + return prettyError(err) + } + fmt.Fprintln(g.out, res.Release.Manifest) + return nil +} diff --git a/cmd/helm/get_test.go b/cmd/helm/get_test.go new file mode 100644 index 000000000..0ee6ff356 --- /dev/null +++ b/cmd/helm/get_test.go @@ -0,0 +1,63 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "bytes" + "regexp" + "testing" + + "k8s.io/helm/pkg/proto/hapi/release" +) + +func TestGetCmd(t *testing.T) { + tests := []struct { + name string + args []string + resp *release.Release + expected string + err bool + }{ + { + name: "with a release", + resp: releaseMock("thomas-guide"), + args: []string{"thomas-guide"}, + expected: "CHART: foo-0.1.0-beta.1\nRELEASED: (.*)\nUSER-SUPPLIED VALUES:\nname: \"value\"\nCOMPUTED VALUES:\nname: value\n\nMANIFEST:", + }, + { + name: "requires release name arg", + err: true, + }, + } + + var buf bytes.Buffer + for _, tt := range tests { + c := &fakeReleaseClient{ + rels: []*release.Release{tt.resp}, + } + cmd := newGetCmd(c, &buf) + err := cmd.RunE(cmd, tt.args) + if (err != nil) != tt.err { + t.Errorf("%q. expected error: %v, got %v", tt.name, tt.err, err) + } + re := regexp.MustCompile(tt.expected) + if !re.Match(buf.Bytes()) { + t.Errorf("%q. expected %q, got %q", tt.name, tt.expected, buf.String()) + } + buf.Reset() + } +} diff --git a/cmd/helm/get_values.go b/cmd/helm/get_values.go new file mode 100644 index 000000000..b62833db1 --- /dev/null +++ b/cmd/helm/get_values.go @@ -0,0 +1,87 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + "io" + + "github.com/spf13/cobra" + + "k8s.io/helm/pkg/chartutil" + "k8s.io/helm/pkg/helm" +) + +var getValuesHelp = ` +This command downloads a values file for a given release. +` + +type getValuesCmd struct { + release string + allValues bool + out io.Writer + client helm.Interface +} + +func newGetValuesCmd(client helm.Interface, out io.Writer) *cobra.Command { + get := &getValuesCmd{ + out: out, + client: client, + } + cmd := &cobra.Command{ + Use: "values [flags] RELEASE_NAME", + Short: "download the values file for a named release", + Long: getValuesHelp, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + return errReleaseRequired + } + get.release = args[0] + if get.client == nil { + get.client = helm.NewClient(helm.HelmHost(helm.Config.ServAddr)) + } + return get.run() + }, + } + cmd.Flags().BoolVarP(&get.allValues, "all", "a", false, "dump all (computed) values") + return cmd +} + +// getValues implements 'helm get values' +func (g *getValuesCmd) run() error { + res, err := g.client.ReleaseContent(g.release) + if err != nil { + return prettyError(err) + } + + // If the user wants all values, compute the values and return. + if g.allValues { + cfg, err := chartutil.CoalesceValues(res.Release.Chart, res.Release.Config, nil) + if err != nil { + return err + } + cfgStr, err := cfg.YAML() + if err != nil { + return err + } + fmt.Fprintln(g.out, cfgStr) + return nil + } + + fmt.Fprintln(g.out, res.Release.Config.Raw) + return nil +} diff --git a/cmd/helm/get_values_test.go b/cmd/helm/get_values_test.go new file mode 100644 index 000000000..4a28ccb24 --- /dev/null +++ b/cmd/helm/get_values_test.go @@ -0,0 +1,62 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "bytes" + "testing" + + "k8s.io/helm/pkg/proto/hapi/release" +) + +func TestGetValuesCmd(t *testing.T) { + tests := []struct { + name string + args []string + resp *release.Release + expected string + err bool + }{ + { + name: "with a release", + resp: releaseMock("thomas-guide"), + args: []string{"thomas-guide"}, + expected: "name: \"value\"", + }, + { + name: "requires release name arg", + err: true, + }, + } + + var buf bytes.Buffer + for _, tt := range tests { + c := &fakeReleaseClient{ + rels: []*release.Release{tt.resp}, + } + cmd := newGetValuesCmd(c, &buf) + err := cmd.RunE(cmd, tt.args) + if (err != nil) != tt.err { + t.Errorf("%q. expected error: %v, got %v", tt.name, tt.err, err) + } + actual := string(bytes.TrimSpace(buf.Bytes())) + if actual != tt.expected { + t.Errorf("%q. expected %q, got %q", tt.name, tt.expected, actual) + } + buf.Reset() + } +} diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 3a42044e0..e2a39c48b 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -19,6 +19,7 @@ package main import ( "errors" "fmt" + "io" "os" "strings" @@ -63,30 +64,39 @@ Environment: $HELM_HOST Set an alternative Tiller host. The format is host:port (default ":44134"). ` -// RootCommand is the top-level command for Helm. -var RootCommand = &cobra.Command{ - Use: "helm", - Short: "The Helm package manager for Kubernetes.", - Long: globalUsage, - PersistentPostRun: teardown, - SilenceUsage: true, -} - -func init() { +func newRootCmd(out io.Writer) *cobra.Command { + cmd := &cobra.Command{ + Use: "helm", + Short: "The Helm package manager for Kubernetes.", + Long: globalUsage, + SilenceUsage: true, + PersistentPostRun: func(cmd *cobra.Command, args []string) { + teardown() + }, + } home := os.Getenv(homeEnvVar) if home == "" { home = "$HOME/.helm" } thost := os.Getenv(hostEnvVar) - p := RootCommand.PersistentFlags() + p := cmd.PersistentFlags() p.StringVar(&helmHome, "home", home, "location of your Helm config. Overrides $HELM_HOME.") p.StringVar(&tillerHost, "host", thost, "address of tiller. Overrides $HELM_HOST.") p.StringVarP(&tillerNamespace, "namespace", "", "", "kubernetes namespace") p.BoolVarP(&flagDebug, "debug", "", false, "enable verbose output") + + cmd.AddCommand(newListCmd(nil, out)) + cmd.AddCommand(newGetCmd(nil, out)) + + return cmd } +// RootCommand is the top-level command for Helm. +var RootCommand = newRootCmd(os.Stdout) + func main() { - if err := RootCommand.Execute(); err != nil { + cmd := RootCommand + if err := cmd.Execute(); err != nil { os.Exit(1) } } @@ -112,7 +122,7 @@ func setupConnection(c *cobra.Command, args []string) error { return nil } -func teardown(c *cobra.Command, args []string) { +func teardown() { if tunnel != nil { tunnel.Close() } diff --git a/cmd/helm/helm_test.go b/cmd/helm/helm_test.go new file mode 100644 index 000000000..1a0a8a338 --- /dev/null +++ b/cmd/helm/helm_test.go @@ -0,0 +1,86 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "github.com/golang/protobuf/ptypes/timestamp" + + "k8s.io/helm/pkg/helm" + "k8s.io/helm/pkg/proto/hapi/chart" + "k8s.io/helm/pkg/proto/hapi/release" + rls "k8s.io/helm/pkg/proto/hapi/services" +) + +func releaseMock(name string) *release.Release { + date := timestamp.Timestamp{Seconds: 242085845, Nanos: 0} + return &release.Release{ + Name: name, + Info: &release.Info{ + FirstDeployed: &date, + LastDeployed: &date, + Status: &release.Status{Code: release.Status_DEPLOYED}, + }, + Chart: &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "foo", + Version: "0.1.0-beta.1", + }, + Templates: []*chart.Template{ + {Name: "foo.tpl", Data: []byte("Hello")}, + }, + }, + Config: &chart.Config{Raw: `name: "value"`}, + } +} + +type fakeReleaseClient struct { + rels []*release.Release + err error +} + +func (c *fakeReleaseClient) ListReleases(opts ...helm.ReleaseListOption) (*rls.ListReleasesResponse, error) { + resp := &rls.ListReleasesResponse{ + Count: int64(len(c.rels)), + Releases: c.rels, + } + return resp, c.err +} + +func (c *fakeReleaseClient) InstallRelease(chStr string, opts ...helm.InstallOption) (*rls.InstallReleaseResponse, error) { + return nil, nil +} + +func (c *fakeReleaseClient) DeleteRelease(rlsName string, opts ...helm.DeleteOption) (*rls.UninstallReleaseResponse, error) { + return nil, nil +} + +func (c *fakeReleaseClient) ReleaseStatus(rlsName string, opts ...helm.StatusOption) (*rls.GetReleaseStatusResponse, error) { + return nil, nil +} + +func (c *fakeReleaseClient) UpdateRelease(rlsName string, opts ...helm.UpdateOption) (*rls.UpdateReleaseResponse, error) { + return nil, nil +} + +func (c *fakeReleaseClient) ReleaseContent(rlsName string, opts ...helm.ContentOption) (resp *rls.GetReleaseContentResponse, err error) { + if len(c.rels) > 0 { + resp = &rls.GetReleaseContentResponse{ + Release: c.rels[0], + } + } + return resp, c.err +} diff --git a/cmd/helm/list.go b/cmd/helm/list.go index 01e22f4e7..ede7cb01d 100644 --- a/cmd/helm/list.go +++ b/cmd/helm/list.go @@ -18,6 +18,7 @@ package main import ( "fmt" + "io" "strings" "github.com/gosuri/uitable" @@ -52,51 +53,66 @@ server's default, which may be much higher than 256. Pairing the '--max' flag with the '--offset' flag allows you to page through results. ` -var listCommand = &cobra.Command{ - Use: "list [flags] [FILTER]", - Short: "list releases", - Long: listHelp, - RunE: listCmd, - Aliases: []string{"ls"}, - PersistentPreRunE: setupConnection, +type listCmd struct { + filter string + long bool + limit int + offset string + byDate bool + sortDesc bool + out io.Writer + client helm.Interface } -var ( - listLong bool - listMax int - listOffset string - listByDate bool - listSortDesc bool -) - -func init() { - f := listCommand.Flags() - f.BoolVarP(&listLong, "long", "l", false, "output long listing format") - f.BoolVarP(&listByDate, "date", "d", false, "sort by release date") - f.BoolVarP(&listSortDesc, "reverse", "r", false, "reverse the sort order") - f.IntVarP(&listMax, "max", "m", 256, "maximum number of releases to fetch") - f.StringVarP(&listOffset, "offset", "o", "", "the next release name in the list, used to offset from start value") - - RootCommand.AddCommand(listCommand) -} - -func listCmd(cmd *cobra.Command, args []string) error { - var filter string - if len(args) > 0 { - filter = strings.Join(args, " ") +func newListCmd(client helm.Interface, out io.Writer) *cobra.Command { + list := &listCmd{ + out: out, + client: client, + } + cmd := &cobra.Command{ + Use: "list [flags] [FILTER]", + Short: "list releases", + Long: listHelp, + Aliases: []string{"ls"}, + PersistentPreRunE: setupConnection, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) > 0 { + list.filter = strings.Join(args, " ") + } + if list.client == nil { + list.client = helm.NewClient(helm.HelmHost(helm.Config.ServAddr)) + } + return list.run() + }, } + f := cmd.Flags() + f.BoolVarP(&list.long, "long", "l", false, "output long listing format") + f.BoolVarP(&list.byDate, "date", "d", false, "sort by release date") + f.BoolVarP(&list.sortDesc, "reverse", "r", false, "reverse the sort order") + f.IntVarP(&list.limit, "max", "m", 256, "maximum number of releases to fetch") + f.StringVarP(&list.offset, "offset", "o", "", "the next release name in the list, used to offset from start value") + return cmd +} +func (l *listCmd) run() error { sortBy := services.ListSort_NAME - if listByDate { + if l.byDate { sortBy = services.ListSort_LAST_RELEASED } sortOrder := services.ListSort_ASC - if listSortDesc { + if l.sortDesc { sortOrder = services.ListSort_DESC } - res, err := helm.ListReleases(listMax, listOffset, sortBy, sortOrder, filter) + res, err := l.client.ListReleases( + helm.ReleaseListLimit(l.limit), + helm.ReleaseListOffset(l.offset), + helm.ReleaseListFilter(l.filter), + helm.ReleaseListSort(int32(sortBy)), + helm.ReleaseListOrder(int32(sortOrder)), + ) + if err != nil { return prettyError(err) } @@ -106,21 +122,23 @@ func listCmd(cmd *cobra.Command, args []string) error { } if res.Next != "" { - fmt.Printf("\tnext: %s", res.Next) + fmt.Fprintf(l.out, "\tnext: %s", res.Next) } rels := res.Releases - if listLong { - return formatList(rels) + + if l.long { + fmt.Fprintln(l.out, formatList(rels)) + return nil } for _, r := range rels { - fmt.Println(r.Name) + fmt.Fprintln(l.out, r.Name) } return nil } -func formatList(rels []*release.Release) error { +func formatList(rels []*release.Release) string { table := uitable.New() table.MaxColWidth = 30 table.AddRow("NAME", "UPDATED", "STATUS", "CHART") @@ -130,7 +148,5 @@ func formatList(rels []*release.Release) error { s := r.Info.Status.Code.String() table.AddRow(r.Name, t, s, c) } - fmt.Println(table) - - return nil + return table.String() } diff --git a/cmd/helm/list_test.go b/cmd/helm/list_test.go new file mode 100644 index 000000000..c3bec76ec --- /dev/null +++ b/cmd/helm/list_test.go @@ -0,0 +1,119 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "bytes" + "regexp" + "testing" + + "k8s.io/helm/pkg/proto/hapi/release" +) + +func TestListRun(t *testing.T) { + tests := []struct { + name string + listCmd *listCmd + expected string + err bool + }{ + { + name: "with a release", + listCmd: &listCmd{ + client: &fakeReleaseClient{ + rels: []*release.Release{ + releaseMock("thomas-guide"), + }, + }, + }, + expected: "thomas-guide", + }, + { + name: "list --long", + listCmd: &listCmd{ + client: &fakeReleaseClient{ + rels: []*release.Release{ + releaseMock("atlas"), + }, + }, + long: true, + }, + expected: "NAME \tUPDATED \tSTATUS \tCHART \natlas\t(.*)\tDEPLOYED\tfoo-0.1.0-beta.1", + }, + } + + var buf bytes.Buffer + for _, tt := range tests { + tt.listCmd.out = &buf + err := tt.listCmd.run() + if (err != nil) != tt.err { + t.Errorf("%q. expected error: %v, got %v", tt.name, tt.err, err) + } + re := regexp.MustCompile(tt.expected) + if !re.Match(buf.Bytes()) { + t.Errorf("%q. expected %q, got %q", tt.name, tt.expected, buf.String()) + } + buf.Reset() + } +} + +func TestListCmd(t *testing.T) { + tests := []struct { + name string + args []string + flags map[string]string + resp []*release.Release + expected string + err bool + }{ + { + name: "with a release", + resp: []*release.Release{ + releaseMock("thomas-guide"), + }, + expected: "thomas-guide", + }, + { + name: "list --long", + flags: map[string]string{"long": "1"}, + resp: []*release.Release{ + releaseMock("atlas"), + }, + expected: "NAME \tUPDATED \tSTATUS \tCHART \natlas\t(.*)\tDEPLOYED\tfoo-0.1.0-beta.1", + }, + } + + var buf bytes.Buffer + for _, tt := range tests { + c := &fakeReleaseClient{ + rels: tt.resp, + } + cmd := newListCmd(c, &buf) + for flag, value := range tt.flags { + cmd.Flags().Set(flag, value) + } + err := cmd.RunE(cmd, tt.args) + if (err != nil) != tt.err { + t.Errorf("%q. expected error: %v, got %v", tt.name, tt.err, err) + } + re := regexp.MustCompile(tt.expected) + if !re.Match(buf.Bytes()) { + t.Errorf("%q. expected %q, got %q", tt.name, tt.expected, buf.String()) + } + buf.Reset() + } +} diff --git a/pkg/helm/interface.go b/pkg/helm/interface.go new file mode 100644 index 000000000..4cba4db43 --- /dev/null +++ b/pkg/helm/interface.go @@ -0,0 +1,31 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package helm + +import ( + rls "k8s.io/helm/pkg/proto/hapi/services" +) + +// Interface for helm client for mocking in tests +type Interface interface { + ListReleases(opts ...ReleaseListOption) (*rls.ListReleasesResponse, error) + InstallRelease(chStr string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) + DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error) + ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) + UpdateRelease(rlsName string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) + ReleaseContent(rlsName string, opts ...ContentOption) (*rls.GetReleaseContentResponse, error) +}