From cc05008e9a1f8b8209256ad3678b0dce22d0348b Mon Sep 17 00:00:00 2001 From: yutaoj <105471132+yutaoj@users.noreply.github.com> Date: Wed, 17 Jan 2024 14:58:03 +0800 Subject: [PATCH] MBT build command support "strict" parameter (#305) Co-authored-by: Jiang, Yu-tao --- mta/mta_services.go | 51 ++++++-- mta/mta_services_test.go | 274 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 312 insertions(+), 13 deletions(-) diff --git a/mta/mta_services.go b/mta/mta_services.go index 6666922..496e115 100644 --- a/mta/mta_services.go +++ b/mta/mta_services.go @@ -3,15 +3,16 @@ package mta import ( "crypto/sha256" "fmt" - "github.com/pkg/errors" - "gopkg.in/yaml.v3" "io" "io/ioutil" "os" "path/filepath" + "github.com/pkg/errors" + "gopkg.in/yaml.v3" + ghodss "github.com/ghodss/yaml" - "github.com/json-iterator/go" + jsoniter "github.com/json-iterator/go" "github.com/SAP/cloud-mta/internal/fs" "github.com/SAP/cloud-mta/internal/logs" @@ -59,6 +60,30 @@ func GetMtaFromFile(path string, extensions []string, returnMergeError bool) (mt return mta, messages, nil } +func GetMtaFromFileWithStrict(path string, extensions []string, returnMergeError bool, strict bool) (mta *MTA, messages []string, err error) { + mtaContent, err := fs.ReadFile(filepath.Join(path)) + if err != nil { + return nil, nil, err + } + mta, err = Unmarshal(mtaContent) + if strict && err != nil { + return nil, nil, errors.Wrapf(err, UnmarshalFailsMsg, path) + } + if strict == false && err != nil { + messages = []string{errors.Wrapf(err, UnmarshalFailsMsg, path).Error()} + } + + // If there is an error during the merge return the result so far and return the error as a message (or error if required). + extErr := mergeWithExtensionFiles(mta, extensions, path) + if extErr != nil { + if returnMergeError { + return mta, nil, extErr + } + messages = []string{extErr.Error()} + } + return mta, messages, nil +} + func unmarshalData(dataJSON string, o interface{}) error { dataYaml, err := ghodss.JSONToYAML([]byte(dataJSON)) if err != nil { @@ -93,7 +118,7 @@ func DeleteMta(path string) error { return fs.DeleteDir(path) } -//AddModule - adds a new module. +// AddModule - adds a new module. func AddModule(path string, moduleDataJSON string, marshal func(*MTA) ([]byte, error)) ([]string, error) { mta, messages, err := GetMtaFromFile(filepath.Join(path), nil, false) if err != nil { @@ -110,7 +135,7 @@ func AddModule(path string, moduleDataJSON string, marshal func(*MTA) ([]byte, e return messages, saveMTA(path, mta, marshal) } -//AddResource - adds a new resource. +// AddResource - adds a new resource. func AddResource(path string, resourceDataJSON string, marshal func(*MTA) ([]byte, error)) ([]string, error) { mta, messages, err := GetMtaFromFile(path, nil, false) if err != nil { @@ -127,7 +152,7 @@ func AddResource(path string, resourceDataJSON string, marshal func(*MTA) ([]byt return messages, saveMTA(path, mta, marshal) } -//GetModules - gets all modules. +// GetModules - gets all modules. func GetModules(path string, extensions []string) ([]*Module, []string, error) { mta, messages, err := GetMtaFromFile(path, extensions, false) if err != nil { @@ -136,7 +161,7 @@ func GetModules(path string, extensions []string) ([]*Module, []string, error) { return mta.Modules, messages, nil } -//GetResources - gets all resources. +// GetResources - gets all resources. func GetResources(path string, extensions []string) ([]*Resource, []string, error) { mta, messages, err := GetMtaFromFile(path, extensions, false) if err != nil { @@ -261,7 +286,7 @@ func UpdateResource(path string, resourceDataJSON string, marshal func(*MTA) ([] return messages, fmt.Errorf("the '%s' resource does not exist", resource.Name) } -//GetMtaID - gets MTA ID. +// GetMtaID - gets MTA ID. func GetMtaID(path string) (string, []string, error) { mta, messages, err := GetMtaFromFile(path, nil, false) if err != nil { @@ -270,7 +295,7 @@ func GetMtaID(path string) (string, []string, error) { return mta.ID, messages, nil } -//IsNameUnique - checks if the name already exists as a `module`/`resource`/`provide` name. +// IsNameUnique - checks if the name already exists as a `module`/`resource`/`provide` name. func IsNameUnique(path string, name string) (bool, []string, error) { mta, messages, err := GetMtaFromFile(path, nil, false) if err != nil { @@ -295,7 +320,7 @@ func IsNameUnique(path string, name string) (bool, []string, error) { return false, messages, nil } -//getBuildParameters - gets the MTA build parameters. +// getBuildParameters - gets the MTA build parameters. func GetBuildParameters(path string, extensions []string) (*ProjectBuild, []string, error) { mta, messages, err := GetMtaFromFile(path, extensions, false) if err != nil { @@ -304,7 +329,7 @@ func GetBuildParameters(path string, extensions []string) (*ProjectBuild, []stri return mta.BuildParams, messages, nil } -//getParameters - gets the MTA parameters. +// getParameters - gets the MTA parameters. func GetParameters(path string, extensions []string) (*map[string]interface{}, []string, error) { mta, messages, err := GetMtaFromFile(path, extensions, false) if err != nil { @@ -313,7 +338,7 @@ func GetParameters(path string, extensions []string) (*map[string]interface{}, [ return &mta.Parameters, messages, nil } -//UpdateBuildParameters - updates the MTA build parameters. +// UpdateBuildParameters - updates the MTA build parameters. func UpdateBuildParameters(path string, buildParamsDataJSON string) ([]string, error) { mta, messages, err := GetMtaFromFile(path, nil, false) if err != nil { @@ -330,7 +355,7 @@ func UpdateBuildParameters(path string, buildParamsDataJSON string) ([]string, e return messages, saveMTA(path, mta, Marshal) } -//UpdateParameters - updates the MTA parameters. +// UpdateParameters - updates the MTA parameters. func UpdateParameters(path string, paramsDataJSON string) ([]string, error) { mta, messages, err := GetMtaFromFile(path, nil, false) if err != nil { diff --git a/mta/mta_services_test.go b/mta/mta_services_test.go index 94468c5..3283328 100644 --- a/mta/mta_services_test.go +++ b/mta/mta_services_test.go @@ -326,6 +326,280 @@ var _ = Describe("MtaServices", func() { }) }) + Describe("GetMtaFromFileWithStrict", func() { + wd, _ := os.Getwd() + mtaYamlSchemaVersion := "2.1" + + It("returns MTA for valid filename without extensions", func() { + mta, messages, err := GetMtaFromFileWithStrict(filepath.Join(wd, "testdata", "mtaValid.yaml"), nil, true, true) + Ω(err).Should(Succeed()) + Ω(messages).Should(BeEmpty()) + Ω(mta).ShouldNot(BeNil()) + Ω(*mta).Should(Equal(MTA{ + ID: "demo", + SchemaVersion: &mtaYamlSchemaVersion, + Version: "0.0.1", + Modules: []*Module{ + { + Name: "srv", + Type: "java", + Path: "srv", + Properties: map[string]interface{}{ + "APPC_LOG_LEVEL": "info", + "VSCODE_JAVA_DEBUG_LOG_LEVEL": "ALL", + }, + Parameters: map[string]interface{}{ + "memory": "512M", + }, + Provides: []Provides{ + { + Name: "srv_api", + Properties: map[string]interface{}{ + "url": "${default-url}", + }, + }, + }, + Requires: []Requires{ + { + Name: "db", + Properties: map[string]interface{}{ + "JBP_CONFIG_RESOURCE_CONFIGURATION": "[tomcat/webapps/ROOT/META-INF/context.xml: {\"service_name_for_DefaultDB\" : \"~{hdi-container-name}\"}]", + }, + }, + }, + }, + { + Name: "ui", + Type: "html5", + Path: "ui", + Parameters: map[string]interface{}{ + "disk-quota": "256M", + "memory": "256M", + }, + BuildParams: map[string]interface{}{ + "builder": "grunt", + }, + Requires: []Requires{ + { + Name: "srv_api", + Group: "destinations", + Properties: map[string]interface{}{ + "forwardAuthToken": true, + "strictSSL": false, + "name": "srv_api", + "url": "~{url}", + }, + }, + }, + }, + }, + Resources: []*Resource{ + { + Name: "hdi_db", + Type: "com.company.xs.hdi-container", + Properties: map[string]interface{}{ + "hdi-container-name": "${service-name}", + }, + }, + }, + })) + }) + It("returns error for invalid filename", func() { + _, messages, err := GetMtaFromFileWithStrict(filepath.Join(wd, "testdata", "mtaNonExisting.yaml"), nil, true, false) + Ω(err).Should(HaveOccurred()) + Ω(messages).Should(BeEmpty()) + }) + It("returns error for invalid mta yaml file", func() { + _, messages, err := GetMtaFromFileWithStrict(filepath.Join(wd, "testdata", "mtaInvalid.yaml"), nil, true, true) + Ω(err).Should(HaveOccurred()) + Ω(messages).Should(BeEmpty()) + }) + It("returns MTA with merged extensions for valid mta.yaml and extensions", func() { + mtaPath := filepath.Join(wd, "testdata", "testext", "mta.yaml") + extPath := filepath.Join(wd, "testdata", "testext", "cf-mtaext.yaml") + mta, messages, err := GetMtaFromFileWithStrict(mtaPath, []string{extPath}, true, false) + Ω(err).Should(Succeed()) + Ω(messages).Should(BeEmpty()) + Ω(mta).ShouldNot(BeNil()) + activeFalse := false + expected := MTA{ + ID: "mtahtml5", + SchemaVersion: &mtaYamlSchemaVersion, + Version: "0.0.1", + Modules: []*Module{ + { + Name: "ui5app", + Type: "html5", + Path: "ui5app", + Parameters: map[string]interface{}{ + "disk-quota": "256M", + "memory": "256M", + }, + Properties: map[string]interface{}{ + "my_prop": 1, + }, + Requires: []Requires{ + { + Name: "uaa_mtahtml5", + }, + }, + BuildParams: map[string]interface{}{ + "builder": "zip", + "ignore": []interface{}{"ui5app/"}, + }, + }, + { + Name: "ui5app2", + Type: "html5", + Parameters: map[string]interface{}{ + "disk-quota": "256M", + "memory": "512M", + }, + Requires: []Requires{ + { + Name: "uaa_mtahtml5", + }, + }, + }, + }, + Resources: []*Resource{ + { + Name: "uaa_mtahtml5", + Type: "com.company.xs.uaa", + Parameters: map[string]interface{}{ + "path": "./xs-security.json", + "service-plan": "application", + }, + Active: &activeFalse, + }, + }, + } + Ω(*mta).Should(Equal(expected)) + }) + It("returns extensions errors in messages when extensions are invalid and returnMergeError is false", func() { + mtaPath := filepath.Join(wd, "testdata", "testext", "mta.yaml") + extPath := filepath.Join(wd, "testdata", "testext", "unknown_extends.mtaext") + mta, messages, err := GetMtaFromFile(mtaPath, []string{extPath}, false) + Ω(err).Should(Succeed()) + Ω(messages).Should(ConsistOf(ContainSubstring(unknownExtendsMsg, ""))) + Ω(mta).ShouldNot(BeNil()) + expected := MTA{ + ID: "mtahtml5", + SchemaVersion: &mtaYamlSchemaVersion, + Version: "0.0.1", + Modules: []*Module{ + { + Name: "ui5app", + Type: "html5", + Path: "ui5app", + Parameters: map[string]interface{}{ + "disk-quota": "256M", + "memory": "256M", + }, + Requires: []Requires{ + { + Name: "uaa_mtahtml5", + }, + }, + BuildParams: map[string]interface{}{ + "builder": "zip", + "ignore": []interface{}{"ui5app/"}, + }, + }, + { + Name: "ui5app2", + Type: "html5", + Parameters: map[string]interface{}{ + "disk-quota": "256M", + "memory": "256M", + }, + Requires: []Requires{ + { + Name: "uaa_mtahtml5", + }, + }, + }, + }, + Resources: []*Resource{ + { + Name: "uaa_mtahtml5", + Type: "com.company.xs.uaa", + Parameters: map[string]interface{}{ + "path": "./xs-security.json", + "service-plan": "application", + }, + }, + }, + } + Ω(*mta).Should(Equal(expected)) + }) + It("returns extensions errors as error when extensions are invalid and returnMergeError is true", func() { + mtaPath := filepath.Join(wd, "testdata", "testext", "mta.yaml") + extPath := filepath.Join(wd, "testdata", "testext", "unknown_extends.mtaext") + mta, messages, err := GetMtaFromFile(mtaPath, []string{extPath}, true) + Ω(err).Should(HaveOccurred()) + Ω(err.Error()).Should(ContainSubstring(unknownExtendsMsg, "")) + Ω(messages).Should(BeEmpty()) + Ω(mta).ShouldNot(BeNil()) + expected := MTA{ + ID: "mtahtml5", + SchemaVersion: &mtaYamlSchemaVersion, + Version: "0.0.1", + Modules: []*Module{ + { + Name: "ui5app", + Type: "html5", + Path: "ui5app", + Parameters: map[string]interface{}{ + "disk-quota": "256M", + "memory": "256M", + }, + Requires: []Requires{ + { + Name: "uaa_mtahtml5", + }, + }, + BuildParams: map[string]interface{}{ + "builder": "zip", + "ignore": []interface{}{"ui5app/"}, + }, + }, + { + Name: "ui5app2", + Type: "html5", + Parameters: map[string]interface{}{ + "disk-quota": "256M", + "memory": "256M", + }, + Requires: []Requires{ + { + Name: "uaa_mtahtml5", + }, + }, + }, + }, + Resources: []*Resource{ + { + Name: "uaa_mtahtml5", + Type: "com.company.xs.uaa", + Parameters: map[string]interface{}{ + "path": "./xs-security.json", + "service-plan": "application", + }, + }, + }, + } + Ω(*mta).Should(Equal(expected)) + }) + It("returns error on extension when an extension version mismatches the MTA version", func() { + mtaPath := filepath.Join(wd, "testdata", "testext", "mta.yaml") + extPath := filepath.Join(wd, "testdata", "testext", "bad_version.mtaext") + _, _, err := GetMtaFromFile(mtaPath, []string{extPath}, true) + Ω(err).Should(HaveOccurred()) + Ω(err.Error()).Should(ContainSubstring(versionMismatchMsg, "3.1", extPath, mtaYamlSchemaVersion)) + }) + }) + var _ = Describe("CreateMta", func() { It("Create MTA", func() { jsonData, err := json.Marshal(getMtaInput())