From 9c99d89a7e11321b6dd61fd826270cab1991df9e Mon Sep 17 00:00:00 2001 From: Nick DiZazzo Date: Tue, 12 Aug 2025 23:10:43 -0400 Subject: [PATCH] fix: Make parameter return values consistent between WithParameter calls --- actions/docker/docker_compose_ls_action.go | 4 +- .../docker/docker_compose_ls_action_test.go | 123 +++++++++++------- actions/docker/docker_load_action.go | 4 +- actions/docker/docker_load_action_test.go | 52 +++++--- actions/docker/docker_run_action.go | 4 +- actions/docker/docker_run_action_test.go | 20 +-- actions/docker/docker_status_action.go | 4 +- actions/docker/docker_status_action_test.go | 102 +++++++++------ actions/file/create_symlink_action.go | 4 +- actions/file/create_symlink_action_test.go | 77 ++++++----- actions/file/delete_path_action.go | 4 +- actions/file/delete_path_action_test.go | 72 ++++++---- actions/file/move_file_action.go | 4 +- actions/file/move_file_action_test.go | 43 +++--- actions/file/replace_lines_action.go | 4 +- actions/file/replace_lines_action_test.go | 9 +- tasks/example_docker_load_operations.go | 96 ++++++++++++-- tasks/example_docker_status_operations.go | 72 ++++++++-- tasks/example_file_operations.go | 18 ++- tasks/example_symlink_operations.go | 56 ++++++-- 20 files changed, 529 insertions(+), 243 deletions(-) diff --git a/actions/docker/docker_compose_ls_action.go b/actions/docker/docker_compose_ls_action.go index 48d4c35..9354e6b 100644 --- a/actions/docker/docker_compose_ls_action.go +++ b/actions/docker/docker_compose_ls_action.go @@ -37,7 +37,7 @@ func NewDockerComposeLsAction(logger *slog.Logger) *DockerComposeLsActionBuilder } // WithParameters sets the parameters for working directory and configuration -func (b *DockerComposeLsActionBuilder) WithParameters(workingDirParam task_engine.ActionParameter, config DockerComposeLsConfig) *task_engine.Action[*DockerComposeLsAction] { +func (b *DockerComposeLsActionBuilder) WithParameters(workingDirParam task_engine.ActionParameter, config DockerComposeLsConfig) (*task_engine.Action[*DockerComposeLsAction], error) { // Determine whether to treat the provided parameter as active // - Non-empty static string: active (resolve at runtime) // - Non-string static parameter: active (so Execute will error as tests expect) @@ -79,7 +79,7 @@ func (b *DockerComposeLsActionBuilder) WithParameters(workingDirParam task_engin ID: id, Name: "Docker Compose LS", Wrapped: action, - } + }, nil } // DockerComposeLsOption is a function type for configuring DockerComposeLsAction diff --git a/actions/docker/docker_compose_ls_action_test.go b/actions/docker/docker_compose_ls_action_test.go index 0e2f4cf..f73550d 100644 --- a/actions/docker/docker_compose_ls_action_test.go +++ b/actions/docker/docker_compose_ls_action_test.go @@ -25,7 +25,8 @@ func TestDockerComposeLsActionTestSuite(t *testing.T) { func (suite *DockerComposeLsActionTestSuite) TestNewDockerComposeLsAction() { logger := slog.Default() - action := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig()) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig()) + suite.NoError(err) suite.NotNil(action) suite.Equal("docker-compose-ls-action", action.ID) @@ -39,7 +40,7 @@ func (suite *DockerComposeLsActionTestSuite) TestNewDockerComposeLsAction() { func (suite *DockerComposeLsActionTestSuite) TestNewDockerComposeLsActionWithOptions() { logger := slog.Default() - action := docker.NewDockerComposeLsAction(logger).WithParameters( + action, err := docker.NewDockerComposeLsAction(logger).WithParameters( task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig( docker.WithComposeAll(), @@ -49,6 +50,7 @@ func (suite *DockerComposeLsActionTestSuite) TestNewDockerComposeLsActionWithOpt docker.WithWorkingDir("/path/to/compose"), ), ) + suite.NoError(err) suite.NotNil(action) suite.True(action.Wrapped.All) @@ -67,10 +69,11 @@ testapp stopped /path/to/compose.yml,/path/to/override.y mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "compose", "ls").Return(expectedOutput, nil) - action := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig()) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig()) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.Equal(expectedOutput, action.Wrapped.Output) @@ -94,10 +97,11 @@ testapp stopped /path/to/compose.yml` mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "compose", "ls", "--all").Return(expectedOutput, nil) - action := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig(docker.WithComposeAll())) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig(docker.WithComposeAll())) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.Equal(expectedOutput, action.Wrapped.Output) @@ -113,10 +117,11 @@ myapp running /path/to/docker-compose.yml` mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "compose", "ls", "--filter", "name=myapp").Return(expectedOutput, nil) - action := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig(docker.WithComposeFilter("name=myapp"))) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig(docker.WithComposeFilter("name=myapp"))) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.Equal(expectedOutput, action.Wrapped.Output) @@ -131,12 +136,13 @@ func (suite *DockerComposeLsActionTestSuite) TestDockerComposeLsAction_Execute_W myapp running /path/to/docker-compose.yml` mockRunner := &mocks.MockCommandRunner{} - mockRunner.On("RunCommand", "docker", "compose", "ls", "--format", "table {{.Name}}\t{{.Status}}").Return(expectedOutput, nil) + mockRunner.On("RunCommand", "docker", "compose", "ls", "--format", "table {{.Name}}\t{{.Status}}\t{{.ConfigFiles}}").Return(expectedOutput, nil) - action := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig(docker.WithComposeFormat("table {{.Name}}\t{{.Status}}"))) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig(docker.WithComposeFormat("table {{.Name}}\t{{.Status}}\t{{.ConfigFiles}}"))) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.Equal(expectedOutput, action.Wrapped.Output) @@ -152,10 +158,11 @@ testapp` mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "compose", "ls", "--quiet").Return(expectedOutput, nil) - action := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig(docker.WithComposeLsQuiet())) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig(docker.WithComposeLsQuiet())) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.Equal(expectedOutput, action.Wrapped.Output) @@ -172,10 +179,11 @@ func (suite *DockerComposeLsActionTestSuite) TestDockerComposeLsAction_Execute_C mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "compose", "ls").Return("", expectedError) - action := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig()) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig()) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.Error(err) suite.Contains(err.Error(), "docker compose command failed", "Error should contain the command failure message") @@ -192,10 +200,11 @@ func (suite *DockerComposeLsActionTestSuite) TestDockerComposeLsAction_Execute_C mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "compose", "ls").Return("", context.Canceled) - action := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig()) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig()) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(ctx) + err = action.Wrapped.Execute(ctx) suite.Error(err) suite.Contains(err.Error(), "context canceled", "Error should contain the context cancellation message") @@ -215,11 +224,12 @@ devapp created /path/to/dev-compose.yml` mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "compose", "ls").Return(output, nil) - action := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig()) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig()) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) // Execute the action to trigger parseStacks internally - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.Len(action.Wrapped.Stacks, 3) @@ -245,10 +255,11 @@ func (suite *DockerComposeLsActionTestSuite) TestDockerComposeLsAction_Execute_E mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "compose", "ls").Return(expectedOutput, nil) - action := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig()) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig()) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.Equal(expectedOutput, action.Wrapped.Output) @@ -265,10 +276,11 @@ testapp stopped /path/to/compose.yml` mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "compose", "ls").Return(expectedOutput, nil) - action := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig()) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig()) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.Equal(expectedOutput, action.Wrapped.Output) @@ -281,7 +293,8 @@ func (suite *DockerComposeLsActionTestSuite) TestNewDockerComposeLsActionWithPar logger := slog.Default() workingDirParam := task_engine.StaticParameter{Value: "/tmp/test-dir"} - action := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + suite.NoError(err) suite.NotNil(action) suite.Equal("docker-compose-ls-with-params-action", action.ID) @@ -294,7 +307,7 @@ func (suite *DockerComposeLsActionTestSuite) TestNewDockerComposeLsActionWithPar logger := slog.Default() workingDirParam := task_engine.StaticParameter{Value: "/tmp/test-dir"} - action := docker.NewDockerComposeLsAction(logger).WithParameters( + action, err := docker.NewDockerComposeLsAction(logger).WithParameters( workingDirParam, docker.NewDockerComposeLsConfig( docker.WithComposeAll(), @@ -303,6 +316,7 @@ func (suite *DockerComposeLsActionTestSuite) TestNewDockerComposeLsActionWithPar docker.WithComposeLsQuiet(), ), ) + suite.NoError(err) suite.NotNil(action) suite.True(action.Wrapped.All) @@ -323,10 +337,11 @@ myapp running /path/to/docker-compose.yml` mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "compose", "ls").Return(expectedOutput, nil) - action := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.Equal("/tmp/test-dir", action.Wrapped.WorkingDir) @@ -356,10 +371,11 @@ api-service running /path/to/docker-compose.yml` mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "compose", "ls").Return(expectedOutput, nil) - action := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.WithValue(context.Background(), task_engine.GlobalContextKey, globalContext)) + err = action.Wrapped.Execute(context.WithValue(context.Background(), task_engine.GlobalContextKey, globalContext)) suite.NoError(err) suite.Equal("/tmp/from-action", action.Wrapped.WorkingDir) @@ -389,10 +405,11 @@ frontend-service running /path/to/docker-compose.yml` mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "compose", "ls").Return(expectedOutput, nil) - action := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.WithValue(context.Background(), task_engine.GlobalContextKey, globalContext)) + err = action.Wrapped.Execute(context.WithValue(context.Background(), task_engine.GlobalContextKey, globalContext)) suite.NoError(err) suite.Equal("/tmp/from-task", action.Wrapped.WorkingDir) @@ -423,10 +440,11 @@ cache-service running /path/to/docker-compose.yml` mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "compose", "ls").Return(expectedOutput, nil) - action := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.WithValue(context.Background(), task_engine.GlobalContextKey, globalContext)) + err = action.Wrapped.Execute(context.WithValue(context.Background(), task_engine.GlobalContextKey, globalContext)) suite.NoError(err) suite.Equal("/tmp/from-build", action.Wrapped.WorkingDir) @@ -449,9 +467,10 @@ func (suite *DockerComposeLsActionTestSuite) TestExecute_WithInvalidActionOutput OutputKey: "workingDir", } - action := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + suite.NoError(err) - err := action.Wrapped.Execute(context.WithValue(context.Background(), task_engine.GlobalContextKey, globalContext)) + err = action.Wrapped.Execute(context.WithValue(context.Background(), task_engine.GlobalContextKey, globalContext)) suite.Error(err) suite.Contains(err.Error(), "failed to resolve working directory parameter") @@ -471,9 +490,10 @@ func (suite *DockerComposeLsActionTestSuite) TestExecute_WithInvalidOutputKey() OutputKey: "workingDir", // This key doesn't exist } - action := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + suite.NoError(err) - err := action.Wrapped.Execute(context.WithValue(context.Background(), task_engine.GlobalContextKey, globalContext)) + err = action.Wrapped.Execute(context.WithValue(context.Background(), task_engine.GlobalContextKey, globalContext)) suite.Error(err) suite.Contains(err.Error(), "failed to resolve working directory parameter") @@ -487,9 +507,10 @@ func (suite *DockerComposeLsActionTestSuite) TestExecute_WithEmptyActionID() { OutputKey: "workingDir", } - action := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + suite.NoError(err) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.Error(err) suite.Contains(err.Error(), "failed to resolve working directory parameter") @@ -507,9 +528,10 @@ func (suite *DockerComposeLsActionTestSuite) TestExecute_WithNonMapOutput() { OutputKey: "workingDir", } - action := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + suite.NoError(err) - err := action.Wrapped.Execute(context.WithValue(context.Background(), task_engine.GlobalContextKey, globalContext)) + err = action.Wrapped.Execute(context.WithValue(context.Background(), task_engine.GlobalContextKey, globalContext)) suite.Error(err) suite.Contains(err.Error(), "failed to resolve working directory parameter") @@ -520,9 +542,10 @@ func (suite *DockerComposeLsActionTestSuite) TestExecute_WithNonStringWorkingDir logger := slog.Default() workingDirParam := task_engine.StaticParameter{Value: 123} // Not a string - action := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + suite.NoError(err) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.Error(err) suite.Contains(err.Error(), "working directory parameter is not a string, got int") @@ -546,16 +569,17 @@ static-service running /path/to/docker-compose.yml` mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "compose", "ls", "--all", "--filter", "name=static-service").Return(expectedOutput, nil) - action := docker.NewDockerComposeLsAction(logger).WithParameters( + action, err := docker.NewDockerComposeLsAction(logger).WithParameters( workingDirParam, docker.NewDockerComposeLsConfig( docker.WithComposeAll(), docker.WithComposeFilter("name=static-service"), ), ) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.WithValue(context.Background(), task_engine.GlobalContextKey, globalContext)) + err = action.Wrapped.Execute(context.WithValue(context.Background(), task_engine.GlobalContextKey, globalContext)) suite.NoError(err) suite.Equal("/tmp/from-action", action.Wrapped.WorkingDir) // From action output @@ -572,7 +596,8 @@ func (suite *DockerComposeLsActionTestSuite) TestBackwardCompatibility_OriginalC logger := slog.Default() workingDir := "/tmp/test-dir" - action := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig(docker.WithWorkingDir(workingDir))) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, docker.NewDockerComposeLsConfig(docker.WithWorkingDir(workingDir))) + suite.NoError(err) suite.NotNil(action) suite.Equal(workingDir, action.Wrapped.WorkingDir) @@ -588,12 +613,12 @@ myapp running /path/to/docker-compose.yml` mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "compose", "ls").Return(expectedOutput, nil) - action := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + action, err := docker.NewDockerComposeLsAction(logger).WithParameters(workingDirParam, docker.NewDockerComposeLsConfig()) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) - suite.NoError(err) suite.NoError(err) suite.Equal("/tmp/test-dir", action.Wrapped.WorkingDir) suite.Equal(expectedOutput, action.Wrapped.Output) diff --git a/actions/docker/docker_load_action.go b/actions/docker/docker_load_action.go index 1944c39..67fafa2 100644 --- a/actions/docker/docker_load_action.go +++ b/actions/docker/docker_load_action.go @@ -25,7 +25,7 @@ func NewDockerLoadAction(logger *slog.Logger) *DockerLoadActionBuilder { } // WithParameters sets the parameters for tar file path -func (b *DockerLoadActionBuilder) WithParameters(tarFilePathParam task_engine.ActionParameter) *task_engine.Action[*DockerLoadAction] { +func (b *DockerLoadActionBuilder) WithParameters(tarFilePathParam task_engine.ActionParameter) (*task_engine.Action[*DockerLoadAction], error) { b.tarFilePathParam = tarFilePathParam action := &DockerLoadAction{ @@ -62,7 +62,7 @@ func (b *DockerLoadActionBuilder) WithParameters(tarFilePathParam task_engine.Ac ID: id, Name: "Docker Load", Wrapped: action, - } + }, nil } // WithOptions adds options to the builder diff --git a/actions/docker/docker_load_action_test.go b/actions/docker/docker_load_action_test.go index 4708304..a73bf47 100644 --- a/actions/docker/docker_load_action_test.go +++ b/actions/docker/docker_load_action_test.go @@ -25,7 +25,8 @@ func (suite *DockerLoadActionTestSuite) TestNewDockerLoadAction() { logger := slog.Default() tarFilePath := "/path/to/image.tar" - action := NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + action, err := NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + suite.NoError(err) suite.NotNil(action) suite.Equal("docker-load--path-to-image.tar-action", action.ID) @@ -39,7 +40,8 @@ func (suite *DockerLoadActionTestSuite) TestNewDockerLoadActionWithOptions() { logger := slog.Default() tarFilePath := "/path/to/image.tar" - action := NewDockerLoadAction(logger).WithOptions(WithPlatform("linux/amd64"), WithQuiet()).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + action, err := NewDockerLoadAction(logger).WithOptions(WithPlatform("linux/amd64"), WithQuiet()).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + suite.NoError(err) suite.NotNil(action) suite.NotNil(action.Wrapped.TarFilePathParam) @@ -55,10 +57,11 @@ func (suite *DockerLoadActionTestSuite) TestDockerLoadAction_Execute_Success() { mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "load", "-i", tarFilePath).Return(expectedOutput, nil) - action := NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + action, err := NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.Equal(expectedOutput, action.Wrapped.Output) @@ -75,10 +78,11 @@ func (suite *DockerLoadActionTestSuite) TestDockerLoadAction_Execute_WithPlatfor mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "load", "-i", tarFilePath, "--platform", platform).Return(expectedOutput, nil) - action := NewDockerLoadAction(logger).WithOptions(WithPlatform(platform)).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + action, err := NewDockerLoadAction(logger).WithOptions(WithPlatform(platform)).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.Equal(expectedOutput, action.Wrapped.Output) @@ -94,10 +98,11 @@ func (suite *DockerLoadActionTestSuite) TestDockerLoadAction_Execute_WithQuiet() mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "load", "-i", tarFilePath, "-q").Return(expectedOutput, nil) - action := NewDockerLoadAction(logger).WithOptions(WithQuiet()).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + action, err := NewDockerLoadAction(logger).WithOptions(WithQuiet()).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.Equal(expectedOutput, action.Wrapped.Output) @@ -114,10 +119,11 @@ func (suite *DockerLoadActionTestSuite) TestDockerLoadAction_Execute_WithPlatfor mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "load", "-i", tarFilePath, "--platform", platform, "-q").Return(expectedOutput, nil) - action := NewDockerLoadAction(logger).WithOptions(WithPlatform(platform), WithQuiet()).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + action, err := NewDockerLoadAction(logger).WithOptions(WithPlatform(platform), WithQuiet()).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.Equal(expectedOutput, action.Wrapped.Output) @@ -133,10 +139,11 @@ func (suite *DockerLoadActionTestSuite) TestDockerLoadAction_Execute_CommandErro mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "load", "-i", tarFilePath).Return("", errors.New(expectedError)) - action := NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + action, err := NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.Error(err) suite.Contains(err.Error(), expectedError) @@ -152,10 +159,11 @@ func (suite *DockerLoadActionTestSuite) TestDockerLoadAction_Execute_ContextCanc mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "load", "-i", tarFilePath).Return("", context.Canceled) - action := NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + action, err := NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.Error(err) suite.True(errors.Is(err, context.Canceled)) @@ -174,10 +182,11 @@ Loaded image: postgres:13` mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "load", "-i", tarFilePath).Return(output, nil) - action := NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + action, err := NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.Equal(output, action.Wrapped.Output) @@ -189,7 +198,8 @@ func (suite *DockerLoadActionTestSuite) TestDockerLoadAction_Execute_EmptyTarFil logger := slog.Default() tarFilePath := "" - action := NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + action, err := NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + suite.NoError(err) suite.NotNil(action) suite.Equal("docker-load--action", action.ID) @@ -200,7 +210,8 @@ func (suite *DockerLoadActionTestSuite) TestDockerLoadAction_Execute_SpecialChar logger := slog.Default() tarFilePath := "/path/with spaces/and-special-chars@#$%.tar" - action := NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + action, err := NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + suite.NoError(err) suite.NotNil(action) suite.Equal("docker-load--path-with-spaces-and-special-chars.tar-action", action.ID) @@ -216,10 +227,11 @@ func (suite *DockerLoadActionTestSuite) TestDockerLoadAction_Execute_OutputWithT mockRunner := &mocks.MockCommandRunner{} mockRunner.On("RunCommand", "docker", "load", "-i", tarFilePath).Return(output, nil) - action := NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + action, err := NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: tarFilePath}) + suite.NoError(err) action.Wrapped.SetCommandRunner(mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.Equal(output, action.Wrapped.Output) diff --git a/actions/docker/docker_run_action.go b/actions/docker/docker_run_action.go index cbf6d5c..d1e8766 100644 --- a/actions/docker/docker_run_action.go +++ b/actions/docker/docker_run_action.go @@ -27,7 +27,7 @@ func NewDockerRunAction(logger *slog.Logger) *DockerRunActionBuilder { } // WithParameters sets the parameters for image, output buffer, and run arguments -func (b *DockerRunActionBuilder) WithParameters(imageParam task_engine.ActionParameter, outputBuffer *bytes.Buffer, runArgs ...string) *task_engine.Action[*DockerRunAction] { +func (b *DockerRunActionBuilder) WithParameters(imageParam task_engine.ActionParameter, outputBuffer *bytes.Buffer, runArgs ...string) (*task_engine.Action[*DockerRunAction], error) { b.imageParam = imageParam b.outputBuffer = outputBuffer b.runArgs = runArgs @@ -44,7 +44,7 @@ func (b *DockerRunActionBuilder) WithParameters(imageParam task_engine.ActionPar commandRunner: command.NewDefaultCommandRunner(), ImageParam: b.imageParam, }, - } + }, nil } // NOTE: Command arguments for inside the container should be part of RunArgs diff --git a/actions/docker/docker_run_action_test.go b/actions/docker/docker_run_action_test.go index 2173e4a..a9618d5 100644 --- a/actions/docker/docker_run_action_test.go +++ b/actions/docker/docker_run_action_test.go @@ -26,13 +26,14 @@ func (suite *DockerRunTestSuite) TestExecuteSuccess() { image := "hello-world:latest" runArgs := []string{"--rm", image} logger := command_mock.NewDiscardLogger() - action := docker.NewDockerRunAction(logger).WithParameters(task_engine.StaticParameter{Value: image}, nil, runArgs...) + action, err := docker.NewDockerRunAction(logger).WithParameters(task_engine.StaticParameter{Value: image}, nil, runArgs...) + suite.NoError(err) action.Wrapped.SetCommandRunner(suite.mockProcessor) expectedOutput := "Hello from Docker! ...some more output..." suite.mockProcessor.On("RunCommand", "docker", "run", "--rm", image).Return(expectedOutput+"\n ", nil) // Simulate untrimmed output - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.mockProcessor.AssertExpectations(suite.T()) @@ -43,13 +44,14 @@ func (suite *DockerRunTestSuite) TestExecuteSuccessWithCommand() { image := "busybox:latest" runArgs := []string{"--rm", image, "echo", "hello from busybox"} logger := command_mock.NewDiscardLogger() - action := docker.NewDockerRunAction(logger).WithParameters(task_engine.StaticParameter{Value: image}, nil, runArgs...) + action, err := docker.NewDockerRunAction(logger).WithParameters(task_engine.StaticParameter{Value: image}, nil, runArgs...) + suite.NoError(err) action.Wrapped.SetCommandRunner(suite.mockProcessor) expectedOutput := "hello from busybox" suite.mockProcessor.On("RunCommand", "docker", "run", "--rm", image, "echo", "hello from busybox").Return(expectedOutput+"\n", nil) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.mockProcessor.AssertExpectations(suite.T()) @@ -60,13 +62,14 @@ func (suite *DockerRunTestSuite) TestExecuteCommandFailure() { image := "nonexistent-image:latest" runArgs := []string{"--rm", image} logger := command_mock.NewDiscardLogger() - action := docker.NewDockerRunAction(logger).WithParameters(task_engine.StaticParameter{Value: image}, nil, runArgs...) + action, err := docker.NewDockerRunAction(logger).WithParameters(task_engine.StaticParameter{Value: image}, nil, runArgs...) + suite.NoError(err) action.Wrapped.SetCommandRunner(suite.mockProcessor) expectedOutput := "Error: image not found..." suite.mockProcessor.On("RunCommand", "docker", "run", "--rm", image).Return(expectedOutput+" ", assert.AnError) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.Error(err) suite.Contains(err.Error(), "failed to run docker container") @@ -80,13 +83,14 @@ func (suite *DockerRunTestSuite) TestExecuteSuccessWithBuffer() { logger := command_mock.NewDiscardLogger() var buffer bytes.Buffer // Create buffer - action := docker.NewDockerRunAction(logger).WithParameters(task_engine.StaticParameter{Value: image}, &buffer, runArgs...) + action, err := docker.NewDockerRunAction(logger).WithParameters(task_engine.StaticParameter{Value: image}, &buffer, runArgs...) + suite.NoError(err) action.Wrapped.SetCommandRunner(suite.mockProcessor) expectedOutput := "buffer test" suite.mockProcessor.On("RunCommand", "docker", "run", "--rm", image, "echo", "-n", "buffer test").Return(expectedOutput, nil) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.mockProcessor.AssertExpectations(suite.T()) suite.Equal(expectedOutput, action.Wrapped.Output) diff --git a/actions/docker/docker_status_action.go b/actions/docker/docker_status_action.go index 8bb7925..32a9fe9 100644 --- a/actions/docker/docker_status_action.go +++ b/actions/docker/docker_status_action.go @@ -33,7 +33,7 @@ func NewGetContainerStateAction(logger *slog.Logger) *GetContainerStateActionBui } // WithParameters sets the parameters for container name -func (b *GetContainerStateActionBuilder) WithParameters(containerNameParam task_engine.ActionParameter) *task_engine.Action[*GetContainerStateAction] { +func (b *GetContainerStateActionBuilder) WithParameters(containerNameParam task_engine.ActionParameter) (*task_engine.Action[*GetContainerStateAction], error) { b.containerNameParam = containerNameParam id := "get-container-state-action" @@ -46,7 +46,7 @@ func (b *GetContainerStateActionBuilder) WithParameters(containerNameParam task_ CommandProcessor: command.NewDefaultCommandRunner(), ContainerNameParam: b.containerNameParam, }, - } + }, nil } // GetContainerStateAction retrieves the state of Docker containers diff --git a/actions/docker/docker_status_action_test.go b/actions/docker/docker_status_action_test.go index bc81a02..8283ba5 100644 --- a/actions/docker/docker_status_action_test.go +++ b/actions/docker/docker_status_action_test.go @@ -21,16 +21,17 @@ func (suite *DockerStatusActionTestSuite) SetupTest() { suite.mockProcessor = new(command_mock.MockCommandRunner) } -func (suite *DockerStatusActionTestSuite) TestGetSpecificContainerState() { +func (suite *DockerStatusActionTestSuite) TestGetSingleContainerState() { containerName := "test-container" expectedOutput := `{"ID":"abc123","Names":"test-container","Image":"nginx:latest","Status":"Up 2 hours"}` logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: containerName}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: containerName}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json", "--filter", "name=test-container").Return(expectedOutput, nil) - err := action.Execute(suite.T().Context()) + err = action.Execute(suite.T().Context()) suite.NoError(err) suite.mockProcessor.AssertExpectations(suite.T()) @@ -48,12 +49,13 @@ func (suite *DockerStatusActionTestSuite) TestGetMultipleContainerStates() { expectedOutput := `{"ID":"abc123","Names":"container1","Image":"nginx:latest","Status":"Up 2 hours"} {"ID":"def456","Names":"container2","Image":"redis:alpine","Status":"Exited (0) 1 hour ago"}` logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: containerNames}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: containerNames}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json", "--filter", "name=container1", "--filter", "name=container2").Return(expectedOutput, nil) - err := action.Execute(suite.T().Context()) + err = action.Execute(suite.T().Context()) suite.NoError(err) suite.mockProcessor.AssertExpectations(suite.T()) @@ -78,12 +80,13 @@ func (suite *DockerStatusActionTestSuite) TestGetAllContainersState() { {"ID":"def456","Names":"container2","Image":"redis:alpine","Status":"Exited (0) 1 hour ago"} {"ID":"ghi789","Names":"container3","Image":"postgres:13","Status":"Paused"}` logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json").Return(expectedOutput, nil) - err := action.Execute(suite.T().Context()) + err = action.Execute(suite.T().Context()) suite.NoError(err) suite.mockProcessor.AssertExpectations(suite.T()) @@ -113,12 +116,13 @@ func (suite *DockerStatusActionTestSuite) TestContainerWithMultipleNames() { containerName := "test-container" expectedOutput := `{"ID":"abc123","Names":"test-container,my-container,alias1","Image":"nginx:latest","Status":"Up 2 hours"}` logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: containerName}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: containerName}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json", "--filter", "name=test-container").Return(expectedOutput, nil) - err := action.Execute(suite.T().Context()) + err = action.Execute(suite.T().Context()) suite.NoError(err) suite.mockProcessor.AssertExpectations(suite.T()) @@ -133,12 +137,13 @@ func (suite *DockerStatusActionTestSuite) TestContainerWithMultipleNames() { func (suite *DockerStatusActionTestSuite) TestEmptyOutput() { logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json").Return("", nil) - err := action.Execute(suite.T().Context()) + err = action.Execute(suite.T().Context()) suite.NoError(err) suite.mockProcessor.AssertExpectations(suite.T()) @@ -147,12 +152,13 @@ func (suite *DockerStatusActionTestSuite) TestEmptyOutput() { func (suite *DockerStatusActionTestSuite) TestWhitespaceOnlyOutput() { logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json").Return(" \n \t ", nil) - err := action.Execute(suite.T().Context()) + err = action.Execute(suite.T().Context()) suite.NoError(err) suite.mockProcessor.AssertExpectations(suite.T()) @@ -165,12 +171,13 @@ func (suite *DockerStatusActionTestSuite) TestMalformedJSONLine() { {"ID":"ghi789","Names":"container3","Image":"postgres:13","Status":"Paused"} {"ID":"jkl012","Names":"container4","Image":"invalid-json","Status":"Up 1 hour` logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json").Return(expectedOutput, nil) - err := action.Execute(suite.T().Context()) + err = action.Execute(suite.T().Context()) suite.NoError(err) suite.mockProcessor.AssertExpectations(suite.T()) @@ -192,12 +199,13 @@ func (suite *DockerStatusActionTestSuite) TestMalformedJSONLine() { func (suite *DockerStatusActionTestSuite) TestCommandFailure() { logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "test-container"}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "test-container"}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json", "--filter", "name=test-container").Return("", assert.AnError) - err := action.Execute(suite.T().Context()) + err = action.Execute(suite.T().Context()) suite.Error(err) suite.Contains(err.Error(), "failed to get container state") @@ -207,12 +215,13 @@ func (suite *DockerStatusActionTestSuite) TestCommandFailure() { func (suite *DockerStatusActionTestSuite) TestContainerWithEmptyNames() { expectedOutput := `{"ID":"abc123","Names":"","Image":"nginx:latest","Status":"Up 2 hours"}` logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json").Return(expectedOutput, nil) - err := action.Execute(suite.T().Context()) + err = action.Execute(suite.T().Context()) suite.NoError(err) suite.mockProcessor.AssertExpectations(suite.T()) @@ -228,12 +237,13 @@ func (suite *DockerStatusActionTestSuite) TestContainerWithEmptyNames() { func (suite *DockerStatusActionTestSuite) TestContainerWithWhitespaceInNames() { expectedOutput := `{"ID":"abc123","Names":" container1 , container2 , container3 ","Image":"nginx:latest","Status":"Up 2 hours"}` logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json").Return(expectedOutput, nil) - err := action.Execute(suite.T().Context()) + err = action.Execute(suite.T().Context()) suite.NoError(err) suite.mockProcessor.AssertExpectations(suite.T()) @@ -249,12 +259,13 @@ func (suite *DockerStatusActionTestSuite) TestContainerWithWhitespaceInNames() { func (suite *DockerStatusActionTestSuite) TestContainerWithCommasInNames() { expectedOutput := `{"ID":"abc123","Names":"container1,container2,container3","Image":"nginx:latest","Status":"Up 2 hours"}` logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json").Return(expectedOutput, nil) - err := action.Execute(suite.T().Context()) + err = action.Execute(suite.T().Context()) suite.NoError(err) suite.mockProcessor.AssertExpectations(suite.T()) @@ -277,12 +288,13 @@ func (suite *DockerStatusActionTestSuite) TestAllContainerStates() { {"ID":"stu901","Names":"removing-container","Image":"nginx:latest","Status":"Removing"}` logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json").Return(expectedOutput, nil) - err := action.Execute(suite.T().Context()) + err = action.Execute(suite.T().Context()) suite.NoError(err) suite.mockProcessor.AssertExpectations(suite.T()) @@ -319,12 +331,13 @@ func (suite *DockerStatusActionTestSuite) TestRealisticDockerOutput() { {"ID":"feedcafe5678","Names":"/temp-container","Image":"busybox:latest","Status":"Dead"}` logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json").Return(expectedOutput, nil) - err := action.Execute(suite.T().Context()) + err = action.Execute(suite.T().Context()) suite.NoError(err) suite.mockProcessor.AssertExpectations(suite.T()) @@ -355,13 +368,14 @@ func (suite *DockerStatusActionTestSuite) TestRealisticDockerOutput() { func (suite *DockerStatusActionTestSuite) TestNonExistentContainer() { logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "non-existent-container"}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "non-existent-container"}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) // Docker returns empty output for non-existent containers suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json", "--filter", "name=non-existent-container").Return("", nil) - err := action.Execute(suite.T().Context()) + err = action.Execute(suite.T().Context()) suite.NoError(err) suite.mockProcessor.AssertExpectations(suite.T()) @@ -370,7 +384,8 @@ func (suite *DockerStatusActionTestSuite) TestNonExistentContainer() { func (suite *DockerStatusActionTestSuite) TestContextCancellation() { logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "test-container"}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "test-container"}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) ctx, cancel := context.WithCancel(context.Background()) @@ -378,7 +393,7 @@ func (suite *DockerStatusActionTestSuite) TestContextCancellation() { suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json", "--filter", "name=test-container").Return("", context.Canceled) - err := action.Execute(ctx) + err = action.Execute(ctx) suite.Error(err) suite.Contains(err.Error(), "failed to get container state") @@ -387,7 +402,8 @@ func (suite *DockerStatusActionTestSuite) TestContextCancellation() { func (suite *DockerStatusActionTestSuite) TestParseContainerOutputWithMissingRequiredFields() { logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "test-container"}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "test-container"}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) // Output with missing ID field @@ -396,7 +412,7 @@ func (suite *DockerStatusActionTestSuite) TestParseContainerOutputWithMissingReq suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json", "--filter", "name=test-container").Return(outputWithMissingID, nil) - err := action.Execute(suite.T().Context()) + err = action.Execute(suite.T().Context()) suite.NoError(err) suite.mockProcessor.AssertExpectations(suite.T()) @@ -406,7 +422,8 @@ func (suite *DockerStatusActionTestSuite) TestParseContainerOutputWithMissingReq func (suite *DockerStatusActionTestSuite) TestParseContainerOutputWithMissingStatusField() { logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "test-container"}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "test-container"}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) // Output with missing Status field @@ -415,7 +432,7 @@ func (suite *DockerStatusActionTestSuite) TestParseContainerOutputWithMissingSta suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json", "--filter", "name=test-container").Return(outputWithMissingStatus, nil) - err := action.Execute(suite.T().Context()) + err = action.Execute(suite.T().Context()) suite.NoError(err) suite.mockProcessor.AssertExpectations(suite.T()) @@ -425,7 +442,8 @@ func (suite *DockerStatusActionTestSuite) TestParseContainerOutputWithMissingSta func (suite *DockerStatusActionTestSuite) TestParseContainerOutputWithAllInvalidLines() { logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "test-container"}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "test-container"}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) // Output with all invalid lines (missing required fields) @@ -435,7 +453,7 @@ func (suite *DockerStatusActionTestSuite) TestParseContainerOutputWithAllInvalid suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json", "--filter", "name=test-container").Return(outputWithAllInvalid, nil) - err := action.Execute(suite.T().Context()) + err = action.Execute(suite.T().Context()) suite.Error(err) suite.Contains(err.Error(), "failed to parse any valid containers") @@ -445,7 +463,8 @@ func (suite *DockerStatusActionTestSuite) TestParseContainerOutputWithAllInvalid func (suite *DockerStatusActionTestSuite) TestParseContainerOutputWithTooManyErrors() { logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "test-container"}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "test-container"}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) // Output with more than 50% invalid lines (5 invalid, 3 valid = 62.5% error rate) @@ -460,7 +479,7 @@ func (suite *DockerStatusActionTestSuite) TestParseContainerOutputWithTooManyErr suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json", "--filter", "name=test-container").Return(outputWithTooManyErrors, nil) - err := action.Execute(suite.T().Context()) + err = action.Execute(suite.T().Context()) suite.Error(err) suite.Contains(err.Error(), "too many parsing errors") @@ -470,7 +489,8 @@ func (suite *DockerStatusActionTestSuite) TestParseContainerOutputWithTooManyErr func (suite *DockerStatusActionTestSuite) TestParseContainerOutputWithMixedValidAndInvalid() { logger := command_mock.NewDiscardLogger() - action := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "test-container"}) + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "test-container"}) + suite.NoError(err) action.Wrapped.SetCommandProcessor(suite.mockProcessor) // Output with some valid and some invalid lines (less than 50% errors) @@ -482,7 +502,7 @@ func (suite *DockerStatusActionTestSuite) TestParseContainerOutputWithMixedValid suite.mockProcessor.On("RunCommandWithContext", mock.Anything, "docker", "ps", "-a", "--format", "json", "--filter", "name=test-container").Return(outputWithMixed, nil) - err := action.Execute(suite.T().Context()) + err = action.Execute(suite.T().Context()) suite.NoError(err) suite.mockProcessor.AssertExpectations(suite.T()) diff --git a/actions/file/create_symlink_action.go b/actions/file/create_symlink_action.go index 6e89916..7f9e5a4 100644 --- a/actions/file/create_symlink_action.go +++ b/actions/file/create_symlink_action.go @@ -31,7 +31,7 @@ func NewCreateSymlinkAction(logger *slog.Logger) *CreateSymlinkAction { } // WithParameters sets the parameters for target, link path, overwrite flag, and create directories flag -func (a *CreateSymlinkAction) WithParameters(targetParam, linkPathParam task_engine.ActionParameter, overwrite, createDirs bool) *task_engine.Action[*CreateSymlinkAction] { +func (a *CreateSymlinkAction) WithParameters(targetParam, linkPathParam task_engine.ActionParameter, overwrite, createDirs bool) (*task_engine.Action[*CreateSymlinkAction], error) { a.TargetParam = targetParam a.LinkPathParam = linkPathParam a.Overwrite = overwrite @@ -41,7 +41,7 @@ func (a *CreateSymlinkAction) WithParameters(targetParam, linkPathParam task_eng ID: "create-symlink-action", Name: "Create Symlink", Wrapped: a, - } + }, nil } func (a *CreateSymlinkAction) Execute(execCtx context.Context) error { diff --git a/actions/file/create_symlink_action_test.go b/actions/file/create_symlink_action_test.go index c1223b6..d48be01 100644 --- a/actions/file/create_symlink_action_test.go +++ b/actions/file/create_symlink_action_test.go @@ -32,7 +32,8 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_Success() { // Create symlink linkPath := filepath.Join(suite.tempDir, "link.txt") - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, false) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, false) + suite.Require().NoError(err) err = action.Execute(context.Background()) suite.Require().NoError(err) @@ -53,7 +54,8 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_WithCreateDirs() { // Create symlink in a subdirectory that doesn't exist linkPath := filepath.Join(suite.tempDir, "subdir", "link.txt") - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, true) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, true) + suite.Require().NoError(err) err = action.Execute(context.Background()) suite.Require().NoError(err) @@ -74,7 +76,8 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_OverwriteExisting() // Create initial symlink linkPath := filepath.Join(suite.tempDir, "link.txt") - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, false) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, false) + suite.Require().NoError(err) err = action.Execute(context.Background()) suite.Require().NoError(err) @@ -83,7 +86,8 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_OverwriteExisting() suite.Require().NoError(err) // Overwrite the symlink - action = NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: newTargetFile}, task_engine.StaticParameter{Value: linkPath}, true, false) + action, err = NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: newTargetFile}, task_engine.StaticParameter{Value: linkPath}, true, false) + suite.Require().NoError(err) err = action.Execute(context.Background()) suite.Require().NoError(err) @@ -100,7 +104,8 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_RelativeTarget() { // Create symlink with relative target linkPath := filepath.Join(suite.tempDir, "link.txt") relativeTarget := "target.txt" - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: relativeTarget}, task_engine.StaticParameter{Value: linkPath}, false, false) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: relativeTarget}, task_engine.StaticParameter{Value: linkPath}, false, false) + suite.Require().NoError(err) err = action.Execute(context.Background()) suite.Require().NoError(err) info, err := os.Lstat(linkPath) @@ -123,7 +128,8 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_ToDirectory() { // Create symlink to directory linkPath := filepath.Join(suite.tempDir, "dir_link") - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetDir}, task_engine.StaticParameter{Value: linkPath}, false, false) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetDir}, task_engine.StaticParameter{Value: linkPath}, false, false) + suite.Require().NoError(err) err = action.Execute(context.Background()) suite.Require().NoError(err) info, err := os.Lstat(linkPath) @@ -141,8 +147,9 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_ToNonExistentTarget // Create symlink to non-existent target linkPath := filepath.Join(suite.tempDir, "link.txt") nonExistentTarget := filepath.Join(suite.tempDir, "nonexistent.txt") - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: nonExistentTarget}, task_engine.StaticParameter{Value: linkPath}, false, false) - err := action.Execute(context.Background()) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: nonExistentTarget}, task_engine.StaticParameter{Value: linkPath}, false, false) + suite.Require().NoError(err) + err = action.Execute(context.Background()) suite.Require().NoError(err) info, err := os.Lstat(linkPath) @@ -156,8 +163,9 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_InvalidTargetPath() linkPath := filepath.Join(suite.tempDir, "link.txt") invalidTarget := "" - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: invalidTarget}, task_engine.StaticParameter{Value: linkPath}, false, false) - err := action.Execute(context.Background()) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: invalidTarget}, task_engine.StaticParameter{Value: linkPath}, false, false) + suite.Require().NoError(err) + err = action.Execute(context.Background()) suite.Require().Error(err) } @@ -167,7 +175,8 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_InvalidLinkPath() { suite.Require().NoError(err) invalidLinkPath := "" - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: invalidLinkPath}, false, false) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: invalidLinkPath}, false, false) + suite.Require().NoError(err) err = action.Execute(context.Background()) suite.Require().Error(err) } @@ -177,7 +186,8 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_SameTargetAndLink() err := os.WriteFile(targetFile, []byte("content"), 0o600) suite.Require().NoError(err) - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: targetFile}, false, false) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: targetFile}, false, false) + suite.Require().NoError(err) err = action.Execute(context.Background()) suite.Require().Error(err) } @@ -188,12 +198,12 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_ExistingSymlinkNoOv // Create initial symlink linkPath := filepath.Join(suite.tempDir, "link.txt") - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, false) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, false) suite.Require().NoError(err) err = action.Execute(context.Background()) // Try to create symlink again without overwrite - action = NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, false) + action, err = NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, false) suite.Require().NoError(err) err = action.Execute(context.Background()) } @@ -207,7 +217,7 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_ExistingFileNoOverw err = os.WriteFile(linkPath, []byte("existing file"), 0o600) // Try to create symlink without overwrite - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, false) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, false) suite.Require().NoError(err) err = action.Execute(context.Background()) } @@ -221,7 +231,7 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_ExistingFileWithOve err = os.WriteFile(linkPath, []byte("existing file"), 0o600) // Create symlink with overwrite - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, true, false) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, true, false) suite.Require().NoError(err) err = action.Execute(context.Background()) info, err := os.Lstat(linkPath) @@ -238,7 +248,7 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_WithoutCreateDirs() // Try to create symlink in non-existent directory without createDirs linkPath := filepath.Join(suite.tempDir, "nonexistent", "link.txt") - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, false) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, false) suite.Require().NoError(err) err = action.Execute(context.Background()) } @@ -246,8 +256,9 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_WithoutCreateDirs() func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_CircularSymlink() { // Create a circular symlink (this should work, but accessing it will fail) linkPath := filepath.Join(suite.tempDir, "circular") - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: linkPath}, task_engine.StaticParameter{Value: linkPath}, false, false) - err := action.Execute(context.Background()) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: linkPath}, task_engine.StaticParameter{Value: linkPath}, false, false) + suite.Require().NoError(err) + err = action.Execute(context.Background()) suite.Require().NoError(err) } @@ -262,7 +273,8 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_ComplexRelativePath // Create symlink with complex relative path linkPath := filepath.Join(suite.tempDir, "link.txt") relativeTarget := "target_dir/target.txt" - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: relativeTarget}, task_engine.StaticParameter{Value: linkPath}, false, false) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: relativeTarget}, task_engine.StaticParameter{Value: linkPath}, false, false) + suite.Require().NoError(err) err = action.Execute(context.Background()) suite.Require().NoError(err) info, err := os.Lstat(linkPath) @@ -279,7 +291,8 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_VerifySymlinkCreati // Create symlink linkPath := filepath.Join(suite.tempDir, "link.txt") - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, false) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, false) + suite.Require().NoError(err) err = action.Execute(context.Background()) suite.Require().NoError(err) info, err := os.Lstat(linkPath) @@ -293,8 +306,9 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_VerifySymlinkCreati func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_EmptyTarget() { linkPath := filepath.Join(suite.tempDir, "link.txt") - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: ""}, task_engine.StaticParameter{Value: linkPath}, false, false) - err := action.Execute(context.Background()) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: ""}, task_engine.StaticParameter{Value: linkPath}, false, false) + suite.Require().NoError(err) + err = action.Execute(context.Background()) suite.Require().Error(err) } @@ -302,7 +316,8 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_EmptyLinkPath() { targetFile := filepath.Join(suite.tempDir, "target.txt") err := os.WriteFile(targetFile, []byte("content"), 0o600) - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: ""}, false, false) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: ""}, false, false) + suite.Require().NoError(err) err = action.Execute(context.Background()) suite.Require().Error(err) } @@ -318,7 +333,7 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_StatError() { err = os.MkdirAll(linkDir, 0o400) // Read-only directory linkPath := filepath.Join(linkDir, "link.txt") - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, false) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, false) suite.Require().NoError(err) // This should fail due to permission issues when trying to stat @@ -335,7 +350,7 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_DirectoryCreationFa // Try to create symlink in a subdirectory of the read-only directory linkPath := filepath.Join(readonlyDir, "subdir", "link.txt") - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, true) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, true) suite.Require().NoError(err) // This should fail due to permission issues when creating directories @@ -351,7 +366,7 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_SymlinkCreationFail err = os.MkdirAll(linkDir, 0o400) // Read-only directory linkPath := filepath.Join(linkDir, "link.txt") - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, false) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, false, false) suite.Require().NoError(err) // This should fail due to permission issues @@ -368,7 +383,7 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_VerifySymlinkTarget err = os.Symlink(wrongTarget, linkPath) // Try to create a symlink with the correct target - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, true, false) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, true, false) suite.Require().NoError(err) // This should succeed because overwrite is true @@ -388,7 +403,7 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_VerifySymlinkRelati err = os.Symlink(relativeTarget, linkPath) // Try to create a symlink with absolute target - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, true, false) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, true, false) suite.Require().NoError(err) // This should succeed and the verification should handle the path resolution @@ -412,7 +427,7 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_VerifySymlinkComple err = os.Symlink(complexRelativeTarget, linkPath) // Try to create a symlink with absolute target - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, true, false) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, true, false) suite.Require().NoError(err) // This should succeed and the verification should handle the complex path resolution @@ -434,7 +449,7 @@ func (suite *CreateSymlinkActionTestSuite) TestCreateSymlink_VerifySymlinkPathRe suite.Require().NoError(err) // Try to create a symlink with the correct target - action := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, true, false) + action, err := NewCreateSymlinkAction(nil).WithParameters(task_engine.StaticParameter{Value: targetFile}, task_engine.StaticParameter{Value: linkPath}, true, false) suite.Require().NoError(err) // This should succeed because overwrite is true diff --git a/actions/file/delete_path_action.go b/actions/file/delete_path_action.go index a4a95c9..536a349 100644 --- a/actions/file/delete_path_action.go +++ b/actions/file/delete_path_action.go @@ -38,7 +38,7 @@ func NewDeletePathAction(logger *slog.Logger) *DeletePathAction { } // WithParameters sets the parameters for path, recursive flag, dry run flag, include hidden flag, and exclude patterns -func (a *DeletePathAction) WithParameters(pathParam task_engine.ActionParameter, recursive, dryRun, includeHidden bool, excludePatterns []string) *task_engine.Action[*DeletePathAction] { +func (a *DeletePathAction) WithParameters(pathParam task_engine.ActionParameter, recursive, dryRun, includeHidden bool, excludePatterns []string) (*task_engine.Action[*DeletePathAction], error) { a.PathParam = pathParam a.Recursive = recursive a.DryRun = dryRun @@ -49,7 +49,7 @@ func (a *DeletePathAction) WithParameters(pathParam task_engine.ActionParameter, ID: "delete-path-action", Name: "Delete Path", Wrapped: a, - } + }, nil } func (a *DeletePathAction) Execute(execCtx context.Context) error { diff --git a/actions/file/delete_path_action_test.go b/actions/file/delete_path_action_test.go index 7abdbcb..ba71dd8 100644 --- a/actions/file/delete_path_action_test.go +++ b/actions/file/delete_path_action_test.go @@ -27,7 +27,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_Success() { err := os.WriteFile(filePath, []byte("test content"), 0o600) suite.NoError(err) - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: filePath}, false, false, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: filePath}, false, false, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) suite.NoError(err) @@ -38,8 +39,9 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_Success() { func (suite *DeletePathActionTestSuite) TestDeletePath_FileNotExists() { filePath := filepath.Join(suite.tempDir, "nonexistent.txt") - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: filePath}, false, false, false, nil) - err := deleteAction.Execute(context.Background()) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: filePath}, false, false, false, nil) + suite.NoError(err) + err = deleteAction.Execute(context.Background()) suite.NoError(err) } @@ -48,7 +50,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_PermissionDenied() { err := os.WriteFile(filePath, []byte("content"), 0o400) suite.NoError(err) - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: filePath}, false, false, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: filePath}, false, false, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) // os.RemoveAll can delete read-only files, so this should succeed suite.NoError(err) @@ -62,7 +65,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_DirectoryWithoutRecursive err := os.MkdirAll(dirPath, 0o750) suite.NoError(err) - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, false, false, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, false, false, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) suite.Error(err) } @@ -77,7 +81,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_DirectoryWithRecursive() err = os.WriteFile(filePath, []byte("content"), 0o600) suite.NoError(err) - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) suite.NoError(err) @@ -103,7 +108,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_RecursiveWithNestedDirect err = os.WriteFile(file2, []byte("content2"), 0o600) suite.NoError(err) - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) suite.NoError(err) @@ -122,7 +128,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_RecursiveWithSymlinks() { err = os.Symlink(filePath, symlinkPath) suite.NoError(err) - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) suite.NoError(err) @@ -140,7 +147,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_RecursiveWithBrokenSymlin err = os.Symlink("/nonexistent/path", brokenLink) suite.NoError(err) - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) suite.NoError(err) @@ -156,7 +164,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_RecursiveWithSpecialFiles err = os.WriteFile(regularFile, []byte("regular content"), 0o600) suite.NoError(err) - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) suite.NoError(err) @@ -182,7 +191,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_RecursiveWithHiddenFiles( err = os.WriteFile(hiddenNestedFile, []byte("nested content"), 0o600) suite.NoError(err) - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) suite.NoError(err) @@ -208,7 +218,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_RecursiveWithDeepNesting( suite.NoError(err) } - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) suite.NoError(err) @@ -228,7 +239,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_RecursiveWithPermissionEr err = os.Chmod(dirPath, 0o555) suite.NoError(err) - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) suite.Error(err) os.Chmod(dirPath, 0o755) @@ -247,7 +259,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_RecursiveWithDirectoryDel err = os.Chmod(dirPath, 0o555) suite.NoError(err) - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) // Note: os.RemoveAll can sometimes succeed even with permission issues // This test may pass or fail depending on the system, which is acceptable @@ -269,7 +282,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_RecursiveWithRootDirector err = os.Chmod(dirPath, 0o555) suite.NoError(err) - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) suite.Error(err) os.Chmod(dirPath, 0o755) @@ -280,7 +294,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_EmptyDirectory() { err := os.MkdirAll(dirPath, 0o750) suite.NoError(err) - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) suite.NoError(err) @@ -300,7 +315,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_LargeDirectory() { suite.NoError(err) } - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) suite.NoError(err) @@ -310,8 +326,9 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_LargeDirectory() { func (suite *DeletePathActionTestSuite) TestNewDeletePathAction_InvalidParameters() { logger := mocks.NewDiscardLogger() - action := file.NewDeletePathAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, false, false, false, nil) - err := action.Execute(context.Background()) + action, err := file.NewDeletePathAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}, false, false, false, nil) + suite.NoError(err) + err = action.Execute(context.Background()) suite.Error(err) } @@ -321,7 +338,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_SpecialCharacters() { err := os.WriteFile(filePath, []byte("content"), 0o600) suite.NoError(err) - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: filePath}, false, false, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: filePath}, false, false, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) suite.NoError(err) @@ -341,7 +359,7 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_ConcurrentAccess() { suite.NoError(err) } - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, false, false, nil) // Simulate concurrent access by modifying files during deletion // This is a basic test - in real scenarios, you might use goroutines @@ -357,7 +375,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_DryRunFile() { err := os.WriteFile(filePath, []byte("test content"), 0o600) suite.NoError(err) - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: filePath}, false, true, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: filePath}, false, true, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) suite.NoError(err) @@ -376,7 +395,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_DryRunDirectory() { err = os.WriteFile(filePath, []byte("content"), 0o600) suite.NoError(err) - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, true, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, true, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) suite.NoError(err) @@ -410,7 +430,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_DryRunWithNestedStructure err = os.Symlink(file1, symlinkPath) suite.NoError(err) - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, true, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, true, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) suite.NoError(err) @@ -443,7 +464,8 @@ func (suite *DeletePathActionTestSuite) TestDeletePath_DryRunWithSymlinks() { err = os.Symlink("/nonexistent/path", brokenLink) suite.NoError(err) - deleteAction := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, true, false, nil) + deleteAction, err := file.NewDeletePathAction(nil).WithParameters(task_engine.StaticParameter{Value: dirPath}, true, true, false, nil) + suite.NoError(err) err = deleteAction.Execute(context.Background()) suite.NoError(err) diff --git a/actions/file/move_file_action.go b/actions/file/move_file_action.go index 49fa5ae..23bf61f 100644 --- a/actions/file/move_file_action.go +++ b/actions/file/move_file_action.go @@ -24,7 +24,7 @@ func NewMoveFileAction(logger *slog.Logger) *MoveFileAction { } // WithParameters sets the parameters for source, destination, and create directories flag -func (a *MoveFileAction) WithParameters(sourceParam, destinationParam task_engine.ActionParameter, createDirs bool) *task_engine.Action[*MoveFileAction] { +func (a *MoveFileAction) WithParameters(sourceParam, destinationParam task_engine.ActionParameter, createDirs bool) (*task_engine.Action[*MoveFileAction], error) { a.SourceParam = sourceParam a.DestinationParam = destinationParam a.CreateDirs = createDirs @@ -33,7 +33,7 @@ func (a *MoveFileAction) WithParameters(sourceParam, destinationParam task_engin ID: "move-file-action", Name: "Move File", Wrapped: a, - } + }, nil } type MoveFileAction struct { diff --git a/actions/file/move_file_action_test.go b/actions/file/move_file_action_test.go index c49dd85..7c73118 100644 --- a/actions/file/move_file_action_test.go +++ b/actions/file/move_file_action_test.go @@ -40,12 +40,13 @@ func (suite *MoveFileTestSuite) TearDownTest() { func (suite *MoveFileTestSuite) TestNewMoveFileAction_ValidInputs() { logger := command_mock.NewDiscardLogger() destination := filepath.Join(suite.tempDir, "destination.txt") - action := file.NewMoveFileAction(logger).WithParameters( + action, err := file.NewMoveFileAction(logger).WithParameters( task_engine.StaticParameter{Value: suite.tempFile}, task_engine.StaticParameter{Value: destination}, false, ) + suite.NoError(err) suite.NotNil(action) suite.Equal("move-file-action", action.ID) } @@ -55,34 +56,37 @@ func (suite *MoveFileTestSuite) TestNewMoveFileAction_InvalidInputs() { destination := filepath.Join(suite.tempDir, "destination.txt") { - action := file.NewMoveFileAction(logger).WithParameters( + action, err := file.NewMoveFileAction(logger).WithParameters( task_engine.StaticParameter{Value: ""}, task_engine.StaticParameter{Value: destination}, false, ) + suite.NoError(err) // Execute to trigger validation error action.Wrapped.SetCommandRunner(suite.mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.Error(err) } { - action := file.NewMoveFileAction(logger).WithParameters( + action, err := file.NewMoveFileAction(logger).WithParameters( task_engine.StaticParameter{Value: suite.tempFile}, task_engine.StaticParameter{Value: ""}, false, ) + suite.NoError(err) action.Wrapped.SetCommandRunner(suite.mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.Error(err) } { - action := file.NewMoveFileAction(logger).WithParameters( + action, err := file.NewMoveFileAction(logger).WithParameters( task_engine.StaticParameter{Value: suite.tempFile}, task_engine.StaticParameter{Value: suite.tempFile}, false, ) + suite.NoError(err) action.Wrapped.SetCommandRunner(suite.mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.Error(err) } } @@ -90,16 +94,17 @@ func (suite *MoveFileTestSuite) TestNewMoveFileAction_InvalidInputs() { func (suite *MoveFileTestSuite) TestExecute_SimpleMove() { logger := command_mock.NewDiscardLogger() destination := filepath.Join(suite.tempDir, "destination.txt") - action := file.NewMoveFileAction(logger).WithParameters( + action, err := file.NewMoveFileAction(logger).WithParameters( task_engine.StaticParameter{Value: suite.tempFile}, task_engine.StaticParameter{Value: destination}, false, ) + suite.NoError(err) action.Wrapped.SetCommandRunner(suite.mockRunner) suite.mockRunner.On("RunCommandWithContext", context.Background(), "mv", suite.tempFile, destination).Return("", nil) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.mockRunner.AssertExpectations(suite.T()) @@ -108,16 +113,17 @@ func (suite *MoveFileTestSuite) TestExecute_SimpleMove() { func (suite *MoveFileTestSuite) TestExecute_WithCreateDirs() { logger := command_mock.NewDiscardLogger() destination := filepath.Join(suite.tempDir, "subdir", "destination.txt") - action := file.NewMoveFileAction(logger).WithParameters( + action, err := file.NewMoveFileAction(logger).WithParameters( task_engine.StaticParameter{Value: suite.tempFile}, task_engine.StaticParameter{Value: destination}, true, ) + suite.NoError(err) action.Wrapped.SetCommandRunner(suite.mockRunner) suite.mockRunner.On("RunCommandWithContext", context.Background(), "mv", suite.tempFile, destination).Return("", nil) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.mockRunner.AssertExpectations(suite.T()) @@ -129,14 +135,15 @@ func (suite *MoveFileTestSuite) TestExecute_WithCreateDirs() { func (suite *MoveFileTestSuite) TestExecute_NonExistentSource() { logger := command_mock.NewDiscardLogger() destination := filepath.Join(suite.tempDir, "destination.txt") - action := file.NewMoveFileAction(logger).WithParameters( + action, err := file.NewMoveFileAction(logger).WithParameters( task_engine.StaticParameter{Value: "/nonexistent/source.txt"}, task_engine.StaticParameter{Value: destination}, false, ) + suite.NoError(err) action.Wrapped.SetCommandRunner(suite.mockRunner) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.Error(err) suite.Contains(err.Error(), "source path does not exist") @@ -145,16 +152,17 @@ func (suite *MoveFileTestSuite) TestExecute_NonExistentSource() { func (suite *MoveFileTestSuite) TestExecute_CommandFailure() { logger := command_mock.NewDiscardLogger() destination := filepath.Join(suite.tempDir, "destination.txt") - action := file.NewMoveFileAction(logger).WithParameters( + action, err := file.NewMoveFileAction(logger).WithParameters( task_engine.StaticParameter{Value: suite.tempFile}, task_engine.StaticParameter{Value: destination}, false, ) + suite.NoError(err) action.Wrapped.SetCommandRunner(suite.mockRunner) suite.mockRunner.On("RunCommandWithContext", context.Background(), "mv", suite.tempFile, destination).Return("permission denied", assert.AnError) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.Error(err) suite.Contains(err.Error(), "failed to move") @@ -164,16 +172,17 @@ func (suite *MoveFileTestSuite) TestExecute_CommandFailure() { func (suite *MoveFileTestSuite) TestExecute_RenameFile() { logger := command_mock.NewDiscardLogger() destination := filepath.Join(suite.tempDir, "renamed.txt") - action := file.NewMoveFileAction(logger).WithParameters( + action, err := file.NewMoveFileAction(logger).WithParameters( task_engine.StaticParameter{Value: suite.tempFile}, task_engine.StaticParameter{Value: destination}, false, ) + suite.NoError(err) action.Wrapped.SetCommandRunner(suite.mockRunner) suite.mockRunner.On("RunCommandWithContext", context.Background(), "mv", suite.tempFile, destination).Return("", nil) - err := action.Wrapped.Execute(context.Background()) + err = action.Wrapped.Execute(context.Background()) suite.NoError(err) suite.mockRunner.AssertExpectations(suite.T()) diff --git a/actions/file/replace_lines_action.go b/actions/file/replace_lines_action.go index 062ab8d..0c6eb23 100644 --- a/actions/file/replace_lines_action.go +++ b/actions/file/replace_lines_action.go @@ -30,7 +30,7 @@ func NewReplaceLinesAction(logger *slog.Logger) *ReplaceLinesAction { } // WithParameters sets the parameters for file path and replacement patterns -func (a *ReplaceLinesAction) WithParameters(filePathParam task_engine.ActionParameter, replaceParamPatterns map[*regexp.Regexp]task_engine.ActionParameter) *task_engine.Action[*ReplaceLinesAction] { +func (a *ReplaceLinesAction) WithParameters(filePathParam task_engine.ActionParameter, replaceParamPatterns map[*regexp.Regexp]task_engine.ActionParameter) (*task_engine.Action[*ReplaceLinesAction], error) { a.FilePathParam = filePathParam a.ReplaceParamPatterns = replaceParamPatterns @@ -38,7 +38,7 @@ func (a *ReplaceLinesAction) WithParameters(filePathParam task_engine.ActionPara ID: "replace-lines-action", Name: "Replace Lines", Wrapped: a, - } + }, nil } func (a *ReplaceLinesAction) Execute(ctx context.Context) error { diff --git a/actions/file/replace_lines_action_test.go b/actions/file/replace_lines_action_test.go index 7453642..0f7926b 100644 --- a/actions/file/replace_lines_action_test.go +++ b/actions/file/replace_lines_action_test.go @@ -138,7 +138,8 @@ func (suite *ReplaceLinesTestSuite) TestWithParameters() { patterns := make(map[*regexp.Regexp]engine.ActionParameter) patterns[regexp.MustCompile(`test`)] = engine.StaticParameter{Value: "replacement"} - wrappedAction := action.WithParameters(filePath, patterns) + wrappedAction, err := action.WithParameters(filePath, patterns) + suite.NoError(err) suite.NotNil(wrappedAction) suite.Equal("replace-lines-action", wrappedAction.ID) suite.Equal("Replace Lines", wrappedAction.Name) @@ -150,7 +151,8 @@ func (suite *ReplaceLinesTestSuite) TestWithParametersNilParams() { logger := command_mock.NewDiscardLogger() action := file.NewReplaceLinesAction(logger) - wrappedAction := action.WithParameters(nil, nil) + wrappedAction, err := action.WithParameters(nil, nil) + suite.NoError(err) suite.NotNil(wrappedAction) suite.Nil(wrappedAction.Wrapped.FilePathParam) suite.Nil(wrappedAction.Wrapped.ReplaceParamPatterns) @@ -171,7 +173,8 @@ func (suite *ReplaceLinesTestSuite) TestExecuteWithFilePathParameter() { patterns[regexp.MustCompile(`^interface=.*$`)] = engine.StaticParameter{Value: "interface=eth0"} patterns[regexp.MustCompile(`^server=.*$`)] = engine.StaticParameter{Value: "server=new"} - wrappedAction := action.WithParameters(filePathParam, patterns) + wrappedAction, err := action.WithParameters(filePathParam, patterns) + suite.NoError(err) // Create context with global context for parameter resolution gc := &engine.GlobalContext{} diff --git a/tasks/example_docker_load_operations.go b/tasks/example_docker_load_operations.go index 0e1c9e3..af48e3f 100644 --- a/tasks/example_docker_load_operations.go +++ b/tasks/example_docker_load_operations.go @@ -17,28 +17,44 @@ func NewDockerLoadTask(logger *slog.Logger) *task_engine.Task { Actions: []task_engine.ActionWrapper{ // Example 1: Basic image load from tar file func() task_engine.ActionWrapper { - action := docker.NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: "/path/to/nginx.tar"}) + action, err := docker.NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: "/path/to/nginx.tar"}) + if err != nil { + logger.Error("Failed to create docker load action", "error", err) + return nil + } return action }(), // Example 2: Load with platform specification func() task_engine.ActionWrapper { - action := docker.NewDockerLoadAction(logger).WithOptions(docker.WithPlatform("linux/amd64")).WithParameters(task_engine.StaticParameter{Value: "/path/to/multi-platform.tar"}) + action, err := docker.NewDockerLoadAction(logger).WithOptions(docker.WithPlatform("linux/amd64")).WithParameters(task_engine.StaticParameter{Value: "/path/to/multi-platform.tar"}) + if err != nil { + logger.Error("Failed to create docker load action", "error", err) + return nil + } return action }(), // Example 3: Load with quiet mode func() task_engine.ActionWrapper { - action := docker.NewDockerLoadAction(logger).WithOptions(docker.WithQuiet()).WithParameters(task_engine.StaticParameter{Value: "/path/to/redis.tar"}) + action, err := docker.NewDockerLoadAction(logger).WithOptions(docker.WithQuiet()).WithParameters(task_engine.StaticParameter{Value: "/path/to/redis.tar"}) + if err != nil { + logger.Error("Failed to create docker load action", "error", err) + return nil + } return action }(), // Example 4: Load with both platform and quiet options func() task_engine.ActionWrapper { - action := docker.NewDockerLoadAction(logger).WithOptions( + action, err := docker.NewDockerLoadAction(logger).WithOptions( docker.WithPlatform("linux/arm64"), docker.WithQuiet(), ).WithParameters(task_engine.StaticParameter{Value: "/path/to/postgres.tar"}) + if err != nil { + logger.Error("Failed to create docker load action", "error", err) + return nil + } return action }(), }, @@ -73,10 +89,38 @@ func NewDockerLoadBatchTask(logger *slog.Logger) *task_engine.Task { Name: "Docker Load Batch Operations Example", Actions: []task_engine.ActionWrapper{ // Load multiple images in sequence - docker.NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: "/images/nginx.tar"}), - docker.NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: "/images/redis.tar"}), - docker.NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: "/images/postgres.tar"}), - docker.NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: "/images/node.tar"}), + func() task_engine.ActionWrapper { + action, err := docker.NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: "/images/nginx.tar"}) + if err != nil { + logger.Error("Failed to create docker load action", "error", err) + return nil + } + return action + }(), + func() task_engine.ActionWrapper { + action, err := docker.NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: "/images/redis.tar"}) + if err != nil { + logger.Error("Failed to create docker load action", "error", err) + return nil + } + return action + }(), + func() task_engine.ActionWrapper { + action, err := docker.NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: "/images/postgres.tar"}) + if err != nil { + logger.Error("Failed to create docker load action", "error", err) + return nil + } + return action + }(), + func() task_engine.ActionWrapper { + action, err := docker.NewDockerLoadAction(logger).WithParameters(task_engine.StaticParameter{Value: "/images/node.tar"}) + if err != nil { + logger.Error("Failed to create docker load action", "error", err) + return nil + } + return action + }(), }, Logger: logger, } @@ -109,12 +153,40 @@ func NewDockerLoadPlatformSpecificTask(logger *slog.Logger) *task_engine.Task { Name: "Docker Load Platform-Specific Operations Example", Actions: []task_engine.ActionWrapper{ // Load AMD64 images - docker.NewDockerLoadAction(logger).WithOptions(docker.WithPlatform("linux/amd64")).WithParameters(task_engine.StaticParameter{Value: "/images/amd64/nginx.tar"}), - docker.NewDockerLoadAction(logger).WithOptions(docker.WithPlatform("linux/amd64")).WithParameters(task_engine.StaticParameter{Value: "/images/amd64/redis.tar"}), + func() task_engine.ActionWrapper { + action, err := docker.NewDockerLoadAction(logger).WithOptions(docker.WithPlatform("linux/amd64")).WithParameters(task_engine.StaticParameter{Value: "/images/amd64/nginx.tar"}) + if err != nil { + logger.Error("Failed to create docker load action", "error", err) + return nil + } + return action + }(), + func() task_engine.ActionWrapper { + action, err := docker.NewDockerLoadAction(logger).WithOptions(docker.WithPlatform("linux/amd64")).WithParameters(task_engine.StaticParameter{Value: "/images/amd64/redis.tar"}) + if err != nil { + logger.Error("Failed to create docker load action", "error", err) + return nil + } + return action + }(), // Load ARM64 images - docker.NewDockerLoadAction(logger).WithOptions(docker.WithPlatform("linux/arm64")).WithParameters(task_engine.StaticParameter{Value: "/images/arm64/nginx.tar"}), - docker.NewDockerLoadAction(logger).WithOptions(docker.WithPlatform("linux/arm64")).WithParameters(task_engine.StaticParameter{Value: "/images/arm64/redis.tar"}), + func() task_engine.ActionWrapper { + action, err := docker.NewDockerLoadAction(logger).WithOptions(docker.WithPlatform("linux/arm64")).WithParameters(task_engine.StaticParameter{Value: "/images/arm64/nginx.tar"}) + if err != nil { + logger.Error("Failed to create docker load action", "error", err) + return nil + } + return action + }(), + func() task_engine.ActionWrapper { + action, err := docker.NewDockerLoadAction(logger).WithOptions(docker.WithPlatform("linux/arm64")).WithParameters(task_engine.StaticParameter{Value: "/images/arm64/redis.tar"}) + if err != nil { + logger.Error("Failed to create docker load action", "error", err) + return nil + } + return action + }(), }, Logger: logger, } diff --git a/tasks/example_docker_status_operations.go b/tasks/example_docker_status_operations.go index 5ff08ba..3d3d0fd 100644 --- a/tasks/example_docker_status_operations.go +++ b/tasks/example_docker_status_operations.go @@ -16,12 +16,40 @@ func NewDockerStatusTask(logger *slog.Logger) *task_engine.Task { Name: "Container State Operations Example", Actions: []task_engine.ActionWrapper{ // Example 1: Get state of all containers (empty param -> all) - docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}), + func() task_engine.ActionWrapper { + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + if err != nil { + logger.Error("Failed to create docker status action", "error", err) + return nil + } + return action + }(), // Example 2: Get state of specific containers by name (run twice) - docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "nginx"}), - docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "redis"}), + func() task_engine.ActionWrapper { + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "nginx"}) + if err != nil { + logger.Error("Failed to create docker status action", "error", err) + return nil + } + return action + }(), + func() task_engine.ActionWrapper { + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "redis"}) + if err != nil { + logger.Error("Failed to create docker status action", "error", err) + return nil + } + return action + }(), // Example 3: Get state of a single container - docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "my-app"}), + func() task_engine.ActionWrapper { + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "my-app"}) + if err != nil { + logger.Error("Failed to create docker status action", "error", err) + return nil + } + return action + }(), }, Logger: logger, } @@ -57,7 +85,14 @@ func NewDockerStatusFilteringTask(logger *slog.Logger) *task_engine.Task { Name: "Docker Status Filtering Example", Actions: []task_engine.ActionWrapper{ // Get all containers - docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}), + func() task_engine.ActionWrapper { + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: ""}) + if err != nil { + logger.Error("Failed to create docker status action", "error", err) + return nil + } + return action + }(), }, Logger: logger, } @@ -90,9 +125,30 @@ func NewDockerStatusMonitoringTask(logger *slog.Logger) *task_engine.Task { Name: "Docker Status Monitoring Example", Actions: []task_engine.ActionWrapper{ // Get state of critical containers - docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "web-server"}), - docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "database"}), - docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "cache"}), + func() task_engine.ActionWrapper { + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "web-server"}) + if err != nil { + logger.Error("Failed to create docker status action", "error", err) + return nil + } + return action + }(), + func() task_engine.ActionWrapper { + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "database"}) + if err != nil { + logger.Error("Failed to create docker status action", "error", err) + return nil + } + return action + }(), + func() task_engine.ActionWrapper { + action, err := docker.NewGetContainerStateAction(logger).WithParameters(task_engine.StaticParameter{Value: "cache"}) + if err != nil { + logger.Error("Failed to create docker status action", "error", err) + return nil + } + return action + }(), }, Logger: logger, } diff --git a/tasks/example_file_operations.go b/tasks/example_file_operations.go index 2054af1..4376d13 100644 --- a/tasks/example_file_operations.go +++ b/tasks/example_file_operations.go @@ -75,23 +75,31 @@ func NewFileOperationsTask(logger *slog.Logger, workingDir string) *engine.Task // Step 5: Replace placeholder text in the source file func() engine.ActionWrapper { - action := file.NewReplaceLinesAction(logger).WithParameters( + action, err := file.NewReplaceLinesAction(logger).WithParameters( engine.StaticParameter{Value: workingDir + "/src/main.go"}, map[*regexp.Regexp]engine.ActionParameter{ regexp.MustCompile("TODO: implement main logic"): engine.StaticParameter{Value: "fmt.Println(\"Hello, Task Engine!\")"}, }, ) + if err != nil { + logger.Error("Failed to create replace lines action", "error", err) + return nil + } return action }(), // Step 6: Replace configuration values func() engine.ActionWrapper { - action := file.NewReplaceLinesAction(logger).WithParameters( + action, err := file.NewReplaceLinesAction(logger).WithParameters( engine.StaticParameter{Value: workingDir + "/config.json"}, map[*regexp.Regexp]engine.ActionParameter{ regexp.MustCompile("\"development\""): engine.StaticParameter{Value: "\"production\""}, }, ) + if err != nil { + logger.Error("Failed to create replace lines action", "error", err) + return nil + } return action }(), @@ -127,13 +135,17 @@ func NewFileOperationsTask(logger *slog.Logger, workingDir string) *engine.Task // Step 9: Clean up temporary file func() engine.ActionWrapper { - action := file.NewDeletePathAction(logger).WithParameters( + action, err := file.NewDeletePathAction(logger).WithParameters( engine.StaticParameter{Value: workingDir + "/tmp/test.txt"}, false, false, false, nil, ) + if err != nil { + logger.Error("Failed to create delete path action", "error", err) + return nil + } return action }(), }, diff --git a/tasks/example_symlink_operations.go b/tasks/example_symlink_operations.go index 9e61c85..8e49fdc 100644 --- a/tasks/example_symlink_operations.go +++ b/tasks/example_symlink_operations.go @@ -26,12 +26,16 @@ func ExampleSymlinkOperations() { return } - createSymlinkAction := file.NewCreateSymlinkAction(logger).WithParameters( + createSymlinkAction, err := file.NewCreateSymlinkAction(logger).WithParameters( task_engine.StaticParameter{Value: "/tmp/source.txt"}, task_engine.StaticParameter{Value: "/tmp/link.txt"}, false, false, ) + if err != nil { + logger.Error("Failed to create symlink action", "error", err) + return + } // builder returns action only; errors occur at execution // Example 2: Create a symlink to a directory @@ -44,39 +48,55 @@ func ExampleSymlinkOperations() { return } - createDirSymlinkAction := file.NewCreateSymlinkAction(logger).WithParameters( + createDirSymlinkAction, err := file.NewCreateSymlinkAction(logger).WithParameters( task_engine.StaticParameter{Value: "/tmp/source_dir"}, task_engine.StaticParameter{Value: "/tmp/dir_link"}, false, false, ) + if err != nil { + logger.Error("Failed to create symlink action", "error", err) + return + } // builder returns action only; errors occur at execution // Example 3: Create a symlink with overwrite - createOverwriteSymlinkAction := file.NewCreateSymlinkAction(logger).WithParameters( + createOverwriteSymlinkAction, err := file.NewCreateSymlinkAction(logger).WithParameters( task_engine.StaticParameter{Value: "/tmp/source.txt"}, task_engine.StaticParameter{Value: "/tmp/overwrite_link.txt"}, true, false, ) + if err != nil { + logger.Error("Failed to create symlink action", "error", err) + return + } // builder returns action only; errors occur at execution // Example 4: Create a symlink with directory creation - createSymlinkWithDirsAction := file.NewCreateSymlinkAction(logger).WithParameters( + createSymlinkWithDirsAction, err := file.NewCreateSymlinkAction(logger).WithParameters( task_engine.StaticParameter{Value: "/tmp/source.txt"}, task_engine.StaticParameter{Value: "/tmp/nested/dirs/link.txt"}, false, true, ) + if err != nil { + logger.Error("Failed to create symlink action", "error", err) + return + } // builder returns action only; errors occur at execution // Example 5: Create a relative symlink - createRelativeSymlinkAction := file.NewCreateSymlinkAction(logger).WithParameters( + createRelativeSymlinkAction, err := file.NewCreateSymlinkAction(logger).WithParameters( task_engine.StaticParameter{Value: "source.txt"}, task_engine.StaticParameter{Value: "/tmp/relative_link.txt"}, false, false, ) + if err != nil { + logger.Error("Failed to create symlink action", "error", err) + return + } // builder returns action only; errors occur at execution // Create a task @@ -116,35 +136,47 @@ func ExampleSymlinkErrorHandling() { logger := slog.Default() // Example 1: Try to create symlink with empty target (should fail) - _ = file.NewCreateSymlinkAction(logger).WithParameters( + _, err := file.NewCreateSymlinkAction(logger).WithParameters( task_engine.StaticParameter{Value: ""}, task_engine.StaticParameter{Value: "/tmp/link.txt"}, false, false, ) + if err != nil { + logger.Error("Failed to create symlink action", "error", err) + return + } // execution-time error expected, not at build time // Example 2: Try to create symlink with empty link path (should fail) - _ = file.NewCreateSymlinkAction(logger).WithParameters( + _, err = file.NewCreateSymlinkAction(logger).WithParameters( task_engine.StaticParameter{Value: "/tmp/source.txt"}, task_engine.StaticParameter{Value: ""}, false, false, ) + if err != nil { + logger.Error("Failed to create symlink action", "error", err) + return + } // execution-time error expected, not at build time // Example 3: Try to create symlink with same target and link (should fail) - _ = file.NewCreateSymlinkAction(logger).WithParameters( + _, err = file.NewCreateSymlinkAction(logger).WithParameters( task_engine.StaticParameter{Value: "/tmp/source.txt"}, task_engine.StaticParameter{Value: "/tmp/source.txt"}, false, false, ) + if err != nil { + logger.Error("Failed to create symlink action", "error", err) + return + } // execution-time error expected, not at build time // Example 4: Try to create symlink without overwrite when target exists // First create a file - _, err := file.NewWriteFileAction(logger).WithParameters( + _, err = file.NewWriteFileAction(logger).WithParameters( task_engine.StaticParameter{Value: "/tmp/existing.txt"}, task_engine.StaticParameter{Value: []byte("content")}, false, @@ -152,12 +184,16 @@ func ExampleSymlinkErrorHandling() { ) if err == nil { // Then try to create a symlink at the same location without overwrite - _ = file.NewCreateSymlinkAction(logger).WithParameters( + _, err = file.NewCreateSymlinkAction(logger).WithParameters( task_engine.StaticParameter{Value: "/tmp/source.txt"}, task_engine.StaticParameter{Value: "/tmp/existing.txt"}, false, false, ) + if err != nil { + logger.Error("Failed to create symlink action", "error", err) + return + } // This will fail during execution if run }