Skip to content

Commit

Permalink
generate mtad.yaml in partial modules build (#720)
Browse files Browse the repository at this point in the history
* generate mtad.yaml in partial modules build

* fix linter; tests added

* fix linter

* code review fixes

* fix linter

* fix test description
  • Loading branch information
allaVolkov authored Apr 1, 2020
1 parent f2e412e commit 073f446
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 44 deletions.
10 changes: 9 additions & 1 deletion cmd/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ var soloBuildModuleCmdTrg string
var soloBuildModuleCmdExtensions []string
var soloBuildModuleCmdModules []string
var soloBuildModuleCmdAllDependencies bool
var soloBuildModuleCmdMtadGen bool
var soloBuildModuleCmdPlatform string

func init() {

Expand Down Expand Up @@ -66,6 +68,10 @@ func init() {
"The names of the modules")
soloBuildModuleCmd.Flags().BoolVarP(&soloBuildModuleCmdAllDependencies, "with-all-dependencies", "a", false,
"Build modules including all dependencies")
soloBuildModuleCmd.Flags().BoolVarP(&soloBuildModuleCmdMtadGen, "mtad-gen", "g", false,
`Generate "mtad.yaml" file`)
soloBuildModuleCmd.Flags().StringVarP(&soloBuildModuleCmdPlatform, "platform", "p", "cf",
`The deployment platform; supported platforms: "cf", "xsa", "neo"`)
}

// soloBuildModuleCmd - Build module command used stand alone
Expand All @@ -75,7 +81,9 @@ var soloBuildModuleCmd = &cobra.Command{
Long: "Builds specified modules according to configurations in the MTA development descriptor (mta.yaml)",
Args: cobra.MaximumNArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
err := artifacts.ExecuteSoloBuild(soloBuildModuleCmdSrc, soloBuildModuleCmdTrg, soloBuildModuleCmdExtensions, soloBuildModuleCmdModules, soloBuildModuleCmdAllDependencies, os.Getwd)
err := artifacts.ExecuteSoloBuild(soloBuildModuleCmdSrc, soloBuildModuleCmdTrg, soloBuildModuleCmdExtensions,
soloBuildModuleCmdModules, soloBuildModuleCmdAllDependencies, soloBuildModuleCmdMtadGen, soloBuildModuleCmdPlatform,
os.Getwd)
logError(err)
return err
},
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ require (
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 // indirect
golang.org/x/text v0.3.2 // indirect
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
gopkg.in/yaml.v2 v2.2.7
gopkg.in/yaml.v2 v2.2.8
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 // indirect
sigs.k8s.io/yaml v1.2.0
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,10 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 h1:XZx7nhd5GMaZpmDaEHFVafUZC7ya0fuo7cSJ3UCKYmM=
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
9 changes: 1 addition & 8 deletions internal/artifacts/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,7 @@ func genMetaInfo(source dir.IModule, ep dir.ITargetArtifacts, targetPathGetter d
}
}

if !deploymentDesc {
err := removeBuildParamsFromMta(targetPathGetter, mtaStr, validatePaths)
if err != nil {
return err
}
}

err := genMtad(mtaStr, ep, deploymentDesc, platform, yaml.Marshal)
err := genMtad(mtaStr, ep, targetPathGetter, deploymentDesc, platform, validatePaths, nil, yaml.Marshal)
if err != nil {
return errors.Wrap(err, genMetaMTADMsg)
}
Expand Down
49 changes: 44 additions & 5 deletions internal/artifacts/module_arch.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package artifacts

import (
"fmt"
"gopkg.in/yaml.v2"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -40,7 +41,9 @@ func ExecuteBuild(source, target string, extensions []string, moduleName, platfo
}

// ExecuteSoloBuild - executes build of module from stand alone command
func ExecuteSoloBuild(source, target string, extensions []string, modulesNames []string, allDependencies bool, wdGetter func() (string, error)) error {
func ExecuteSoloBuild(source, target string, extensions []string, modulesNames []string, allDependencies bool,
generateMtadFlag bool, platform string,
wdGetter func() (string, error)) error {

if len(modulesNames) == 0 {
return errors.New(buildFailedOnEmptyModulesMsg)
Expand Down Expand Up @@ -93,18 +96,49 @@ func ExecuteSoloBuild(source, target string, extensions []string, modulesNames [
logs.Logger.Infof(multiBuildMsg, `"`+strings.Join(sortedModules, `", "`)+`"`)
}

err = buildModules(sourceDir, target, extensions, sortedModules, selectedModulesMap, wdGetter)
packedModulePaths, err := buildModules(sourceDir, target, extensions, sortedModules, selectedModulesMap, wdGetter)
if err != nil {
return wrapBuildError(err, modulesNames)
}

if generateMtadFlag {
err = generateMtad(mtaObj, loc, target, platform, packedModulePaths, wdGetter)
if err != nil {
return wrapBuildError(err, modulesNames)
}
}

if len(modulesNames) > 1 {
logs.Logger.Infof(multiBuildFinishedMsg)
}

return nil
}

func generateMtad(mtaObj *mta.MTA, loc dir.ITargetPath, target string,
platform string, packedModulePaths map[string]string, wdGetter func() (string, error)) error {

platform, err := validatePlatform(platform)
if err != nil {
return err
}

mtadTargetPath, err := getMtadPath(target, wdGetter)
if err != nil {
return err
}
mtadLocation := mtadLoc{path: mtadTargetPath}

return genMtad(mtaObj, &mtadLocation, loc, false, platform, false, packedModulePaths, yaml.Marshal)
}

func getMtadPath(target string, wdGetter func() (string, error)) (string, error) {
if target != "" {
return target, nil
}
return wdGetter()
}

func wrapBuildError(err error, modules []string) error {
if len(modules) == 1 {
return errors.Wrapf(err, buildFailedMsg, modules[0])
Expand Down Expand Up @@ -138,17 +172,22 @@ func collectSelectedModulesAndDependencies(mtaObj *mta.MTA, modulesWithDependenc
}

func buildModules(source, target string, extensions []string, modulesToBuild []string,
modulesToPack map[string]bool, wdGetter func() (string, error)) error {
modulesToPack map[string]bool, wdGetter func() (string, error)) (packedModulePaths map[string]string, err error) {

buildResults := make(map[string]string)
for _, module := range modulesToBuild {
err := buildSelectedModule(source, target, extensions, module, modulesToPack[module], buildResults, wdGetter)

if err != nil {
return err
return nil, err
}
}
return nil

packedModulePaths = make(map[string]string)
for buildResult, moduleName := range buildResults {
packedModulePaths[moduleName] = buildResult
}
return packedModulePaths, nil
}

func buildSelectedModule(source, target string, extensions []string, module string,
Expand Down
120 changes: 96 additions & 24 deletions internal/artifacts/module_arch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/SAP/cloud-mta-build-tool/internal/buildops"
"github.com/SAP/cloud-mta-build-tool/internal/commands"
"github.com/SAP/cloud-mta-build-tool/internal/exec"
"github.com/SAP/cloud-mta-build-tool/internal/platform"
"github.com/SAP/cloud-mta/mta"
)

Expand Down Expand Up @@ -89,68 +90,110 @@ builders:
Ω(os.Remove(getTestPath("mtaModelsBuild", "ui5app", "test2_copy.txt"))).Should(Succeed())
Ω(os.Remove(getTestPath("mtaModelsBuild", "ui5app2", "test2_copy.txt"))).Should(Succeed())
})
It("required module m2 has ready artifact 'test2.txt' and creates a new one 'test2_copy.txt'", func() {
Ω(ExecuteSoloBuild(getTestPath("mtaModelsBuild"), getResultPath(), nil, []string{"m1", "m3"}, true, os.Getwd)).Should(Succeed())

It("required module m2 has ready artifact 'test2.txt' and creates a new one 'test2_copy.txt', mtad.yaml generated", func() {
Ω(ExecuteSoloBuild(getTestPath("mtaModelsBuild"), getResultPath(), nil, []string{"m1", "m3"}, true, true, "cf", os.Getwd)).Should(Succeed())
Ω(getTestPath("result", "data.zip")).Should(BeAnExistingFile())
Ω(getTestPath("result", "m3.zip")).Should(BeAnExistingFile())
validateArchiveContents([]string{"test.txt", "test2.txt", "test2_copy.txt"}, getTestPath("result", "data.zip"))
mtadContent, err := ioutil.ReadFile(getTestPath("result", "mtad.yaml"))
Ω(err).Should(Succeed())
mtadObj, err := mta.Unmarshal(mtadContent)
Ω(err).Should(Succeed())
moduleM1, err := mtadObj.GetModuleByName("m1")
Ω(err).Should(Succeed())
Ω(moduleM1.Path).Should(Equal(getTestPath("result", "data.zip")))
moduleM3, err := mtadObj.GetModuleByName("m3")
Ω(err).Should(Succeed())
Ω(moduleM3.Path).Should(Equal(getTestPath("result", "m3.zip")))
})

Describe("corrupted platform configuration", func() {

var platformConfig []byte

BeforeEach(func() {
platformConfig = platform.PlatformConfig
platform.PlatformConfig = []byte("corrupted")
})

AfterEach(func() {
platform.PlatformConfig = platformConfig
})

It("mtad.yaml generation fails", func() {
Ω(ExecuteSoloBuild(getTestPath("mtaModelsBuild"), getResultPath(), nil, []string{"m1", "m3"}, true, true, "cf", os.Getwd)).Should(HaveOccurred())
})
})

It("required module m2 has ready artifact 'test2.txt' and creates a new one 'test2_copy.txt', mtad.yaml not generated", func() {
Ω(ExecuteSoloBuild(getTestPath("mtaModelsBuild"), getResultPath(), nil, []string{"m1"}, true, false, "cf", os.Getwd)).Should(Succeed())
Ω(getTestPath("result", "data.zip")).Should(BeAnExistingFile())
Ω(getTestPath("result", "m3.zip")).ShouldNot(BeAnExistingFile())
Ω(getTestPath("result", "mtad.yaml")).ShouldNot(BeAnExistingFile())
validateArchiveContents([]string{"test.txt", "test2.txt", "test2_copy.txt"}, getTestPath("result", "data.zip"))
})

It("modules m1 and m2 have conflicting build results", func() {
err := ExecuteSoloBuild(getTestPath("mtaModelsBuild"), getResultPath(), nil, []string{"m1", "m2"}, true, os.Getwd)
err := ExecuteSoloBuild(getTestPath("mtaModelsBuild"), getResultPath(), nil, []string{"m1", "m2"}, true, false, "", os.Getwd)
Ω(err).Should(HaveOccurred())
Ω(err.Error()).Should(ContainSubstring(fmt.Sprintf(multiBuildWithPathsConflictMsg, "m2", "m1", getResultPath(), "data.zip")))
})

It("fails on platform validation when mtad.yaml should be generated", func() {
Ω(ExecuteSoloBuild(getTestPath("mtaModelsBuild"), getResultPath(), nil, []string{"m1"}, true, true, "xx", os.Getwd)).Should(HaveOccurred())
})
})

Describe("Sanity, with target path, without dependencies", func() {
AfterEach(func() {
Ω(os.Remove(getTestPath("mtaModelsBuild", "ui5app", "test2.txt"))).Should(Succeed())
})
It("required module m2 has ready artifact 'test2.txt', only this one will be copied to m1", func() {
Ω(ExecuteSoloBuild(getTestPath("mtaModelsBuild"), getResultPath(), nil, []string{"m1", "m3"}, false, os.Getwd)).Should(Succeed())
Ω(ExecuteSoloBuild(getTestPath("mtaModelsBuild"), getResultPath(), nil, []string{"m1", "m3"}, false, false, "", os.Getwd)).Should(Succeed())
Ω(getTestPath("result", "data.zip")).Should(BeAnExistingFile())
Ω(getTestPath("result", "m3.zip")).Should(BeAnExistingFile())
validateArchiveContents([]string{"test.txt", "test2.txt"}, getTestPath("result", "data.zip"))
})
})

It("Sanity, no target path", func() {
Ω(ExecuteSoloBuild(getTestPath("mta"), "", nil, []string{"node-js"}, true,
Ω(ExecuteSoloBuild(getTestPath("mta"), "", nil, []string{"node-js"}, true, false, "",
func() (string, error) {
return getTestPath("result", "test_dir"), nil
})).Should(Succeed())
Ω(getTestPath("result", "test_dir", ".mta_mta_build_tmp", "node-js", "data.zip")).Should(BeAnExistingFile())
})

It("fails on empty list of modules", func() {
Ω(ExecuteSoloBuild(getTestPath("mta"), getResultPath(), nil, []string{}, true, os.Getwd)).Should(HaveOccurred())
Ω(ExecuteSoloBuild(getTestPath("mta"), getResultPath(), nil, []string{}, true, false, "", os.Getwd)).Should(HaveOccurred())
})

It("Fails on source getter", func() {
err := ExecuteSoloBuild("", "", nil, []string{"ui5app"}, true, failingGetWd)
err := ExecuteSoloBuild("", "", nil, []string{"ui5app"}, true, false, "", failingGetWd)
Ω(err).Should(HaveOccurred())
Ω(err.Error()).Should(ContainSubstring(fmt.Sprintf(buildFailedMsg, "ui5app")))
})

It("Fails on source getter with multiple modules", func() {
err := ExecuteSoloBuild("", "", nil, []string{"ui5app", "ui5app2"}, true, failingGetWd)
err := ExecuteSoloBuild("", "", nil, []string{"ui5app", "ui5app2"}, true, false, "", failingGetWd)
Ω(err).Should(HaveOccurred())
Ω(err.Error()).Should(ContainSubstring(multiBuildFailedMsg))
})

It("Fails on wrong build dependencies - on sortModules", func() {
Ω(ExecuteSoloBuild(getTestPath("mtahtml5"), "", []string{"mtaExtWithCyclicDependencies.yaml"},
[]string{"ui5app"}, true, os.Getwd)).Should(HaveOccurred())
[]string{"ui5app"}, true, false, "", os.Getwd)).Should(HaveOccurred())
})

It("Fails on unknown builder", func() {
Ω(ExecuteSoloBuild(getTestPath("mtahtml5"), "", []string{"mtaExtWithUnkownBuilder.yaml"},
[]string{"ui5app"}, true, os.Getwd)).Should(HaveOccurred())
[]string{"ui5app"}, true, false, "", os.Getwd)).Should(HaveOccurred())
})

It("Fails on location initialization", func() {
counter := 0
Ω(ExecuteSoloBuild("", "", nil, []string{"ui5app"}, true, func() (string, error) {
Ω(ExecuteSoloBuild("", "", nil, []string{"ui5app"}, true, false, "", func() (string, error) {
if counter == 0 {
counter++
return "", nil
Expand All @@ -160,11 +203,12 @@ builders:
})

It("Fails on wrong module", func() {
Ω(ExecuteSoloBuild(getTestPath("mta"), getResultPath(), nil, []string{"ui5app"}, true, os.Getwd)).Should(HaveOccurred())
Ω(ExecuteSoloBuild(getTestPath("mta"), getResultPath(), nil, []string{"ui5app"}, true, false, "", os.Getwd)).Should(HaveOccurred())
})

It("Fails on getting default source", func() {
Ω(ExecuteSoloBuild(getTestPath("mta"), "", nil, []string{"ui5app"}, true,
false, "",
failingGetWd)).Should(HaveOccurred())
})

Expand All @@ -173,13 +217,14 @@ builders:
// failure on dir.Location after 2 successful calls to getSoloModuleBuildAbsSource & getSoloModuleBuildAbsTarget
It("Fails on creation of Location object", func() {
counter := 1
Ω(ExecuteSoloBuild("", "", nil, []string{"ui5app"}, true, func() (string, error) {
if counter <= 2 {
counter++
return "", nil
}
return "", errors.New("err")
})).Should(HaveOccurred())
Ω(ExecuteSoloBuild("", "", nil, []string{"ui5app"}, true, false, "",
func() (string, error) {
if counter <= 2 {
counter++
return "", nil
}
return "", errors.New("err")
})).Should(HaveOccurred())
})

It("getSoloModuleBuildAbsTarget fails on current folder getter", func() {
Expand All @@ -188,31 +233,58 @@ builders:
})
})

Describe("generateMtad", func() {
It("fails on mtad location getter", func() {
Ω(generateMtad(nil, nil, "", "cf", nil, failingGetWd)).Should(HaveOccurred())
})
})

Describe("buildModules", func() {

AfterEach(func() {
Ω(os.RemoveAll(getTestPath("result"))).Should(Succeed())
})

It("sanity", func() {
Ω(buildModules(getTestPath("mtahtml5"), getTestPath("result"), nil, []string{"ui5app"}, map[string]bool{"ui5app": true}, os.Getwd)).Should(Succeed())
_, err := buildModules(getTestPath("mtahtml5"), getTestPath("result"), nil, []string{"ui5app"}, map[string]bool{"ui5app": true}, os.Getwd)
Ω(err).Should(Succeed())
Ω(getTestPath("result", "data.zip")).Should(BeAnExistingFile())
})

It("fails on module location getter", func() {
Ω(buildModules(getTestPath("mtahtml5"), "", nil, []string{"ui5app2"}, map[string]bool{}, failingGetWd)).Should(HaveOccurred())
_, err := buildModules(getTestPath("mtahtml5"), "", nil, []string{"ui5app2"}, map[string]bool{}, failingGetWd)
Ω(err).Should(HaveOccurred())
})

It("fails on wrong selected module", func() {
Ω(buildModules(getTestPath("mtahtml5"), "", nil, []string{"unknown"}, map[string]bool{"unknown": true}, os.Getwd)).Should(HaveOccurred())
_, err := buildModules(getTestPath("mtahtml5"), "", nil, []string{"unknown"}, map[string]bool{"unknown": true}, os.Getwd)
Ω(err).Should(HaveOccurred())
})

It("fails on module location getter of dependency", func() {
Ω(buildModules("", "", nil, []string{"ui5app"}, map[string]bool{"ui5app": true}, failingGetWd)).Should(HaveOccurred())
_, err := buildModules("", "", nil, []string{"ui5app"}, map[string]bool{"ui5app": true}, failingGetWd)
Ω(err).Should(HaveOccurred())
})

It("fails on buildModule because of the unknown builder", func() {
Ω(buildModules(getTestPath("mtahtml5"), getTestPath("result"), nil, []string{"ui5app3"}, map[string]bool{"ui5app3": true}, os.Getwd)).Should(HaveOccurred())
_, err := buildModules(getTestPath("mtahtml5"), getTestPath("result"), nil, []string{"ui5app3"}, map[string]bool{"ui5app3": true}, os.Getwd)
Ω(err).Should(HaveOccurred())
})
})

Describe("getMtadPath", func() {
It("target provided", func() {
mtadPath, err := getMtadPath(getResultPath(), os.Getwd)
Ω(err).Should(Succeed())
Ω(mtadPath).Should(Equal(getResultPath()))
})

It("target not provided", func() {
mtadPath, err := getMtadPath("", os.Getwd)
Ω(err).Should(Succeed())
wd, err := os.Getwd()
Ω(err).Should(Succeed())
Ω(mtadPath).Should(Equal(wd))
})
})

Expand Down
Loading

0 comments on commit 073f446

Please sign in to comment.