diff --git a/pkg/cmd/create_formula_test.go b/pkg/cmd/create_formula_test.go index 8b9055e8e..3c60a8c6a 100644 --- a/pkg/cmd/create_formula_test.go +++ b/pkg/cmd/create_formula_test.go @@ -18,12 +18,9 @@ package cmd import ( "errors" - "fmt" "net/http" "os" "path/filepath" - "runtime" - "strings" "testing" "github.com/stretchr/testify/assert" @@ -40,7 +37,6 @@ import ( "github.com/ZupIT/ritchie-cli/pkg/formula/workspace" "github.com/ZupIT/ritchie-cli/pkg/git/github" "github.com/ZupIT/ritchie-cli/pkg/git/gitlab" - "github.com/ZupIT/ritchie-cli/pkg/os/osutil" "github.com/ZupIT/ritchie-cli/pkg/rtutorial" "github.com/ZupIT/ritchie-cli/pkg/stream" ) @@ -340,15 +336,7 @@ func TestCreateFormula(t *testing.T) { assert.DirExists(t, filepath.Join(reposDir, "local-default")) assert.FileExists(t, filepath.Join(reposDir, "local-default", "tree.json")) - if osutil.Darwin == runtime.GOOS { - tmpDir := strings.ReplaceAll(os.TempDir(), "/", "-") - hashFile := fmt.Sprintf("%s.ritchie-formulas-local-test-test.txt", tmpDir) - assert.FileExists(t, filepath.Join(hashesDir, hashFile)) - } - - if osutil.Linux == runtime.GOOS { - assert.FileExists(t, filepath.Join(hashesDir, "-tmp-.ritchie-formulas-local-test-test.txt")) - } + assert.FileExists(t, filepath.Join(hashesDir, "-tmp-.ritchie-formulas-local-test-test.txt")) assert.FileExists(t, filepath.Join(reposDir, "repositories.json")) } diff --git a/pkg/commands/builder.go b/pkg/commands/builder.go index 11b6d7ef2..725a18c34 100644 --- a/pkg/commands/builder.go +++ b/pkg/commands/builder.go @@ -142,6 +142,8 @@ func Build() *cobra.Command { formBuildDocker := builder.NewBuildDocker(fileManager) formBuildLocal := builder.NewBuildLocal(ritchieHomeDir, dirManager, repoAdder) + postRunner := runner.NewPostRunner(fileManager, dirManager) + promptInManager := fprompt.NewInputManager(credResolver, inputList, inputText, inputTextValidator, inputTextDefault, inputBool, inputPassword, inputMultiselect, inputAutocomplete) stdinInManager := stdin.NewInputManager(credResolver) flagInManager := flag.NewInputManager(credResolver) @@ -154,10 +156,10 @@ func Build() *cobra.Command { inputResolver := runner.NewInputResolver(termInputTypes) formulaLocalPreRun := local.NewPreRun(ritchieHomeDir, formBuildMake, formBuildBat, formBuildSh, dirManager, fileManager) - formulaLocalRun := local.NewRunner(userHomeDir, fileManager, envFinder, inputResolver, formulaLocalPreRun) + formulaLocalRun := local.NewRunner(postRunner, inputResolver, formulaLocalPreRun, fileManager, envFinder, userHomeDir) formulaDockerPreRun := docker.NewPreRun(ritchieHomeDir, formBuildDocker, dirManager, fileManager) - formulaDockerRun := docker.NewRunner(userHomeDir, inputResolver, formulaDockerPreRun, envFinder) + formulaDockerRun := docker.NewRunner(postRunner, inputResolver, formulaDockerPreRun, fileManager, envFinder, userHomeDir) runners := formula.Runners{ formula.LocalRun: formulaLocalRun, diff --git a/pkg/formula/builder/make.go b/pkg/formula/builder/make.go index 59329a3c8..48f6f146a 100644 --- a/pkg/formula/builder/make.go +++ b/pkg/formula/builder/make.go @@ -39,13 +39,9 @@ func NewBuildMake() MakeManager { } func (ma MakeManager) Build(info formula.BuildInfo) error { - pwd, _ := os.Getwd() - defer os.Chdir(pwd) //nolint:errcheck - if err := os.Chdir(info.FormulaPath); err != nil { return err } - var stderr bytes.Buffer cmd := exec.Command("make", "build") cmd.Stderr = &stderr @@ -53,9 +49,5 @@ func (ma MakeManager) Build(info formula.BuildInfo) error { return fmt.Errorf(errMsgFmt, ErrBuildFormulaMakefile, stderr.String()) } - if err := os.Chdir(pwd); err != nil { - return err - } - return nil } diff --git a/pkg/formula/builder/shell.go b/pkg/formula/builder/shell.go index d7c272cd7..f764b6c9a 100644 --- a/pkg/formula/builder/shell.go +++ b/pkg/formula/builder/shell.go @@ -44,9 +44,6 @@ func NewBuildShell() ShellManager { } func (sh ShellManager) Build(info formula.BuildInfo) error { - pwd, _ := os.Getwd() - defer os.Chdir(pwd) //nolint:errcheck - if err := os.Chdir(info.FormulaPath); err != nil { return err } diff --git a/pkg/formula/formula.go b/pkg/formula/formula.go index b4b97191a..9f19a2709 100644 --- a/pkg/formula/formula.go +++ b/pkg/formula/formula.go @@ -21,6 +21,7 @@ import ( "runtime" "strings" + "github.com/google/uuid" "github.com/spf13/pflag" "github.com/ZupIT/ritchie-cli/pkg/api" @@ -104,6 +105,7 @@ type ( FormulaPath string BinName string BinPath string + TmpDir string Config Config ContainerId string } @@ -145,6 +147,13 @@ func (d *Definition) FormulaPath(home string) string { return filepath.Join(home, ReposDir, d.RepoName, d.Path) } +// TmpWorkDirPath builds the tmp paths to run formula, first parameter is tmpDir created +// second parameter is tmpBinDir +func (d *Definition) TmpWorkDirPath(home string) string { + u := uuid.New().String() + return filepath.Join(home, TmpDir, u) +} + func (d *Definition) UnixBinFilePath(fPath string) string { return filepath.Join(fPath, BinDir, BinUnix) } diff --git a/pkg/formula/formula_test.go b/pkg/formula/formula_test.go index f72a1993c..776c2ad4c 100644 --- a/pkg/formula/formula_test.go +++ b/pkg/formula/formula_test.go @@ -47,6 +47,13 @@ func TestFormulaPath(t *testing.T) { assert.Equal(t, want, got) } +func TestTmpWorkDirPath(t *testing.T) { + want := filepath.Join(home, TmpDir) + gotTmpDir := def.TmpWorkDirPath(home) + + assert.Contains(t, gotTmpDir, want) +} + func TestBinPath(t *testing.T) { want := filepath.Join(home, "repos", "commons", "scaffold", "coffee-java", "bin") formulaPath := def.FormulaPath(home) diff --git a/pkg/formula/runner/docker/pre_run.go b/pkg/formula/runner/docker/pre_run.go index 5196dfec7..11798b3a9 100644 --- a/pkg/formula/runner/docker/pre_run.go +++ b/pkg/formula/runner/docker/pre_run.go @@ -24,6 +24,7 @@ import ( "os/exec" "path/filepath" "strings" + "time" "github.com/kaduartur/go-cli-spinner/pkg/spinner" @@ -78,7 +79,6 @@ func NewPreRun( func (pr PreRunManager) PreRun(def formula.Definition) (formula.Setup, error) { pwd, _ := os.Getwd() formulaPath := def.FormulaPath(pr.ritchieHome) - binPath := def.BinPath(formulaPath) config, err := pr.loadConfig(formulaPath, def) if err != nil { @@ -88,11 +88,13 @@ func (pr PreRunManager) PreRun(def formula.Definition) (formula.Setup, error) { binFilePath := def.UnixBinFilePath(formulaPath) if !pr.file.Exists(binFilePath) { s := spinner.StartNew("Building formula...") + time.Sleep(2 * time.Second) + if err := pr.buildFormula(formulaPath, config.DockerIB); err != nil { s.Stop() // Remove /bin dir to force formula rebuild in next execution - if err := pr.dir.Remove(binPath); err != nil { + if err := pr.dir.Remove(def.BinPath(formulaPath)); err != nil { return formula.Setup{}, err } @@ -102,7 +104,12 @@ func (pr PreRunManager) PreRun(def formula.Definition) (formula.Setup, error) { s.Success(prompt.Green("Formula was successfully built!")) } - if err := os.Chdir(binPath); err != nil { + tmpDir, err := pr.createWorkDir(pr.ritchieHome, formulaPath, def) + if err != nil { + return formula.Setup{}, err + } + + if err := os.Chdir(tmpDir); err != nil { return formula.Setup{}, err } @@ -110,11 +117,12 @@ func (pr PreRunManager) PreRun(def formula.Definition) (formula.Setup, error) { Pwd: pwd, FormulaPath: formulaPath, BinName: def.BinName(), - BinPath: binPath, + BinPath: def.BinPath(formulaPath), + TmpDir: tmpDir, Config: config, } - dockerFile := filepath.Join(binPath, "Dockerfile") + dockerFile := filepath.Join(tmpDir, "Dockerfile") if !pr.file.Exists(dockerFile) { return formula.Setup{}, ErrDockerfileNotFound } @@ -158,6 +166,20 @@ func (pr PreRunManager) loadConfig(formulaPath string, def formula.Definition) ( return formulaConfig, nil } +func (pr PreRunManager) createWorkDir(home, formulaPath string, def formula.Definition) (string, error) { + tDir := def.TmpWorkDirPath(home) + if err := pr.dir.Create(tDir); err != nil { + return "", err + } + + binPath := def.BinPath(formulaPath) + if err := pr.dir.Copy(binPath, tDir); err != nil { + return "", err + } + + return tDir, nil +} + func buildRunImg(def formula.Definition) (string, error) { prompt.Info("Docker image build started") formName := strings.ReplaceAll(def.Path, string(os.PathSeparator), "-") diff --git a/pkg/formula/runner/docker/pre_run_test.go b/pkg/formula/runner/docker/pre_run_test.go index ed7acdef1..0e7b4ce6f 100644 --- a/pkg/formula/runner/docker/pre_run_test.go +++ b/pkg/formula/runner/docker/pre_run_test.go @@ -22,10 +22,9 @@ import ( "fmt" "os" "path/filepath" + "reflect" "testing" - "github.com/stretchr/testify/assert" - "github.com/ZupIT/ritchie-cli/pkg/formula" "github.com/ZupIT/ritchie-cli/pkg/formula/builder" "github.com/ZupIT/ritchie-cli/pkg/stream" @@ -100,7 +99,7 @@ func TestPreRun(t *testing.T) { out: out{ want: formula.Setup{}, wantErr: true, - err: errors.New("failed building formula with Docker, we will try to build your formula locally"), + err: nil, }, }, { @@ -164,6 +163,32 @@ func TestPreRun(t *testing.T) { err: errors.New("invalid character 'e' looking for beginning of value"), }, }, + { + name: "create work dir error", + in: in{ + def: formula.Definition{Path: "testing/formula", RepoName: "commons"}, + dockerBuild: dockerBuilder, + file: fileManager, + dir: dirManagerMock{createErr: errors.New("error to create dir")}, + }, + out: out{ + wantErr: true, + err: errors.New("error to create dir"), + }, + }, + { + name: "copy work dir error", + in: in{ + def: formula.Definition{Path: "testing/formula", RepoName: "commons"}, + dockerBuild: dockerBuilder, + file: fileManager, + dir: dirManagerMock{copyErr: errors.New("error to copy dir")}, + }, + out: out{ + wantErr: true, + err: errors.New("error to copy dir"), + }, + }, } for _, tt := range tests { @@ -173,11 +198,19 @@ func TestPreRun(t *testing.T) { preRun := NewPreRun(ritHome, in.dockerBuild, in.dir, in.file) got, err := preRun.PreRun(in.def) - if err != nil || tt.out.err != nil { - assert.EqualError(t, tt.out.err, err.Error()) + if tt.out.wantErr { + if tt.out.err == nil && err == nil { + t.Errorf("PreRun(%s) want a error", tt.name) + } + + if tt.out.err != nil && err != nil && tt.out.err.Error() != err.Error() { + t.Errorf("PreRun(%s) got %v, want %v", tt.name, err, tt.out.err) + } } - assert.Equal(t, tt.out.want.Config, got.Config) + if !reflect.DeepEqual(tt.out.want.Config, got.Config) { + t.Errorf("PreRun(%s) got %v, want %v", tt.name, got.Config, tt.out.want.Config) + } _ = os.Chdir(got.Pwd) // Return to test folder }) @@ -219,7 +252,6 @@ type fileManagerMock struct { rErr error wErr error aErr error - reErr error exist bool } @@ -239,10 +271,6 @@ func (fi fileManagerMock) Append(path string, content []byte) error { return fi.aErr } -func (fi fileManagerMock) Remove(path string) error { - return fi.reErr -} - const ( configJson = `{ "dockerImageBuilder": "cimg/go:1.14", diff --git a/pkg/formula/runner/docker/runner.go b/pkg/formula/runner/docker/runner.go index 7203a843b..90c884e38 100644 --- a/pkg/formula/runner/docker/runner.go +++ b/pkg/formula/runner/docker/runner.go @@ -18,11 +18,9 @@ package docker import ( "fmt" - "io/ioutil" "os" "os/exec" "strconv" - "strings" "github.com/ZupIT/ritchie-cli/pkg/env" @@ -31,6 +29,8 @@ import ( "github.com/ZupIT/ritchie-cli/pkg/api" "github.com/ZupIT/ritchie-cli/pkg/formula" + "github.com/ZupIT/ritchie-cli/pkg/prompt" + "github.com/ZupIT/ritchie-cli/pkg/stream" ) const ( @@ -41,21 +41,27 @@ const ( var _ formula.Runner = RunManager{} type RunManager struct { - homeDir string - env env.Finder + formula.PostRunner formula.InputResolver formula.PreRunner + file stream.FileWriteExistAppender + env env.Finder + homeDir string } func NewRunner( - homeDir string, + postRun formula.PostRunner, input formula.InputResolver, preRun formula.PreRunner, + file stream.FileWriteExistAppender, env env.Finder, + homeDir string, ) formula.Runner { return RunManager{ + PostRunner: postRun, InputResolver: input, PreRunner: preRun, + file: file, env: env, homeDir: homeDir, } @@ -68,7 +74,8 @@ func (ru RunManager) Run(def formula.Definition, inputType api.TermInputType, ve } defer func() { - if err := os.Remove(envFile); err != nil { + if err := ru.PostRun(setup, true); err != nil { + prompt.Error(err.Error()) return } }() @@ -155,14 +162,16 @@ func (ru RunManager) setEnvs(cmd *exec.Cmd, pwd string, verbose bool) error { verboseEnv := fmt.Sprintf(formula.EnvPattern, formula.VerboseEnv, strconv.FormatBool(verbose)) cmd.Env = append(cmd.Env, pwdEnv, ctxEnv, verboseEnv, dockerEnv, env) - envs := strings.Builder{} - for _, e := range cmd.Env { - envs.WriteString(e + "\n") - } - - // Create a file named .env and add the environment variable inName=inValue - if err := ioutil.WriteFile(envFile, []byte(envs.String()), os.ModePerm); err != nil { - return err + for _, e := range cmd.Env { // Create a file named .envHolder and add the environment variable inName=inValue + if !ru.file.Exists(envFile) { + if err := ru.file.Write(envFile, []byte(e+"\n")); err != nil { + return err + } + continue + } + if err := ru.file.Append(envFile, []byte(e+"\n")); err != nil { + return err + } } return nil diff --git a/pkg/formula/runner/docker/runner_test.go b/pkg/formula/runner/docker/runner_test.go index fee705798..61839ff4e 100644 --- a/pkg/formula/runner/docker/runner_test.go +++ b/pkg/formula/runner/docker/runner_test.go @@ -22,8 +22,6 @@ import ( "path/filepath" "testing" - "github.com/stretchr/testify/assert" - "github.com/ZupIT/ritchie-cli/internal/mocks" "github.com/ZupIT/ritchie-cli/pkg/api" "github.com/ZupIT/ritchie-cli/pkg/env" @@ -57,7 +55,7 @@ func TestRun(t *testing.T) { envFinder := env.NewFinder(ritHome, fileManager) preRunner := NewPreRun(ritHome, dockerBuilder, dirManager, fileManager) - + postRunner := runner.NewPostRunner(fileManager, dirManager) pInputRunner := prompt.NewInputManager(envResolverMock{in: "test"}, inputMock{}, inputMock{}, inputTextValidatorMock{str: "test"}, inputTextDefaultMock{}, inputMock{}, inputMock{}, inputMock{}, inPath) sInputRunner := stdin.NewInputManager(envResolverMock{in: "test"}) fInputRunner := flag.NewInputManager(envResolverMock{in: "test"}) @@ -72,8 +70,10 @@ func TestRun(t *testing.T) { type in struct { def formula.Definition preRun formula.PreRunner + postRun formula.PostRunner inputResolver formula.InputResolver env env.Finder + fileManager stream.FileWriteExistAppender } type out struct { @@ -90,7 +90,9 @@ func TestRun(t *testing.T) { in: in{ def: formula.Definition{Path: "testing/formula", RepoName: "commons"}, preRun: preRunner, + postRun: postRunner, inputResolver: inputResolver, + fileManager: fileManager, env: envFinder, }, out: out{ @@ -102,7 +104,9 @@ func TestRun(t *testing.T) { in: in{ def: formula.Definition{Path: "testing/formula", RepoName: "commons"}, preRun: preRunner, + postRun: postRunner, inputResolver: inputResolverMock{err: runner.ErrInputNotRecognized}, + fileManager: fileManager, env: envFinder, }, out: out{ @@ -114,19 +118,65 @@ func TestRun(t *testing.T) { in: in{ def: formula.Definition{Path: "testing/formula", RepoName: "commons"}, preRun: preRunnerMock{err: errors.New("pre runner error")}, + postRun: postRunner, inputResolver: inputResolver, + fileManager: fileManager, env: envFinder, }, out: out{ err: errors.New("pre runner error"), }, }, + { + name: "post run error", + in: in{ + def: formula.Definition{Path: "testing/formula", RepoName: "commons"}, + preRun: preRunner, + postRun: postRunnerMock{err: errors.New("post runner error")}, + inputResolver: inputResolver, + fileManager: fileManager, + env: envFinder, + }, + out: out{ + err: nil, + }, + }, + { + name: "run docker write .env error", + in: in{ + def: formula.Definition{Path: "testing/formula", RepoName: "commons"}, + preRun: preRunner, + postRun: postRunner, + inputResolver: inputResolver, + fileManager: fileManagerMock{wErr: errors.New("error to write env file")}, + env: envFinder, + }, + out: out{ + err: errors.New("error to write env file"), + }, + }, + { + name: "Run docker append .env error", + in: in{ + def: formula.Definition{Path: "testing/formula", RepoName: "commons"}, + preRun: preRunner, + postRun: postRunner, + inputResolver: inputResolver, + fileManager: fileManagerMock{exist: true, aErr: errors.New("error to append env file")}, + env: envFinder, + }, + out: out{ + err: errors.New("error to append env file"), + }, + }, { name: "env find error", in: in{ def: formula.Definition{Path: "testing/formula", RepoName: "commons"}, preRun: preRunner, + postRun: postRunner, inputResolver: inputResolver, + fileManager: fileManagerMock{exist: true, aErr: errors.New("error to append env file")}, env: envFinderMock{err: errors.New("env not found")}, }, out: out{ @@ -137,23 +187,13 @@ func TestRun(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - pwd, _ := os.Getwd() - formulaPath := tt.in.def.FormulaPath(ritHome) - _ = os.Chdir(formulaPath) - in := tt.in - docker := NewRunner(homeDir, in.inputResolver, in.preRun, in.env) + docker := NewRunner(in.postRun, in.inputResolver, in.preRun, in.fileManager, in.env, homeDir) got := docker.Run(in.def, api.Prompt, false, nil) - if got != nil || tt.out.err != nil { - assert.EqualError(t, tt.out.err, got.Error()) - } else { - fileCreated := filepath.Join(formulaPath, "test.txt") - assert.FileExists(t, fileCreated) - _ = os.Remove(fileCreated) + if tt.out.err != nil && got != nil && tt.out.err.Error() != got.Error() { + t.Errorf("Run(%s) got %v, want %v", tt.name, got, tt.out.err) } - - _ = os.Chdir(pwd) }) } @@ -168,6 +208,14 @@ func (pr preRunnerMock) PreRun(def formula.Definition) (formula.Setup, error) { return pr.setup, pr.err } +type postRunnerMock struct { + err error +} + +func (po postRunnerMock) PostRun(p formula.Setup, docker bool) error { + return po.err +} + type envResolverMock struct { in string err error diff --git a/pkg/formula/runner/local/pre_run.go b/pkg/formula/runner/local/pre_run.go index 255378546..76fdf2dbc 100644 --- a/pkg/formula/runner/local/pre_run.go +++ b/pkg/formula/runner/local/pre_run.go @@ -22,6 +22,7 @@ import ( "os" "path/filepath" "runtime" + "time" "github.com/kaduartur/go-cli-spinner/pkg/spinner" @@ -76,6 +77,7 @@ func (pr PreRunManager) PreRun(def formula.Definition) (formula.Setup, error) { binFilePath := def.BinFilePath(formulaPath) if !pr.file.Exists(binFilePath) { s := spinner.StartNew("Building formula...") + time.Sleep(2 * time.Second) if err := pr.buildFormula(formulaPath); err != nil { s.Stop() @@ -91,11 +93,21 @@ func (pr PreRunManager) PreRun(def formula.Definition) (formula.Setup, error) { s.Success(prompt.Green("Formula was successfully built!")) } + tmpDir, err := pr.createWorkDir(pr.ritchieHome, formulaPath, def) + if err != nil { + return formula.Setup{}, err + } + + if err := os.Chdir(tmpDir); err != nil { + return formula.Setup{}, err + } + s := formula.Setup{ Pwd: pwd, FormulaPath: formulaPath, BinName: def.BinName(), BinPath: def.BinPath(formulaPath), + TmpDir: tmpDir, Config: config, } @@ -139,3 +151,16 @@ func (pr PreRunManager) loadConfig(formulaPath string, def formula.Definition) ( } return formulaConfig, nil } + +func (pr PreRunManager) createWorkDir(home, formulaPath string, def formula.Definition) (string, error) { + tDir := def.TmpWorkDirPath(home) + if err := pr.dir.Create(tDir); err != nil { + return "", err + } + + if err := pr.dir.Copy(def.BinPath(formulaPath), tDir); err != nil { + return "", err + } + + return tDir, nil +} diff --git a/pkg/formula/runner/local/pre_run_test.go b/pkg/formula/runner/local/pre_run_test.go index 8683c200e..f2f780661 100644 --- a/pkg/formula/runner/local/pre_run_test.go +++ b/pkg/formula/runner/local/pre_run_test.go @@ -153,6 +153,86 @@ func TestPreRun(t *testing.T) { err: errors.New("invalid character 'e' looking for beginning of value"), }, }, + { + name: "create work dir error", + in: in{ + def: formula.Definition{Path: "testing/formula", RepoName: "commons"}, + makeBuild: makeBuildMock{ + build: func(formulaPath string) error { + return dirManager.Create(filepath.Join(formulaPath, "bin")) + }, + }, + batBuild: batBuildMock{ + build: func(formulaPath string) error { + return dirManager.Create(filepath.Join(formulaPath, "bin")) + }, + }, + shellBuild: shellBuildMock{ + build: func(formulaPath string) error { + return dirManager.Create(filepath.Join(formulaPath, "bin")) + }, + }, + file: fileManager, + dir: dirManagerMock{createErr: errors.New("error to create dir")}, + }, + out: out{ + wantErr: true, + err: errors.New("error to create dir"), + }, + }, + { + name: "copy work dir error", + in: in{ + def: formula.Definition{Path: "testing/formula", RepoName: "commons"}, + makeBuild: makeBuildMock{ + build: func(formulaPath string) error { + return dirManager.Create(filepath.Join(formulaPath, "bin")) + }, + }, + batBuild: batBuildMock{ + build: func(formulaPath string) error { + return dirManager.Create(filepath.Join(formulaPath, "bin")) + }, + }, + shellBuild: shellBuildMock{ + build: func(formulaPath string) error { + return dirManager.Create(filepath.Join(formulaPath, "bin")) + }, + }, + file: fileManager, + dir: dirManagerMock{copyErr: errors.New("error to copy dir")}, + }, + out: out{ + wantErr: true, + err: errors.New("error to copy dir"), + }, + }, + { + name: "Chdir error", + in: in{ + def: formula.Definition{Path: "testing/formula", RepoName: "commons"}, + makeBuild: makeBuildMock{ + build: func(formulaPath string) error { + return dirManager.Create(filepath.Join(formulaPath, "bin")) + }, + }, + batBuild: batBuildMock{ + build: func(formulaPath string) error { + return dirManager.Create(filepath.Join(formulaPath, "bin")) + }, + }, + shellBuild: shellBuildMock{ + build: func(formulaPath string) error { + return dirManager.Create(filepath.Join(formulaPath, "bin")) + }, + }, + file: fileManager, + dir: dirManagerMock{}, + }, + out: out{ + wantErr: true, + }, + }, { name: "local build error delete bin dir", in: in{ @@ -256,15 +336,11 @@ func (di dirManagerMock) Remove(dir string) error { } type fileManagerMock struct { - rBytes []byte - rErr error - wErr error - aErr error - exist bool - remErr error - movErr error - files []string - listErr error + rBytes []byte + rErr error + wErr error + aErr error + exist bool } func (fi fileManagerMock) Write(string, []byte) error { @@ -283,18 +359,6 @@ func (fi fileManagerMock) Append(path string, content []byte) error { return fi.aErr } -func (fi fileManagerMock) Remove(path string) error { - return fi.remErr -} - -func (fi fileManagerMock) List(file string) ([]string, error) { - return fi.files, fi.listErr -} - -func (fi fileManagerMock) Move(oldPath, newPath string, files []string) error { - return fi.movErr -} - const configJson = `{ "dockerImageBuilder": "cimg/go:1.14", "inputs": [ diff --git a/pkg/formula/runner/local/runner.go b/pkg/formula/runner/local/runner.go index 2c99f06e9..197ebbbb8 100644 --- a/pkg/formula/runner/local/runner.go +++ b/pkg/formula/runner/local/runner.go @@ -23,11 +23,9 @@ import ( "path/filepath" "strconv" - "github.com/spf13/pflag" - "github.com/ZupIT/ritchie-cli/pkg/env" - "github.com/ZupIT/ritchie-cli/pkg/os/osutil" - "github.com/ZupIT/ritchie-cli/pkg/slice/sliceutil" + + "github.com/spf13/pflag" "github.com/ZupIT/ritchie-cli/pkg/api" "github.com/ZupIT/ritchie-cli/pkg/formula" @@ -39,26 +37,29 @@ import ( var _ formula.Runner = RunManager{} type RunManager struct { - homeDir string - file stream.FileListMover - env env.Finder + formula.PostRunner formula.InputResolver formula.PreRunner + file stream.FileWriteExistAppender + env env.Finder + homeDir string } func NewRunner( - homeDir string, - file stream.FileListMover, - env env.Finder, + postRun formula.PostRunner, input formula.InputResolver, preRun formula.PreRunner, + file stream.FileWriteExistAppender, + env env.Finder, + homeDir string, ) formula.Runner { return RunManager{ - homeDir: homeDir, - file: file, - env: env, + PostRunner: postRun, InputResolver: input, PreRunner: preRun, + file: file, + env: env, + homeDir: homeDir, } } @@ -68,7 +69,14 @@ func (ru RunManager) Run(def formula.Definition, inputType api.TermInputType, ve return err } - formulaRun := filepath.Join(setup.BinPath, setup.BinName) + defer func() { + if err := ru.PostRun(setup, false); err != nil { + prompt.Error(err.Error()) + return + } + }() + + formulaRun := filepath.Join(setup.TmpDir, setup.BinName) cmd := exec.Command(formulaRun) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout @@ -87,47 +95,11 @@ func (ru RunManager) Run(def formula.Definition, inputType api.TermInputType, ve return err } - metric.RepoName = def.RepoName - - if osutil.IsWindows() { - if err := ru.runWin(cmd, setup); err != nil { - return err - } - - return nil - } - if err := cmd.Run(); err != nil { return err } - return nil -} - -func (ru RunManager) runWin(cmd *exec.Cmd, setup formula.Setup) error { - if err := os.Chdir(setup.BinPath); err != nil { - return err - } - - of, err := ru.file.List(setup.BinPath) - if err != nil { - return err - } - - if err := cmd.Run(); err != nil { - return err - } - - nf, err := ru.file.List(setup.BinPath) - if err != nil { - return err - } - - files := append(of, nf...) - newFiles := sliceutil.Unique(files) - if err := ru.file.Move(setup.BinPath, setup.Pwd, newFiles); err != nil { - return err - } + metric.RepoName = def.RepoName return nil } diff --git a/pkg/formula/runner/local/runner_test.go b/pkg/formula/runner/local/runner_test.go index b01d76473..ac3afcb77 100644 --- a/pkg/formula/runner/local/runner_test.go +++ b/pkg/formula/runner/local/runner_test.go @@ -22,8 +22,6 @@ import ( "path/filepath" "testing" - "github.com/stretchr/testify/assert" - "github.com/ZupIT/ritchie-cli/internal/mocks" "github.com/ZupIT/ritchie-cli/pkg/api" "github.com/ZupIT/ritchie-cli/pkg/env" @@ -44,9 +42,6 @@ func TestRun(t *testing.T) { homeDir, _ := os.UserHomeDir() ritHome := filepath.Join(tmpDir, ".rit-runner-local") repoPath := filepath.Join(ritHome, "repos", "commons") - defer os.Remove("test.txt") - defer os.RemoveAll(ritHome) - inPath := &mocks.InputPathMock{} inPath.On("Read", "Type : ").Return("", nil) @@ -62,7 +57,7 @@ func TestRun(t *testing.T) { envFinder := env.NewFinder(ritHome, fileManager) preRunner := NewPreRun(ritHome, makeBuilder, batBuilder, shellBuilder, dirManager, fileManager) - + postRunner := runner.NewPostRunner(fileManager, dirManager) pInputRunner := prompt.NewInputManager(envResolverMock{in: "test"}, inputMock{}, inputMock{}, inputTextValidatorMock{}, inputTextDefaultMock{}, inputMock{}, inputMock{}, inputMock{}, inPath) sInputRunner := stdin.NewInputManager(envResolverMock{in: "test"}) fInputRunner := flag.NewInputManager(envResolverMock{in: "test"}) @@ -77,86 +72,121 @@ func TestRun(t *testing.T) { type in struct { def formula.Definition preRun formula.PreRunner + postRun formula.PostRunner inputResolver formula.InputResolver - fileManager stream.FileListMover + fileManager stream.FileWriteExistAppender env env.Finder } + type out struct { + err error + } + tests := []struct { name string in in - want error + out out }{ { name: "run local success", in: in{ def: formula.Definition{Path: "testing/formula", RepoName: "commons"}, preRun: preRunner, + postRun: postRunner, inputResolver: inputResolver, fileManager: fileManager, env: envFinder, }, - want: nil, + out: out{ + err: nil, + }, }, { - name: "success with a non default env", + name: "Input error local", in: in{ def: formula.Definition{Path: "testing/formula", RepoName: "commons"}, preRun: preRunner, - inputResolver: inputResolver, - env: envFinderMock{env: env.Holder{ - Current: "prod", - }}, + postRun: postRunner, + inputResolver: inputResolverMock{err: runner.ErrInputNotRecognized}, + fileManager: fileManager, + env: envFinder, + }, + out: out{ + err: runner.ErrInputNotRecognized, }, - want: nil, }, { - name: "input error local", + name: "Pre run error", in: in{ def: formula.Definition{Path: "testing/formula", RepoName: "commons"}, - preRun: preRunner, - inputResolver: inputResolverMock{err: runner.ErrInputNotRecognized}, + preRun: preRunnerMock{err: errors.New("pre runner error")}, + postRun: postRunner, + inputResolver: inputResolver, fileManager: fileManager, env: envFinder, }, - want: runner.ErrInputNotRecognized, + out: out{ + err: errors.New("pre runner error"), + }, }, { - name: "pre run error", + name: "Post run error", in: in{ def: formula.Definition{Path: "testing/formula", RepoName: "commons"}, - preRun: preRunnerMock{err: errors.New("pre runner error")}, + preRun: preRunner, + postRun: postRunnerMock{err: errors.New("post runner error")}, inputResolver: inputResolver, fileManager: fileManager, env: envFinder, }, - want: errors.New("pre runner error"), + out: out{ + err: errors.New("post runner error"), + }, }, { name: "env find error", in: in{ def: formula.Definition{Path: "testing/formula", RepoName: "commons"}, preRun: preRunner, + postRun: postRunner, inputResolver: inputResolver, + fileManager: fileManagerMock{exist: true, aErr: errors.New("error to append env file")}, env: envFinderMock{err: errors.New("env not found")}, }, - want: errors.New("env not found"), + out: out{ + err: errors.New("env not found"), + }, + }, + { + name: "success with a non default env", + in: in{ + def: formula.Definition{Path: "testing/formula", RepoName: "commons"}, + preRun: preRunner, + postRun: postRunner, + inputResolver: inputResolver, + fileManager: fileManagerMock{exist: true, aErr: errors.New("error to append env file")}, + env: envFinderMock{env: env.Holder{ + Current: "prod", + }}, + }, + out: out{ + err: nil, + }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { in := tt.in - local := NewRunner(homeDir, in.fileManager, in.env, in.inputResolver, in.preRun) + local := NewRunner(in.postRun, in.inputResolver, in.preRun, in.fileManager, in.env, homeDir) got := local.Run(in.def, api.Prompt, false, nil) - if tt.want != nil || got != nil { - assert.EqualError(t, got, tt.want.Error()) - } else { - assert.FileExists(t, "test.txt") + if tt.out.err != nil && got != nil && tt.out.err.Error() != got.Error() { + t.Errorf("Run(%s) got %v, want %v", tt.name, got, tt.out.err) } }) } + } type preRunnerMock struct { @@ -168,6 +198,14 @@ func (pr preRunnerMock) PreRun(def formula.Definition) (formula.Setup, error) { return pr.setup, pr.err } +type postRunnerMock struct { + err error +} + +func (po postRunnerMock) PostRun(p formula.Setup, docker bool) error { + return po.err +} + type envResolverMock struct { in string err error diff --git a/pkg/formula/runner/post_run.go b/pkg/formula/runner/post_run.go new file mode 100644 index 000000000..58abf746d --- /dev/null +++ b/pkg/formula/runner/post_run.go @@ -0,0 +1,76 @@ +/* + * Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package runner + +import ( + "fmt" + + "github.com/ZupIT/ritchie-cli/pkg/formula" + "github.com/ZupIT/ritchie-cli/pkg/formula/input" + "github.com/ZupIT/ritchie-cli/pkg/prompt" + "github.com/ZupIT/ritchie-cli/pkg/stream" +) + +type PostRunnerManager struct { + file stream.FileNewListMoveRemover + dir stream.DirRemover +} + +const deprecatedMsg = "\nWarning: dynamic input are deprecated and will no " + + "longer be supported in future versions\n" + +func NewPostRunner(file stream.FileNewListMoveRemover, dir stream.DirRemover) PostRunnerManager { + return PostRunnerManager{file: file, dir: dir} +} + +func (po PostRunnerManager) PostRun(p formula.Setup, docker bool) error { + if docker { + if err := po.file.Remove(".env"); err != nil { + return err + } + } + + defer po.removeWorkDir(p.TmpDir) + + df, err := po.file.ListNews(p.BinPath, p.TmpDir) + if err != nil { + return err + } + + if err = po.file.Move(p.TmpDir, p.Pwd, df); err != nil { + return err + } + + po.deprecatedInput(p) + + return nil +} + +func (po PostRunnerManager) removeWorkDir(tmpDir string) { + if err := po.dir.Remove(tmpDir); err != nil { + fmt.Sprintln("Error in remove dir") + } +} + +func (po PostRunnerManager) deprecatedInput(p formula.Setup) { + for _, in := range p.Config.Inputs { + if in.Type == input.DynamicType { + prompt.Warning(deprecatedMsg) + break + } + } +} diff --git a/pkg/formula/runner/post_run_test.go b/pkg/formula/runner/post_run_test.go new file mode 100644 index 000000000..e63ae0565 --- /dev/null +++ b/pkg/formula/runner/post_run_test.go @@ -0,0 +1,137 @@ +/* + * Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package runner + +import ( + "errors" + "testing" + + "github.com/ZupIT/ritchie-cli/internal/mocks" + "github.com/ZupIT/ritchie-cli/pkg/formula" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestPostRun(t *testing.T) { + type in struct { + wrErr error + rdErr error + apErr error + mvErr error + rmErr error + lnErr error + exist bool + dir error + setup formula.Setup + docker bool + } + + tests := []struct { + name string + in in + want error + }{ + { + name: "success", + in: in{ + setup: formula.Setup{}, + docker: false, + }, + want: nil, + }, + { + name: "success docker", + in: in{ + setup: formula.Setup{}, + docker: true, + }, + want: nil, + }, + { + name: "error remove .env file docker", + in: in{ + rmErr: errors.New("error to remove .env file"), + setup: formula.Setup{}, + docker: true, + }, + want: errors.New("error to remove .env file"), + }, + { + name: "error list new files", + in: in{ + lnErr: errors.New("error to list new files"), + setup: formula.Setup{}, + docker: false, + }, + want: errors.New("error to list new files"), + }, + { + name: "error move new files", + in: in{ + mvErr: errors.New("error to move new files"), + setup: formula.Setup{}, + docker: false, + }, + want: errors.New("error to move new files"), + }, + { + name: "error remove work dir", + in: in{ + dir: errors.New("error to remove workdir"), + setup: formula.Setup{}, + docker: false, + }, + want: nil, + }, + { + name: "input deprecated", + in: in{ + setup: formula.Setup{ + Config: formula.Config{ + Inputs: formula.Inputs{ + formula.Input{ + Type: "dynamic", + }, + }, + }, + }, + docker: false, + }, + want: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + dm := &mocks.DirManagerMock{} + dm.On("Remove", mock.Anything).Return(tt.in.dir) + fm := &mocks.FileManagerMock{} + fm.On("Write", mock.Anything, mock.Anything).Return(tt.in.wrErr) + fm.On("Read", mock.Anything).Return([]byte{}, tt.in.rdErr) + fm.On("Exists", mock.Anything).Return(tt.in.exist) + fm.On("Append", mock.Anything, mock.Anything).Return(tt.in.apErr) + fm.On("Move", mock.Anything, mock.Anything, mock.Anything).Return(tt.in.mvErr) + fm.On("Remove", mock.Anything).Return(tt.in.rmErr) + fm.On("ListNews", mock.Anything, mock.Anything).Return([]string{}, tt.in.lnErr) + runner := NewPostRunner(fm, dm) + got := runner.PostRun(tt.in.setup, tt.in.docker) + + assert.Equal(t, tt.want, got) + }) + } + +} diff --git a/pkg/os/osutil/os.go b/pkg/os/osutil/os.go index dd2e37360..63c9f3d3d 100644 --- a/pkg/os/osutil/os.go +++ b/pkg/os/osutil/os.go @@ -16,14 +16,8 @@ package osutil -import "runtime" - const ( Darwin = "darwin" Linux = "linux" Windows = "windows" ) - -func IsWindows() bool { - return runtime.GOOS == Windows -} diff --git a/pkg/slice/sliceutil/slice_util.go b/pkg/slice/sliceutil/slice_util.go index ef64a6a51..696b11988 100644 --- a/pkg/slice/sliceutil/slice_util.go +++ b/pkg/slice/sliceutil/slice_util.go @@ -25,26 +25,3 @@ func Contains(aa []string, s string) bool { } return false } - -// Unique returns a slice that contains -// only non repeated values. -func Unique(aa []string) []string { - check := make(map[string]int) - for _, v := range aa { - if check[v] == 1 { - check[v]++ - continue - } - - check[v] = 1 - } - - var res []string - for _, v := range aa { - if check[v] == 1 { - res = append(res, v) - } - } - - return res -} diff --git a/pkg/slice/sliceutil/slice_util_test.go b/pkg/slice/sliceutil/slice_util_test.go index 055dc9de8..e0d253b3f 100644 --- a/pkg/slice/sliceutil/slice_util_test.go +++ b/pkg/slice/sliceutil/slice_util_test.go @@ -38,10 +38,3 @@ func TestContains(t *testing.T) { }) } } - -func TestUnique(t *testing.T) { - aa := []string{"Dockerfile", "run.sh", "Dockerfile", "run.sh", "docker-compose.yml"} - unique := Unique(aa) - assert.Len(t, unique, 1) - assert.Equal(t, unique[0], "docker-compose.yml") -} diff --git a/pkg/stream/file.go b/pkg/stream/file.go index 44889608b..c01b78521 100644 --- a/pkg/stream/file.go +++ b/pkg/stream/file.go @@ -80,11 +80,6 @@ type FileNewListMoveRemover interface { FileNewLister } -type FileListMover interface { - FileLister - FileMover -} - type FileCopyExistListerWriter interface { FileLister FileCopier @@ -105,11 +100,10 @@ type FileWriteReadExistLister interface { FileLister } -type FileWriteExistAppendRemover interface { +type FileWriteExistAppender interface { FileWriter FileExister FileAppender - FileRemover } type FileWriteReadExistRemover interface { diff --git a/testdata/ritchie-formulas-test.zip b/testdata/ritchie-formulas-test.zip index 4dd04f464..1ab24b443 100644 Binary files a/testdata/ritchie-formulas-test.zip and b/testdata/ritchie-formulas-test.zip differ