From b4b81be1f78c4718e4947029b9e56cbb77ca0cf4 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Thu, 22 Aug 2019 12:26:25 -0500 Subject: [PATCH 1/3] Split the install target Make it easier to install just the porter binaries or just the mixins. This is useful when you are iterating on VS Code work and need to just drop in the porter binaries without messing up which mixins are installed. --- Makefile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 84624d072..52a4aaa4c 100644 --- a/Makefile +++ b/Makefile @@ -168,12 +168,16 @@ fetch-bundle-schema: @curl --fail --silent --show-error -o $(BUNDLE_SCHEMA_PATH) \ https://raw.githubusercontent.com/deislabs/cnab-spec/master/schema/bundle.schema.json -install: +install: install-porter install-mixins + +install-porter: mkdir -p $(HOME)/.porter - cp -R bin/mixins $(HOME)/.porter/ cp bin/porter* $(HOME)/.porter/ ln -f -s $(HOME)/.porter/porter /usr/local/bin/porter +install-mixins: + cp -R bin/mixins $(HOME)/.porter/ + clean: clean-mixins clean-last-testrun clean-mixins: From 393f94c0cf6f4f0b7695ac462f47d0484bd62f07 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Thu, 22 Aug 2019 12:28:09 -0500 Subject: [PATCH 2/3] Add troubleshooting hook to porter schema When porter.json is present in PORTER_HOME, the porter schema command will return it, instead of generating a schema. This is intended to assist with troubleshooting VS Code. It will allow someone to tweak the schema without modifying porter or the mixins and quickly iterate inside of VS Code, and then we can update the Go code to match the desired schema later. --- pkg/porter/schema.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/pkg/porter/schema.go b/pkg/porter/schema.go index 0c7a3e77b..cc8585054 100644 --- a/pkg/porter/schema.go +++ b/pkg/porter/schema.go @@ -3,6 +3,7 @@ package porter import ( "encoding/json" "fmt" + "path/filepath" "strings" "github.com/pkg/errors" @@ -27,6 +28,14 @@ func (p *Porter) PrintManifestSchema() error { } func (p *Porter) GetManifestSchema() (jsonSchema, error) { + replacementSchema, err := p.GetReplacementSchema() + if err != nil && p.Debug { + fmt.Fprintln(p.Err, errors.Wrap(err, "ignoring replacement schema")) + } + if replacementSchema != nil { + return replacementSchema, nil + } + b, err := p.Templates.GetSchema() if err != nil { return nil, err @@ -145,4 +154,28 @@ func (p *Porter) GetManifestSchema() (jsonSchema, error) { mixinItemSchema["enum"] = mixinEnumSchema return manifestSchema, nil + +func (p *Porter) GetReplacementSchema() (jsonSchema, error) { + home, err := p.GetHomeDir() + if err != nil { + return nil, err + } + + replacementSchemaPath := filepath.Join(home, "porter.json") + if exists, _ := p.FileSystem.Exists(replacementSchemaPath); !exists { + return nil, nil + } + + b, err := p.FileSystem.ReadFile(replacementSchemaPath) + if err != nil { + return nil, errors.Wrapf(err, "could not read replacement schema at %s", replacementSchemaPath) + } + + replacementSchema := make(jsonSchema) + err = json.Unmarshal(b, &replacementSchema) + if err != nil { + return nil, errors.Wrapf(err, "could not unmarshal replacement schema in %s", replacementSchemaPath) + } + + return replacementSchema, nil } From 790e94e64eb3156d0a37ebab18862b8ed9484b6e Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Thu, 22 Aug 2019 12:30:08 -0500 Subject: [PATCH 3/3] Make porter schema more robust * When an error occurs generating a schema, return the template so that we at least have the basic schema available at all times. * When an error occurs injecting a mixin, always skip and continue to the next, never error out so that an out of date mixin doesn't cause the entire command to fail. --- pkg/porter/schema.go | 49 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/pkg/porter/schema.go b/pkg/porter/schema.go index cc8585054..5a8f690d7 100644 --- a/pkg/porter/schema.go +++ b/pkg/porter/schema.go @@ -47,16 +47,34 @@ func (p *Porter) GetManifestSchema() (jsonSchema, error) { return nil, errors.Wrap(err, "could not unmarshal the root porter manifest schema") } + combinedSchema, err := p.injectMixinSchemas(manifestSchema) + if err != nil { + if p.Debug { + fmt.Fprintln(p.Err, err) + } + // Fallback to the porter schema, without any mixins + return manifestSchema, nil + } + + return combinedSchema, nil +} + +func (p *Porter) injectMixinSchemas(manifestSchema jsonSchema) (jsonSchema, error) { propertiesSchema, ok := manifestSchema["properties"].(jsonSchema) if !ok { return nil, errors.Errorf("root porter manifest schema has invalid properties type, expected map[string]interface{} but got %T", manifestSchema["properties"]) } - patternPropertiesSchema, ok := manifestSchema["patternProperties"].(jsonSchema)[".*"].(jsonSchema) + patternProperties, ok := manifestSchema["patternProperties"].(jsonSchema) if !ok { return nil, errors.Errorf("root porter manifest schema has invalid patternProperties type, expected map[string]interface{} but got %T", manifestSchema["patternProperties"]) } + patternPropertiesSchema, ok := patternProperties[".*"].(jsonSchema) + if !ok { + return nil, errors.Errorf("root porter manifest schema has invalid patternProperties[.*] type, expected map[string]interface{} but got %T", patternProperties[".*"]) + } + mixinSchema, ok := propertiesSchema["mixins"].(jsonSchema) if !ok { return nil, errors.Errorf("root porter manifest schema has invalid properties.mixins type, expected map[string]interface{} but got %T", propertiesSchema["mixins"]) @@ -87,6 +105,7 @@ func (p *Porter) GetManifestSchema() (jsonSchema, error) { return nil, err } + // If there is an error with any mixin, print a warning and skip the mixin, do not return an error for _, mixin := range mixins { mixinSchema, err := p.Mixins.GetSchema(mixin) if err != nil { @@ -102,8 +121,9 @@ func (p *Porter) GetManifestSchema() (jsonSchema, error) { mixinSchemaMap := make(jsonSchema) 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) + if err != nil && p.Debug { + fmt.Fprintln(p.Err, errors.Wrapf(err, "could not unmarshal mixin schema for %s, %q", mixin.Name, mixinSchema)) + continue } mixinEnumSchema = append(mixinEnumSchema, mixin.Name) @@ -113,13 +133,17 @@ func (p *Porter) GetManifestSchema() (jsonSchema, error) { for _, action := range coreActions { actionItemSchema, ok := actionSchemas[string(action)]["items"].(jsonSchema) - if err != nil { - return nil, errors.Errorf("root porter manifest schema has invalid properties.%s.items type, expected map[string]interface{} but got %T", action, actionSchemas[string(action)]["items"]) + if err != nil && p.Debug { + fmt.Fprintln(p.Err, errors.Errorf("root porter manifest schema has invalid properties.%s.items type, expected map[string]interface{} but got %T", action, actionSchemas[string(action)]["items"])) + continue } actionAnyOfSchema, ok := actionItemSchema["anyOf"].([]interface{}) if !ok { - return nil, errors.Errorf("root porter manifest schema has invalid properties.%s.items.anyOf type, expected []interface{} but got %T", action, actionItemSchema["anyOf"]) + if err != nil && p.Debug { + fmt.Fprintln(p.Err, errors.Errorf("root porter manifest schema has invalid properties.%s.items.anyOf type, expected []interface{} but got %T", action, actionItemSchema["anyOf"])) + continue + } } actionRef := fmt.Sprintf("#/mixin.%s/definitions/%sStep", mixin.Name, action) @@ -136,13 +160,15 @@ func (p *Porter) GetManifestSchema() (jsonSchema, error) { actionRef := fmt.Sprintf("#/mixin.%s/definitions/invokeStep", mixin.Name) actionItemSchema, ok := patternPropertiesSchema["items"].(jsonSchema) - if err != nil { - return nil, errors.Errorf("root porter manifest schema has invalid patternProperties.items type, expected map[string]interface{} but got %T", patternPropertiesSchema["items"]) + if err != nil && p.Debug { + fmt.Fprintln(p.Err, errors.Errorf("root porter manifest schema has invalid patternProperties.items type, expected map[string]interface{} but got %T", patternPropertiesSchema["items"])) + continue } actionAnyOfSchema, ok := actionItemSchema["anyOf"].([]interface{}) - if !ok { - return nil, errors.Errorf("root porter manifest schema has invalid patternProperties.items.anyOf type, expected []interface{} but got %T", actionItemSchema["anyOf"]) + if !ok && p.Debug { + fmt.Fprintln(p.Err, errors.Errorf("root porter manifest schema has invalid patternProperties.items.anyOf type, expected []interface{} but got %T", actionItemSchema["anyOf"])) + continue } actionAnyOfSchema = append(actionAnyOfSchema, jsonObject{"$ref": actionRef}) @@ -153,7 +179,8 @@ func (p *Porter) GetManifestSchema() (jsonSchema, error) { // Save the updated arrays into the json schema document mixinItemSchema["enum"] = mixinEnumSchema - return manifestSchema, nil + return manifestSchema, err +} func (p *Porter) GetReplacementSchema() (jsonSchema, error) { home, err := p.GetHomeDir()