From 5057114efc801ed833769965b27e2b6a6aafbaed Mon Sep 17 00:00:00 2001 From: bryanl <bryanliles@gmail.com> Date: Sat, 24 Mar 2018 16:04:36 -0400 Subject: [PATCH] Update prototype list action Signed-off-by: bryanl <bryanliles@gmail.com> --- actions/prototype_list.go | 101 ++++++++++++++++++ actions/prototype_list_test.go | 44 ++++++++ actions/testdata/prototype/list/output.txt | 7 ++ cmd/prototype.go | 56 ---------- cmd/prototype_list.go | 42 ++++++++ e2e/prototype_test.go | 18 +++- .../prototype/list/output-with-addition.txt | 8 ++ pkg/pkg/pkg.go | 6 +- 8 files changed, 219 insertions(+), 63 deletions(-) create mode 100644 actions/prototype_list.go create mode 100644 actions/prototype_list_test.go create mode 100644 actions/testdata/prototype/list/output.txt create mode 100644 cmd/prototype_list.go create mode 100644 e2e/testdata/output/prototype/list/output-with-addition.txt diff --git a/actions/prototype_list.go b/actions/prototype_list.go new file mode 100644 index 00000000..99e0c1bc --- /dev/null +++ b/actions/prototype_list.go @@ -0,0 +1,101 @@ +// Copyright 2018 The ksonnet authors +// +// +// 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 +// +// Upless 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 actions + +import ( + "io" + "os" + "sort" + + "github.com/ksonnet/ksonnet/metadata/app" + "github.com/ksonnet/ksonnet/pkg/pkg" + "github.com/ksonnet/ksonnet/pkg/util/table" + "github.com/ksonnet/ksonnet/prototype" +) + +// RunPrototypeList runs `prototype list` +func RunPrototypeList(ksApp app.App) error { + pl, err := NewPrototypeList(ksApp) + if err != nil { + return err + } + + return pl.Run() +} + +// PrototypeList lists available namespaces +type PrototypeList struct { + app app.App + out io.Writer + prototypes func(app.App, pkg.Descriptor) (prototype.SpecificationSchemas, error) +} + +// NewPrototypeList creates an instance of PrototypeList +func NewPrototypeList(ksApp app.App) (*PrototypeList, error) { + pl := &PrototypeList{ + app: ksApp, + out: os.Stdout, + prototypes: pkg.LoadPrototypes, + } + + return pl, nil +} + +// Run runs the env list action. +func (pl *PrototypeList) Run() error { + libraries, err := pl.app.Libraries() + if err != nil { + return err + } + + var prototypes prototype.SpecificationSchemas + + for _, library := range libraries { + d := pkg.Descriptor{ + Registry: library.Registry, + Part: library.Name, + } + + p, err := pl.prototypes(pl.app, d) + if err != nil { + return err + } + + prototypes = append(prototypes, p...) + } + + index := prototype.NewIndex(prototypes) + prototypes, err = index.List() + if err != nil { + return nil + } + + var rows [][]string + for _, p := range prototypes { + rows = append(rows, []string{p.Name, p.Template.ShortDescription}) + } + + t := table.New(pl.out) + t.SetHeader([]string{"name", "description"}) + + sort.Slice(rows, func(i, j int) bool { + return rows[i][0] < rows[j][0] + }) + + t.AppendBulk(rows) + + return t.Render() +} diff --git a/actions/prototype_list_test.go b/actions/prototype_list_test.go new file mode 100644 index 00000000..618e8b8b --- /dev/null +++ b/actions/prototype_list_test.go @@ -0,0 +1,44 @@ +// Copyright 2018 The ksonnet authors +// +// +// 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 actions + +import ( + "bytes" + "testing" + + "github.com/ksonnet/ksonnet/metadata/app" + amocks "github.com/ksonnet/ksonnet/metadata/app/mocks" + "github.com/stretchr/testify/require" +) + +func TestPrototypeList(t *testing.T) { + withApp(t, func(appMock *amocks.App) { + libaries := app.LibraryRefSpecs{} + + appMock.On("Libraries").Return(libaries, nil) + + a, err := NewPrototypeList(appMock) + require.NoError(t, err) + + var buf bytes.Buffer + a.out = &buf + + err = a.Run() + require.NoError(t, err) + + assertOutput(t, "prototype/list/output.txt", buf.String()) + }) +} diff --git a/actions/testdata/prototype/list/output.txt b/actions/testdata/prototype/list/output.txt new file mode 100644 index 00000000..1c060c2b --- /dev/null +++ b/actions/testdata/prototype/list/output.txt @@ -0,0 +1,7 @@ +NAME DESCRIPTION +==== =========== +io.ksonnet.pkg.configMap A simple config map with optional user-specified data +io.ksonnet.pkg.deployed-service A deployment exposed with a service +io.ksonnet.pkg.namespace Namespace with labels automatically populated from the name +io.ksonnet.pkg.single-port-deployment Replicates a container n times, exposes a single port +io.ksonnet.pkg.single-port-service Service that exposes a single port diff --git a/cmd/prototype.go b/cmd/prototype.go index cb4faadd..5985824c 100644 --- a/cmd/prototype.go +++ b/cmd/prototype.go @@ -43,7 +43,6 @@ var protoShortDesc = map[string]string{ func init() { RootCmd.AddCommand(prototypeCmd) RootCmd.AddCommand(generateCmd) - prototypeCmd.AddCommand(prototypeListCmd) prototypeCmd.AddCommand(prototypeDescribeCmd) prototypeCmd.AddCommand(prototypeSearchCmd) prototypeCmd.AddCommand(prototypeUseCmd) @@ -77,61 +76,6 @@ for your use case. `, } -var prototypeListCmd = &cobra.Command{ - Use: "list", - Short: protoShortDesc["list"], - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) != 0 { - return fmt.Errorf("Command 'prototype list' does not take any arguments") - } - - cwd, err := os.Getwd() - if err != nil { - return err - } - - manager, err := metadata.Find(cwd) - if err != nil { - return err - } - - extProtos, err := manager.GetAllPrototypes() - if err != nil { - return err - } - - index := prototype.NewIndex(extProtos) - protos, err := index.List() - if err != nil { - return err - } else if len(protos) == 0 { - return fmt.Errorf("No prototypes found") - } - - fmt.Print(protos) - - return nil - }, - Long: ` -The ` + "`list`" + ` command displays all prototypes that are available locally, as -well as brief descriptions of what they generate. - -ksonnet comes with a set of system prototypes that you can use out-of-the-box -(e.g.` + " `io.ksonnet.pkg.configMap`" + `). However, you can use more advanced -prototypes like ` + "`io.ksonnet.pkg.redis-stateless`" + ` by downloading extra packages -from the *incubator* registry. - -### Related Commands - -* ` + "`ks prototype describe` " + `— ` + protoShortDesc["describe"] + ` -* ` + "`ks prototype preview` " + `— ` + protoShortDesc["preview"] + ` -* ` + "`ks prototype use` " + `— ` + protoShortDesc["use"] + ` -* ` + "`ks pkg install` " + pkgShortDesc["install"] + ` - -### Syntax -`, -} - var prototypeDescribeCmd = &cobra.Command{ Use: "describe <prototype-name>", Short: protoShortDesc["describe"], diff --git a/cmd/prototype_list.go b/cmd/prototype_list.go new file mode 100644 index 00000000..da358d40 --- /dev/null +++ b/cmd/prototype_list.go @@ -0,0 +1,42 @@ +package cmd + +import ( + "fmt" + + "github.com/ksonnet/ksonnet/actions" + "github.com/spf13/cobra" +) + +var prototypeListCmd = &cobra.Command{ + Use: "list", + Short: protoShortDesc["list"], + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) != 0 { + return fmt.Errorf("Command 'prototype list' does not take any arguments") + } + + return actions.RunPrototypeList(ka) + }, + Long: ` +The ` + "`list`" + ` command displays all prototypes that are available locally, as +well as brief descriptions of what they generate. + +ksonnet comes with a set of system prototypes that you can use out-of-the-box +(e.g.` + " `io.ksonnet.pkg.configMap`" + `). However, you can use more advanced +prototypes like ` + "`io.ksonnet.pkg.redis-stateless`" + ` by downloading extra packages +from the *incubator* registry. + +### Related Commands + +* ` + "`ks prototype describe` " + `— ` + protoShortDesc["describe"] + ` +* ` + "`ks prototype preview` " + `— ` + protoShortDesc["preview"] + ` +* ` + "`ks prototype use` " + `— ` + protoShortDesc["use"] + ` +* ` + "`ks pkg install` " + pkgShortDesc["install"] + ` + +### Syntax +`, +} + +func init() { + prototypeCmd.AddCommand(prototypeListCmd) +} diff --git a/e2e/prototype_test.go b/e2e/prototype_test.go index e54967b6..cadfbd70 100644 --- a/e2e/prototype_test.go +++ b/e2e/prototype_test.go @@ -48,10 +48,20 @@ var _ = Describe("ks prototype", func() { }) Describe("list", func() { - It("lists available prototypes", func() { - o := a.runKs("prototype", "list") - assertExitStatus(o, 0) - assertOutput("prototype/list/output.txt", o.stdout) + Context("with system prototypes", func() { + It("lists available prototypes", func() { + o := a.runKs("prototype", "list") + assertExitStatus(o, 0) + assertOutput("prototype/list/output.txt", o.stdout) + }) + }) + Context("with a part installed", func() { + It("lists available prototypes", func() { + a.pkgInstall("incubator/apache") + o := a.runKs("prototype", "list") + assertExitStatus(o, 0) + assertOutput("prototype/list/output-with-addition.txt", o.stdout) + }) }) }) diff --git a/e2e/testdata/output/prototype/list/output-with-addition.txt b/e2e/testdata/output/prototype/list/output-with-addition.txt new file mode 100644 index 00000000..4fae5015 --- /dev/null +++ b/e2e/testdata/output/prototype/list/output-with-addition.txt @@ -0,0 +1,8 @@ +NAME DESCRIPTION +==== =========== +io.ksonnet.pkg.apache-simple A simple, stateless Apache HTTP server. +io.ksonnet.pkg.configMap A simple config map with optional user-specified data +io.ksonnet.pkg.deployed-service A deployment exposed with a service +io.ksonnet.pkg.namespace Namespace with labels automatically populated from the name +io.ksonnet.pkg.single-port-deployment Replicates a container n times, exposes a single port +io.ksonnet.pkg.single-port-service Service that exposes a single port diff --git a/pkg/pkg/pkg.go b/pkg/pkg/pkg.go index dae545c5..9b8ff1c3 100644 --- a/pkg/pkg/pkg.go +++ b/pkg/pkg/pkg.go @@ -36,7 +36,7 @@ type Package struct { // New creates a new new instance of Package using a part. func New(a app.App, d Descriptor, part *parts.Spec) (*Package, error) { - prototypes, err := loadPrototypes(a, d) + prototypes, err := LoadPrototypes(a, d) if err != nil { return nil, err } @@ -60,8 +60,8 @@ func NewFromData(a app.App, d Descriptor, data []byte) (*Package, error) { return New(a, d, part) } -// loadPrototypes returns prototypes for a Package. -func loadPrototypes(a app.App, d Descriptor) (prototype.SpecificationSchemas, error) { +// LoadPrototypes returns prototypes for a Package. +func LoadPrototypes(a app.App, d Descriptor) (prototype.SpecificationSchemas, error) { vp := vendorPath(a) var prototypes prototype.SpecificationSchemas -- GitLab