From b2f7336c334e1932102fa3c02e7c88208c00517e Mon Sep 17 00:00:00 2001 From: Nicola Ferraro Date: Wed, 22 Apr 2020 16:30:45 +0200 Subject: [PATCH 1/3] chore(CLI): add support for multiline scripts in config --- README.md | 4 ++ pkg/cmd/test.go | 99 ++++++++++++++++++++++++++++++++----------------- 2 files changed, 70 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 8c73f011..d1cedf13 100644 --- a/README.md +++ b/README.md @@ -445,6 +445,10 @@ config: pre: - script: prepare.sh - run: echo Start! + - run: | + echo "Multiline" + echo "Commands are also" + echo "Supported!" post: - script: finish.sh - run: echo Bye! diff --git a/pkg/cmd/test.go b/pkg/cmd/test.go index e3a6235e..5ceec508 100644 --- a/pkg/cmd/test.go +++ b/pkg/cmd/test.go @@ -56,9 +56,9 @@ const ( ) const ( - CucumberOptions = "CUCUMBER_OPTIONS" - CucumberGlue = "CUCUMBER_GLUE" - CucumberFeatures = "CUCUMBER_FEATURES" + CucumberOptions = "CUCUMBER_OPTIONS" + CucumberGlue = "CUCUMBER_GLUE" + CucumberFeatures = "CUCUMBER_FEATURES" CucumberFilterTags = "CUCUMBER_FILTER_TAGS" ) @@ -97,8 +97,8 @@ type testCmdOptions struct { env []string tags []string features []string - glue []string - options string + glue []string + options string } func (o *testCmdOptions) validateArgs(_ *cobra.Command, args []string) error { @@ -128,7 +128,7 @@ func (o *testCmdOptions) run(_ *cobra.Command, args []string) error { func (o *testCmdOptions) runTest(source string) error { c, err := o.GetCmdClient() if err != nil { - return err; + return err } var runConfig *config.RunConfig @@ -136,10 +136,12 @@ func (o *testCmdOptions) runTest(source string) error { return err } + testNamespace := runConfig.Config.Namespace.Name if runConfig.Config.Namespace.Temporary { if namespace, err := o.createTempNamespace(runConfig, c); err != nil { return err } else if namespace != nil && runConfig.Config.Namespace.AutoRemove { + testNamespace = namespace.GetName() defer deleteTempNamespace(namespace, c, o.Context) } } @@ -149,8 +151,8 @@ func (o *testCmdOptions) runTest(source string) error { } baseDir := getBaseDir(source) - defer runSteps(runConfig.Post, baseDir) - if err = runSteps(runConfig.Pre, baseDir); err != nil { + defer runSteps(runConfig.Post, testNamespace, baseDir) + if err = runSteps(runConfig.Pre, testNamespace, baseDir); err != nil { return err } @@ -169,10 +171,12 @@ func (o *testCmdOptions) runTestGroup(source string, results *map[string]error) return err } + var testNamespace = runConfig.Config.Namespace.Name if runConfig.Config.Namespace.Temporary { if namespace, err := o.createTempNamespace(runConfig, c); err != nil { return err } else if namespace != nil && runConfig.Config.Namespace.AutoRemove { + testNamespace = namespace.GetName() defer deleteTempNamespace(namespace, c, o.Context) } } @@ -188,8 +192,8 @@ func (o *testCmdOptions) runTestGroup(source string, results *map[string]error) } baseDir := getBaseDir(source) - defer runSteps(runConfig.Post, baseDir) - if err = runSteps(runConfig.Pre, baseDir); err != nil { + defer runSteps(runConfig.Post, testNamespace, baseDir) + if err = runSteps(runConfig.Pre, testNamespace, baseDir); err != nil { return err } @@ -221,7 +225,7 @@ func getBaseDir(source string) string { if isDir(source) { return source } else { - dir, _ := path.Split(source); + dir, _ := path.Split(source) return dir } } @@ -251,8 +255,8 @@ func (o *testCmdOptions) getRunConfig(source string) (*config.RunConfig, error) configFile = path.Join(source, ConfigFile) } else { // search for config file in same directory as given file - dir, _ := path.Split(source); - configFile = path.Join(dir, ConfigFile); + dir, _ := path.Split(source) + configFile = path.Join(dir, ConfigFile) } runConfig, err := config.LoadConfig(configFile) @@ -261,13 +265,13 @@ func (o *testCmdOptions) getRunConfig(source string) (*config.RunConfig, error) } if runConfig.Config.Namespace.Name == "" && !runConfig.Config.Namespace.Temporary { - runConfig.Config.Namespace.Name = o.Namespace; + runConfig.Config.Namespace.Name = o.Namespace } return runConfig, nil } -func (o *testCmdOptions) createTempNamespace(runConfig *config.RunConfig,c client.Client) (metav1.Object, error) { +func (o *testCmdOptions) createTempNamespace(runConfig *config.RunConfig, c client.Client) (metav1.Object, error) { namespaceName := "yaks-" + uuid.New().String() namespace, err := initializeTempNamespace(namespaceName, c, o.Context) if err != nil { @@ -413,25 +417,25 @@ func (o *testCmdOptions) setupEnvSettings(test *v1alpha1.Test, runConfig *config env := make([]string, 0) if o.tags != nil { - env = append(env, CucumberFilterTags + "=" + strings.Join(o.tags, ",")) + env = append(env, CucumberFilterTags+"="+strings.Join(o.tags, ",")) } else if len(runConfig.Config.Runtime.Cucumber.Tags) > 0 { - env = append(env, CucumberFilterTags + "=" + strings.Join(runConfig.Config.Runtime.Cucumber.Tags, ",")) + env = append(env, CucumberFilterTags+"="+strings.Join(runConfig.Config.Runtime.Cucumber.Tags, ",")) } if o.features != nil { - env = append(env, CucumberFeatures + "=" + strings.Join(o.features, ",")) + env = append(env, CucumberFeatures+"="+strings.Join(o.features, ",")) } if o.glue != nil { - env = append(env, CucumberGlue + "=" + strings.Join(o.glue, ",")) + env = append(env, CucumberGlue+"="+strings.Join(o.glue, ",")) } else if len(runConfig.Config.Runtime.Cucumber.Glue) > 0 { - env = append(env, CucumberGlue + "=" + strings.Join(runConfig.Config.Runtime.Cucumber.Glue, ",")) + env = append(env, CucumberGlue+"="+strings.Join(runConfig.Config.Runtime.Cucumber.Glue, ",")) } if len(o.options) > 0 { - env = append(env, CucumberOptions + "=" + o.options) + env = append(env, CucumberOptions+"="+o.options) } else if len(runConfig.Config.Runtime.Cucumber.Options) > 0 { - env = append(env, CucumberOptions + "=" + runConfig.Config.Runtime.Cucumber.Options) + env = append(env, CucumberOptions+"="+runConfig.Config.Runtime.Cucumber.Options) } if o.env != nil { @@ -522,8 +526,8 @@ func isDir(fileName string) bool { return false } -func runSteps(steps []config.StepConfig, baseDir string) error { - for _, step := range steps { +func runSteps(steps []config.StepConfig, namespace, baseDir string) error { + for idx, step := range steps { if len(step.Script) > 0 { var scriptFile string @@ -533,20 +537,39 @@ func runSteps(steps []config.StepConfig, baseDir string) error { scriptFile = step.Script } - if out, err := exec.Command(scriptFile).Output(); err == nil { - fmt.Printf("Running script %s: \n%s\n", step.Script, out) - } else { - fmt.Printf("Failed to run script %s: \n%s\n", step.Script, err) + if err := runScript(scriptFile, fmt.Sprintf("script %s", scriptFile), namespace, baseDir); err != nil { return err } } if len(step.Run) > 0 { - tokens := strings.Split(step.Run, " ") - if out, err := exec.Command(tokens[0], tokens[1:]...).Output(); err == nil { - fmt.Printf("Running command %s: \n%s\n", step.Run, out) - } else { - fmt.Printf("Failed to run command %s: \n%s\n", step.Run, err) + // Let's save it to a bash script to allow for multiline scripts + file, err := ioutil.TempFile("", "yaks-script-*.sh") + if err != nil { + return err + } + defer os.Remove(file.Name()) + + _, err = file.WriteString("#!/bin/bash\n\n") + if err != nil { + return err + } + + _, err = file.WriteString(step.Run) + if err != nil { + return err + } + + if err = file.Close(); err != nil { + return err + } + + // Make it executable + if err = os.Chmod(file.Name(), 0777); err != nil { + return err + } + + if err := runScript(file.Name(), fmt.Sprintf("inline command %d", idx), namespace, baseDir); err != nil { return err } } @@ -555,6 +578,16 @@ func runSteps(steps []config.StepConfig, baseDir string) error { return nil } +func runScript(scriptFile, desc, namespace, baseDir string) error { + if out, err := exec.Command(scriptFile).Output(); err == nil { + fmt.Printf("Running %s: \n%s\n", desc, out) + } else { + fmt.Printf("Failed to run %s: \n%v\n", desc, err) + return err + } + return nil +} + func initializeTempNamespace(name string, c client.Client, context context.Context) (metav1.Object, error) { var obj runtime.Object From a25d744a480ed9eae663b6a2446f97ebaa47ba4d Mon Sep 17 00:00:00 2001 From: Nicola Ferraro Date: Wed, 22 Apr 2020 16:52:49 +0200 Subject: [PATCH 2/3] chore(CLI): inject YAKS_NAMESPACE environment variable in the scripts --- README.md | 4 ++++ pkg/cmd/test.go | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d1cedf13..752558ca 100644 --- a/README.md +++ b/README.md @@ -463,6 +463,10 @@ given it is assumed to be a file path relative to the current test group directo With `run` you can add any shell command. At the moment only single line commands are supported here. You can add multiple `run` commands in a `pre` or `post` section. +Scripts can leverage the following environment variables that are set automatically by the Yaks runtime: + +- **YAKS_NAMESPACE**: always contains the namespace where the tests will be executed, no matter if the namespace is fixed or temporary + ## For YAKS Developers Requirements: diff --git a/pkg/cmd/test.go b/pkg/cmd/test.go index 5ceec508..c9367288 100644 --- a/pkg/cmd/test.go +++ b/pkg/cmd/test.go @@ -579,7 +579,10 @@ func runSteps(steps []config.StepConfig, namespace, baseDir string) error { } func runScript(scriptFile, desc, namespace, baseDir string) error { - if out, err := exec.Command(scriptFile).Output(); err == nil { + command := exec.Command(scriptFile) + command.Env = os.Environ() + command.Env = append(command.Env, fmt.Sprintf("YAKS_NAMESPACE=%s", namespace)) + if out, err := command.Output(); err == nil { fmt.Printf("Running %s: \n%s\n", desc, out) } else { fmt.Printf("Failed to run %s: \n%v\n", desc, err) From 51d2077868074a2611f5a2f8bf497778281cae49 Mon Sep 17 00:00:00 2001 From: Nicola Ferraro Date: Wed, 22 Apr 2020 16:54:49 +0200 Subject: [PATCH 3/3] chore(CLI): always use the config file location as script base dir --- pkg/cmd/test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/cmd/test.go b/pkg/cmd/test.go index c9367288..451c2002 100644 --- a/pkg/cmd/test.go +++ b/pkg/cmd/test.go @@ -580,8 +580,12 @@ func runSteps(steps []config.StepConfig, namespace, baseDir string) error { func runScript(scriptFile, desc, namespace, baseDir string) error { command := exec.Command(scriptFile) + command.Env = os.Environ() command.Env = append(command.Env, fmt.Sprintf("YAKS_NAMESPACE=%s", namespace)) + + command.Dir = baseDir + if out, err := command.Output(); err == nil { fmt.Printf("Running %s: \n%s\n", desc, out) } else {