From 00f0db7f324878a2515564eff87426df7df77804 Mon Sep 17 00:00:00 2001 From: petergmurphy Date: Wed, 29 Jun 2022 16:06:54 +0100 Subject: [PATCH] Refactor pkg --- cmd/exec/exec.go | 10 +- cmd/exec/exec_test.go | 3 +- cmd/get/get.go | 5 +- cmd/install/install.go | 4 +- cmd/set/backend.go | 18 +-- cmd/set/puppet.go | 4 +- cmd/set/set.go | 6 +- cmd/set/set_test.go | 14 +-- cmd/status/status.go | 6 +- cmd/validate/validate.go | 39 +++++-- cmd/validate/validate_test.go | 3 +- .../pkg/config_processor/config_processor.go | 4 +- internal/pkg/mock/backend.go | 34 +++--- internal/pkg/mock/docker.go | 5 +- internal/pkg/mock/utils.go | 5 +- pkg/backend/backend.go | 74 +++++++++++++ pkg/{prm => backend/docker}/docker.go | 104 +++++++++--------- pkg/{prm => backend/docker}/docker_test.go | 58 +++++----- pkg/{prm => backend}/status.go | 17 +-- pkg/{prm => backend}/status_test.go | 44 ++++---- pkg/{prm => config}/config.go | 49 ++++++--- pkg/{prm => config}/config_test.go | 23 ++-- pkg/{prm => exec}/exec.go | 29 +++-- pkg/{prm => exec}/exec_test.go | 35 +++--- pkg/prm/backend.go | 43 -------- pkg/prm/prm.go | 53 ++++----- pkg/prm/prm_test.go | 63 +++++------ pkg/{prm => tool}/tool.go | 2 +- pkg/{prm => tool}/tool_groups.go | 2 +- pkg/utils/utils.go | 38 ++++--- pkg/{prm => utils}/worker_pool.go | 8 +- pkg/{prm => validate}/validate.go | 103 ++++++++--------- pkg/{prm => validate}/validate_test.go | 77 ++++++++----- 33 files changed, 553 insertions(+), 429 deletions(-) create mode 100644 pkg/backend/backend.go rename pkg/{prm => backend/docker}/docker.go (86%) rename pkg/{prm => backend/docker}/docker_test.go (84%) rename pkg/{prm => backend}/status.go (77%) rename pkg/{prm => backend}/status_test.go (78%) rename pkg/{prm => config}/config.go (69%) rename pkg/{prm => config}/config_test.go (71%) rename pkg/{prm => exec}/exec.go (64%) rename pkg/{prm => exec}/exec_test.go (84%) delete mode 100644 pkg/prm/backend.go rename pkg/{prm => tool}/tool.go (99%) rename pkg/{prm => tool}/tool_groups.go (98%) rename pkg/{prm => utils}/worker_pool.go (93%) rename pkg/{prm => validate}/validate.go (59%) rename pkg/{prm => validate}/validate_test.go (74%) diff --git a/cmd/exec/exec.go b/cmd/exec/exec.go index 7200a18..b06e49e 100644 --- a/cmd/exec/exec.go +++ b/cmd/exec/exec.go @@ -2,6 +2,8 @@ package exec import ( "fmt" + "github.com/puppetlabs/prm/pkg/backend/docker" + "github.com/puppetlabs/prm/pkg/config" "os" "os/user" "path/filepath" @@ -92,10 +94,10 @@ func preExecute(cmd *cobra.Command, args []string) error { } switch prmApi.RunningConfig.Backend { - case prm.DOCKER: - prmApi.Backend = &prm.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, AlwaysBuild: alwaysBuild, ContextTimeout: prmApi.RunningConfig.Timeout} + case config.DOCKER: + prmApi.Backend = &docker.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, AlwaysBuild: alwaysBuild, ContextTimeout: prmApi.RunningConfig.Timeout} default: - prmApi.Backend = &prm.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, AlwaysBuild: alwaysBuild, ContextTimeout: prmApi.RunningConfig.Timeout} + prmApi.Backend = &docker.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, AlwaysBuild: alwaysBuild, ContextTimeout: prmApi.RunningConfig.Timeout} } if prmApi.CodeDir == "" { @@ -142,7 +144,7 @@ func flagCompletion(cmd *cobra.Command, args []string, toComplete string) ([]str if len(args) != 0 { return nil, cobra.ShellCompDirectiveNoFileComp } - localToolPath = viper.GetString(prm.ToolPathCfgKey) + localToolPath = viper.GetString(config.ToolPathCfgKey) return completeName(localToolPath, toComplete), cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp } diff --git a/cmd/exec/exec_test.go b/cmd/exec/exec_test.go index 9098674..221ea9c 100644 --- a/cmd/exec/exec_test.go +++ b/cmd/exec/exec_test.go @@ -2,6 +2,7 @@ package exec_test import ( "bytes" + "github.com/puppetlabs/prm/pkg/config" "io/ioutil" "path" "regexp" @@ -89,7 +90,7 @@ plugin: prmObj := &prm.Prm{ AFS: &afero.Afero{Fs: fs}, IOFS: &afero.IOFS{Fs: fs}, - RunningConfig: prm.Config{ + RunningConfig: config.Config{ ToolPath: toolDir, }, } diff --git a/cmd/get/get.go b/cmd/get/get.go index fc35831..56e0dcb 100644 --- a/cmd/get/get.go +++ b/cmd/get/get.go @@ -2,6 +2,7 @@ package get import ( "fmt" + "github.com/puppetlabs/prm/pkg/config" "github.com/puppetlabs/prm/pkg/prm" "github.com/spf13/cobra" @@ -9,11 +10,11 @@ import ( func CreateGetCommand(parent *prm.Prm) *cobra.Command { tmp := &cobra.Command{ - Use: fmt.Sprintf("get <%s|%s>", prm.BackendCmdFlag, prm.PuppetCmdFlag), + Use: fmt.Sprintf("get <%s|%s>", config.BackendCmdFlag, config.PuppetCmdFlag), Short: "Displays the requested configuration value", Long: "Displays the requested configuration value", DisableFlagsInUseLine: true, - ValidArgs: []string{prm.BackendCmdFlag, prm.PuppetCmdFlag}, + ValidArgs: []string{config.BackendCmdFlag, config.PuppetCmdFlag}, Run: func(cmd *cobra.Command, args []string) { cmd.HelpFunc()(cmd, args) }, diff --git a/cmd/install/install.go b/cmd/install/install.go index 556b747..15de7e0 100644 --- a/cmd/install/install.go +++ b/cmd/install/install.go @@ -2,12 +2,12 @@ package install import ( "fmt" + "github.com/puppetlabs/prm/pkg/config" "github.com/spf13/afero" "github.com/puppetlabs/pct/pkg/install" "github.com/puppetlabs/pct/pkg/telemetry" - "github.com/puppetlabs/prm/pkg/prm" "github.com/rs/zerolog/log" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -77,7 +77,7 @@ func (ic *InstallCommand) executeInstall(cmd *cobra.Command, args []string) erro func (ic *InstallCommand) setInstallPath() error { if ic.InstallPath == "" { - defaultToolPath := viper.GetString(prm.ToolPathCfgKey) + defaultToolPath := viper.GetString(config.ToolPathCfgKey) if defaultToolPath == "" { return fmt.Errorf("Could not determine location to install tool") //: %v", err) } diff --git a/cmd/set/backend.go b/cmd/set/backend.go index 8dfb481..22d2b9a 100644 --- a/cmd/set/backend.go +++ b/cmd/set/backend.go @@ -2,13 +2,13 @@ package set import ( "fmt" + "github.com/puppetlabs/prm/pkg/config" "strings" - "github.com/puppetlabs/prm/pkg/prm" "github.com/spf13/cobra" ) -var SelectedBackend prm.BackendType +var SelectedBackend config.BackendType func (sc *SetCommand) createSetBackendCommand() *cobra.Command { tmp := &cobra.Command{ @@ -17,7 +17,7 @@ func (sc *SetCommand) createSetBackendCommand() *cobra.Command { Long: `Sets the backend exec environment to the specified type`, PreRunE: sc.setBackendPreRunE, RunE: sc.setBackendType, - ValidArgs: []string{string(prm.DOCKER)}, + ValidArgs: []string{string(config.DOCKER)}, } return tmp @@ -25,23 +25,23 @@ func (sc *SetCommand) createSetBackendCommand() *cobra.Command { func (sc *SetCommand) setBackendPreRunE(cmd *cobra.Command, args []string) (err error) { if len(args) > 1 { - return fmt.Errorf("too many args, please specify ONE of the following backend types after 'set backend':\n- %s", prm.DOCKER) + return fmt.Errorf("too many args, please specify ONE of the following backend types after 'set backend':\n- %s", config.DOCKER) } if len(args) < 1 { - return fmt.Errorf("please specify specify one of the following backend types after 'set backend':\n- %s", prm.DOCKER) + return fmt.Errorf("please specify specify one of the following backend types after 'set backend':\n- %s", config.DOCKER) } switch strings.ToLower(args[0]) { - case string(prm.DOCKER): - SelectedBackend = prm.DOCKER + case string(config.DOCKER): + SelectedBackend = config.DOCKER default: - return fmt.Errorf("'%s' is not a valid backend type, please specify one of the following backend types:\n- %s", args[0], prm.DOCKER) + return fmt.Errorf("'%s' is not a valid backend type, please specify one of the following backend types:\n- %s", args[0], config.DOCKER) } return nil } func (sc *SetCommand) setBackendType(cmd *cobra.Command, args []string) error { - return sc.Utils.SetAndWriteConfig(prm.BackendCfgKey, string(SelectedBackend)) + return config.SetAndWriteConfig(config.BackendCfgKey, string(SelectedBackend)) } diff --git a/cmd/set/puppet.go b/cmd/set/puppet.go index 95c6654..ed77559 100644 --- a/cmd/set/puppet.go +++ b/cmd/set/puppet.go @@ -2,9 +2,9 @@ package set import ( "fmt" + "github.com/puppetlabs/prm/pkg/config" "github.com/Masterminds/semver" - "github.com/puppetlabs/prm/pkg/prm" "github.com/spf13/cobra" ) @@ -33,7 +33,7 @@ func (sc *SetCommand) setPuppetVersion(cmd *cobra.Command, args []string) error return fmt.Errorf("'%s' is not a semantic (x.y.z) Puppet version: %s", args[0], err) } - return sc.Utils.SetAndWriteConfig(prm.PuppetVerCfgKey, puppetSemVer.String()) + return config.SetAndWriteConfig(config.PuppetVerCfgKey, puppetSemVer.String()) } // TODO: (GH-26) Consume a list of available Puppet versions to faciliate tab completion diff --git a/cmd/set/set.go b/cmd/set/set.go index ee8c5b1..9933d24 100644 --- a/cmd/set/set.go +++ b/cmd/set/set.go @@ -2,8 +2,8 @@ package set import ( "fmt" + "github.com/puppetlabs/prm/pkg/config" - "github.com/puppetlabs/prm/pkg/prm" "github.com/puppetlabs/prm/pkg/utils" "github.com/spf13/cobra" ) @@ -14,11 +14,11 @@ type SetCommand struct { func (sc *SetCommand) CreateSetCommand() *cobra.Command { tmp := &cobra.Command{ - Use: fmt.Sprintf("set <%s|%s> value", prm.BackendCmdFlag, prm.PuppetCmdFlag), + Use: fmt.Sprintf("set <%s|%s> value", config.BackendCmdFlag, config.PuppetCmdFlag), Short: "Sets the specified configuration to the specified value", Long: "Sets the specified configuration to the specified value", DisableFlagsInUseLine: true, - ValidArgs: []string{prm.BackendCmdFlag, prm.PuppetCmdFlag}, + ValidArgs: []string{config.BackendCmdFlag, config.PuppetCmdFlag}, Run: func(cmd *cobra.Command, args []string) { cmd.HelpFunc()(cmd, args) }, diff --git a/cmd/set/set_test.go b/cmd/set/set_test.go index 9f9d354..0fc6015 100644 --- a/cmd/set/set_test.go +++ b/cmd/set/set_test.go @@ -3,12 +3,12 @@ package set_test import ( "bytes" "fmt" + "github.com/puppetlabs/prm/pkg/config" "io/ioutil" "testing" "github.com/puppetlabs/prm/cmd/set" "github.com/puppetlabs/prm/internal/pkg/mock" - "github.com/puppetlabs/prm/pkg/prm" "github.com/stretchr/testify/assert" ) @@ -17,7 +17,7 @@ type test struct { args []string expectedOutput string expectedPuppetVer string - expectedBackedType prm.BackendType + expectedBackedType config.BackendType expectError bool } @@ -78,29 +78,29 @@ func Test_SetBackendCommand(t *testing.T) { { name: "Should handle valid backend selection (docker)", args: []string{"backend", "docker"}, - expectedBackedType: prm.DOCKER, + expectedBackedType: config.DOCKER, }, { name: "Should handle valid backend selection (dOcKeR)", args: []string{"backend", "dOcKeR"}, - expectedBackedType: prm.DOCKER, + expectedBackedType: config.DOCKER, }, { name: "Should error when too many args supplied to 'backend' sub cmd", args: []string{"backend", "foo", "bar"}, - expectedOutput: fmt.Sprintf("Error: too many args, please specify ONE of the following backend types after 'set backend':\n- %s", prm.DOCKER), + expectedOutput: fmt.Sprintf("Error: too many args, please specify ONE of the following backend types after 'set backend':\n- %s", config.DOCKER), expectError: true, }, { name: "Should error when no arg supplied to 'badckend' sub cmd", args: []string{"backend"}, - expectedOutput: fmt.Sprintf("please specify specify one of the following backend types after 'set backend':\n- %s", prm.DOCKER), + expectedOutput: fmt.Sprintf("please specify specify one of the following backend types after 'set backend':\n- %s", config.DOCKER), expectError: true, }, { name: "Should error when invalid backend type supplied to 'badckend' sub cmd", args: []string{"backend", "foo"}, - expectedOutput: fmt.Sprintf("Error: 'foo' is not a valid backend type, please specify one of the following backend types:\n- %s", prm.DOCKER), + expectedOutput: fmt.Sprintf("Error: 'foo' is not a valid backend type, please specify one of the following backend types:\n- %s", config.DOCKER), expectError: true, }, } diff --git a/cmd/status/status.go b/cmd/status/status.go index da2d62e..d65276d 100644 --- a/cmd/status/status.go +++ b/cmd/status/status.go @@ -2,6 +2,8 @@ package status import ( "fmt" + "github.com/puppetlabs/prm/pkg/backend" + "github.com/puppetlabs/prm/pkg/backend/docker" "github.com/puppetlabs/prm/pkg/prm" "github.com/spf13/cobra" @@ -36,13 +38,13 @@ func CreateStatusCommand(parent *prm.Prm) *cobra.Command { func preExecute(cmd *cobra.Command, args []string) error { switch prmApi.RunningConfig.Backend { default: - prmApi.Backend = &prm.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, ContextTimeout: prmApi.RunningConfig.Timeout} + prmApi.Backend = &docker.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, ContextTimeout: prmApi.RunningConfig.Timeout} } return nil } func execute(cmd *cobra.Command, args []string) error { - status, err := prm.FormatStatus(prmApi.GetStatus(), format) + status, err := backend.FormatStatus(prmApi.GetStatus(), format) if err != nil { return err } diff --git a/cmd/validate/validate.go b/cmd/validate/validate.go index 81433d4..af3b670 100644 --- a/cmd/validate/validate.go +++ b/cmd/validate/validate.go @@ -2,6 +2,10 @@ package validate import ( "fmt" + "github.com/puppetlabs/prm/pkg/backend" + "github.com/puppetlabs/prm/pkg/backend/docker" + "github.com/puppetlabs/prm/pkg/config" + "github.com/puppetlabs/prm/pkg/validate" "os" "os/user" "path" @@ -127,10 +131,10 @@ func preExecute(cmd *cobra.Command, args []string) error { } switch prmApi.RunningConfig.Backend { - case prm.DOCKER: - prmApi.Backend = &prm.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, AlwaysBuild: alwaysBuild, ContextTimeout: prmApi.RunningConfig.Timeout} + case config.DOCKER: + prmApi.Backend = &docker.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, AlwaysBuild: alwaysBuild, ContextTimeout: prmApi.RunningConfig.Timeout} default: - prmApi.Backend = &prm.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, AlwaysBuild: alwaysBuild, ContextTimeout: prmApi.RunningConfig.Timeout} + prmApi.Backend = &docker.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, AlwaysBuild: alwaysBuild, ContextTimeout: prmApi.RunningConfig.Timeout} } if !listTools { @@ -179,7 +183,7 @@ func flagCompletion(cmd *cobra.Command, args []string, toComplete string) ([]str if len(args) != 0 { return nil, cobra.ShellCompDirectiveNoFileComp } - localToolPath = viper.GetString(prm.ToolPathCfgKey) + localToolPath = viper.GetString(config.ToolPathCfgKey) return completeName(localToolPath, toComplete), cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp } @@ -233,16 +237,23 @@ func execute(cmd *cobra.Command, args []string) error { additionalToolArgs, _ = shlex.Split(toolArgs) } - toolInfo := prm.ToolInfo{ + toolInfo := backend.ToolInfo{ Tool: cachedTool, Args: additionalToolArgs, } - settings := prm.OutputSettings{ + settings := backend.OutputSettings{ ResultsView: resultsView, OutputDir: path.Join(prmApi.CodeDir, ".prm-validate"), } - err := prmApi.Validate([]prm.ToolInfo{toolInfo}, 1, settings) + validator := validate.Validator{ + Backend: prmApi.Backend, + AFS: prmApi.AFS, + DirectoryPaths: backend.DirectoryPaths{CodeDir: prmApi.CodeDir, CacheDir: prmApi.CacheDir}, + RunningConfig: prmApi.RunningConfig, + } + + err := validator.Validate([]backend.ToolInfo{toolInfo}, 1, settings) if err != nil { return err } @@ -264,14 +275,14 @@ func execute(cmd *cobra.Command, args []string) error { } // Gather a list of tools - var toolList []prm.ToolInfo + var toolList []backend.ToolInfo for _, tool := range toolGroup.Tools { cachedTool, ok := prmApi.IsToolAvailable(tool.Name) if !ok { return fmt.Errorf("Tool %s not found in cache", tool) } - info := prm.ToolInfo{Tool: cachedTool, Args: tool.Args} + info := backend.ToolInfo{Tool: cachedTool, Args: tool.Args} toolList = append(toolList, info) } @@ -281,7 +292,15 @@ func execute(cmd *cobra.Command, args []string) error { if isSerial || workerCount < 1 { workerCount = 1 } - err = prmApi.Validate(toolList, workerCount, prm.OutputSettings{ResultsView: resultsView, OutputDir: outputDir}) + + validator := validate.Validator{ + Backend: prmApi.Backend, + AFS: prmApi.AFS, + DirectoryPaths: backend.DirectoryPaths{CodeDir: prmApi.CodeDir, CacheDir: prmApi.CacheDir}, + RunningConfig: prmApi.RunningConfig, + } + + err = validator.Validate(toolList, workerCount, backend.OutputSettings{ResultsView: resultsView, OutputDir: outputDir}) if err != nil { return err } diff --git a/cmd/validate/validate_test.go b/cmd/validate/validate_test.go index 5092835..44f10be 100644 --- a/cmd/validate/validate_test.go +++ b/cmd/validate/validate_test.go @@ -2,6 +2,7 @@ package validate_test import ( "bytes" + "github.com/puppetlabs/prm/pkg/config" "io/ioutil" "path" "testing" @@ -141,7 +142,7 @@ common: prmObj := &prm.Prm{ AFS: &afero.Afero{Fs: fs}, IOFS: &afero.IOFS{Fs: fs}, - RunningConfig: prm.Config{ + RunningConfig: config.Config{ ToolPath: toolDir, }, } diff --git a/internal/pkg/config_processor/config_processor.go b/internal/pkg/config_processor/config_processor.go index ae418e0..271b450 100644 --- a/internal/pkg/config_processor/config_processor.go +++ b/internal/pkg/config_processor/config_processor.go @@ -3,9 +3,9 @@ package config_processor import ( "bytes" "fmt" + "github.com/puppetlabs/prm/pkg/tool" "github.com/puppetlabs/pct/pkg/config_processor" - "github.com/puppetlabs/prm/pkg/prm" "github.com/spf13/afero" "github.com/spf13/viper" ) @@ -59,7 +59,7 @@ func (p *ConfigProcessor) CheckConfig(configFile string) error { return nil } -func (p *ConfigProcessor) ReadConfig(configFile string) (info prm.ToolConfigInfo, err error) { +func (p *ConfigProcessor) ReadConfig(configFile string) (info tool.ToolConfigInfo, err error) { fileBytes, err := p.AFS.ReadFile(configFile) if err != nil { return info, err diff --git a/internal/pkg/mock/backend.go b/internal/pkg/mock/backend.go index f01d30f..108c3e1 100644 --- a/internal/pkg/mock/backend.go +++ b/internal/pkg/mock/backend.go @@ -2,8 +2,10 @@ package mock import ( "errors" - - "github.com/puppetlabs/prm/pkg/prm" + "github.com/puppetlabs/prm/pkg/backend" + "github.com/puppetlabs/prm/pkg/backend/docker" + "github.com/puppetlabs/prm/pkg/config" + "github.com/puppetlabs/prm/pkg/tool" ) type MockBackend struct { @@ -14,11 +16,11 @@ type MockBackend struct { ValidateReturn string } -func (m *MockBackend) Status() prm.BackendStatus { - return prm.BackendStatus{IsAvailable: m.StatusIsAvailable, StatusMsg: m.StatusMessageString} +func (m *MockBackend) Status() backend.BackendStatus { + return backend.BackendStatus{IsAvailable: m.StatusIsAvailable, StatusMessage: m.StatusMessageString} } -func (m *MockBackend) GetTool(tool *prm.Tool, prmConfig prm.Config) error { +func (m *MockBackend) GetTool(tool *tool.Tool, prmConfig config.Config) error { if m.ToolAvalible { return nil } else { @@ -27,30 +29,30 @@ func (m *MockBackend) GetTool(tool *prm.Tool, prmConfig prm.Config) error { } // Implement when needed -func (m *MockBackend) Validate(toolInfo prm.ToolInfo, prmConfig prm.Config, paths prm.DirectoryPaths) (prm.ValidateExitCode, string, error) { +func (m *MockBackend) Validate(toolInfo backend.ToolInfo, prmConfig config.Config, paths backend.DirectoryPaths) (backend.ValidateExitCode, string, error) { switch m.ValidateReturn { case "PASS": - return prm.VALIDATION_PASS, "", nil + return backend.VALIDATION_PASS, "", nil case "FAIL": - return prm.VALIDATION_FAILED, "", errors.New("VALIDATION FAIL") + return backend.VALIDATION_FAILED, "", errors.New("VALIDATION FAIL") case "ERROR": - return prm.VALIDATION_ERROR, "", errors.New("DOCKER ERROR") + return backend.VALIDATION_ERROR, "", errors.New("DOCKER ERROR") default: - return prm.VALIDATION_ERROR, "", errors.New("DOCKER FAIL") + return backend.VALIDATION_ERROR, "", errors.New("DOCKER FAIL") } } -func (m *MockBackend) Exec(tool *prm.Tool, args []string, prmConfig prm.Config, paths prm.DirectoryPaths) (prm.ToolExitCode, error) { +func (m *MockBackend) Exec(t *tool.Tool, args []string, prmConfig config.Config, paths backend.DirectoryPaths) (tool.ToolExitCode, error) { switch m.ExecReturn { case "SUCCESS": - return prm.SUCCESS, nil + return tool.SUCCESS, nil case "FAILURE": - return prm.FAILURE, nil + return tool.FAILURE, nil case "TOOL_ERROR": - return prm.TOOL_ERROR, nil + return tool.TOOL_ERROR, nil case "TOOL_NOT_FOUND": - return prm.TOOL_NOT_FOUND, nil + return tool.TOOL_NOT_FOUND, nil default: - return prm.FAILURE, prm.ErrDockerNotRunning + return tool.FAILURE, docker.ErrDockerNotRunning } } diff --git a/internal/pkg/mock/docker.go b/internal/pkg/mock/docker.go index 6f86a3b..c966216 100644 --- a/internal/pkg/mock/docker.go +++ b/internal/pkg/mock/docker.go @@ -4,6 +4,8 @@ import ( "bytes" "context" "fmt" + "github.com/puppetlabs/prm/pkg/config" + "github.com/puppetlabs/prm/pkg/tool" "io" "time" @@ -12,7 +14,6 @@ import ( "github.com/docker/docker/api/types/network" "github.com/docker/docker/pkg/stdcopy" specs "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/puppetlabs/prm/pkg/prm" ) type DockerClient struct { @@ -124,7 +125,7 @@ func (m *DockerClient) ImageRemove(ctx context.Context, imageID string, options return []types.ImageDeleteResponseItem{{Deleted: "test_id"}}, nil } -func (m *DockerClient) ImageName(tool *prm.Tool, prmConfig prm.Config) string { +func (m *DockerClient) ImageName(tool *tool.Tool, prmConfig config.Config) string { // build up a name based on the tool and puppet version imageName := fmt.Sprintf("pdk:puppet-%s_%s-%s_%s", prmConfig.PuppetVersion.String(), tool.Cfg.Plugin.Author, tool.Cfg.Plugin.Id, tool.Cfg.Plugin.Version) return imageName diff --git a/internal/pkg/mock/utils.go b/internal/pkg/mock/utils.go index 5648e82..2bab2c0 100644 --- a/internal/pkg/mock/utils.go +++ b/internal/pkg/mock/utils.go @@ -2,8 +2,7 @@ package mock import ( "fmt" - - "github.com/puppetlabs/prm/pkg/prm" + "github.com/puppetlabs/prm/pkg/config" ) type Utils struct { @@ -12,7 +11,7 @@ type Utils struct { } func (u *Utils) SetAndWriteConfig(k, v string) error { - if k == prm.PuppetVerCfgKey && v == u.ExpectedPuppetVer || k == prm.BackendCfgKey && v == u.ExpectedBackendType { + if k == config.PuppetVerCfgKey && v == u.ExpectedPuppetVer || k == config.BackendCfgKey && v == u.ExpectedBackendType { return nil } return fmt.Errorf(`mock.SetAndWriteConfig(): Unexpected args, diff --git a/pkg/backend/backend.go b/pkg/backend/backend.go new file mode 100644 index 0000000..6b7f8af --- /dev/null +++ b/pkg/backend/backend.go @@ -0,0 +1,74 @@ +//nolint:structcheck,unused +package backend + +import ( + "github.com/puppetlabs/prm/pkg/backend/docker" + "github.com/puppetlabs/prm/pkg/config" + "github.com/puppetlabs/prm/pkg/tool" +) + +const ( + VALIDATION_PASS ValidateExitCode = iota + VALIDATION_FAILED + VALIDATION_ERROR +) + +type BackendI interface { + GetTool(tool *tool.Tool, prmConfig config.Config) error + Validate(toolInfo ToolInfo, prmConfig config.Config, paths DirectoryPaths) (ValidateExitCode, string, error) + Exec(tool *tool.Tool, args []string, prmConfig config.Config, paths DirectoryPaths) (tool.ToolExitCode, error) + Status() BackendStatus +} + +func GetBackend(backendType config.BackendType) BackendI { + switch backendType { + case config.DOCKER: + return &docker.Docker{ + Client: nil, + Context: nil, + ContextCancel: nil, + ContextTimeout: 0, + AFS: nil, + IOFS: nil, + AlwaysBuild: false, + } + default: + return nil + } +} + +// The BackendStatus must report whether the backend is available +// and any useful status information; in the case of the backend +// being unavailable, report the error message to the user. +type BackendStatus struct { + IsAvailable bool + StatusMessage string +} + +type DirectoryPaths struct { + CodeDir string + CacheDir string +} + +type OutputSettings struct { + ResultsView string // Either "terminal" or "file" + OutputDir string // Directory to write log file to +} + +type ToolInfo struct { + Tool *tool.Tool + Args []string +} + +type ContainerOutput struct { + Stdout string + Stderr string +} + +type ValidateExitCode int64 + +type ValidationOutput struct { + Err error + ExitCode ValidateExitCode + Stdout string +} diff --git a/pkg/prm/docker.go b/pkg/backend/docker/docker.go similarity index 86% rename from pkg/prm/docker.go rename to pkg/backend/docker/docker.go index df34532..7e3fee0 100644 --- a/pkg/prm/docker.go +++ b/pkg/backend/docker/docker.go @@ -1,4 +1,4 @@ -package prm +package docker import ( "bufio" @@ -6,6 +6,9 @@ import ( "context" "encoding/json" "fmt" + "github.com/puppetlabs/prm/pkg/backend" + "github.com/puppetlabs/prm/pkg/config" + "github.com/puppetlabs/prm/pkg/tool" "io" "os" "path/filepath" @@ -27,17 +30,6 @@ import ( "github.com/spf13/afero" ) -type Docker struct { - // We need to be able to mock the docker client in testing - Client DockerClientI - Context context.Context - ContextCancel func() - ContextTimeout time.Duration - AFS *afero.Afero - IOFS *afero.IOFS - AlwaysBuild bool -} - var ( ErrDockerNotRunning = fmt.Errorf("docker is not running, please start the docker process") ) @@ -56,8 +48,18 @@ type DockerClientI interface { ContainerStop(ctx context.Context, containerID string, timeout *time.Duration) error } -func (d *Docker) GetTool(tool *Tool, prmConfig Config) error { +type Docker struct { + // We need to be able to mock the docker client in testing + Client DockerClientI + Context context.Context + ContextCancel func() + ContextTimeout time.Duration + AFS *afero.Afero + IOFS *afero.IOFS + AlwaysBuild bool +} +func (d *Docker) GetTool(tool *tool.Tool, prmConfig config.Config) error { // initialise the docker client err := d.initClient() if err != nil { @@ -171,7 +173,7 @@ func (d *Docker) GetTool(tool *Tool, prmConfig Config) error { return nil } -func (d *Docker) createDockerfile(tool *Tool, prmConfig Config) string { +func (d *Docker) createDockerfile(tool *tool.Tool, prmConfig config.Config) string { // create a dockerfile from the Tool and prmConfig dockerfile := strings.Builder{} dockerfile.WriteString(fmt.Sprintf("FROM puppet/puppet-agent:%s\n", prmConfig.PuppetVersion.String())) @@ -243,13 +245,13 @@ func (d *Docker) createDockerfile(tool *Tool, prmConfig Config) string { } // Creates a unique name for the image based on the tool and the PRM configuration -func (d *Docker) ImageName(tool *Tool, prmConfig Config) string { +func (d *Docker) ImageName(tool *tool.Tool, prmConfig config.Config) string { // build up a name based on the tool and puppet version imageName := fmt.Sprintf("pdk:puppet-%s_%s-%s_%s", prmConfig.PuppetVersion.String(), tool.Cfg.Plugin.Author, tool.Cfg.Plugin.Id, tool.Cfg.Plugin.Version) return imageName } -func getOutputAsStrings(containerOutput *ContainerOutput, reader io.ReadCloser) error { +func getOutputAsStrings(containerOutput *backend.ContainerOutput, reader io.ReadCloser) error { stdoutBuf := new(bytes.Buffer) stderrBuf := new(bytes.Buffer) @@ -258,8 +260,8 @@ func getOutputAsStrings(containerOutput *ContainerOutput, reader io.ReadCloser) return err } - containerOutput.stdout = stdoutBuf.String() - containerOutput.stderr = stderrBuf.String() + containerOutput.Stdout = stdoutBuf.String() + containerOutput.Stderr = stderrBuf.String() return nil } @@ -273,18 +275,18 @@ func (d *Docker) setTimeoutContext() (context.Context, context.CancelFunc) { return ctx, cancel } -func (d *Docker) Validate(toolInfo ToolInfo, prmConfig Config, paths DirectoryPaths) (ValidateExitCode, string, error) { +func (d *Docker) Validate(toolInfo backend.ToolInfo, prmConfig config.Config, paths backend.DirectoryPaths) (backend.ValidateExitCode, string, error) { // is Docker up and running? status := d.Status() if !status.IsAvailable { log.Error().Msgf("Docker is not available") - return VALIDATION_ERROR, "", fmt.Errorf("%s", status.StatusMsg) + return backend.VALIDATION_ERROR, "", fmt.Errorf("%s", status.StatusMessage) } // clean up paths - codeDir, _ := filepath.Abs(paths.codeDir) + codeDir, _ := filepath.Abs(paths.CodeDir) log.Debug().Msgf("Code path: %s", codeDir) - cacheDir, _ := filepath.Abs(paths.cacheDir) + cacheDir, _ := filepath.Abs(paths.CacheDir) log.Debug().Msgf("Cache path: %s", cacheDir) // stand up a container @@ -317,7 +319,7 @@ func (d *Docker) Validate(toolInfo ToolInfo, prmConfig Config, paths DirectoryPa }, nil, nil, "") if err != nil { - return VALIDATION_ERROR, "", err + return backend.VALIDATION_ERROR, "", err } // the autoremove functionality is too aggressive // it fires before we can get at the logs @@ -338,7 +340,7 @@ func (d *Docker) Validate(toolInfo ToolInfo, prmConfig Config, paths DirectoryPa }() if err := d.Client.ContainerStart(timeoutCtx, resp.ID, types.ContainerStartOptions{}); err != nil { - return VALIDATION_ERROR, "", err + return backend.VALIDATION_ERROR, "", err } isError := make(chan error) @@ -354,55 +356,55 @@ func (d *Docker) Validate(toolInfo ToolInfo, prmConfig Config, paths DirectoryPa }() // parse out the containers logs while we wait for the container to finish - containerOutput := ContainerOutput{} + containerOutput := backend.ContainerOutput{} for { out, err := d.Client.ContainerLogs(timeoutCtx, resp.ID, types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Tail: "all", Follow: true}) if err != nil { - return VALIDATION_ERROR, "", err + return backend.VALIDATION_ERROR, "", err } err = getOutputAsStrings(&containerOutput, out) if err != nil { - return VALIDATION_ERROR, "", err + return backend.VALIDATION_ERROR, "", err } select { case err := <-isError: - return VALIDATION_ERROR, containerOutput.stdout, err + return backend.VALIDATION_ERROR, containerOutput.Stdout, err case exitValues := <-toolExit: if exitValues.StatusCode == int64(toolInfo.Tool.Cfg.Common.SuccessExitCode) { - return VALIDATION_PASS, containerOutput.stdout, nil + return backend.VALIDATION_PASS, containerOutput.Stdout, nil } else { - if containerOutput.stderr != "" { - err = fmt.Errorf("%s", containerOutput.stderr) + if containerOutput.Stderr != "" { + err = fmt.Errorf("%s", containerOutput.Stderr) } else { err = fmt.Errorf("") } - return VALIDATION_FAILED, containerOutput.stdout, err + return backend.VALIDATION_FAILED, containerOutput.Stdout, err } } } } -func (d *Docker) Exec(tool *Tool, args []string, prmConfig Config, paths DirectoryPaths) (ToolExitCode, error) { +func (d *Docker) Exec(selectedTool *tool.Tool, args []string, prmConfig config.Config, paths backend.DirectoryPaths) (tool.ToolExitCode, error) { // is Docker up and running? status := d.Status() if !status.IsAvailable { log.Error().Msgf("Docker is not available") - return FAILURE, fmt.Errorf("%s", status.StatusMsg) + return tool.FAILURE, fmt.Errorf("%s", status.StatusMessage) } // clean up paths - codeDir, _ := filepath.Abs(paths.codeDir) + codeDir, _ := filepath.Abs(paths.CodeDir) log.Info().Msgf("Code path: %s", codeDir) - cacheDir, _ := filepath.Abs(paths.cacheDir) + cacheDir, _ := filepath.Abs(paths.CacheDir) log.Info().Msgf("Cache path: %s", cacheDir) log.Info().Msgf("Additional Args: %v", args) // stand up a container containerConf := container.Config{ - Image: d.ImageName(tool, prmConfig), + Image: d.ImageName(selectedTool, prmConfig), Tty: false, } // args can override the default CMD @@ -430,12 +432,12 @@ func (d *Docker) Exec(tool *Tool, args []string, prmConfig Config, paths Directo }, nil, nil, "") if err != nil { - return FAILURE, err + return tool.FAILURE, err } // the autoremove functionality is too aggressive // it fires before we can get at the logs defer func() { - newContext := context.Background() // allows container to be removed after the tool times out + newContext := context.Background() // allows container to be removed after the selectedTool times out duration := time.Duration(1) err := d.Client.ContainerStop(newContext, resp.ID, &duration) if err != nil { @@ -451,7 +453,7 @@ func (d *Docker) Exec(tool *Tool, args []string, prmConfig Config, paths Directo }() if err := d.Client.ContainerStart(timeoutCtx, resp.ID, types.ContainerStartOptions{}); err != nil { - return FAILURE, err + return tool.FAILURE, err } isError := make(chan error) @@ -470,29 +472,29 @@ func (d *Docker) Exec(tool *Tool, args []string, prmConfig Config, paths Directo for { out, err := d.Client.ContainerLogs(timeoutCtx, resp.ID, types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Tail: "all", Follow: true}) if err != nil { - return FAILURE, err + return tool.FAILURE, err } _, err = stdcopy.StdCopy(os.Stdout, os.Stderr, out) if err != nil { - return FAILURE, err + return tool.FAILURE, err } select { case err := <-isError: - return FAILURE, err + return tool.FAILURE, err case exitValues := <-toolExit: - if exitValues.StatusCode == int64(tool.Cfg.Common.SuccessExitCode) { - return SUCCESS, nil + if exitValues.StatusCode == int64(selectedTool.Cfg.Common.SuccessExitCode) { + return tool.SUCCESS, nil } else { - // If we have more details on why the tool failed, use that info + // If we have more details on why the selectedTool failed, use that info if exitValues.Error != nil { err = fmt.Errorf("%s", exitValues.Error.Message) } else { // otherwise, just log the exit code err = fmt.Errorf("Tool exited with code: %d", exitValues.StatusCode) } - return TOOL_ERROR, err + return tool.TOOL_ERROR, err } } @@ -519,10 +521,10 @@ func (d *Docker) initClient() (err error) { // Check to see if the Docker runtime is available: // if so, return true and info about Docker on this node; // if not, return false and the error message -func (d *Docker) Status() BackendStatus { +func (d *Docker) Status() backend.BackendStatus { err := d.initClient() if err != nil { - return BackendStatus{ + return backend.BackendStatus{ IsAvailable: false, StatusMsg: fmt.Sprintf("unable to initialize the docker client: %s", err.Error()), } @@ -541,13 +543,13 @@ func (d *Docker) Status() BackendStatus { if strings.Contains(message, daemonNotRunning) { message = daemonNotRunning } - return BackendStatus{ + return backend.BackendStatus{ IsAvailable: false, StatusMsg: message, } } status := fmt.Sprintf("\tPlatform: %s\n\tVersion: %s\n\tAPI Version: %s", dockerInfo.Platform.Name, dockerInfo.Version, dockerInfo.APIVersion) - return BackendStatus{ + return backend.BackendStatus{ IsAvailable: true, StatusMsg: status, } diff --git a/pkg/prm/docker_test.go b/pkg/backend/docker/docker_test.go similarity index 84% rename from pkg/prm/docker_test.go rename to pkg/backend/docker/docker_test.go index 8795d49..25c570d 100644 --- a/pkg/prm/docker_test.go +++ b/pkg/backend/docker/docker_test.go @@ -1,7 +1,12 @@ -package prm_test +package docker_test import ( "context" + "github.com/puppetlabs/prm/pkg/backend" + "github.com/puppetlabs/prm/pkg/backend/docker" + "github.com/puppetlabs/prm/pkg/config" + "github.com/puppetlabs/prm/pkg/tool" + "github.com/puppetlabs/prm/pkg/validate" "reflect" "testing" "time" @@ -11,7 +16,6 @@ import ( "github.com/mitchellh/mapstructure" "github.com/puppetlabs/pct/pkg/install" "github.com/puppetlabs/prm/internal/pkg/mock" - "github.com/puppetlabs/prm/pkg/prm" "github.com/spf13/afero" "github.com/stretchr/testify/assert" ) @@ -20,14 +24,14 @@ func TestDocker_Status(t *testing.T) { tests := []struct { name string mockClient mock.DockerClient - want prm.BackendStatus + want backend.BackendStatus }{ { name: "When connection unavailable", mockClient: mock.DockerClient{ ErrorString: "error during connect: This error may indicate that the docker daemon is not running.: Get \"http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.41/version\": open //./pipe/docker_engine: The system cannot find the file specified.", }, - want: prm.BackendStatus{ + want: backend.BackendStatus{ IsAvailable: false, StatusMsg: "error during connect: This error may indicate that the docker daemon is not running.", }, @@ -37,7 +41,7 @@ func TestDocker_Status(t *testing.T) { mockClient: mock.DockerClient{ ErrorString: "Something has gone terribly wrong!", }, - want: prm.BackendStatus{ + want: backend.BackendStatus{ IsAvailable: false, StatusMsg: "Something has gone terribly wrong!", }, @@ -49,7 +53,7 @@ func TestDocker_Status(t *testing.T) { Version: "1.2.3", ApiVersion: "3.2.1", }, - want: prm.BackendStatus{ + want: backend.BackendStatus{ IsAvailable: true, StatusMsg: "\tPlatform: Docker\n\tVersion: 1.2.3\n\tAPI Version: 3.2.1", }, @@ -60,7 +64,7 @@ func TestDocker_Status(t *testing.T) { // Uncomment to run unmocked // cli, _ := dockerClient.NewClientWithOpts(dockerClient.FromEnv) // d := &Docker{Client: cli} - d := &prm.Docker{Client: &tt.mockClient} + d := &docker.Docker{Client: &tt.mockClient} if got := d.Status(); !reflect.DeepEqual(got, tt.want) { t.Errorf("Docker.Status() = %v, want %v", got, tt.want) } @@ -77,15 +81,15 @@ func TestDocker_GetTool(t *testing.T) { tests := []struct { name string mockClient mock.DockerClient - tool prm.Tool - config prm.Config + tool tool.Tool + config config.Config toolInfo ToolInfo errorMsg string alwaysBuild bool }{ { name: "Image not found and create new image", - config: prm.Config{PuppetVersion: &semver.Version{}}, + config: config.Config{PuppetVersion: &semver.Version{}}, }, { name: "Image found and alwaysBuild set to false", @@ -98,7 +102,7 @@ func TestDocker_GetTool(t *testing.T) { }, }, }, - config: prm.Config{PuppetVersion: &semver.Version{}}, + config: config.Config{PuppetVersion: &semver.Version{}}, }, { name: "Image found and alwaysBuild set to true", @@ -112,7 +116,7 @@ func TestDocker_GetTool(t *testing.T) { }, }, alwaysBuild: true, - config: prm.Config{PuppetVersion: &semver.Version{}}, + config: config.Config{PuppetVersion: &semver.Version{}}, }, } for _, tt := range tests { @@ -127,7 +131,7 @@ func TestDocker_GetTool(t *testing.T) { fs := afero.NewMemMapFs() afs := &afero.Afero{Fs: fs} - d := &prm.Docker{Client: &tt.mockClient, AFS: afs, AlwaysBuild: tt.alwaysBuild} + d := &docker.Docker{Client: &tt.mockClient, AFS: afs, AlwaysBuild: tt.alwaysBuild} err := d.GetTool(&tt.tool, tt.config) if err != nil { assert.Contains(t, err.Error(), tt.errorMsg) @@ -148,7 +152,7 @@ func TestDocker_Validate(t *testing.T) { AlwaysBuild bool } type args struct { - paths prm.DirectoryPaths + paths backend.DirectoryPaths author string version string id string @@ -159,7 +163,7 @@ func TestDocker_Validate(t *testing.T) { name string fields fields args args - want prm.ValidateExitCode + want validate.ValidateExitCode wantErr bool wantStdout string }{ @@ -170,7 +174,7 @@ func TestDocker_Validate(t *testing.T) { ErrorString: "Invalid server verison", }, }, - want: prm.VALIDATION_ERROR, + want: validate.VALIDATION_ERROR, wantErr: true, }, { @@ -187,7 +191,7 @@ func TestDocker_Validate(t *testing.T) { id: "good-project", version: "0.1.0", }, - want: prm.VALIDATION_PASS, + want: validate.VALIDATION_PASS, wantStdout: defaultStdoutText, }, { @@ -205,7 +209,7 @@ func TestDocker_Validate(t *testing.T) { version: "0.1.0", toolArgs: []string{"-l", "-v"}, }, - want: prm.VALIDATION_PASS, + want: validate.VALIDATION_PASS, wantStdout: defaultStdoutText, }, { @@ -223,7 +227,7 @@ func TestDocker_Validate(t *testing.T) { id: "good-project", version: "0.1.0", }, - want: prm.VALIDATION_FAILED, + want: validate.VALIDATION_FAILED, wantErr: true, wantStdout: defaultStdoutText, }, @@ -242,7 +246,7 @@ func TestDocker_Validate(t *testing.T) { id: "good-project", version: "0.1.0", }, - want: prm.VALIDATION_ERROR, + want: validate.VALIDATION_ERROR, wantErr: true, }, } @@ -252,7 +256,7 @@ func TestDocker_Validate(t *testing.T) { afs := &afero.Afero{Fs: fs} iofs := &afero.IOFS{Fs: fs} - d := &prm.Docker{ + d := &docker.Docker{ Client: tt.fields.Client, Context: tt.fields.Context, ContextCancel: tt.fields.ContextCancel, @@ -270,7 +274,7 @@ func TestDocker_Validate(t *testing.T) { t.Errorf("Invalid Puppet Version %s", tt.args.puppetVersion) return } - prmConfig := prm.Config{ + prmConfig := config.Config{ PuppetVersion: puppetVersion, } @@ -291,10 +295,10 @@ func TestDocker_Validate(t *testing.T) { } } -func CreateToolInfo(id, author, version string, args []string) prm.ToolInfo { - tool := &prm.Tool{ - Cfg: prm.ToolConfig{ - Plugin: &prm.PluginConfig{ +func CreateToolInfo(id, author, version string, args []string) backend.ToolInfo { + tool := &tool.Tool{ + Cfg: tool.ToolConfig{ + Plugin: &tool.PluginConfig{ ConfigParams: install.ConfigParams{ Id: id, Author: author, @@ -304,7 +308,7 @@ func CreateToolInfo(id, author, version string, args []string) prm.ToolInfo { }, } - return prm.ToolInfo{ + return backend.ToolInfo{ Tool: tool, Args: args, } diff --git a/pkg/prm/status.go b/pkg/backend/status.go similarity index 77% rename from pkg/prm/status.go rename to pkg/backend/status.go index c267521..6af2c33 100644 --- a/pkg/prm/status.go +++ b/pkg/backend/status.go @@ -1,8 +1,9 @@ -package prm +package backend import ( "encoding/json" "fmt" + "github.com/puppetlabs/prm/pkg/config" "strings" "github.com/Masterminds/semver" @@ -10,14 +11,16 @@ import ( type Status struct { PuppetVersion *semver.Version - Backend BackendType + Backend config.BackendType BackendStatus BackendStatus } -func (p *Prm) GetStatus() (status Status) { - status.PuppetVersion = p.RunningConfig.PuppetVersion - status.Backend = p.RunningConfig.Backend - status.BackendStatus = p.Backend.Status() +func GetStatus(cfg config.Config) Status { + status := Status{ + PuppetVersion: cfg.PuppetVersion, + Backend: cfg.Backend, + BackendStatus: back, + } return status } @@ -35,7 +38,7 @@ func FormatStatus(status Status, outputType string) (statusMessage string, err e messageLines.WriteString(fmt.Sprintf("> Backend: %s (running)\n", status.Backend)) } else { messageLines.WriteString(fmt.Sprintf("> Backend: %s (error)\n", status.Backend)) - messageLines.WriteString(fmt.Sprintf("> %s\n", status.BackendStatus.StatusMsg)) + messageLines.WriteString(fmt.Sprintf("> %s\n", status.BackendStatus.StatusMessage)) } statusMessage = messageLines.String() } diff --git a/pkg/prm/status_test.go b/pkg/backend/status_test.go similarity index 78% rename from pkg/prm/status_test.go rename to pkg/backend/status_test.go index adf468d..8821de5 100644 --- a/pkg/prm/status_test.go +++ b/pkg/backend/status_test.go @@ -1,6 +1,8 @@ -package prm_test +package backend_test import ( + "github.com/puppetlabs/prm/pkg/backend" + "github.com/puppetlabs/prm/pkg/config" "reflect" "testing" @@ -14,24 +16,24 @@ func TestPrm_GetStatus(t *testing.T) { tests := []struct { name string p *prm.Prm - wantStatus prm.Status + wantStatus backend.Status }{ { name: "Returns a correct Status object", p: &prm.Prm{ - RunningConfig: prm.Config{ + RunningConfig: config.Config{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, + Backend: DOCKER, }, Backend: &mock.MockBackend{ StatusIsAvailable: true, StatusMessageString: "Running just fine!", }, }, - wantStatus: prm.Status{ + wantStatus: backend.Status{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, - BackendStatus: prm.BackendStatus{ + Backend: DOCKER, + BackendStatus: BackendStatus{ IsAvailable: true, StatusMsg: "Running just fine!", }, @@ -49,7 +51,7 @@ func TestPrm_GetStatus(t *testing.T) { func TestFormatStatus(t *testing.T) { type args struct { - status prm.Status + status backend.Status outputType string } tests := []struct { @@ -62,10 +64,10 @@ func TestFormatStatus(t *testing.T) { name: "human format running backend", args: args{ outputType: "human", - status: prm.Status{ + status: backend.Status{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, - BackendStatus: prm.BackendStatus{ + Backend: DOCKER, + BackendStatus: BackendStatus{ IsAvailable: true, StatusMsg: "Running just fine", }, @@ -80,10 +82,10 @@ func TestFormatStatus(t *testing.T) { name: "human format errored backend", args: args{ outputType: "human", - status: prm.Status{ + status: backend.Status{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, - BackendStatus: prm.BackendStatus{ + Backend: DOCKER, + BackendStatus: BackendStatus{ IsAvailable: false, StatusMsg: "Descriptive error!", }, @@ -99,10 +101,10 @@ func TestFormatStatus(t *testing.T) { name: "json format running backend", args: args{ outputType: "json", - status: prm.Status{ + status: backend.Status{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, - BackendStatus: prm.BackendStatus{ + Backend: DOCKER, + BackendStatus: BackendStatus{ IsAvailable: true, StatusMsg: "Running just fine", }, @@ -118,10 +120,10 @@ func TestFormatStatus(t *testing.T) { name: "json format errored backend", args: args{ outputType: "json", - status: prm.Status{ + status: backend.Status{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, - BackendStatus: prm.BackendStatus{ + Backend: DOCKER, + BackendStatus: BackendStatus{ IsAvailable: false, StatusMsg: "Descriptive error!", }, @@ -137,7 +139,7 @@ func TestFormatStatus(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - gotStatusMessage, err := prm.FormatStatus(tt.args.status, tt.args.outputType) + gotStatusMessage, err := backend.FormatStatus(tt.args.status, tt.args.outputType) if (err != nil) != tt.wantErr { t.Errorf("FormatStatus() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/pkg/prm/config.go b/pkg/config/config.go similarity index 69% rename from pkg/prm/config.go rename to pkg/config/config.go index e5260f7..d674ac9 100644 --- a/pkg/prm/config.go +++ b/pkg/config/config.go @@ -1,4 +1,4 @@ -package prm +package config import ( "fmt" @@ -23,6 +23,12 @@ const ( DefaultToolTimeout int = 1800 // 30 minutes ) +const ( + DOCKER BackendType = "docker" +) + +type BackendType string + type Config struct { PuppetVersion *semver.Version Backend BackendType @@ -30,7 +36,7 @@ type Config struct { Timeout time.Duration } -func (p *Prm) GenerateDefaultCfg() { +func GenerateDefaultCfg() { // Generate default configuration puppetVer, err := semver.NewVersion(DefaultPuppetVer) if err != nil { @@ -42,7 +48,7 @@ func (p *Prm) GenerateDefaultCfg() { log.Trace().Msgf("Setting default config (%s: %s)", BackendCfgKey, DefaultBackend) viper.SetDefault(BackendCfgKey, string(DefaultBackend)) - defaultToolPath, err := p.GetDefaultToolPath() + defaultToolPath, err := GetDefaultToolPath() if err != nil { panic(fmt.Sprintf("Unable to generate default cfg value for 'toolpath': %s", err)) } @@ -53,33 +59,29 @@ func (p *Prm) GenerateDefaultCfg() { viper.SetDefault(ToolTimeoutCfgKey, DefaultToolTimeout) } -func (p *Prm) LoadConfig() error { +func LoadConfig() (Config, error) { // If the scenario where any other config value has been set AND the Puppet version is unset, a '{}' is written // to the config file on disk. This causes issues when attempting to call semver.NewVersion. puppetVer := viper.GetString(PuppetVerCfgKey) if puppetVer == "" { puppetVer = DefaultPuppetVer } - pupperSemVer, err := semver.NewVersion(puppetVer) + puppetSemVer, err := semver.NewVersion(puppetVer) if err != nil { - return fmt.Errorf("could not load '%s' from config '%s': %s", PuppetVerCfgKey, viper.GetViper().ConfigFileUsed(), err) + return Config{}, fmt.Errorf("could not load '%s' from config '%s': %s", PuppetVerCfgKey, viper.GetViper().ConfigFileUsed(), err) } - p.RunningConfig.PuppetVersion = pupperSemVer - - // Load Backend from config - p.RunningConfig.Backend = BackendType(viper.GetString(BackendCfgKey)) - - // Load ToolPath from config - p.RunningConfig.ToolPath = viper.GetString(ToolPathCfgKey) - - // Load Timeout from config - p.RunningConfig.Timeout = viper.GetDuration(ToolTimeoutCfgKey) * time.Second + config := Config{ + PuppetVersion: puppetSemVer, + Backend: BackendType(viper.GetString(BackendCfgKey)), + ToolPath: viper.GetString(ToolPathCfgKey), + Timeout: viper.GetDuration(ToolTimeoutCfgKey) * time.Second, + } - return nil + return config, nil } -func (p *Prm) GetDefaultToolPath() (string, error) { +func GetDefaultToolPath() (string, error) { execDir, err := os.Executable() if err != nil { return "", err @@ -89,3 +91,14 @@ func (p *Prm) GetDefaultToolPath() (string, error) { log.Trace().Msgf("Default tool config path: %v", defaultToolPath) return defaultToolPath, nil } + +func SetAndWriteConfig(k, v string) (err error) { + log.Trace().Msgf("Setting and saving config '%s' to '%s' in %s", k, v, viper.ConfigFileUsed()) + + viper.Set(k, v) + + if err = viper.WriteConfig(); err != nil { + log.Error().Msgf("could not write config to %s: %s", viper.ConfigFileUsed(), err) + } + return err +} diff --git a/pkg/prm/config_test.go b/pkg/config/config_test.go similarity index 71% rename from pkg/prm/config_test.go rename to pkg/config/config_test.go index 0803649..97c2e57 100644 --- a/pkg/prm/config_test.go +++ b/pkg/config/config_test.go @@ -1,10 +1,10 @@ -package prm_test +package config_test import ( "fmt" + "github.com/puppetlabs/prm/pkg/config" "testing" - "github.com/puppetlabs/prm/pkg/prm" "github.com/spf13/viper" "github.com/stretchr/testify/assert" ) @@ -19,16 +19,15 @@ func TestGenerateDefaultCfg(t *testing.T) { { name: "Should generate default Puppet and Backend cfgs", expectedPuppetVersion: "7.15.0", - expectedBackend: string(prm.DOCKER), + expectedBackend: string(config.DOCKER), expectedToolPath: "tools", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - prmObj := &prm.Prm{} - prmObj.GenerateDefaultCfg() - assert.Equal(t, tt.expectedPuppetVersion, viper.GetString(prm.PuppetVerCfgKey)) - assert.Equal(t, tt.expectedBackend, viper.Get(prm.BackendCfgKey)) + config.GenerateDefaultCfg() + assert.Equal(t, tt.expectedPuppetVersion, viper.GetString(config.PuppetVerCfgKey)) + assert.Equal(t, tt.expectedBackend, viper.Get(config.BackendCfgKey)) }) } } @@ -43,11 +42,11 @@ func TestLoadConfig(t *testing.T) { }{ { name: "Should error when nil returned for Puppet ver", - expectedErrMsg: fmt.Sprintf("could not load '%s' from config '%s': Invalid Semantic Version", prm.PuppetVerCfgKey, viper.GetViper().ConfigFileUsed()), + expectedErrMsg: fmt.Sprintf("could not load '%s' from config '%s': Invalid Semantic Version", config.PuppetVerCfgKey, viper.GetViper().ConfigFileUsed()), }, { name: "Should error when invalid semver returned for Puppet ver", - expectedErrMsg: fmt.Sprintf("could not load '%s' from config '%s': Invalid Semantic Version", prm.PuppetVerCfgKey, viper.GetViper().ConfigFileUsed()), + expectedErrMsg: fmt.Sprintf("could not load '%s' from config '%s': Invalid Semantic Version", config.PuppetVerCfgKey, viper.GetViper().ConfigFileUsed()), configuredPuppetVer: "foo.bar", }, { @@ -57,11 +56,9 @@ func TestLoadConfig(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - viper.SetDefault(prm.PuppetVerCfgKey, tt.configuredPuppetVer) - - prmObj := &prm.Prm{} - err := prmObj.LoadConfig() + viper.SetDefault(config.PuppetVerCfgKey, tt.configuredPuppetVer) + _, err := config.LoadConfig() if tt.expectedErrMsg != "" && err != nil { assert.Contains(t, tt.expectedErrMsg, err.Error()) return diff --git a/pkg/prm/exec.go b/pkg/exec/exec.go similarity index 64% rename from pkg/prm/exec.go rename to pkg/exec/exec.go index fb46952..646f334 100644 --- a/pkg/prm/exec.go +++ b/pkg/exec/exec.go @@ -1,7 +1,12 @@ //nolint:structcheck,unused -package prm +package exec import ( + "fmt" + "github.com/puppetlabs/prm/pkg/backend" + "github.com/puppetlabs/prm/pkg/config" + "github.com/puppetlabs/prm/pkg/prm" + "github.com/puppetlabs/prm/pkg/tool" "github.com/rs/zerolog/log" ) @@ -13,10 +18,16 @@ const ( EXEC_ERROR ) +type Exec struct { + Prm *prm.Prm + RunningConfig config.Config +} + // Executes a tool with the given arguments, against the codeDir. -func (p *Prm) Exec(tool *Tool, args []string) error { - if status := p.Backend.Status(); !status.IsAvailable { - return ErrDockerNotRunning +func (e *Exec) Exec(tool *tool.Tool, args []string) error { + status := e.Prm.Backend.Status() + if !status.IsAvailable { + return fmt.Errorf("backend is unavailable: %s", status.StatusMessage) } // is the tool available? @@ -27,22 +38,22 @@ func (p *Prm) Exec(tool *Tool, args []string) error { } // the tool is available so execute against it - exit, err := p.Backend.Exec(tool, args, p.RunningConfig, DirectoryPaths{codeDir: p.CodeDir, cacheDir: p.CacheDir}) + exit, err := p.Backend.Exec(tool, args, p.RunningConfig, backend.DirectoryPaths{codeDir: p.CodeDir, cacheDir: p.CacheDir}) if err != nil { log.Error().Msgf("Error executing tool %s/%s: %s", tool.Cfg.Plugin.Author, tool.Cfg.Plugin.Id, err.Error()) return err } switch exit { - case SUCCESS: + case tool.SUCCESS: log.Info().Msgf("Tool %s/%s executed successfully", tool.Cfg.Plugin.Author, tool.Cfg.Plugin.Id) - case FAILURE: + case tool.FAILURE: log.Error().Msgf("Tool %s/%s failed to execute", tool.Cfg.Plugin.Author, tool.Cfg.Plugin.Id) return err - case TOOL_ERROR: + case tool.TOOL_ERROR: log.Error().Msgf("Tool %s/%s encountered an error", tool.Cfg.Plugin.Author, tool.Cfg.Plugin.Id) return err - case TOOL_NOT_FOUND: + case tool.TOOL_NOT_FOUND: log.Error().Msgf("Tool %s/%s not found", tool.Cfg.Plugin.Author, tool.Cfg.Plugin.Id) return err default: diff --git a/pkg/prm/exec_test.go b/pkg/exec/exec_test.go similarity index 84% rename from pkg/prm/exec_test.go rename to pkg/exec/exec_test.go index 278f15a..2bc1006 100644 --- a/pkg/prm/exec_test.go +++ b/pkg/exec/exec_test.go @@ -1,6 +1,9 @@ -package prm_test +package exec_test import ( + "github.com/puppetlabs/prm/pkg/backend/docker" + "github.com/puppetlabs/prm/pkg/config" + "github.com/puppetlabs/prm/pkg/tool" "testing" "github.com/Masterminds/semver" @@ -16,7 +19,7 @@ func TestPrm_Exec(t *testing.T) { expectError bool expectedErrMsg string p *prm.Prm - tool *prm.Tool + tool *tool.Tool args []string toolId string toolAuthor string @@ -25,9 +28,9 @@ func TestPrm_Exec(t *testing.T) { { name: "Tool is unavailible", p: &prm.Prm{ - RunningConfig: prm.Config{ + RunningConfig: config.Config{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, + Backend: config.DOCKER, }, Backend: &mock.MockBackend{ ToolAvalible: false, @@ -39,9 +42,9 @@ func TestPrm_Exec(t *testing.T) { { name: "Tool is availible and reports Success", p: &prm.Prm{ - RunningConfig: prm.Config{ + RunningConfig: config.Config{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, + Backend: config.DOCKER, }, Backend: &mock.MockBackend{ ToolAvalible: true, @@ -58,9 +61,9 @@ func TestPrm_Exec(t *testing.T) { { name: "Tool is availible and reports Failure", p: &prm.Prm{ - RunningConfig: prm.Config{ + RunningConfig: config.Config{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, + Backend: config.DOCKER, }, Backend: &mock.MockBackend{ ToolAvalible: true, @@ -77,9 +80,9 @@ func TestPrm_Exec(t *testing.T) { { name: "Tool is availible and reports Tool Error", p: &prm.Prm{ - RunningConfig: prm.Config{ + RunningConfig: config.Config{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, + Backend: config.DOCKER, }, Backend: &mock.MockBackend{ ToolAvalible: true, @@ -96,9 +99,9 @@ func TestPrm_Exec(t *testing.T) { { name: "Tool is availible and reports Tool Not Found", p: &prm.Prm{ - RunningConfig: prm.Config{ + RunningConfig: config.Config{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, + Backend: config.DOCKER, }, Backend: &mock.MockBackend{ ToolAvalible: true, @@ -115,9 +118,9 @@ func TestPrm_Exec(t *testing.T) { { name: "Error executing tool", p: &prm.Prm{ - RunningConfig: prm.Config{ + RunningConfig: config.Config{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, + Backend: config.DOCKER, }, Backend: &mock.MockBackend{ ToolAvalible: true, @@ -129,7 +132,7 @@ func TestPrm_Exec(t *testing.T) { toolId: "test", toolAuthor: "user", toolVersion: "0.1.0", - expectedErrMsg: prm.ErrDockerNotRunning.Error(), + expectedErrMsg: docker.ErrDockerNotRunning.Error(), }, } for _, tt := range tests { @@ -139,7 +142,7 @@ func TestPrm_Exec(t *testing.T) { "author": tt.toolAuthor, "version": tt.toolVersion, } - var tool prm.Tool + var tool tool.Tool _ = mapstructure.Decode(toolinfo, &tool.Cfg.Plugin) tt.tool = &tool diff --git a/pkg/prm/backend.go b/pkg/prm/backend.go deleted file mode 100644 index bf8a535..0000000 --- a/pkg/prm/backend.go +++ /dev/null @@ -1,43 +0,0 @@ -//nolint:structcheck,unused -package prm - -type BackendType string - -const ( - DOCKER BackendType = "docker" -) - -type BackendI interface { - GetTool(tool *Tool, prmConfig Config) error - Validate(toolInfo ToolInfo, prmConfig Config, paths DirectoryPaths) (ValidateExitCode, string, error) - Exec(tool *Tool, args []string, prmConfig Config, paths DirectoryPaths) (ToolExitCode, error) - Status() BackendStatus -} - -// The BackendStatus must report whether the backend is available -// and any useful status information; in the case of the backend -// being unavailable, report the error message to the user. -type BackendStatus struct { - IsAvailable bool - StatusMsg string -} - -type DirectoryPaths struct { - codeDir string - cacheDir string -} - -type OutputSettings struct { - ResultsView string // Either "terminal" or "file" - OutputDir string // Directory to write log file to -} - -type ToolInfo struct { - Tool *Tool - Args []string -} - -type ContainerOutput struct { - stdout string - stderr string -} diff --git a/pkg/prm/prm.go b/pkg/prm/prm.go index f7c107d..d4d8ecf 100644 --- a/pkg/prm/prm.go +++ b/pkg/prm/prm.go @@ -4,6 +4,9 @@ package prm import ( "bytes" "fmt" + "github.com/puppetlabs/prm/pkg/backend" + "github.com/puppetlabs/prm/pkg/config" + "github.com/puppetlabs/prm/pkg/tool" "path/filepath" "sort" "strings" @@ -26,11 +29,11 @@ const ( type Prm struct { AFS *afero.Afero IOFS *afero.IOFS - RunningConfig Config + RunningConfig config.Config CodeDir string CacheDir string - Cache map[string]*Tool - Backend BackendI + Cache map[string]*tool.Tool + Backend backend.BackendI } type PuppetVersion struct { @@ -38,8 +41,8 @@ type PuppetVersion struct { } type Group struct { - ID string `yaml:"id"` - Tools []ToolInst `yaml:"tools"` + ID string `yaml:"id"` + Tools []tool.ToolInst `yaml:"tools"` } type ValidateYmlContent struct { @@ -72,7 +75,7 @@ func (p *Prm) getGroupsFromFile(validateFile string) ([]Group, error) { return contentStruct.Groups, nil } -func checkDuplicateToolsInGroups(tools []ToolInst) error { +func checkDuplicateToolsInGroups(tools []tool.ToolInst) error { toolNames := make(map[string]bool) for _, tool := range tools { @@ -124,7 +127,7 @@ func (p *Prm) GetValidationGroupFromFile(selectedGroupID string) (Group, error) // Check to see if the requested tool can be found installed. // If installed read the tool configuration and return -func (p *Prm) IsToolAvailable(tool string) (*Tool, bool) { +func (p *Prm) IsToolAvailable(tool string) (*tool.Tool, bool) { if p.Cache[tool] != nil { return p.Cache[tool], true @@ -134,7 +137,7 @@ func (p *Prm) IsToolAvailable(tool string) (*Tool, bool) { } // Check to see if the tool is ready to execute -func (p *Prm) IsToolReady(tool *Tool) bool { +func (p *Prm) IsToolReady(tool *tool.Tool) bool { err := p.Backend.GetTool(tool, p.RunningConfig) return err == nil } @@ -144,25 +147,25 @@ func (*Prm) getPuppetVersion() PuppetVersion { return PuppetVersion{} } -func (p *Prm) readToolConfig(configFile string) Tool { +func (p *Prm) readToolConfig(configFile string) tool.Tool { file, err := p.AFS.ReadFile(configFile) if err != nil { log.Error().Msgf("unable to read tool config, %s", configFile) } - var tool Tool + var tool tool.Tool viper.SetConfigType("yaml") err = viper.ReadConfig(bytes.NewBuffer(file)) if err != nil { log.Error().Msgf("unable to read tool config, %s: %s", configFile, err.Error()) - return Tool{} + return tool.Tool{} } err = viper.Unmarshal(&tool.Cfg) if err != nil { log.Error().Msgf("unable to parse tool config, %s", configFile) - return Tool{} + return tool.Tool{} } return tool @@ -176,7 +179,7 @@ func (p *Prm) List(toolPath string, toolName string, onlyValidators bool) error // Triple glob to match author/id/version/ToolConfigFileName matches, _ := p.IOFS.Glob(toolPath + "/**/**/**/" + ToolConfigFileName) - var tmpls []ToolConfig + var tmpls []tool.ToolConfig for _, file := range matches { log.Debug().Msgf("Found: %+v", file) i := p.readToolConfig(file) @@ -199,7 +202,7 @@ func (p *Prm) List(toolPath string, toolName string, onlyValidators bool) error if toolName != "" { log.Debug().Msgf("Filtering for: %s", toolName) - tmpls = p.FilterFiles(tmpls, func(f ToolConfig) bool { return f.Plugin.Id == toolName }) + tmpls = p.FilterFiles(tmpls, func(f tool.ToolConfig) bool { return f.Plugin.Id == toolName }) } tmpls = p.filterNewestVersions(tmpls) @@ -211,16 +214,16 @@ func (p *Prm) List(toolPath string, toolName string, onlyValidators bool) error return nil } -func (p *Prm) filterNewestVersions(tt []ToolConfig) (ret []ToolConfig) { +func (p *Prm) filterNewestVersions(tt []tool.ToolConfig) (ret []tool.ToolConfig) { for _, t := range tt { id := t.Plugin.Id author := t.Plugin.Author // Look for tools with the same author and id - tools := p.FilterFiles(tt, func(f ToolConfig) bool { return f.Plugin.Id == id && f.Plugin.Author == author }) + tools := p.FilterFiles(tt, func(f tool.ToolConfig) bool { return f.Plugin.Id == id && f.Plugin.Author == author }) if len(tools) > 1 { // If the author/id template has 2+ entries, that's multiple versions // check first to see if the return list already has an entry for this template - if len(p.FilterFiles(ret, func(f ToolConfig) bool { return f.Plugin.Id == id && f.Plugin.Author == author })) == 0 { + if len(p.FilterFiles(ret, func(f tool.ToolConfig) bool { return f.Plugin.Id == id && f.Plugin.Author == author })) == 0 { // turn the version strings into version objects for sorting and comparison versionsRaw := []string{} for _, t := range tools { @@ -234,7 +237,7 @@ func (p *Prm) filterNewestVersions(tt []ToolConfig) (ret []ToolConfig) { sort.Sort(version.Collection(versions)) // select the latest version highestVersion := versions[len(versions)-1] - highestVersionTemplate := p.FilterFiles(tools, func(f ToolConfig) bool { + highestVersionTemplate := p.FilterFiles(tools, func(f tool.ToolConfig) bool { actualVersion, _ := version.NewVersion(f.Plugin.Version) return actualVersion.Equal(highestVersion) }) @@ -249,7 +252,7 @@ func (p *Prm) filterNewestVersions(tt []ToolConfig) (ret []ToolConfig) { return ret } -func (p *Prm) FilterFiles(ss []ToolConfig, test func(ToolConfig) bool) (ret []ToolConfig) { +func (p *Prm) FilterFiles(ss []tool.ToolConfig, test func(tool.ToolConfig) bool) (ret []tool.ToolConfig) { for _, s := range ss { if test(s) { ret = append(ret, s) @@ -258,14 +261,14 @@ func (p *Prm) FilterFiles(ss []ToolConfig, test func(ToolConfig) bool) (ret []To return } -func (p *Prm) createToolCache(tmpls []ToolConfig) { +func (p *Prm) createToolCache(tmpls []tool.ToolConfig) { // initialise the cache - p.Cache = make(map[string]*Tool) + p.Cache = make(map[string]*tool.Tool) // Iterate through the list of tool configs and // add them to the map for _, t := range tmpls { name := t.Plugin.Author + "/" + t.Plugin.Id - tool := Tool{ + tool := tool.Tool{ Cfg: t, } p.Cache[name] = &tool @@ -274,7 +277,7 @@ func (p *Prm) createToolCache(tmpls []ToolConfig) { // FormatTools formats one or more templates to display on the console in // table format or json format. -func (*Prm) FormatTools(tools map[string]*Tool, jsonOutput string) (string, error) { +func (*Prm) FormatTools(tools map[string]*tool.Tool, jsonOutput string) (string, error) { output := "" switch jsonOutput { case "table": @@ -314,8 +317,8 @@ func (*Prm) FormatTools(tools map[string]*Tool, jsonOutput string) (string, erro return output, nil } -func sortTools(tools map[string]*Tool) []*Tool { - var sortedTools []*Tool +func sortTools(tools map[string]*tool.Tool) []*tool.Tool { + var sortedTools []*tool.Tool for _, tool := range tools { sortedTools = append(sortedTools, tool) } diff --git a/pkg/prm/prm_test.go b/pkg/prm/prm_test.go index 4929962..ce1c81b 100644 --- a/pkg/prm/prm_test.go +++ b/pkg/prm/prm_test.go @@ -1,6 +1,7 @@ package prm_test import ( + "github.com/puppetlabs/prm/pkg/tool" "io/ioutil" "os" "path/filepath" @@ -22,7 +23,7 @@ func TestMain(m *testing.M) { func TestFormatTools(t *testing.T) { type args struct { - tools map[string]*prm.Tool + tools map[string]*tool.Tool jsonOutput string } tests := []struct { @@ -34,7 +35,7 @@ func TestFormatTools(t *testing.T) { { name: "When no tools are passed", args: args{ - tools: map[string]*prm.Tool{}, + tools: map[string]*tool.Tool{}, jsonOutput: "table", }, matches: []string{}, @@ -42,10 +43,10 @@ func TestFormatTools(t *testing.T) { { name: "When only one tool is passed", args: args{ - tools: map[string]*prm.Tool{ + tools: map[string]*tool.Tool{ "bar/foo": { - Cfg: prm.ToolConfig{ - Plugin: &prm.PluginConfig{ + Cfg: tool.ToolConfig{ + Plugin: &tool.PluginConfig{ ConfigParams: install.ConfigParams{ Id: "foo", Author: "bar", @@ -70,10 +71,10 @@ func TestFormatTools(t *testing.T) { { name: "When more than one tool is passed", args: args{ - tools: map[string]*prm.Tool{ + tools: map[string]*tool.Tool{ "baz/foo": { - Cfg: prm.ToolConfig{ - Plugin: &prm.PluginConfig{ + Cfg: tool.ToolConfig{ + Plugin: &tool.PluginConfig{ ConfigParams: install.ConfigParams{ Id: "foo", Author: "baz", @@ -85,8 +86,8 @@ func TestFormatTools(t *testing.T) { }, }, "baz/bar": { - Cfg: prm.ToolConfig{ - Plugin: &prm.PluginConfig{ + Cfg: tool.ToolConfig{ + Plugin: &tool.PluginConfig{ ConfigParams: install.ConfigParams{ Id: "bar", Version: "0.1.0", @@ -109,10 +110,10 @@ func TestFormatTools(t *testing.T) { { name: "When format is specified as json", args: args{ - tools: map[string]*prm.Tool{ + tools: map[string]*tool.Tool{ "baz/foo": { - Cfg: prm.ToolConfig{ - Plugin: &prm.PluginConfig{ + Cfg: tool.ToolConfig{ + Plugin: &tool.PluginConfig{ ConfigParams: install.ConfigParams{ Id: "foo", Version: "0.1.0", @@ -124,8 +125,8 @@ func TestFormatTools(t *testing.T) { }, }, "baz/bar": { - Cfg: prm.ToolConfig{ - Plugin: &prm.PluginConfig{ + Cfg: tool.ToolConfig{ + Plugin: &tool.PluginConfig{ ConfigParams: install.ConfigParams{ Id: "bar", Author: "baz", @@ -181,7 +182,7 @@ func TestList(t *testing.T) { tests := []struct { name string args args - want map[string]*prm.Tool + want map[string]*tool.Tool wantErr bool }{ { @@ -233,11 +234,11 @@ plugin: }, }, }, - want: map[string]*prm.Tool{ + want: map[string]*tool.Tool{ "some_author/first": { - Cfg: prm.ToolConfig{ + Cfg: tool.ToolConfig{ Path: filepath.Join("stubbed/tools/valid/some_author/first/0.1.0"), - Plugin: &prm.PluginConfig{ + Plugin: &tool.PluginConfig{ ConfigParams: install.ConfigParams{ Author: "some_author", Id: "first", @@ -249,9 +250,9 @@ plugin: }, }, "some_author/second": { - Cfg: prm.ToolConfig{ + Cfg: tool.ToolConfig{ Path: filepath.Join("stubbed/tools/valid/some_author/second/0.1.0"), - Plugin: &prm.PluginConfig{ + Plugin: &tool.PluginConfig{ ConfigParams: install.ConfigParams{ Author: "some_author", Id: "second", @@ -293,11 +294,11 @@ plugin: }, }, }, - want: map[string]*prm.Tool{ + want: map[string]*tool.Tool{ "some_author/first": { - Cfg: prm.ToolConfig{ + Cfg: tool.ToolConfig{ Path: filepath.Join("stubbed/tools/multiversion/some_author/first/0.2.0"), - Plugin: &prm.PluginConfig{ + Plugin: &tool.PluginConfig{ ConfigParams: install.ConfigParams{ Author: "some_author", Version: "0.2.0", @@ -340,11 +341,11 @@ plugin: }, }, }, - want: map[string]*prm.Tool{ + want: map[string]*tool.Tool{ "some_author/first": { - Cfg: prm.ToolConfig{ + Cfg: tool.ToolConfig{ Path: filepath.Join("stubbed/tools/named/some_author/first/0.1.0"), - Plugin: &prm.PluginConfig{ + Plugin: &tool.PluginConfig{ ConfigParams: install.ConfigParams{ Author: "some_author", Id: "first", @@ -394,11 +395,11 @@ common: }, }, }, - want: map[string]*prm.Tool{ + want: map[string]*tool.Tool{ "some_author/first": { - Cfg: prm.ToolConfig{ + Cfg: tool.ToolConfig{ Path: filepath.Join("stubbed/tools/named/some_author/first/0.1.0"), - Plugin: &prm.PluginConfig{ + Plugin: &tool.PluginConfig{ ConfigParams: install.ConfigParams{ Author: "some_author", Id: "first", @@ -407,7 +408,7 @@ common: Display: "First Tool", UpstreamProjUrl: "https://github.com/some_author/pct-first-tool", }, - Common: prm.CommonConfig{CanValidate: true}, + Common: tool.CommonConfig{CanValidate: true}, }, }, }, diff --git a/pkg/prm/tool.go b/pkg/tool/tool.go similarity index 99% rename from pkg/prm/tool.go rename to pkg/tool/tool.go index a9c54d6..1944d03 100644 --- a/pkg/prm/tool.go +++ b/pkg/tool/tool.go @@ -1,5 +1,5 @@ // nolint:structcheck,unused -package prm +package tool import ( "io" diff --git a/pkg/prm/tool_groups.go b/pkg/tool/tool_groups.go similarity index 98% rename from pkg/prm/tool_groups.go rename to pkg/tool/tool_groups.go index 76773e9..6ac05db 100644 --- a/pkg/prm/tool_groups.go +++ b/pkg/tool/tool_groups.go @@ -1,4 +1,4 @@ -package prm +package tool /* This package contains ToolGroups, which defines diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index f5edd46..a86a274 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -1,23 +1,31 @@ package utils -import ( - "github.com/rs/zerolog/log" - "github.com/spf13/viper" -) +//var ( +// fs *FileSystem +//) +// +//type FileSystem interface { +// GetFS() +//} +// +//type FileSystem struct { +// AFS *afero.Afero +// IOFS *afero.IOFS +//} +// +//func (f *FileSystem) GetFS(fileSystem *afero.Fs) *FileSystem { +// if fs == nil { +// fs = &FileSystem{ +// AFS: nil, +// IOFS: nil, +// } +// } +// +// return fs +//} type UtilsI interface { SetAndWriteConfig(string, string) error } type Utils struct{} - -func (u *Utils) SetAndWriteConfig(k, v string) (err error) { - log.Trace().Msgf("Setting and saving config '%s' to '%s' in %s", k, v, viper.ConfigFileUsed()) - - viper.Set(k, v) - - if err = viper.WriteConfig(); err != nil { - log.Error().Msgf("could not write config to %s: %s", viper.ConfigFileUsed(), err) - } - return err -} diff --git a/pkg/prm/worker_pool.go b/pkg/utils/worker_pool.go similarity index 93% rename from pkg/prm/worker_pool.go rename to pkg/utils/worker_pool.go index 020de64..0ceb12a 100644 --- a/pkg/prm/worker_pool.go +++ b/pkg/utils/worker_pool.go @@ -1,4 +1,4 @@ -package prm +package utils import ( "sync" @@ -79,9 +79,3 @@ func CreateTask[T any](name string, f func() T, output T) *Task[T] { f: f, } } - -type ValidationOutput struct { - err error - exitCode ValidateExitCode - stdout string -} diff --git a/pkg/prm/validate.go b/pkg/validate/validate.go similarity index 59% rename from pkg/prm/validate.go rename to pkg/validate/validate.go index db0f94e..474ced6 100644 --- a/pkg/prm/validate.go +++ b/pkg/validate/validate.go @@ -1,9 +1,13 @@ //nolint:structcheck,unused -package prm +package validate import ( "errors" "fmt" + "github.com/puppetlabs/prm/pkg/backend" + "github.com/puppetlabs/prm/pkg/backend/docker" + "github.com/puppetlabs/prm/pkg/config" + "github.com/puppetlabs/prm/pkg/utils" "os" "path" "regexp" @@ -15,21 +19,20 @@ import ( "github.com/spf13/afero" ) -type ValidateExitCode int64 - -const ( - VALIDATION_PASS ValidateExitCode = iota - VALIDATION_FAILED - VALIDATION_ERROR -) - var ( toolLogOutputPaths map[string]string // Key = toolName, Value = logFilePath, stores each tool's log file path ) -func (p *Prm) Validate(toolsInfo []ToolInfo, workerCount int, settings OutputSettings) error { - if status := p.Backend.Status(); !status.IsAvailable { - return ErrDockerNotRunning +type Validator struct { + Backend backend.BackendI + AFS *afero.Afero + DirectoryPaths backend.DirectoryPaths + RunningConfig config.Config +} + +func (v *Validator) Validate(toolsInfo []backend.ToolInfo, workerCount int, settings backend.OutputSettings) error { + if status := v.Backend.Status(); !status.IsAvailable { + return docker.ErrDockerNotRunning } if len(toolsInfo) == 0 { @@ -37,40 +40,40 @@ func (p *Prm) Validate(toolsInfo []ToolInfo, workerCount int, settings OutputSet } toolLogOutputPaths = make(map[string]string) - tasks := p.createTasks(toolsInfo) + tasks := v.createTasks(toolsInfo) - pool := CreateWorkerPool(tasks, workerCount) + pool := utils.CreateWorkerPool(tasks, workerCount) pool.Run() - err := p.outputResults(tasks, settings) + err := v.outputResults(tasks, settings) return err } -func (p Prm) taskFunc(tool ToolInfo) func() ValidationOutput { - return func() ValidationOutput { +func (v Validator) taskFunc(tool backend.ToolInfo) func() backend.ValidationOutput { + return func() backend.ValidationOutput { toolName := tool.Tool.Cfg.Plugin.Id log.Info().Msgf("Validating with the %s tool", toolName) - output := ValidationOutput{err: nil, exitCode: 0} + output := backend.ValidationOutput{Err: nil, ExitCode: 0} - err := p.Backend.GetTool(tool.Tool, p.RunningConfig) + err := v.Backend.GetTool(tool.Tool, v.RunningConfig) if err != nil { log.Error().Msgf("Failed to validate with tool: %s/%s", tool.Tool.Cfg.Plugin.Author, tool.Tool.Cfg.Plugin.Id) - output = ValidationOutput{err: err, exitCode: VALIDATION_ERROR} + output = backend.ValidationOutput{Err: err, ExitCode: backend.VALIDATION_ERROR} return output } - exitCode, stdout, err := p.Backend.Validate(tool, p.RunningConfig, DirectoryPaths{codeDir: p.CodeDir, cacheDir: p.CacheDir}) + exitCode, stdout, err := v.Backend.Validate(tool, v.RunningConfig, v.DirectoryPaths) if err != nil { - output = ValidationOutput{err: err, exitCode: exitCode, stdout: stdout} + output = backend.ValidationOutput{Err: err, ExitCode: exitCode, Stdout: stdout} return output } - output.stdout = stdout + output.Stdout = stdout return output } } -func (p *Prm) outputResults(tasks []*Task[ValidationOutput], settings OutputSettings) error { - err := p.writeOutputLogs(tasks, settings) +func (v *Validator) outputResults(tasks []*utils.Task[backend.ValidationOutput], settings backend.OutputSettings) error { + err := v.writeOutputLogs(tasks, settings) if err != nil { return err } @@ -89,18 +92,18 @@ func (p *Prm) outputResults(tasks []*Task[ValidationOutput], settings OutputSett return nil } -func writeOutputToTerminal(tasks []*Task[ValidationOutput]) { +func writeOutputToTerminal(tasks []*utils.Task[backend.ValidationOutput]) { for _, task := range tasks { output := task.Output - if output.err == nil { + if output.Err == nil { continue } var errText string - if output.err.Error() != "" { - errText = output.err.Error() + if output.Err.Error() != "" { + errText = output.Err.Error() } else { - errText = output.stdout + errText = output.Stdout } errText = cleanOutput(errText) @@ -126,18 +129,18 @@ func renderTable(headers []string, data [][]string) { table.Render() } -func (p *Prm) createTasks(toolsInfo []ToolInfo) []*Task[ValidationOutput] { - tasks := make([]*Task[ValidationOutput], len(toolsInfo)) +func (v *Validator) createTasks(toolsInfo []backend.ToolInfo) []*utils.Task[backend.ValidationOutput] { + tasks := make([]*utils.Task[backend.ValidationOutput], len(toolsInfo)) for i, info := range toolsInfo { - tasks[i] = CreateTask[ValidationOutput](info.Tool.Cfg.Plugin.Id, p.taskFunc(info), ValidationOutput{}) + tasks[i] = utils.CreateTask[backend.ValidationOutput](info.Tool.Cfg.Plugin.Id, v.taskFunc(info), backend.ValidationOutput{}) } return tasks } -func (p *Prm) checkAndCreateDir(dir string) error { - _, err := p.AFS.Stat(dir) +func (v *Validator) checkAndCreateDir(dir string) error { + _, err := v.AFS.Stat(dir) if os.IsNotExist(err) { - err = p.AFS.MkdirAll(dir, 0750) + err = v.AFS.MkdirAll(dir, 0750) return err } else if err != nil { return err @@ -155,9 +158,9 @@ func createLogFilePath(outputDir string, toolId string) string { return fullPath } -func (p *Prm) writeOutputToFile(tasks []*Task[ValidationOutput], outputDir string) error { +func (v *Validator) writeOutputToFile(tasks []*utils.Task[backend.ValidationOutput], outputDir string) error { for _, task := range tasks { - err := p.checkAndCreateDir(outputDir) + err := v.checkAndCreateDir(outputDir) if err != nil { return err } @@ -165,7 +168,7 @@ func (p *Prm) writeOutputToFile(tasks []*Task[ValidationOutput], outputDir strin filePath := createLogFilePath(outputDir, task.Name) log.Debug().Msgf("output filepath: %v", filePath) - file, err := p.AFS.Create(filePath) + file, err := v.AFS.Create(filePath) if err != nil { return err } @@ -183,13 +186,13 @@ func (p *Prm) writeOutputToFile(tasks []*Task[ValidationOutput], outputDir strin return nil } -func writeStringToFile(file afero.File, output ValidationOutput) error { +func writeStringToFile(file afero.File, output backend.ValidationOutput) error { errText := "" // Remove ANSI formatting from output strings - if output.err != nil { - errText = cleanOutput(output.err.Error()) + if output.Err != nil { + errText = cleanOutput(output.Err.Error()) } - stdout := cleanOutput(output.stdout) + stdout := cleanOutput(output.Stdout) _, err := file.WriteString(fmt.Sprintf("%s\n%s", stdout, errText)) if err != nil { @@ -199,31 +202,31 @@ func writeStringToFile(file afero.File, output ValidationOutput) error { return nil } -func (p *Prm) writeOutputLogs(tasks []*Task[ValidationOutput], settings OutputSettings) (err error) { +func (v *Validator) writeOutputLogs(tasks []*utils.Task[backend.ValidationOutput], settings backend.OutputSettings) (err error) { if settings.ResultsView == "terminal" { writeOutputToTerminal(tasks) return nil } if settings.ResultsView == "file" { - err := p.writeOutputToFile(tasks, settings.OutputDir) + err := v.writeOutputToFile(tasks, settings.OutputDir) return err } return fmt.Errorf("invalid --resultsView flag specified") } -func getErrorCount(tasks []*Task[ValidationOutput]) (count int) { +func getErrorCount(tasks []*utils.Task[backend.ValidationOutput]) (count int) { for _, task := range tasks { output := task.Output - if output.err != nil { + if output.Err != nil { count++ } } return count } -func createTableContents(tasks []*Task[ValidationOutput], resultsView string) (tableContents [][]string) { +func createTableContents(tasks []*utils.Task[backend.ValidationOutput], resultsView string) (tableContents [][]string) { for _, task := range tasks { output := task.Output if resultsView == "file" { // Will also include the path to each @@ -232,9 +235,9 @@ func createTableContents(tasks []*Task[ValidationOutput], resultsView string) (t if shortOutputDir := strings.Split(outputPath, ".prm-validate"); len(shortOutputDir) == 2 { outputPath = fmt.Sprint(".prm-validate", shortOutputDir[1]) } - tableContents = append(tableContents, []string{task.Name, fmt.Sprintf("%d", output.exitCode), outputPath}) + tableContents = append(tableContents, []string{task.Name, fmt.Sprintf("%d", output.ExitCode), outputPath}) } else { - tableContents = append(tableContents, []string{task.Name, fmt.Sprintf("%d", output.exitCode)}) + tableContents = append(tableContents, []string{task.Name, fmt.Sprintf("%d", output.ExitCode)}) } } return tableContents diff --git a/pkg/prm/validate_test.go b/pkg/validate/validate_test.go similarity index 74% rename from pkg/prm/validate_test.go rename to pkg/validate/validate_test.go index 81bd5e8..ee7b4c7 100644 --- a/pkg/prm/validate_test.go +++ b/pkg/validate/validate_test.go @@ -1,11 +1,16 @@ -package prm_test +package validate_test import ( "fmt" + "github.com/puppetlabs/pct/pkg/install" + "github.com/puppetlabs/prm/pkg/backend" + "github.com/puppetlabs/prm/pkg/backend/docker" + "github.com/puppetlabs/prm/pkg/config" + "github.com/puppetlabs/prm/pkg/tool" + "github.com/puppetlabs/prm/pkg/validate" "testing" "github.com/puppetlabs/prm/internal/pkg/mock" - "github.com/puppetlabs/prm/pkg/prm" "github.com/spf13/afero" ) @@ -13,18 +18,18 @@ func TestPrm_Validate(t *testing.T) { pathToLogs := "path/to/tools" codeDirPath := "path/to/code" type fields struct { - RunningConfig prm.Config + RunningConfig config.Config CodeDir string CacheDir string - Cache map[string]*prm.Tool - Backend prm.BackendI + Cache map[string]*tool.Tool + Backend backend.BackendI } type args struct { id string validateReturn string expectedErrMsg string toolNotAvailable bool - outputSettings prm.OutputSettings + outputSettings backend.OutputSettings toolArgs []string workerCount int extraTools int @@ -41,7 +46,7 @@ func TestPrm_Validate(t *testing.T) { args: args{ id: "my-tool", validateReturn: "PASS", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "terminal", OutputDir: pathToLogs, }, @@ -53,7 +58,7 @@ func TestPrm_Validate(t *testing.T) { args: args{ id: "my-tool", validateReturn: "PASS", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "terminal", OutputDir: pathToLogs, }, @@ -66,7 +71,7 @@ func TestPrm_Validate(t *testing.T) { args: args{ id: "my-tool", validateReturn: "PASS", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "file", OutputDir: pathToLogs, }, @@ -78,7 +83,7 @@ func TestPrm_Validate(t *testing.T) { args: args{ id: "my-tool", validateReturn: "PASS", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "file", OutputDir: pathToLogs, }, @@ -92,7 +97,7 @@ func TestPrm_Validate(t *testing.T) { id: "fail", validateReturn: "FAIL", expectedErrMsg: "Validation returned 1 error", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "terminal", OutputDir: pathToLogs, }, @@ -106,7 +111,7 @@ func TestPrm_Validate(t *testing.T) { id: "fail", validateReturn: "FAIL", expectedErrMsg: "Validation returned 11 errors", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "terminal", OutputDir: pathToLogs, }, @@ -121,7 +126,7 @@ func TestPrm_Validate(t *testing.T) { id: "fail", validateReturn: "FAIL", expectedErrMsg: "Validation returned 1 error", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "file", OutputDir: pathToLogs, }, @@ -135,7 +140,7 @@ func TestPrm_Validate(t *testing.T) { id: "fail", validateReturn: "FAIL", expectedErrMsg: "Validation returned 11 errors", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "file", OutputDir: pathToLogs, }, @@ -150,7 +155,7 @@ func TestPrm_Validate(t *testing.T) { id: "fail", validateReturn: "FAIL", expectedErrMsg: "Validation returned 1 error", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "terminal", OutputDir: pathToLogs, }, @@ -164,7 +169,7 @@ func TestPrm_Validate(t *testing.T) { args: args{ id: "error", validateReturn: "FAIL", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "invalid flag", OutputDir: pathToLogs, }, @@ -178,12 +183,12 @@ func TestPrm_Validate(t *testing.T) { args: args{ id: "error", validateReturn: "FAIL", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "terminal", OutputDir: pathToLogs, }, workerCount: 1, - expectedErrMsg: prm.ErrDockerNotRunning.Error(), + expectedErrMsg: docker.ErrDockerNotRunning.Error(), statusIsNotAvailable: true, }, wantErr: true, @@ -193,7 +198,7 @@ func TestPrm_Validate(t *testing.T) { t.Run(tt.name, func(t *testing.T) { fs := afero.NewMemMapFs() afs := &afero.Afero{Fs: fs} - iofs := &afero.IOFS{Fs: fs} + //iofs := &afero.IOFS{Fs: fs} if tt.args.outputSettings.ResultsView == "file" { afs.MkdirAll(tt.args.outputSettings.OutputDir, 0755) //nolint:gosec,errcheck @@ -201,29 +206,45 @@ func TestPrm_Validate(t *testing.T) { afs.MkdirAll(pathToLogs, 0755) //nolint:gosec,errcheck afs.MkdirAll(codeDirPath, 0755) //nolint:gosec,errcheck - var tools []prm.ToolInfo + var tools []backend.ToolInfo for i := 0; i < tt.args.extraTools+1; i++ { id, author, version := fmt.Sprint(tt.args.id, i), "puppetlabs", "0.1.0" tools = append(tools, CreateToolInfo(id, author, version, tt.args.toolArgs)) } - p := &prm.Prm{ - AFS: afs, - IOFS: iofs, - RunningConfig: tt.fields.RunningConfig, - CodeDir: codeDirPath, - CacheDir: tt.fields.CacheDir, - Cache: tt.fields.Cache, + validator := validate.Validator{ Backend: &mock.MockBackend{ StatusIsAvailable: !tt.args.statusIsNotAvailable, ToolAvalible: !tt.args.toolNotAvailable, ValidateReturn: tt.args.validateReturn, }, + AFS: afs, + DirectoryPaths: backend.DirectoryPaths{CodeDir: codeDirPath, CacheDir: tt.fields.CacheDir}, + RunningConfig: tt.fields.RunningConfig, } - if err := p.Validate(tools, tt.args.workerCount, tt.args.outputSettings); err != nil && err.Error() != tt.args.expectedErrMsg { + if err := validator.Validate(tools, tt.args.workerCount, tt.args.outputSettings); err != nil && err.Error() != tt.args.expectedErrMsg { t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr) } }) } } + +func CreateToolInfo(id, author, version string, args []string) backend.ToolInfo { + tool := &tool.Tool{ + Cfg: tool.ToolConfig{ + Plugin: &tool.PluginConfig{ + ConfigParams: install.ConfigParams{ + Id: id, + Author: author, + Version: version, + }, + }, + }, + } + + return backend.ToolInfo{ + Tool: tool, + Args: args, + } +}