From 3c4e10533d2ff250f421f046723d747cdd6c0833 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Wed, 6 Feb 2019 18:47:02 -0600 Subject: [PATCH 1/7] porter schema root command Print out the manifest json schema --- CONTRIBUTING.md | 2 +- cmd/porter/main.go | 1 + cmd/porter/run.go | 2 +- cmd/porter/schema.go | 17 ++++ pkg/config/actions.go | 27 ++++-- pkg/config/actions_test.go | 22 +++++ pkg/mixin/runner.go | 10 +-- pkg/porter/mixins.go | 14 +++- pkg/porter/schema.go | 141 ++++++++++++++++++++++++++++++++ pkg/porter/schema/manifest.json | 60 ++++++++++++++ pkg/porter/schema_test.go | 25 ++++++ pkg/porter/testdata/schema.json | 60 ++++++++++++++ 12 files changed, 368 insertions(+), 13 deletions(-) create mode 100644 cmd/porter/schema.go create mode 100644 pkg/config/actions_test.go create mode 100644 pkg/porter/schema.go create mode 100644 pkg/porter/schema/manifest.json create mode 100644 pkg/porter/schema_test.go create mode 100644 pkg/porter/testdata/schema.json diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a17a5e7d4..9e10e4ecc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -46,7 +46,7 @@ We use [Hugo](gohugo.io) to build our documentation site, and it is hosted on [N 1. Run `make docs-preview` to start Hugo. It will watch the file system for changes. 1. Open to preview the site. -If anyone is interested in contributing changes to our makefile to improve the authoring exerience, such +If anyone is interested in contributing changes to our makefile to improve the authoring experience, such as doing this with Docker so that you don't need Hugo installed, it would be a welcome contribution! ❤️ [good-first-issue]: https://github.com/deislabs/porter/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22+label%3Abacklog+ diff --git a/cmd/porter/main.go b/cmd/porter/main.go index fc3899d38..4e91bf5cb 100644 --- a/cmd/porter/main.go +++ b/cmd/porter/main.go @@ -31,6 +31,7 @@ func buildRootCommand() *cobra.Command { cmd.PersistentFlags().BoolVar(&p.Debug, "debug", false, "Enable debug logging") cmd.AddCommand(buildVersionCommand(p)) + cmd.AddCommand(buildSchemaCommand(p)) cmd.AddCommand(buildCreateCommand(p)) cmd.AddCommand(buildRunCommand(p)) cmd.AddCommand(buildBuildCommand(p)) diff --git a/cmd/porter/run.go b/cmd/porter/run.go index 70e4dd200..b8922e070 100644 --- a/cmd/porter/run.go +++ b/cmd/porter/run.go @@ -23,7 +23,7 @@ func buildRunCommand(p *porter.Porter) *cobra.Command { if opts.rawAction == "" { opts.rawAction = os.Getenv(config.EnvACTION) if p.Debug { - fmt.Fprintf(p.Out, "DEBUG: defaulting action to %s (%s)\n", config.EnvACTION, opts.rawAction) + fmt.Fprintf(p.Err, "DEBUG: defaulting action to %s (%s)\n", config.EnvACTION, opts.rawAction) } } diff --git a/cmd/porter/schema.go b/cmd/porter/schema.go new file mode 100644 index 000000000..f9a9ae82b --- /dev/null +++ b/cmd/porter/schema.go @@ -0,0 +1,17 @@ +package main + +import ( + "github.com/deislabs/porter/pkg/porter" + "github.com/spf13/cobra" +) + +func buildSchemaCommand(p *porter.Porter) *cobra.Command { + cmd := &cobra.Command{ + Use: "schema", + Short: "Print the JSON schema for the Porter manifest", + RunE: func(cmd *cobra.Command, args []string) error { + return p.PrintManifestSchema() + }, + } + return cmd +} diff --git a/pkg/config/actions.go b/pkg/config/actions.go index b0a042d35..63442fde4 100644 --- a/pkg/config/actions.go +++ b/pkg/config/actions.go @@ -1,21 +1,38 @@ package config -import "fmt" +import ( + "fmt" + "strings" +) type Action string const ( - ActionInstall Action = "install" - ActionUpgrade Action = "upgrade" - ActionUninstall Action = "uninstall" + ActionInstall Action = "install" + ActionUpgrade Action = "upgrade" + ActionUninstall Action = "uninstall" + ErrInvalidAction string = "invalid action" ) +// IsSupportedAction determines if the value is an action supported by Porter. +func IsSupportedAction(value string) bool { + _, err := ParseAction(value) + return err == nil +} + +// ParseAction converts a string into an Action, or returns an error message. func ParseAction(value string) (Action, error) { action := Action(value) switch action { case ActionInstall, ActionUpgrade, ActionUninstall: return action, nil default: - return "", fmt.Errorf("invalid action %q", value) + return "", fmt.Errorf("%s %q", ErrInvalidAction, value) } } + +// IsInvalidActionError determines if an error is the error returned by ParseAction when +// a value isn't a valid action. +func IsInvalidActionError(err error) bool { + return strings.HasPrefix(err.Error(), ErrInvalidAction) +} diff --git a/pkg/config/actions_test.go b/pkg/config/actions_test.go new file mode 100644 index 000000000..bf9061b36 --- /dev/null +++ b/pkg/config/actions_test.go @@ -0,0 +1,22 @@ +package config + +import "testing" + +func TestIsSupportedAction(t *testing.T) { + testcases := map[string]bool{ + "install": true, + "upgrade": true, + "uninstall": true, + "status": false, + "INSTALL": false, + } + + for action, wantSupported := range testcases { + t.Run(action, func(t *testing.T) { + gotSupported := IsSupportedAction(action) + if wantSupported != gotSupported { + t.Fatalf("IsSupportedAction(%q) failed, want %t, got %t", action, wantSupported, gotSupported) + } + }) + } +} diff --git a/pkg/mixin/runner.go b/pkg/mixin/runner.go index b7dd13563..7827bb424 100644 --- a/pkg/mixin/runner.go +++ b/pkg/mixin/runner.go @@ -50,10 +50,10 @@ func (r *Runner) Validate() error { func (r *Runner) Run() error { if r.Debug { - fmt.Fprintf(r.Out, "DEBUG mixin: %s\n", r.Mixin) - fmt.Fprintf(r.Out, "DEBUG mixinDir: %s\n", r.mixinDir) - fmt.Fprintf(r.Out, "DEBUG file: %s\n", r.File) - fmt.Fprintf(r.Out, "DEBUG stdin:\n%s\n", r.Step) + fmt.Fprintf(r.Err, "DEBUG mixin: %s\n", r.Mixin) + fmt.Fprintf(r.Err, "DEBUG mixinDir: %s\n", r.mixinDir) + fmt.Fprintf(r.Err, "DEBUG file: %s\n", r.File) + fmt.Fprintf(r.Err, "DEBUG stdin:\n%s\n", r.Step) } mixinPath := r.getMixinPath() @@ -84,7 +84,7 @@ func (r *Runner) Run() error { prettyCmd := fmt.Sprintf("%s %s", cmd.Path, strings.Join(cmd.Args, " ")) if r.Debug { - fmt.Fprintln(r.Out, prettyCmd) + fmt.Fprintln(r.Err, prettyCmd) } err := cmd.Start() diff --git a/pkg/porter/mixins.go b/pkg/porter/mixins.go index 2adbde175..794f732a1 100644 --- a/pkg/porter/mixins.go +++ b/pkg/porter/mixins.go @@ -2,13 +2,19 @@ package porter import ( "fmt" + "path/filepath" "github.com/deislabs/porter/pkg/printer" "github.com/pkg/errors" ) type MixinMetaData struct { + // Mixin Name Name string + // Mixin Directory + Dir string + // Path to the client executable + ClientPath string // Version // Repository or Source (where did it come from) // Author @@ -56,7 +62,13 @@ func (p *Porter) GetMixins() ([]MixinMetaData, error) { if !file.IsDir() { continue } - mixins = append(mixins, MixinMetaData{Name: file.Name()}) + + mixinDir := filepath.Join(mixinsDir, file.Name()) + mixins = append(mixins, MixinMetaData{ + Name: file.Name(), + ClientPath: filepath.Join(mixinDir, file.Name()), + Dir: mixinDir, + }) } return mixins, nil diff --git a/pkg/porter/schema.go b/pkg/porter/schema.go new file mode 100644 index 000000000..d440e2161 --- /dev/null +++ b/pkg/porter/schema.go @@ -0,0 +1,141 @@ +package porter + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + + "github.com/pkg/errors" + + "github.com/deislabs/porter/pkg/context" + + "github.com/deislabs/porter/pkg/mixin" + + "github.com/gobuffalo/packr/v2" +) + +func (p *Porter) PrintManifestSchema() error { + schemaMap, err := p.GetManifestSchema() + if err != nil { + return err + } + + schema, err := json.MarshalIndent(&schemaMap, "", " ") + if err != nil { + return errors.Wrap(err, "could not marshal the composite porter manifest schema") + } + + fmt.Fprintln(p.Out, string(schema)) + return nil +} + +func (p *Porter) GetManifestSchema() (map[string]interface{}, error) { + t := packr.New("schema", "./schema") + + b, err := t.Find("manifest.json") + if err != nil { + return nil, err + } + + manifestSchema := make(map[string]interface{}) + err = json.Unmarshal(b, &manifestSchema) + if err != nil { + return nil, errors.Wrap(err, "could not unmarshal the root porter manifest schema") + } + + definitionSchema, ok := manifestSchema["definitions"].(map[string]interface{}) + if !ok { + return nil, errors.Errorf("root porter manifest schema has invalid definitions type, expected map[string]interface{} but got %T", manifestSchema["definitions"]) + } + + propertiesSchema, ok := manifestSchema["properties"].(map[string]interface{}) + if !ok { + return nil, errors.Errorf("root porter manifest schema has invalid properties type, expected map[string]interface{} but got %T", manifestSchema["properties"]) + } + + mixinSchema, ok := propertiesSchema["mixins"].(map[string]interface{}) + if !ok { + return nil, errors.Errorf("root porter manifest schema has invalid properties.mixins type, expected map[string]interface{} but got %T", propertiesSchema["mixins"]) + } + + itemsSchema, ok := mixinSchema["items"].(map[string]interface{}) + if !ok { + return nil, errors.Errorf("root porter manifest schema has invalid properties.mixins.items type, expected map[string]interface{} but got %T", mixinSchema["items"]) + } + + enumSchema, ok := itemsSchema["enum"].([]interface{}) + if !ok { + return nil, errors.Errorf("root porter manifest schema has invalid properties.mixins.items.enum type, expected []interface{} but got %T", itemsSchema["enum"]) + } + + installSchema, ok := propertiesSchema["install"].(map[string]interface{}) + if !ok { + return nil, errors.Errorf("root porter manifest schema has invalid properties.install type, expected map[string]interface{} but got %T", propertiesSchema["install"]) + } + + anyOfSchema, ok := installSchema["anyOf"].([]interface{}) + if !ok { + return nil, errors.Errorf("root porter manifest schema has invalid properties.install.anyOf type, expected []interface{} but got %T", installSchema["anyOf"]) + } + + mixins, err := p.GetMixins() + if err != nil { + return nil, err + } + + for _, mixin := range mixins { + mixinSchema, err := p.getMixinSchema(mixin) + if err != nil { + // if a mixin can't report its schema, don't include it and keep going + if p.Debug { + fmt.Fprintln(p.Err, errors.Wrapf(err, "could not query mixin %s for its schema", mixin.Name)) + } + continue + } + + for action, actionSchema := range mixinSchema { + if !config.IsSupportedAction(action) { + continue + } + + ref := fmt.Sprintf("%s.%s", mixin.Name, action) + definitionSchema[ref] = actionSchema + enumSchema = append(enumSchema, mixin.Name) + anyOfSchema = append(anyOfSchema, map[string]interface{}{"$ref": "#/definitions/" + ref}) + } + } + // Save the updated arrays into the json schema document + itemsSchema["enum"] = enumSchema + installSchema["anyOf"] = anyOfSchema + + return manifestSchema, nil +} + +func (p *Porter) getMixinSchema(m MixinMetaData) (map[string]interface{}, error) { + r := mixin.NewRunner(m.Name, m.Dir, false) + r.Command = "schema" + + // Copy the existing context and tweak to pipe the output differently + mixinSchema := &bytes.Buffer{} + var mixinContext context.Context + mixinContext = *p.Context + mixinContext.Out = mixinSchema + if !p.Debug { + mixinContext.Err = ioutil.Discard + } + r.Context = &mixinContext + + err := r.Run() + if err != nil { + return nil, err + } + + schemaMap := make(map[string]interface{}) + err = json.Unmarshal(mixinSchema.Bytes(), &schemaMap) + if err != nil { + return nil, errors.Wrapf(err, "could not unmarshal mixin schema for %s, %q", m.Name, mixinSchema.String()) + } + + return schemaMap, nil +} diff --git a/pkg/porter/schema/manifest.json b/pkg/porter/schema/manifest.json new file mode 100644 index 000000000..d9ca0af79 --- /dev/null +++ b/pkg/porter/schema/manifest.json @@ -0,0 +1,60 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "exec.install": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "exec": { + "type": "object", + "properties": { + "command": { + "type": "string" + }, + "arguments": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + }, + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "version": { + "type": "string" + }, + "invocationImage": { + "type": "string" + }, + "mixins": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "exec" + ] + } + }, + "install": { + "type": "array", + "anyOf": [ + { + "$ref": "#/definitions/exec.install" + } + ] + } + }, + "additionalProperties": false +} diff --git a/pkg/porter/schema_test.go b/pkg/porter/schema_test.go new file mode 100644 index 000000000..c9c025853 --- /dev/null +++ b/pkg/porter/schema_test.go @@ -0,0 +1,25 @@ +package porter + +import ( + "io/ioutil" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestMixin_PrintSchema(t *testing.T) { + p := NewTestPorter(t) + p.TestConfig.SetupPorterHome() + p.Debug = false // Don't print debug warnings about not being able to query the schema of the mixins, messes up the test + + err := p.PrintManifestSchema() + require.NoError(t, err) + + gotSchema := p.TestConfig.TestContext.GetOutput() + + wantSchema, err := ioutil.ReadFile("testdata/schema.json") + require.NoError(t, err) + + assert.Equal(t, string(wantSchema), gotSchema) +} diff --git a/pkg/porter/testdata/schema.json b/pkg/porter/testdata/schema.json new file mode 100644 index 000000000..efcb81cb9 --- /dev/null +++ b/pkg/porter/testdata/schema.json @@ -0,0 +1,60 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "definitions": { + "exec.install": { + "properties": { + "description": { + "type": "string" + }, + "exec": { + "properties": { + "arguments": { + "items": { + "type": "string" + }, + "type": "array" + }, + "command": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "properties": { + "description": { + "type": "string" + }, + "install": { + "anyOf": [ + { + "$ref": "#/definitions/exec.install" + } + ], + "type": "array" + }, + "invocationImage": { + "type": "string" + }, + "mixins": { + "items": { + "enum": [ + "exec" + ], + "type": "string" + }, + "type": "array" + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + } + }, + "type": "object" +} From 5e72fb29fd010ebb39fc234ba60826ede5eb0b47 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Thu, 21 Feb 2019 19:48:35 -0600 Subject: [PATCH 2/7] Define TestMain's in other packages This lets us mock out calling executables from our unit tests. I'm working on making this not needed. But it may span multiple PRs as I split out the MixinProvider interface from the Porter app --- pkg/mixin/exec/main_test.go | 12 ++++++++++++ pkg/porter/main_test.go | 12 ++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 pkg/mixin/exec/main_test.go create mode 100644 pkg/porter/main_test.go diff --git a/pkg/mixin/exec/main_test.go b/pkg/mixin/exec/main_test.go new file mode 100644 index 000000000..3062d8cea --- /dev/null +++ b/pkg/mixin/exec/main_test.go @@ -0,0 +1,12 @@ +package exec + +import ( + "testing" + + "github.com/deislabs/porter/pkg/test" +) + +// sad hack: not sure how to make a common test main for all my subpackages +func TestMain(m *testing.M) { + test.TestMainWithMockedCommandHandlers(m) +} diff --git a/pkg/porter/main_test.go b/pkg/porter/main_test.go new file mode 100644 index 000000000..c796d7c57 --- /dev/null +++ b/pkg/porter/main_test.go @@ -0,0 +1,12 @@ +package porter + +import ( + "testing" + + "github.com/deislabs/porter/pkg/test" +) + +// sad hack: not sure how to make a common test main for all my subpackages +func TestMain(m *testing.M) { + test.TestMainWithMockedCommandHandlers(m) +} From 442fd8b77b13e032bfffe8afb374d5bed0dae573 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Thu, 21 Feb 2019 19:49:45 -0600 Subject: [PATCH 3/7] Split out GetMixins into MixinProvider --- pkg/mixin/metadata.go | 16 +++++++++++ pkg/mixin/provider/filesystem.go | 47 ++++++++++++++++++++++++++++++ pkg/porter/helpers.go | 10 ++++++- pkg/porter/mixins.go | 49 ++++---------------------------- pkg/porter/porter.go | 6 +++- pkg/porter/schema.go | 2 +- 6 files changed, 84 insertions(+), 46 deletions(-) create mode 100644 pkg/mixin/metadata.go create mode 100644 pkg/mixin/provider/filesystem.go diff --git a/pkg/mixin/metadata.go b/pkg/mixin/metadata.go new file mode 100644 index 000000000..55a2f70f9 --- /dev/null +++ b/pkg/mixin/metadata.go @@ -0,0 +1,16 @@ +package mixin + +// Metadata about a mixin +type Metadata struct { + // Mixin Name + Name string + // Mixin Directory + Dir string + // Path to the client executable + ClientPath string + // Version + // Repository or Source (where did it come from) + // Author + // Is it up to date + // etc +} diff --git a/pkg/mixin/provider/filesystem.go b/pkg/mixin/provider/filesystem.go new file mode 100644 index 000000000..3d93066f3 --- /dev/null +++ b/pkg/mixin/provider/filesystem.go @@ -0,0 +1,47 @@ +package mixinprovider + +import ( + "path/filepath" + + "github.com/deislabs/porter/pkg/config" + "github.com/deislabs/porter/pkg/mixin" + "github.com/pkg/errors" +) + +func NewFileSystem(config *config.Config) *FileSystem { + return &FileSystem{ + config: config, + } +} + +type FileSystem struct { + config *config.Config +} + +func (p *FileSystem) GetMixins() ([]mixin.Metadata, error) { + mixinsDir, err := p.config.GetMixinsDir() + if err != nil { + return nil, err + } + + files, err := p.config.FileSystem.ReadDir(mixinsDir) + if err != nil { + return nil, errors.Wrapf(err, "could not list the contents of the mixins directory %q", mixinsDir) + } + + mixins := make([]mixin.Metadata, 0, len(files)) + for _, file := range files { + if !file.IsDir() { + continue + } + + mixinDir := filepath.Join(mixinsDir, file.Name()) + mixins = append(mixins, mixin.Metadata{ + Name: file.Name(), + ClientPath: filepath.Join(mixinDir, file.Name()), + Dir: mixinDir, + }) + } + + return mixins, nil +} diff --git a/pkg/porter/helpers.go b/pkg/porter/helpers.go index 85047ca59..58d2f654e 100644 --- a/pkg/porter/helpers.go +++ b/pkg/porter/helpers.go @@ -3,6 +3,8 @@ package porter import ( "testing" + mixinprovider "github.com/deislabs/porter/pkg/mixin/provider" + "github.com/deislabs/porter/pkg/config" ) @@ -16,10 +18,16 @@ func NewTestPorter(t *testing.T) *TestPorter { c := config.NewTestConfig(t) p := &TestPorter{ Porter: &Porter{ - Config: c.Config, + Config: c.Config, + MixinProvider: mixinprovider.NewFileSystem(c.Config), }, TestConfig: c, } return p } + +// TODO: use this later to not actually execute a mixin during a unit test +type TestMixinProvider struct { + *mixinprovider.FileSystem +} diff --git a/pkg/porter/mixins.go b/pkg/porter/mixins.go index 794f732a1..d79974b19 100644 --- a/pkg/porter/mixins.go +++ b/pkg/porter/mixins.go @@ -2,24 +2,15 @@ package porter import ( "fmt" - "path/filepath" + + "github.com/deislabs/porter/pkg/mixin" "github.com/deislabs/porter/pkg/printer" - "github.com/pkg/errors" ) -type MixinMetaData struct { - // Mixin Name - Name string - // Mixin Directory - Dir string - // Path to the client executable - ClientPath string - // Version - // Repository or Source (where did it come from) - // Author - // Is it up to date - // etc +// MixinProvider handles searching, listing and communicating with the mixins. +type MixinProvider interface { + GetMixins() ([]mixin.Metadata, error) } func (p *Porter) PrintMixins(opts printer.PrintOptions) error { @@ -32,7 +23,7 @@ func (p *Porter) PrintMixins(opts printer.PrintOptions) error { case printer.FormatTable: printMixinRow := func(v interface{}) []interface{} { - m, ok := v.(MixinMetaData) + m, ok := v.(mixin.Metadata) if !ok { return nil } @@ -45,31 +36,3 @@ func (p *Porter) PrintMixins(opts printer.PrintOptions) error { return fmt.Errorf("invalid format: %s", opts.Format) } } - -func (p *Porter) GetMixins() ([]MixinMetaData, error) { - mixinsDir, err := p.GetMixinsDir() - if err != nil { - return nil, err - } - - files, err := p.FileSystem.ReadDir(mixinsDir) - if err != nil { - return nil, errors.Wrapf(err, "could not list the contents of the mixins directory %q", mixinsDir) - } - - mixins := make([]MixinMetaData, 0, len(files)) - for _, file := range files { - if !file.IsDir() { - continue - } - - mixinDir := filepath.Join(mixinsDir, file.Name()) - mixins = append(mixins, MixinMetaData{ - Name: file.Name(), - ClientPath: filepath.Join(mixinDir, file.Name()), - Dir: mixinDir, - }) - } - - return mixins, nil -} diff --git a/pkg/porter/porter.go b/pkg/porter/porter.go index 0c4621bfd..a0b8fe6cd 100644 --- a/pkg/porter/porter.go +++ b/pkg/porter/porter.go @@ -2,16 +2,20 @@ package porter import ( "github.com/deislabs/porter/pkg/config" + mixinprovider "github.com/deislabs/porter/pkg/mixin/provider" ) // Porter is the logic behind the porter client. type Porter struct { *config.Config + MixinProvider } // New porter client, initialized with useful defaults. func New() *Porter { + c := config.New() return &Porter{ - Config: config.New(), + Config: c, + MixinProvider: mixinprovider.NewFileSystem(c), } } diff --git a/pkg/porter/schema.go b/pkg/porter/schema.go index d440e2161..a4f63a67e 100644 --- a/pkg/porter/schema.go +++ b/pkg/porter/schema.go @@ -112,7 +112,7 @@ func (p *Porter) GetManifestSchema() (map[string]interface{}, error) { return manifestSchema, nil } -func (p *Porter) getMixinSchema(m MixinMetaData) (map[string]interface{}, error) { +func (p *Porter) getMixinSchema(m mixin.Metadata) (map[string]interface{}, error) { r := mixin.NewRunner(m.Name, m.Dir, false) r.Command = "schema" From c95a8609e9aaee967d2cab29a6fa4494fa62378f Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Fri, 22 Feb 2019 08:35:31 -0600 Subject: [PATCH 4/7] Split out GetMixinSchema into MixinProvider --- pkg/mixin/provider/filesystem.go | 40 ++++++++++++++++++++++++++++---- pkg/porter/helpers.go | 31 ++++++++++++++++++++++--- pkg/porter/mixins.go | 1 + pkg/porter/schema.go | 38 +++--------------------------- pkg/porter/schema/exec.json | 26 +++++++++++++++++++++ pkg/porter/schema/manifest.json | 35 +++------------------------- 6 files changed, 97 insertions(+), 74 deletions(-) create mode 100644 pkg/porter/schema/exec.json diff --git a/pkg/mixin/provider/filesystem.go b/pkg/mixin/provider/filesystem.go index 3d93066f3..318f20a97 100644 --- a/pkg/mixin/provider/filesystem.go +++ b/pkg/mixin/provider/filesystem.go @@ -1,30 +1,34 @@ package mixinprovider import ( + "bytes" + "encoding/json" + "io/ioutil" "path/filepath" "github.com/deislabs/porter/pkg/config" + "github.com/deislabs/porter/pkg/context" "github.com/deislabs/porter/pkg/mixin" "github.com/pkg/errors" ) func NewFileSystem(config *config.Config) *FileSystem { return &FileSystem{ - config: config, + Config: config, } } type FileSystem struct { - config *config.Config + *config.Config } func (p *FileSystem) GetMixins() ([]mixin.Metadata, error) { - mixinsDir, err := p.config.GetMixinsDir() + mixinsDir, err := p.GetMixinsDir() if err != nil { return nil, err } - files, err := p.config.FileSystem.ReadDir(mixinsDir) + files, err := p.FileSystem.ReadDir(mixinsDir) if err != nil { return nil, errors.Wrapf(err, "could not list the contents of the mixins directory %q", mixinsDir) } @@ -45,3 +49,31 @@ func (p *FileSystem) GetMixins() ([]mixin.Metadata, error) { return mixins, nil } + +func (p *FileSystem) GetMixinSchema(m mixin.Metadata) (map[string]interface{}, error) { + r := mixin.NewRunner(m.Name, m.Dir, false) + r.Command = "schema" + + // Copy the existing context and tweak to pipe the output differently + mixinSchema := &bytes.Buffer{} + var mixinContext context.Context + mixinContext = *p.Context + mixinContext.Out = mixinSchema + if !p.Debug { + mixinContext.Err = ioutil.Discard + } + r.Context = &mixinContext + + err := r.Run() + if err != nil { + return nil, err + } + + schemaMap := make(map[string]interface{}) + err = json.Unmarshal(mixinSchema.Bytes(), &schemaMap) + if err != nil { + return nil, errors.Wrapf(err, "could not unmarshal mixin schema for %s, %q", m.Name, mixinSchema.String()) + } + + return schemaMap, nil +} diff --git a/pkg/porter/helpers.go b/pkg/porter/helpers.go index 58d2f654e..6a1c389b7 100644 --- a/pkg/porter/helpers.go +++ b/pkg/porter/helpers.go @@ -1,8 +1,14 @@ package porter import ( + "encoding/json" "testing" + "github.com/gobuffalo/packr/v2" + "github.com/pkg/errors" + + "github.com/deislabs/porter/pkg/mixin" + mixinprovider "github.com/deislabs/porter/pkg/mixin/provider" "github.com/deislabs/porter/pkg/config" @@ -18,8 +24,10 @@ func NewTestPorter(t *testing.T) *TestPorter { c := config.NewTestConfig(t) p := &TestPorter{ Porter: &Porter{ - Config: c.Config, - MixinProvider: mixinprovider.NewFileSystem(c.Config), + Config: c.Config, + MixinProvider: &TestMixinProvider{ + MixinProvider: mixinprovider.NewFileSystem(c.Config), + }, }, TestConfig: c, } @@ -29,5 +37,22 @@ func NewTestPorter(t *testing.T) *TestPorter { // TODO: use this later to not actually execute a mixin during a unit test type TestMixinProvider struct { - *mixinprovider.FileSystem + MixinProvider +} + +func (p *TestMixinProvider) GetMixinSchema(m mixin.Metadata) (map[string]interface{}, error) { + t := packr.New("schema", "./schema") + + b, err := t.Find(m.Name + ".json") + if err != nil { + return nil, err + } + + manifestSchema := make(map[string]interface{}) + err = json.Unmarshal(b, &manifestSchema) + if err != nil { + return nil, errors.Wrapf(err, "could not unmarshal the %s mixin schema", m.Name) + } + + return manifestSchema, nil } diff --git a/pkg/porter/mixins.go b/pkg/porter/mixins.go index d79974b19..ba68a1199 100644 --- a/pkg/porter/mixins.go +++ b/pkg/porter/mixins.go @@ -11,6 +11,7 @@ import ( // MixinProvider handles searching, listing and communicating with the mixins. type MixinProvider interface { GetMixins() ([]mixin.Metadata, error) + GetMixinSchema(m mixin.Metadata) (map[string]interface{}, error) } func (p *Porter) PrintMixins(opts printer.PrintOptions) error { diff --git a/pkg/porter/schema.go b/pkg/porter/schema.go index a4f63a67e..ca8ccc3fd 100644 --- a/pkg/porter/schema.go +++ b/pkg/porter/schema.go @@ -1,16 +1,12 @@ package porter import ( - "bytes" "encoding/json" "fmt" - "io/ioutil" - "github.com/pkg/errors" - - "github.com/deislabs/porter/pkg/context" + "github.com/deislabs/porter/pkg/config" - "github.com/deislabs/porter/pkg/mixin" + "github.com/pkg/errors" "github.com/gobuffalo/packr/v2" ) @@ -85,7 +81,7 @@ func (p *Porter) GetManifestSchema() (map[string]interface{}, error) { } for _, mixin := range mixins { - mixinSchema, err := p.getMixinSchema(mixin) + mixinSchema, err := p.GetMixinSchema(mixin) if err != nil { // if a mixin can't report its schema, don't include it and keep going if p.Debug { @@ -111,31 +107,3 @@ func (p *Porter) GetManifestSchema() (map[string]interface{}, error) { return manifestSchema, nil } - -func (p *Porter) getMixinSchema(m mixin.Metadata) (map[string]interface{}, error) { - r := mixin.NewRunner(m.Name, m.Dir, false) - r.Command = "schema" - - // Copy the existing context and tweak to pipe the output differently - mixinSchema := &bytes.Buffer{} - var mixinContext context.Context - mixinContext = *p.Context - mixinContext.Out = mixinSchema - if !p.Debug { - mixinContext.Err = ioutil.Discard - } - r.Context = &mixinContext - - err := r.Run() - if err != nil { - return nil, err - } - - schemaMap := make(map[string]interface{}) - err = json.Unmarshal(mixinSchema.Bytes(), &schemaMap) - if err != nil { - return nil, errors.Wrapf(err, "could not unmarshal mixin schema for %s, %q", m.Name, mixinSchema.String()) - } - - return schemaMap, nil -} diff --git a/pkg/porter/schema/exec.json b/pkg/porter/schema/exec.json new file mode 100644 index 000000000..ea2824d35 --- /dev/null +++ b/pkg/porter/schema/exec.json @@ -0,0 +1,26 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "install": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "exec": { + "type": "object", + "properties": { + "command": { + "type": "string" + }, + "arguments": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "additionalProperties": false +} diff --git a/pkg/porter/schema/manifest.json b/pkg/porter/schema/manifest.json index d9ca0af79..f66d2f8f6 100644 --- a/pkg/porter/schema/manifest.json +++ b/pkg/porter/schema/manifest.json @@ -1,29 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "definitions": { - "exec.install": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "exec": { - "type": "object", - "properties": { - "command": { - "type": "string" - }, - "arguments": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - } - } - }, + "definitions": {}, "type": "object", "properties": { "name": { @@ -42,18 +19,12 @@ "type": "array", "items": { "type": "string", - "enum": [ - "exec" - ] + "enum": [] } }, "install": { "type": "array", - "anyOf": [ - { - "$ref": "#/definitions/exec.install" - } - ] + "anyOf": [] } }, "additionalProperties": false From 2639b56bff3d3b7bbab98c27d64e2d60da7dea7b Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Wed, 27 Feb 2019 06:34:45 -0600 Subject: [PATCH 5/7] Add failing test for getting a mixin's schema --- pkg/mixin/provider/filesystem_test.go | 86 +++++++++++++++++++++++++++ pkg/porter/helpers.go | 7 +++ pkg/porter/mixins_test.go | 22 ------- pkg/porter/schema_test.go | 1 - 4 files changed, 93 insertions(+), 23 deletions(-) create mode 100644 pkg/mixin/provider/filesystem_test.go diff --git a/pkg/mixin/provider/filesystem_test.go b/pkg/mixin/provider/filesystem_test.go new file mode 100644 index 000000000..9f04e9e7e --- /dev/null +++ b/pkg/mixin/provider/filesystem_test.go @@ -0,0 +1,86 @@ +package mixinprovider + +import ( + "encoding/json" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "testing" + + "github.com/deislabs/porter/pkg/config" + "github.com/deislabs/porter/pkg/mixin" + "github.com/spf13/afero" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestFileSystem_GetMixins(t *testing.T) { + // Do this in a temp directory so that we can control which mixins show up in the list + os.Setenv(config.EnvHOME, os.TempDir()) + defer os.Unsetenv(config.EnvHOME) + + c := config.NewTestConfig(t) + c.FileSystem = &afero.Afero{Fs: afero.NewOsFs()} // Hit the real file system for this test + + mixinsDir, err := c.GetMixinsDir() + require.Nil(t, err) + + // Just copy in the exec and helm mixins + srcMixinsDir := filepath.Join(c.TestContext.FindBinDir(), "mixins") + c.CopyDirectory(filepath.Join(srcMixinsDir, "helm"), mixinsDir, true) + c.CopyDirectory(filepath.Join(srcMixinsDir, "exec"), mixinsDir, true) + + p := NewFileSystem(c.Config) + mixins, err := p.GetMixins() + + require.Nil(t, err) + require.Len(t, mixins, 2) + assert.Equal(t, mixins[0].Name, "exec") + assert.Equal(t, mixins[1].Name, "helm") + + dir, err := os.Stat(mixins[0].Dir) + require.NoError(t, err) + assert.True(t, dir.IsDir()) + assert.Equal(t, dir.Name(), "exec") + + binary, err := os.Stat(mixins[0].ClientPath) + require.NoError(t, err) + assert.True(t, binary.Mode().IsRegular()) + assert.Equal(t, binary.Name(), "exec") +} + +func TestFileSystem_GetMixinSchema(t *testing.T) { + c := config.NewTestConfig(t) + // Hit the real file system for this test + c.FileSystem = &afero.Afero{Fs: afero.NewOsFs()} + c.NewCommand = exec.Command + + // bin is my home now + binDir := c.TestContext.FindBinDir() + os.Setenv(config.EnvHOME, binDir) + defer os.Unsetenv(config.EnvHOME) + + p := NewFileSystem(c.Config) + mixins, err := p.GetMixins() + require.NoError(t, err) + + var e *mixin.Metadata + for _, m := range mixins { + if m.Name == "exec" { + e = &m + } + } + require.NotNil(t, e) + + schema, err := p.GetMixinSchema(*e) + require.NoError(t, err) + + gotSchema, err := json.MarshalIndent(schema, "", " ") + require.NoError(t, err) + + wantSchema, err := ioutil.ReadFile("../../porter/schema/exec.json") + require.NoError(t, err) + + assert.Equal(t, string(wantSchema), string(gotSchema)) +} diff --git a/pkg/porter/helpers.go b/pkg/porter/helpers.go index 6a1c389b7..499e021f6 100644 --- a/pkg/porter/helpers.go +++ b/pkg/porter/helpers.go @@ -40,6 +40,13 @@ type TestMixinProvider struct { MixinProvider } +func (p *TestMixinProvider) GetMixins() ([]mixin.Metadata, error) { + mixins := []mixin.Metadata{ + {Name: "exec"}, + } + return mixins, nil +} + func (p *TestMixinProvider) GetMixinSchema(m mixin.Metadata) (map[string]interface{}, error) { t := packr.New("schema", "./schema") diff --git a/pkg/porter/mixins_test.go b/pkg/porter/mixins_test.go index 1b00818e9..e9aa2775e 100644 --- a/pkg/porter/mixins_test.go +++ b/pkg/porter/mixins_test.go @@ -11,28 +11,6 @@ import ( "github.com/stretchr/testify/require" ) -func TestPorter_GetMixins(t *testing.T) { - p := NewTestPorter(t) - p.TestConfig.SetupPorterHome() - - // Start with a fresh mixins dir to make the test more durable as we add more mixins later - mixinsDir, err := p.GetMixinsDir() - require.Nil(t, err) - err = p.FileSystem.RemoveAll(mixinsDir) - require.Nil(t, err) - - // Just copy in the exec and helm mixins - p.TestConfig.TestContext.AddTestDirectory("../../bin/mixins/helm", filepath.Join(mixinsDir, "helm")) - p.TestConfig.TestContext.AddTestDirectory("../../bin/mixins/exec", filepath.Join(mixinsDir, "exec")) - - mixins, err := p.GetMixins() - - require.Nil(t, err) - require.Len(t, mixins, 2) - assert.Equal(t, mixins[0].Name, "exec") - assert.Equal(t, mixins[1].Name, "helm") -} - func TestPorter_PrintMixins(t *testing.T) { p := NewTestPorter(t) p.TestConfig.SetupPorterHome() diff --git a/pkg/porter/schema_test.go b/pkg/porter/schema_test.go index c9c025853..4f55a4424 100644 --- a/pkg/porter/schema_test.go +++ b/pkg/porter/schema_test.go @@ -11,7 +11,6 @@ import ( func TestMixin_PrintSchema(t *testing.T) { p := NewTestPorter(t) p.TestConfig.SetupPorterHome() - p.Debug = false // Don't print debug warnings about not being able to query the schema of the mixins, messes up the test err := p.PrintManifestSchema() require.NoError(t, err) From f6378444cdb90dfa1152119289cc39c0f9816c7f Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Sat, 23 Feb 2019 06:36:25 -0600 Subject: [PATCH 6/7] Tweak GetMixinSchema interface --- pkg/mixin/provider/filesystem.go | 13 +++---------- pkg/mixin/provider/filesystem_test.go | 9 +++------ pkg/porter/helpers.go | 21 +++------------------ pkg/porter/mixins.go | 2 +- pkg/porter/schema.go | 8 +++++++- pkg/porter/schema/exec.json | 26 -------------------------- 6 files changed, 17 insertions(+), 62 deletions(-) delete mode 100644 pkg/porter/schema/exec.json diff --git a/pkg/mixin/provider/filesystem.go b/pkg/mixin/provider/filesystem.go index 318f20a97..c39f30579 100644 --- a/pkg/mixin/provider/filesystem.go +++ b/pkg/mixin/provider/filesystem.go @@ -2,7 +2,6 @@ package mixinprovider import ( "bytes" - "encoding/json" "io/ioutil" "path/filepath" @@ -50,7 +49,7 @@ func (p *FileSystem) GetMixins() ([]mixin.Metadata, error) { return mixins, nil } -func (p *FileSystem) GetMixinSchema(m mixin.Metadata) (map[string]interface{}, error) { +func (p *FileSystem) GetMixinSchema(m mixin.Metadata) (string, error) { r := mixin.NewRunner(m.Name, m.Dir, false) r.Command = "schema" @@ -66,14 +65,8 @@ func (p *FileSystem) GetMixinSchema(m mixin.Metadata) (map[string]interface{}, e err := r.Run() if err != nil { - return nil, err - } - - schemaMap := make(map[string]interface{}) - err = json.Unmarshal(mixinSchema.Bytes(), &schemaMap) - if err != nil { - return nil, errors.Wrapf(err, "could not unmarshal mixin schema for %s, %q", m.Name, mixinSchema.String()) + return "", err } - return schemaMap, nil + return mixinSchema.String(), nil } diff --git a/pkg/mixin/provider/filesystem_test.go b/pkg/mixin/provider/filesystem_test.go index 9f04e9e7e..ff979336a 100644 --- a/pkg/mixin/provider/filesystem_test.go +++ b/pkg/mixin/provider/filesystem_test.go @@ -1,7 +1,6 @@ package mixinprovider import ( - "encoding/json" "io/ioutil" "os" "os/exec" @@ -69,17 +68,15 @@ func TestFileSystem_GetMixinSchema(t *testing.T) { for _, m := range mixins { if m.Name == "exec" { e = &m + break } } require.NotNil(t, e) - schema, err := p.GetMixinSchema(*e) + gotSchema, err := p.GetMixinSchema(*e) require.NoError(t, err) - gotSchema, err := json.MarshalIndent(schema, "", " ") - require.NoError(t, err) - - wantSchema, err := ioutil.ReadFile("../../porter/schema/exec.json") + wantSchema, err := ioutil.ReadFile("../../exec/testdata/schema.json") require.NoError(t, err) assert.Equal(t, string(wantSchema), string(gotSchema)) diff --git a/pkg/porter/helpers.go b/pkg/porter/helpers.go index 499e021f6..fb1565196 100644 --- a/pkg/porter/helpers.go +++ b/pkg/porter/helpers.go @@ -1,15 +1,11 @@ package porter import ( - "encoding/json" "testing" - "github.com/gobuffalo/packr/v2" - "github.com/pkg/errors" - "github.com/deislabs/porter/pkg/mixin" - mixinprovider "github.com/deislabs/porter/pkg/mixin/provider" + "github.com/gobuffalo/packr/v2" "github.com/deislabs/porter/pkg/config" ) @@ -47,19 +43,8 @@ func (p *TestMixinProvider) GetMixins() ([]mixin.Metadata, error) { return mixins, nil } -func (p *TestMixinProvider) GetMixinSchema(m mixin.Metadata) (map[string]interface{}, error) { +func (p *TestMixinProvider) GetMixinSchema(m mixin.Metadata) (string, error) { t := packr.New("schema", "./schema") - b, err := t.Find(m.Name + ".json") - if err != nil { - return nil, err - } - - manifestSchema := make(map[string]interface{}) - err = json.Unmarshal(b, &manifestSchema) - if err != nil { - return nil, errors.Wrapf(err, "could not unmarshal the %s mixin schema", m.Name) - } - - return manifestSchema, nil + return t.FindString(m.Name + ".json") } diff --git a/pkg/porter/mixins.go b/pkg/porter/mixins.go index ba68a1199..2bdd21a6d 100644 --- a/pkg/porter/mixins.go +++ b/pkg/porter/mixins.go @@ -11,7 +11,7 @@ import ( // MixinProvider handles searching, listing and communicating with the mixins. type MixinProvider interface { GetMixins() ([]mixin.Metadata, error) - GetMixinSchema(m mixin.Metadata) (map[string]interface{}, error) + GetMixinSchema(m mixin.Metadata) (string, error) } func (p *Porter) PrintMixins(opts printer.PrintOptions) error { diff --git a/pkg/porter/schema.go b/pkg/porter/schema.go index ca8ccc3fd..e0db8f5d1 100644 --- a/pkg/porter/schema.go +++ b/pkg/porter/schema.go @@ -90,7 +90,13 @@ func (p *Porter) GetManifestSchema() (map[string]interface{}, error) { continue } - for action, actionSchema := range mixinSchema { + mixinSchemaMap := make(map[string]interface{}) + err = json.Unmarshal([]byte(mixinSchema), &mixinSchemaMap) + if err != nil { + return nil, errors.Wrapf(err, "could not unmarshal mixin schema for %s, %q", mixin.Name, mixinSchema) + } + + for action, actionSchema := range mixinSchemaMap { if !config.IsSupportedAction(action) { continue } diff --git a/pkg/porter/schema/exec.json b/pkg/porter/schema/exec.json deleted file mode 100644 index ea2824d35..000000000 --- a/pkg/porter/schema/exec.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "install": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "exec": { - "type": "object", - "properties": { - "command": { - "type": "string" - }, - "arguments": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - } - }, - "additionalProperties": false -} From 106ccfe8f0a9116049a5401978c7d0bf88a39ff0 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Sat, 23 Feb 2019 12:22:13 -0600 Subject: [PATCH 7/7] Box keeping * Use a function to create a box so we use the right name consistently * Save the box variable for reuse * Ensure we don't end up with nil pointers in any code paths --- pkg/config/config.go | 14 +++++++++----- pkg/config/helpers.go | 13 ++++++------- pkg/exec/exec.go | 2 ++ pkg/porter/helpers.go | 29 +++++++++++------------------ pkg/porter/porter.go | 11 +++++++++++ pkg/porter/schema.go | 6 +----- 6 files changed, 40 insertions(+), 35 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index a8568dfa0..4794578b6 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -36,15 +36,21 @@ type Config struct { Manifest *Manifest porterHome string + templates *packr.Box } // New Config initializes a default porter configuration. func New() *Config { return &Config{ - Context: context.New(), + Context: context.New(), + templates: NewTemplatesBox(), } } +func NewTemplatesBox() *packr.Box { + return packr.New("github.com/deislabs/porter/pkg/config/templates", "./templates") +} + // GetHomeDir determines the path to the porter home directory. func (c *Config) GetHomeDir() (string, error) { if c.porterHome != "" { @@ -98,14 +104,12 @@ func (c *Config) GetPorterRuntimePath() (string, error) { // GetPorterConfigTemplate returns a porter.yaml template file for use in new bundles func (c *Config) GetPorterConfigTemplate() ([]byte, error) { - t := packr.New("templates", "./templates") - return t.Find(Name) + return c.templates.Find(Name) } // GetRunScriptTemplate returns a run.sh template for use in new bundles func (c *Config) GetRunScriptTemplate() ([]byte, error) { - t := packr.New("templates", "./templates") - return t.Find(filepath.Base(RunScript)) + return c.templates.Find(filepath.Base(RunScript)) } // GetBundleManifest gets the path to another bundle's manifest. diff --git a/pkg/config/helpers.go b/pkg/config/helpers.go index 80c468bb1..eb62b1250 100644 --- a/pkg/config/helpers.go +++ b/pkg/config/helpers.go @@ -14,14 +14,13 @@ type TestConfig struct { // NewTestConfig initializes a configuration suitable for testing, with the output buffered, and an in-memory file system. func NewTestConfig(t *testing.T) *TestConfig { - cxt := context.NewTestContext(t) - c := &TestConfig{ - Config: &Config{ - Context: cxt.Context, - }, - TestContext: cxt, + tc := context.NewTestContext(t) + cfg := New() + cfg.Context = tc.Context + return &TestConfig{ + Config: cfg, + TestContext: tc, } - return c } // InitializePorterHome initializes the test filesystem with the supporting files in the PORTER_HOME directory. diff --git a/pkg/exec/exec.go b/pkg/exec/exec.go index 69e2bd1ee..967b26d12 100644 --- a/pkg/exec/exec.go +++ b/pkg/exec/exec.go @@ -1,3 +1,5 @@ +//go:generate packr2 + package exec import ( diff --git a/pkg/porter/helpers.go b/pkg/porter/helpers.go index fb1565196..fee780272 100644 --- a/pkg/porter/helpers.go +++ b/pkg/porter/helpers.go @@ -3,11 +3,10 @@ package porter import ( "testing" - "github.com/deislabs/porter/pkg/mixin" - mixinprovider "github.com/deislabs/porter/pkg/mixin/provider" - "github.com/gobuffalo/packr/v2" + "github.com/deislabs/porter/pkg/exec" "github.com/deislabs/porter/pkg/config" + "github.com/deislabs/porter/pkg/mixin" ) type TestPorter struct { @@ -17,23 +16,18 @@ type TestPorter struct { // NewTestPorter initializes a porter test client, with the output buffered, and an in-memory file system. func NewTestPorter(t *testing.T) *TestPorter { - c := config.NewTestConfig(t) - p := &TestPorter{ - Porter: &Porter{ - Config: c.Config, - MixinProvider: &TestMixinProvider{ - MixinProvider: mixinprovider.NewFileSystem(c.Config), - }, - }, - TestConfig: c, + tc := config.NewTestConfig(t) + p := New() + p.Config = tc.Config + p.MixinProvider = &TestMixinProvider{} + return &TestPorter{ + Porter: p, + TestConfig: tc, } - - return p } // TODO: use this later to not actually execute a mixin during a unit test type TestMixinProvider struct { - MixinProvider } func (p *TestMixinProvider) GetMixins() ([]mixin.Metadata, error) { @@ -44,7 +38,6 @@ func (p *TestMixinProvider) GetMixins() ([]mixin.Metadata, error) { } func (p *TestMixinProvider) GetMixinSchema(m mixin.Metadata) (string, error) { - t := packr.New("schema", "./schema") - - return t.FindString(m.Name + ".json") + t := exec.NewSchemaBox() + return t.FindString("exec.json") } diff --git a/pkg/porter/porter.go b/pkg/porter/porter.go index a0b8fe6cd..7d684a351 100644 --- a/pkg/porter/porter.go +++ b/pkg/porter/porter.go @@ -1,14 +1,19 @@ +//go:generate packr2 + package porter import ( "github.com/deislabs/porter/pkg/config" mixinprovider "github.com/deislabs/porter/pkg/mixin/provider" + "github.com/gobuffalo/packr/v2" ) // Porter is the logic behind the porter client. type Porter struct { *config.Config MixinProvider + + schemas *packr.Box } // New porter client, initialized with useful defaults. @@ -17,5 +22,11 @@ func New() *Porter { return &Porter{ Config: c, MixinProvider: mixinprovider.NewFileSystem(c), + schemas: NewSchemaBox(), } } + +// NewSchemas creates or retrieves the packr box with the porter schemas files. +func NewSchemaBox() *packr.Box { + return packr.New("github.com/deislabs/porter/pkg/porter/schema", "./schema") +} diff --git a/pkg/porter/schema.go b/pkg/porter/schema.go index e0db8f5d1..a7e92752e 100644 --- a/pkg/porter/schema.go +++ b/pkg/porter/schema.go @@ -7,8 +7,6 @@ import ( "github.com/deislabs/porter/pkg/config" "github.com/pkg/errors" - - "github.com/gobuffalo/packr/v2" ) func (p *Porter) PrintManifestSchema() error { @@ -27,9 +25,7 @@ func (p *Porter) PrintManifestSchema() error { } func (p *Porter) GetManifestSchema() (map[string]interface{}, error) { - t := packr.New("schema", "./schema") - - b, err := t.Find("manifest.json") + b, err := p.schemas.Find("manifest.json") if err != nil { return nil, err }