diff --git a/runatlantis.io/docs/post-workflow-hooks.md b/runatlantis.io/docs/post-workflow-hooks.md index 16e043a68e..a25163bfc0 100644 --- a/runatlantis.io/docs/post-workflow-hooks.md +++ b/runatlantis.io/docs/post-workflow-hooks.md @@ -6,7 +6,7 @@ workflows](custom-workflows.html#custom-run-command) in that they are run outside of Atlantis commands. Which means they do not surface their output back to the PR as a comment. -Post workflow hooks also only allow `run` commands. +Post workflow hooks also only allow `run` and `description` commands. [[toc]] @@ -40,6 +40,7 @@ repos: workflow: myworkflow post_workflow_hooks: - run: infracost output --path=/tmp/$BASE_REPO_OWNER-$BASE_REPO_NAME-$PULL_NUM-*-infracost.json --format=github-comment --out-file=/tmp/infracost-comment.md + description: Running infracost # Now report the output as desired, e.g. post to GitHub as a comment. # ... ``` @@ -55,9 +56,10 @@ command](custom-workflows.html#custom-run-command). - run: custom-command ``` -| Key | Type | Default | Required | Description | -| --- | ------ | ------- | -------- | -------------------- | -| run | string | none | no | Run a custom command | +| Key | Type | Default | Required | Description | +| ----------- | ------ | ------- | -------- | --------------------- | +| run | string | none | no | Run a custom command | +| description | string | none | no | Post hook description | ::: tip Notes * `run` commands are executed with the following environment variables: @@ -74,4 +76,5 @@ command](custom-workflows.html#custom-run-command). * `USER_NAME` - Username of the VCS user running command, ex. `acme-user`. During an autoplan, the user will be the Atlantis API user, ex. `atlantis`. * `COMMENT_ARGS` - Any additional flags passed in the comment on the pull request. Flags are separated by commas and every character is escaped, ex. `atlantis plan -- arg1 arg2` will result in `COMMENT_ARGS=\a\r\g\1,\a\r\g\2`. + * `OUTPUT_STATUS_FILE` - An output file to customize the success or failure status. ex. `echo 'failure' > $OUTPUT_STATUS_FILE`. ::: diff --git a/runatlantis.io/docs/pre-workflow-hooks.md b/runatlantis.io/docs/pre-workflow-hooks.md index b3b410f156..d90eac7dc8 100644 --- a/runatlantis.io/docs/pre-workflow-hooks.md +++ b/runatlantis.io/docs/pre-workflow-hooks.md @@ -8,7 +8,7 @@ workflows](custom-workflows.html#custom-run-command) in several ways. present. This be utilized to [dynamically generate repo configs](pre-workflow-hooks.html#dynamic-repo-config-generation). 2. Pre workflow hooks are run outside of Atlantis commands. Which means they do not surface their output back to the PR as a comment. -3. Pre workflow hooks only allow `run` commands. +3. Pre workflow hooks only allow `run` and `description` commands. [[toc]] @@ -31,6 +31,7 @@ repos: - id: /.*/ pre_workflow_hooks: - run: ./repo-config-generator.sh + description: Generating configs ``` ## Reference ### Custom `run` Command @@ -39,9 +40,10 @@ command](custom-workflows.html#custom-run-command). ```yaml - run: custom-command ``` -| Key | Type | Default | Required | Description | -| --- | ------ | ------- | -------- | -------------------- | -| run | string | none | no | Run a custom command | +| Key | Type | Default | Required | Description | +| ----------- | ------ | ------- | -------- | -------------------- | +| run | string | none | no | Run a custom command | +| description | string | none | no | Pre hook description | ::: tip Notes * `run` commands are executed with the following environment variables: @@ -58,5 +60,6 @@ command](custom-workflows.html#custom-run-command). * `USER_NAME` - Username of the VCS user running command, ex. `acme-user`. During an autoplan, the user will be the Atlantis API user, ex. `atlantis`. * `COMMENT_ARGS` - Any additional flags passed in the comment on the pull request. Flags are separated by commas and every character is escaped, ex. `atlantis plan -- arg1 arg2` will result in `COMMENT_ARGS=\a\r\g\1,\a\r\g\2`. + * `OUTPUT_STATUS_FILE` - An output file to customize the success or failure status. ex. `echo 'failure' > $OUTPUT_STATUS_FILE`. ::: diff --git a/server/controllers/events/events_controller_e2e_test.go b/server/controllers/events/events_controller_e2e_test.go index 7fc1abe2ed..8de9d3c334 100644 --- a/server/controllers/events/events_controller_e2e_test.go +++ b/server/controllers/events/events_controller_e2e_test.go @@ -966,22 +966,30 @@ func setupE2E(t *testing.T, repoDir, repoConfigFile string) (events_controllers. parallelPoolSize := 1 silenceNoProjects := false + commitStatusUpdater := mocks.NewMockCommitStatusUpdater() + mockPreWorkflowHookRunner = runtimemocks.NewMockPreWorkflowHookRunner() + preWorkflowHookURLGenerator := mocks.NewMockPreWorkflowHookURLGenerator() preWorkflowHooksCommandRunner := &events.DefaultPreWorkflowHooksCommandRunner{ VCSClient: e2eVCSClient, GlobalCfg: globalCfg, WorkingDirLocker: locker, WorkingDir: workingDir, PreWorkflowHookRunner: mockPreWorkflowHookRunner, + CommitStatusUpdater: commitStatusUpdater, + Router: preWorkflowHookURLGenerator, } mockPostWorkflowHookRunner = runtimemocks.NewMockPostWorkflowHookRunner() + postWorkflowHookURLGenerator := mocks.NewMockPostWorkflowHookURLGenerator() postWorkflowHooksCommandRunner := &events.DefaultPostWorkflowHooksCommandRunner{ VCSClient: e2eVCSClient, GlobalCfg: globalCfg, WorkingDirLocker: locker, WorkingDir: workingDir, PostWorkflowHookRunner: mockPostWorkflowHookRunner, + CommitStatusUpdater: commitStatusUpdater, + Router: postWorkflowHookURLGenerator, } statsScope, _, _ := metrics.NewLoggingScope(logger, "atlantis") diff --git a/server/core/config/raw/workflow_step.go b/server/core/config/raw/workflow_step.go index 32218468ac..b825f2a827 100644 --- a/server/core/config/raw/workflow_step.go +++ b/server/core/config/raw/workflow_step.go @@ -72,13 +72,10 @@ func (s WorkflowHook) Validate() error { func (s WorkflowHook) ToValid() *valid.WorkflowHook { // This will trigger in case #4 (see WorkflowHook docs). if len(s.StringVal) > 0 { - // After validation we assume there's only one key and it's a valid - // step name so we just use the first one. - for _, v := range s.StringVal { - return &valid.WorkflowHook{ - StepName: RunStepName, - RunCommand: v, - } + return &valid.WorkflowHook{ + StepName: RunStepName, + RunCommand: s.StringVal["run"], + StepDescription: s.StringVal["description"], } } diff --git a/server/core/config/valid/global_cfg.go b/server/core/config/valid/global_cfg.go index ebdd7546dc..d13ecd3874 100644 --- a/server/core/config/valid/global_cfg.go +++ b/server/core/config/valid/global_cfg.go @@ -96,8 +96,9 @@ type MergedProjectCfg struct { // WorkflowHook is a map of custom run commands to run before or after workflows. type WorkflowHook struct { - StepName string - RunCommand string + StepName string + RunCommand string + StepDescription string } // DefaultApplyStage is the Atlantis default apply stage. diff --git a/server/core/runtime/mocks/matchers/jobs_projectcommandoutputhandler.go b/server/core/runtime/mocks/matchers/jobs_projectcommandoutputhandler.go new file mode 100644 index 0000000000..3f86390e36 --- /dev/null +++ b/server/core/runtime/mocks/matchers/jobs_projectcommandoutputhandler.go @@ -0,0 +1,33 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "github.com/petergtz/pegomock" + "reflect" + + jobs "github.com/runatlantis/atlantis/server/jobs" +) + +func AnyJobsProjectCommandOutputHandler() jobs.ProjectCommandOutputHandler { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(jobs.ProjectCommandOutputHandler))(nil)).Elem())) + var nullValue jobs.ProjectCommandOutputHandler + return nullValue +} + +func EqJobsProjectCommandOutputHandler(value jobs.ProjectCommandOutputHandler) jobs.ProjectCommandOutputHandler { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue jobs.ProjectCommandOutputHandler + return nullValue +} + +func NotEqJobsProjectCommandOutputHandler(value jobs.ProjectCommandOutputHandler) jobs.ProjectCommandOutputHandler { + pegomock.RegisterMatcher(&pegomock.NotEqMatcher{Value: value}) + var nullValue jobs.ProjectCommandOutputHandler + return nullValue +} + +func JobsProjectCommandOutputHandlerThat(matcher pegomock.ArgumentMatcher) jobs.ProjectCommandOutputHandler { + pegomock.RegisterMatcher(matcher) + var nullValue jobs.ProjectCommandOutputHandler + return nullValue +} diff --git a/server/core/runtime/mocks/matchers/models_workflowhookcommandcontext.go b/server/core/runtime/mocks/matchers/models_workflowhookcommandcontext.go index b7f085915f..18a5a5bae9 100644 --- a/server/core/runtime/mocks/matchers/models_workflowhookcommandcontext.go +++ b/server/core/runtime/mocks/matchers/models_workflowhookcommandcontext.go @@ -2,9 +2,8 @@ package matchers import ( - "reflect" - "github.com/petergtz/pegomock" + "reflect" models "github.com/runatlantis/atlantis/server/events/models" ) diff --git a/server/core/runtime/mocks/mock_post_workflows_hook_runner.go b/server/core/runtime/mocks/mock_post_workflows_hook_runner.go index ef45221d0b..8353064617 100644 --- a/server/core/runtime/mocks/mock_post_workflows_hook_runner.go +++ b/server/core/runtime/mocks/mock_post_workflows_hook_runner.go @@ -4,11 +4,10 @@ package mocks import ( - "reflect" - "time" - pegomock "github.com/petergtz/pegomock" models "github.com/runatlantis/atlantis/server/events/models" + "reflect" + "time" ) type MockPostWorkflowHookRunner struct { @@ -26,23 +25,27 @@ func NewMockPostWorkflowHookRunner(options ...pegomock.Option) *MockPostWorkflow func (mock *MockPostWorkflowHookRunner) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockPostWorkflowHookRunner) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockPostWorkflowHookRunner) Run(ctx models.WorkflowHookCommandContext, command string, path string) (string, error) { +func (mock *MockPostWorkflowHookRunner) Run(ctx models.WorkflowHookCommandContext, command string, path string) (string, string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockPostWorkflowHookRunner().") } params := []pegomock.Param{ctx, command, path} - result := pegomock.GetGenericMockFrom(mock).Invoke("Run", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + result := pegomock.GetGenericMockFrom(mock).Invoke("Run", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) var ret0 string - var ret1 error + var ret1 string + var ret2 error if len(result) != 0 { if result[0] != nil { ret0 = result[0].(string) } if result[1] != nil { - ret1 = result[1].(error) + ret1 = result[1].(string) + } + if result[2] != nil { + ret2 = result[2].(error) } } - return ret0, ret1 + return ret0, ret1, ret2 } func (mock *MockPostWorkflowHookRunner) VerifyWasCalledOnce() *VerifierMockPostWorkflowHookRunner { diff --git a/server/core/runtime/mocks/mock_pre_workflows_hook_runner.go b/server/core/runtime/mocks/mock_pre_workflows_hook_runner.go index 0753da0ff7..079cbfb941 100644 --- a/server/core/runtime/mocks/mock_pre_workflows_hook_runner.go +++ b/server/core/runtime/mocks/mock_pre_workflows_hook_runner.go @@ -4,11 +4,10 @@ package mocks import ( - "reflect" - "time" - pegomock "github.com/petergtz/pegomock" models "github.com/runatlantis/atlantis/server/events/models" + "reflect" + "time" ) type MockPreWorkflowHookRunner struct { @@ -26,23 +25,27 @@ func NewMockPreWorkflowHookRunner(options ...pegomock.Option) *MockPreWorkflowHo func (mock *MockPreWorkflowHookRunner) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockPreWorkflowHookRunner) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockPreWorkflowHookRunner) Run(ctx models.WorkflowHookCommandContext, command string, path string) (string, error) { +func (mock *MockPreWorkflowHookRunner) Run(ctx models.WorkflowHookCommandContext, command string, path string) (string, string, error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockPreWorkflowHookRunner().") } params := []pegomock.Param{ctx, command, path} - result := pegomock.GetGenericMockFrom(mock).Invoke("Run", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + result := pegomock.GetGenericMockFrom(mock).Invoke("Run", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) var ret0 string - var ret1 error + var ret1 string + var ret2 error if len(result) != 0 { if result[0] != nil { ret0 = result[0].(string) } if result[1] != nil { - ret1 = result[1].(error) + ret1 = result[1].(string) + } + if result[2] != nil { + ret2 = result[2].(error) } } - return ret0, ret1 + return ret0, ret1, ret2 } func (mock *MockPreWorkflowHookRunner) VerifyWasCalledOnce() *VerifierMockPreWorkflowHookRunner { diff --git a/server/core/runtime/post_workflow_hook_runner.go b/server/core/runtime/post_workflow_hook_runner.go index 11e1db429f..1403961143 100644 --- a/server/core/runtime/post_workflow_hook_runner.go +++ b/server/core/runtime/post_workflow_hook_runner.go @@ -4,36 +4,43 @@ import ( "fmt" "os" "os/exec" + "path/filepath" "strings" "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/jobs" ) //go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_post_workflows_hook_runner.go PostWorkflowHookRunner type PostWorkflowHookRunner interface { - Run(ctx models.WorkflowHookCommandContext, command string, path string) (string, error) + Run(ctx models.WorkflowHookCommandContext, command string, path string) (string, string, error) } -type DefaultPostWorkflowHookRunner struct{} +type DefaultPostWorkflowHookRunner struct { + OutputHandler jobs.ProjectCommandOutputHandler +} + +func (wh DefaultPostWorkflowHookRunner) Run(ctx models.WorkflowHookCommandContext, command string, path string) (string, string, error) { + outputFilePath := filepath.Join(path, "OUTPUT_STATUS_FILE") -func (wh DefaultPostWorkflowHookRunner) Run(ctx models.WorkflowHookCommandContext, command string, path string) (string, error) { cmd := exec.Command("sh", "-c", command) // #nosec cmd.Dir = path baseEnvVars := os.Environ() customEnvVars := map[string]string{ - "BASE_BRANCH_NAME": ctx.Pull.BaseBranch, - "BASE_REPO_NAME": ctx.BaseRepo.Name, - "BASE_REPO_OWNER": ctx.BaseRepo.Owner, - "COMMENT_ARGS": strings.Join(ctx.EscapedCommentArgs, ","), - "DIR": path, - "HEAD_BRANCH_NAME": ctx.Pull.HeadBranch, - "HEAD_COMMIT": ctx.Pull.HeadCommit, - "HEAD_REPO_NAME": ctx.HeadRepo.Name, - "HEAD_REPO_OWNER": ctx.HeadRepo.Owner, - "PULL_AUTHOR": ctx.Pull.Author, - "PULL_NUM": fmt.Sprintf("%d", ctx.Pull.Num), - "USER_NAME": ctx.User.Username, + "BASE_BRANCH_NAME": ctx.Pull.BaseBranch, + "BASE_REPO_NAME": ctx.BaseRepo.Name, + "BASE_REPO_OWNER": ctx.BaseRepo.Owner, + "COMMENT_ARGS": strings.Join(ctx.EscapedCommentArgs, ","), + "DIR": path, + "HEAD_BRANCH_NAME": ctx.Pull.HeadBranch, + "HEAD_COMMIT": ctx.Pull.HeadCommit, + "HEAD_REPO_NAME": ctx.HeadRepo.Name, + "HEAD_REPO_OWNER": ctx.HeadRepo.Owner, + "PULL_AUTHOR": ctx.Pull.Author, + "PULL_NUM": fmt.Sprintf("%d", ctx.Pull.Num), + "USER_NAME": ctx.User.Username, + "OUTPUT_STATUS_FILE": outputFilePath, } finalEnvVars := baseEnvVars @@ -47,8 +54,24 @@ func (wh DefaultPostWorkflowHookRunner) Run(ctx models.WorkflowHookCommandContex if err != nil { err = fmt.Errorf("%s: running %q in %q: \n%s", err, command, path, out) ctx.Log.Debug("error: %s", err) - return "", err + return "", "", err + } + + // Read the value from the "outputFilePath" file + // to be returned as a custom description. + var customStatusOut []byte + if _, err := os.Stat(outputFilePath); err == nil { + var customStatusErr error + customStatusOut, customStatusErr = os.ReadFile(outputFilePath) + if customStatusErr != nil { + err = fmt.Errorf("%s: running %q in %q: \n%s", err, command, path, out) + ctx.Log.Debug("error: %s", err) + return "", "", err + } } + + wh.OutputHandler.SendWorkflowHook(ctx, fmt.Sprintf("%s\n", string(out)), true) + ctx.Log.Info("successfully ran %q in %q", command, path) - return string(out), nil + return string(out), strings.Trim(string(customStatusOut), "\n"), nil } diff --git a/server/core/runtime/post_workflow_hook_runner_test.go b/server/core/runtime/post_workflow_hook_runner_test.go index dfa741d6d1..90ff71bf1f 100644 --- a/server/core/runtime/post_workflow_hook_runner_test.go +++ b/server/core/runtime/post_workflow_hook_runner_test.go @@ -10,15 +10,17 @@ import ( matchers2 "github.com/runatlantis/atlantis/server/core/terraform/mocks/matchers" "github.com/runatlantis/atlantis/server/events/mocks/matchers" "github.com/runatlantis/atlantis/server/events/models" + jobmocks "github.com/runatlantis/atlantis/server/jobs/mocks" "github.com/runatlantis/atlantis/server/logging" . "github.com/runatlantis/atlantis/testing" ) func TestPostWorkflowHookRunner_Run(t *testing.T) { cases := []struct { - Command string - ExpOut string - ExpErr string + Command string + ExpOut string + ExpErr string + ExpDescription string }{ { Command: "", @@ -56,6 +58,10 @@ func TestPostWorkflowHookRunner_Run(t *testing.T) { Command: "echo user_name=$USER_NAME", ExpOut: "user_name=acme-user\n", }, + { + Command: "echo something > $OUTPUT_STATUS_FILE", + ExpDescription: "something", + }, } for _, c := range cases { @@ -71,7 +77,9 @@ func TestPostWorkflowHookRunner_Run(t *testing.T) { logger := logging.NewNoopLogger(t) tmpDir := t.TempDir() - r := runtime.DefaultPostWorkflowHookRunner{} + r := runtime.DefaultPostWorkflowHookRunner{ + OutputHandler: jobmocks.NewMockProjectCommandOutputHandler(), + } t.Run(c.Command, func(t *testing.T) { ctx := models.WorkflowHookCommandContext{ BaseRepo: models.Repo{ @@ -94,7 +102,7 @@ func TestPostWorkflowHookRunner_Run(t *testing.T) { }, Log: logger, } - out, err := r.Run(ctx, c.Command, tmpDir) + out, desc, err := r.Run(ctx, c.Command, tmpDir) if c.ExpErr != "" { ErrContains(t, c.ExpErr, err) return @@ -105,6 +113,7 @@ func TestPostWorkflowHookRunner_Run(t *testing.T) { // temp dir. expOut := strings.Replace(c.ExpOut, "$DIR", tmpDir, -1) Equals(t, expOut, out) + Equals(t, c.ExpDescription, desc) }) } } diff --git a/server/core/runtime/pre_workflow_hook_runner.go b/server/core/runtime/pre_workflow_hook_runner.go index 60520cfcff..5fee355224 100644 --- a/server/core/runtime/pre_workflow_hook_runner.go +++ b/server/core/runtime/pre_workflow_hook_runner.go @@ -4,36 +4,43 @@ import ( "fmt" "os" "os/exec" + "path/filepath" "strings" "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/jobs" ) //go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_pre_workflows_hook_runner.go PreWorkflowHookRunner type PreWorkflowHookRunner interface { - Run(ctx models.WorkflowHookCommandContext, command string, path string) (string, error) + Run(ctx models.WorkflowHookCommandContext, command string, path string) (string, string, error) } -type DefaultPreWorkflowHookRunner struct{} +type DefaultPreWorkflowHookRunner struct { + OutputHandler jobs.ProjectCommandOutputHandler +} + +func (wh DefaultPreWorkflowHookRunner) Run(ctx models.WorkflowHookCommandContext, command string, path string) (string, string, error) { + outputFilePath := filepath.Join(path, "OUTPUT_STATUS_FILE") -func (wh DefaultPreWorkflowHookRunner) Run(ctx models.WorkflowHookCommandContext, command string, path string) (string, error) { cmd := exec.Command("sh", "-c", command) // #nosec cmd.Dir = path baseEnvVars := os.Environ() customEnvVars := map[string]string{ - "BASE_BRANCH_NAME": ctx.Pull.BaseBranch, - "BASE_REPO_NAME": ctx.BaseRepo.Name, - "BASE_REPO_OWNER": ctx.BaseRepo.Owner, - "COMMENT_ARGS": strings.Join(ctx.EscapedCommentArgs, ","), - "DIR": path, - "HEAD_BRANCH_NAME": ctx.Pull.HeadBranch, - "HEAD_COMMIT": ctx.Pull.HeadCommit, - "HEAD_REPO_NAME": ctx.HeadRepo.Name, - "HEAD_REPO_OWNER": ctx.HeadRepo.Owner, - "PULL_AUTHOR": ctx.Pull.Author, - "PULL_NUM": fmt.Sprintf("%d", ctx.Pull.Num), - "USER_NAME": ctx.User.Username, + "BASE_BRANCH_NAME": ctx.Pull.BaseBranch, + "BASE_REPO_NAME": ctx.BaseRepo.Name, + "BASE_REPO_OWNER": ctx.BaseRepo.Owner, + "COMMENT_ARGS": strings.Join(ctx.EscapedCommentArgs, ","), + "DIR": path, + "HEAD_BRANCH_NAME": ctx.Pull.HeadBranch, + "HEAD_COMMIT": ctx.Pull.HeadCommit, + "HEAD_REPO_NAME": ctx.HeadRepo.Name, + "HEAD_REPO_OWNER": ctx.HeadRepo.Owner, + "PULL_AUTHOR": ctx.Pull.Author, + "PULL_NUM": fmt.Sprintf("%d", ctx.Pull.Num), + "USER_NAME": ctx.User.Username, + "OUTPUT_STATUS_FILE": outputFilePath, } finalEnvVars := baseEnvVars @@ -47,8 +54,24 @@ func (wh DefaultPreWorkflowHookRunner) Run(ctx models.WorkflowHookCommandContext if err != nil { err = fmt.Errorf("%s: running %q in %q: \n%s", err, command, path, out) ctx.Log.Debug("error: %s", err) - return "", err + return "", "", err + } + + // Read the value from the "outputFilePath" file + // to be returned as a custom description. + var customStatusOut []byte + if _, err := os.Stat(outputFilePath); err == nil { + var customStatusErr error + customStatusOut, customStatusErr = os.ReadFile(outputFilePath) + if customStatusErr != nil { + err = fmt.Errorf("%s: running %q in %q: \n%s", err, command, path, out) + ctx.Log.Debug("error: %s", err) + return "", "", err + } } + + wh.OutputHandler.SendWorkflowHook(ctx, fmt.Sprintf("%s\n", string(out)), true) + ctx.Log.Info("successfully ran %q in %q", command, path) - return string(out), nil + return string(out), strings.Trim(string(customStatusOut), "\n"), nil } diff --git a/server/core/runtime/pre_workflow_hook_runner_test.go b/server/core/runtime/pre_workflow_hook_runner_test.go index b98b09059d..c6d4e6c3e2 100644 --- a/server/core/runtime/pre_workflow_hook_runner_test.go +++ b/server/core/runtime/pre_workflow_hook_runner_test.go @@ -10,15 +10,17 @@ import ( matchers2 "github.com/runatlantis/atlantis/server/core/terraform/mocks/matchers" "github.com/runatlantis/atlantis/server/events/mocks/matchers" "github.com/runatlantis/atlantis/server/events/models" + jobmocks "github.com/runatlantis/atlantis/server/jobs/mocks" "github.com/runatlantis/atlantis/server/logging" . "github.com/runatlantis/atlantis/testing" ) func TestPreWorkflowHookRunner_Run(t *testing.T) { cases := []struct { - Command string - ExpOut string - ExpErr string + Command string + ExpOut string + ExpErr string + ExpDescription string }{ { Command: "", @@ -56,6 +58,10 @@ func TestPreWorkflowHookRunner_Run(t *testing.T) { Command: "echo user_name=$USER_NAME", ExpOut: "user_name=acme-user\n", }, + { + Command: "echo something > $OUTPUT_STATUS_FILE", + ExpDescription: "something", + }, } for _, c := range cases { @@ -71,7 +77,9 @@ func TestPreWorkflowHookRunner_Run(t *testing.T) { logger := logging.NewNoopLogger(t) tmpDir := t.TempDir() - r := runtime.DefaultPreWorkflowHookRunner{} + r := runtime.DefaultPreWorkflowHookRunner{ + OutputHandler: jobmocks.NewMockProjectCommandOutputHandler(), + } t.Run(c.Command, func(t *testing.T) { ctx := models.WorkflowHookCommandContext{ BaseRepo: models.Repo{ @@ -94,7 +102,7 @@ func TestPreWorkflowHookRunner_Run(t *testing.T) { }, Log: logger, } - out, err := r.Run(ctx, c.Command, tmpDir) + out, desc, err := r.Run(ctx, c.Command, tmpDir) if c.ExpErr != "" { ErrContains(t, c.ExpErr, err) return @@ -105,6 +113,7 @@ func TestPreWorkflowHookRunner_Run(t *testing.T) { // temp dir. expOut := strings.Replace(c.ExpOut, "$DIR", tmpDir, -1) Equals(t, expOut, out) + Equals(t, c.ExpDescription, desc) }) } } diff --git a/server/events/command_runner_internal_test.go b/server/events/command_runner_internal_test.go index 5027a25102..763e29abf0 100644 --- a/server/events/command_runner_internal_test.go +++ b/server/events/command_runner_internal_test.go @@ -166,9 +166,19 @@ func (m *MockCSU) UpdateCombinedCount(repo models.Repo, pull models.PullRequest, m.CalledNumTotal = numTotal return nil } + func (m *MockCSU) UpdateCombined(repo models.Repo, pull models.PullRequest, status models.CommitStatus, command command.Name) error { return nil } + func (m *MockCSU) UpdateProject(ctx command.ProjectContext, cmdName command.Name, status models.CommitStatus, url string) error { return nil } + +func (m *MockCSU) UpdatePreWorkflowHook(pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, url string) error { + return nil +} + +func (m *MockCSU) UpdatePostWorkflowHook(pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, url string) error { + return nil +} diff --git a/server/events/commit_status_updater.go b/server/events/commit_status_updater.go index dc8a07f239..ca2e3d10d6 100644 --- a/server/events/commit_status_updater.go +++ b/server/events/commit_status_updater.go @@ -37,6 +37,9 @@ type CommitStatusUpdater interface { // UpdateProject sets the commit status for the project represented by // ctx. UpdateProject(ctx command.ProjectContext, cmdName command.Name, status models.CommitStatus, url string) error + + UpdatePreWorkflowHook(pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, url string) error + UpdatePostWorkflowHook(pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, url string) error } // DefaultCommitStatusUpdater implements CommitStatusUpdater. @@ -96,3 +99,31 @@ func (d *DefaultCommitStatusUpdater) UpdateProject(ctx command.ProjectContext, c descrip := fmt.Sprintf("%s %s", cases.Title(language.English).String(cmdName.String()), descripWords) return d.Client.UpdateStatus(ctx.BaseRepo, ctx.Pull, status, src, descrip, url) } + +func (d *DefaultCommitStatusUpdater) UpdatePreWorkflowHook(pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, url string) error { + return d.updateWorkflowHook(pull, status, hookDescription, runtimeDescription, "pre_workflow_hook", url) +} + +func (d *DefaultCommitStatusUpdater) UpdatePostWorkflowHook(pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, url string) error { + return d.updateWorkflowHook(pull, status, hookDescription, runtimeDescription, "post_workflow_hook", url) +} + +func (d *DefaultCommitStatusUpdater) updateWorkflowHook(pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, workflowType string, url string) error { + src := fmt.Sprintf("%s/%s: %s", d.StatusName, workflowType, hookDescription) + + var descripWords string + if runtimeDescription != "" { + descripWords = runtimeDescription + } else { + switch status { + case models.PendingCommitStatus: + descripWords = "in progress..." + case models.FailedCommitStatus: + descripWords = "failed." + case models.SuccessCommitStatus: + descripWords = "succeeded." + } + } + + return d.Client.UpdateStatus(pull.BaseRepo, pull, status, src, descripWords, url) +} diff --git a/server/events/mocks/matchers/command_name.go b/server/events/mocks/matchers/command_name.go new file mode 100644 index 0000000000..9dcc26d1e8 --- /dev/null +++ b/server/events/mocks/matchers/command_name.go @@ -0,0 +1,33 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "github.com/petergtz/pegomock" + "reflect" + + command "github.com/runatlantis/atlantis/server/events/command" +) + +func AnyCommandName() command.Name { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(command.Name))(nil)).Elem())) + var nullValue command.Name + return nullValue +} + +func EqCommandName(value command.Name) command.Name { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue command.Name + return nullValue +} + +func NotEqCommandName(value command.Name) command.Name { + pegomock.RegisterMatcher(&pegomock.NotEqMatcher{Value: value}) + var nullValue command.Name + return nullValue +} + +func CommandNameThat(matcher pegomock.ArgumentMatcher) command.Name { + pegomock.RegisterMatcher(matcher) + var nullValue command.Name + return nullValue +} diff --git a/server/events/mocks/matchers/command_projectcontext.go b/server/events/mocks/matchers/command_projectcontext.go new file mode 100644 index 0000000000..c25f35d932 --- /dev/null +++ b/server/events/mocks/matchers/command_projectcontext.go @@ -0,0 +1,33 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "github.com/petergtz/pegomock" + "reflect" + + command "github.com/runatlantis/atlantis/server/events/command" +) + +func AnyCommandProjectContext() command.ProjectContext { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(command.ProjectContext))(nil)).Elem())) + var nullValue command.ProjectContext + return nullValue +} + +func EqCommandProjectContext(value command.ProjectContext) command.ProjectContext { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue command.ProjectContext + return nullValue +} + +func NotEqCommandProjectContext(value command.ProjectContext) command.ProjectContext { + pegomock.RegisterMatcher(&pegomock.NotEqMatcher{Value: value}) + var nullValue command.ProjectContext + return nullValue +} + +func CommandProjectContextThat(matcher pegomock.ArgumentMatcher) command.ProjectContext { + pegomock.RegisterMatcher(matcher) + var nullValue command.ProjectContext + return nullValue +} diff --git a/server/events/mocks/matchers/models_commitstatus.go b/server/events/mocks/matchers/models_commitstatus.go index 5ebf733ee6..1e10ed7823 100644 --- a/server/events/mocks/matchers/models_commitstatus.go +++ b/server/events/mocks/matchers/models_commitstatus.go @@ -2,9 +2,8 @@ package matchers import ( - "reflect" - "github.com/petergtz/pegomock" + "reflect" models "github.com/runatlantis/atlantis/server/events/models" ) diff --git a/server/events/mocks/matchers/models_pullrequest.go b/server/events/mocks/matchers/models_pullrequest.go index db2666f02f..9ae2a7e920 100644 --- a/server/events/mocks/matchers/models_pullrequest.go +++ b/server/events/mocks/matchers/models_pullrequest.go @@ -2,9 +2,8 @@ package matchers import ( - "reflect" - "github.com/petergtz/pegomock" + "reflect" models "github.com/runatlantis/atlantis/server/events/models" ) diff --git a/server/events/mocks/matchers/models_repo.go b/server/events/mocks/matchers/models_repo.go index 2ca60819c3..fd44665f85 100644 --- a/server/events/mocks/matchers/models_repo.go +++ b/server/events/mocks/matchers/models_repo.go @@ -2,9 +2,8 @@ package matchers import ( - "reflect" - "github.com/petergtz/pegomock" + "reflect" models "github.com/runatlantis/atlantis/server/events/models" ) diff --git a/server/events/mocks/matchers/models_workflowhookcommandcontext.go b/server/events/mocks/matchers/models_workflowhookcommandcontext.go new file mode 100644 index 0000000000..18a5a5bae9 --- /dev/null +++ b/server/events/mocks/matchers/models_workflowhookcommandcontext.go @@ -0,0 +1,33 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "github.com/petergtz/pegomock" + "reflect" + + models "github.com/runatlantis/atlantis/server/events/models" +) + +func AnyModelsWorkflowHookCommandContext() models.WorkflowHookCommandContext { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.WorkflowHookCommandContext))(nil)).Elem())) + var nullValue models.WorkflowHookCommandContext + return nullValue +} + +func EqModelsWorkflowHookCommandContext(value models.WorkflowHookCommandContext) models.WorkflowHookCommandContext { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue models.WorkflowHookCommandContext + return nullValue +} + +func NotEqModelsWorkflowHookCommandContext(value models.WorkflowHookCommandContext) models.WorkflowHookCommandContext { + pegomock.RegisterMatcher(&pegomock.NotEqMatcher{Value: value}) + var nullValue models.WorkflowHookCommandContext + return nullValue +} + +func ModelsWorkflowHookCommandContextThat(matcher pegomock.ArgumentMatcher) models.WorkflowHookCommandContext { + pegomock.RegisterMatcher(matcher) + var nullValue models.WorkflowHookCommandContext + return nullValue +} diff --git a/server/events/mocks/matchers/ptr_to_command_context.go b/server/events/mocks/matchers/ptr_to_command_context.go new file mode 100644 index 0000000000..134e02c1f9 --- /dev/null +++ b/server/events/mocks/matchers/ptr_to_command_context.go @@ -0,0 +1,33 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "github.com/petergtz/pegomock" + "reflect" + + command "github.com/runatlantis/atlantis/server/events/command" +) + +func AnyPtrToCommandContext() *command.Context { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(*command.Context))(nil)).Elem())) + var nullValue *command.Context + return nullValue +} + +func EqPtrToCommandContext(value *command.Context) *command.Context { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue *command.Context + return nullValue +} + +func NotEqPtrToCommandContext(value *command.Context) *command.Context { + pegomock.RegisterMatcher(&pegomock.NotEqMatcher{Value: value}) + var nullValue *command.Context + return nullValue +} + +func PtrToCommandContextThat(matcher pegomock.ArgumentMatcher) *command.Context { + pegomock.RegisterMatcher(matcher) + var nullValue *command.Context + return nullValue +} diff --git a/server/events/mocks/matchers/ptr_to_events_commentcommand.go b/server/events/mocks/matchers/ptr_to_events_commentcommand.go index 23d7794d09..55b3b5ba67 100644 --- a/server/events/mocks/matchers/ptr_to_events_commentcommand.go +++ b/server/events/mocks/matchers/ptr_to_events_commentcommand.go @@ -2,9 +2,8 @@ package matchers import ( - "reflect" - "github.com/petergtz/pegomock" + "reflect" events "github.com/runatlantis/atlantis/server/events" ) diff --git a/server/events/mocks/matchers/slice_of_ptr_to_valid_workflowhook.go b/server/events/mocks/matchers/slice_of_ptr_to_valid_workflowhook.go new file mode 100644 index 0000000000..da80607951 --- /dev/null +++ b/server/events/mocks/matchers/slice_of_ptr_to_valid_workflowhook.go @@ -0,0 +1,33 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "github.com/petergtz/pegomock" + "reflect" + + valid "github.com/runatlantis/atlantis/server/core/config/valid" +) + +func AnySliceOfPtrToValidWorkflowHook() []*valid.WorkflowHook { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*([]*valid.WorkflowHook))(nil)).Elem())) + var nullValue []*valid.WorkflowHook + return nullValue +} + +func EqSliceOfPtrToValidWorkflowHook(value []*valid.WorkflowHook) []*valid.WorkflowHook { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue []*valid.WorkflowHook + return nullValue +} + +func NotEqSliceOfPtrToValidWorkflowHook(value []*valid.WorkflowHook) []*valid.WorkflowHook { + pegomock.RegisterMatcher(&pegomock.NotEqMatcher{Value: value}) + var nullValue []*valid.WorkflowHook + return nullValue +} + +func SliceOfPtrToValidWorkflowHookThat(matcher pegomock.ArgumentMatcher) []*valid.WorkflowHook { + pegomock.RegisterMatcher(matcher) + var nullValue []*valid.WorkflowHook + return nullValue +} diff --git a/server/events/mocks/mock_commit_status_updater.go b/server/events/mocks/mock_commit_status_updater.go index 081ed61c6d..0dcca5039b 100644 --- a/server/events/mocks/mock_commit_status_updater.go +++ b/server/events/mocks/mock_commit_status_updater.go @@ -4,12 +4,11 @@ package mocks import ( - "reflect" - "time" - pegomock "github.com/petergtz/pegomock" - "github.com/runatlantis/atlantis/server/events/command" + command "github.com/runatlantis/atlantis/server/events/command" models "github.com/runatlantis/atlantis/server/events/models" + "reflect" + "time" ) type MockCommitStatusUpdater struct { @@ -27,11 +26,11 @@ func NewMockCommitStatusUpdater(options ...pegomock.Option) *MockCommitStatusUpd func (mock *MockCommitStatusUpdater) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockCommitStatusUpdater) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockCommitStatusUpdater) UpdateCombined(repo models.Repo, pull models.PullRequest, status models.CommitStatus, command command.Name) error { +func (mock *MockCommitStatusUpdater) UpdateCombined(repo models.Repo, pull models.PullRequest, status models.CommitStatus, cmdName command.Name) error { if mock == nil { panic("mock must not be nil. Use myMock := NewMockCommitStatusUpdater().") } - params := []pegomock.Param{repo, pull, status, command} + params := []pegomock.Param{repo, pull, status, cmdName} result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateCombined", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) var ret0 error if len(result) != 0 { @@ -42,11 +41,11 @@ func (mock *MockCommitStatusUpdater) UpdateCombined(repo models.Repo, pull model return ret0 } -func (mock *MockCommitStatusUpdater) UpdateCombinedCount(repo models.Repo, pull models.PullRequest, status models.CommitStatus, command command.Name, numSuccess int, numTotal int) error { +func (mock *MockCommitStatusUpdater) UpdateCombinedCount(repo models.Repo, pull models.PullRequest, status models.CommitStatus, cmdName command.Name, numSuccess int, numTotal int) error { if mock == nil { panic("mock must not be nil. Use myMock := NewMockCommitStatusUpdater().") } - params := []pegomock.Param{repo, pull, status, command, numSuccess, numTotal} + params := []pegomock.Param{repo, pull, status, cmdName, numSuccess, numTotal} result := pegomock.GetGenericMockFrom(mock).Invoke("UpdateCombinedCount", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) var ret0 error if len(result) != 0 { @@ -72,6 +71,36 @@ func (mock *MockCommitStatusUpdater) UpdateProject(ctx command.ProjectContext, c return ret0 } +func (mock *MockCommitStatusUpdater) UpdatePreWorkflowHook(pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, url string) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockCommitStatusUpdater().") + } + params := []pegomock.Param{pull, status, hookDescription, runtimeDescription, url} + result := pegomock.GetGenericMockFrom(mock).Invoke("UpdatePreWorkflowHook", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var ret0 error + if len(result) != 0 { + if result[0] != nil { + ret0 = result[0].(error) + } + } + return ret0 +} + +func (mock *MockCommitStatusUpdater) UpdatePostWorkflowHook(pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, url string) error { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockCommitStatusUpdater().") + } + params := []pegomock.Param{pull, status, hookDescription, runtimeDescription, url} + result := pegomock.GetGenericMockFrom(mock).Invoke("UpdatePostWorkflowHook", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) + var ret0 error + if len(result) != 0 { + if result[0] != nil { + ret0 = result[0].(error) + } + } + return ret0 +} + func (mock *MockCommitStatusUpdater) VerifyWasCalledOnce() *VerifierMockCommitStatusUpdater { return &VerifierMockCommitStatusUpdater{ mock: mock, @@ -109,8 +138,8 @@ type VerifierMockCommitStatusUpdater struct { timeout time.Duration } -func (verifier *VerifierMockCommitStatusUpdater) UpdateCombined(repo models.Repo, pull models.PullRequest, status models.CommitStatus, command command.Name) *MockCommitStatusUpdater_UpdateCombined_OngoingVerification { - params := []pegomock.Param{repo, pull, status, command} +func (verifier *VerifierMockCommitStatusUpdater) UpdateCombined(repo models.Repo, pull models.PullRequest, status models.CommitStatus, cmdName command.Name) *MockCommitStatusUpdater_UpdateCombined_OngoingVerification { + params := []pegomock.Param{repo, pull, status, cmdName} methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateCombined", params, verifier.timeout) return &MockCommitStatusUpdater_UpdateCombined_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -121,8 +150,8 @@ type MockCommitStatusUpdater_UpdateCombined_OngoingVerification struct { } func (c *MockCommitStatusUpdater_UpdateCombined_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, models.CommitStatus, command.Name) { - repo, pull, status, command := c.GetAllCapturedArguments() - return repo[len(repo)-1], pull[len(pull)-1], status[len(status)-1], command[len(command)-1] + repo, pull, status, cmdName := c.GetAllCapturedArguments() + return repo[len(repo)-1], pull[len(pull)-1], status[len(status)-1], cmdName[len(cmdName)-1] } func (c *MockCommitStatusUpdater_UpdateCombined_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []models.CommitStatus, _param3 []command.Name) { @@ -148,8 +177,8 @@ func (c *MockCommitStatusUpdater_UpdateCombined_OngoingVerification) GetAllCaptu return } -func (verifier *VerifierMockCommitStatusUpdater) UpdateCombinedCount(repo models.Repo, pull models.PullRequest, status models.CommitStatus, cmd command.Name, numSuccess int, numTotal int) *MockCommitStatusUpdater_UpdateCombinedCount_OngoingVerification { - params := []pegomock.Param{repo, pull, status, cmd, numSuccess, numTotal} +func (verifier *VerifierMockCommitStatusUpdater) UpdateCombinedCount(repo models.Repo, pull models.PullRequest, status models.CommitStatus, cmdName command.Name, numSuccess int, numTotal int) *MockCommitStatusUpdater_UpdateCombinedCount_OngoingVerification { + params := []pegomock.Param{repo, pull, status, cmdName, numSuccess, numTotal} methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdateCombinedCount", params, verifier.timeout) return &MockCommitStatusUpdater_UpdateCombinedCount_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -160,8 +189,8 @@ type MockCommitStatusUpdater_UpdateCombinedCount_OngoingVerification struct { } func (c *MockCommitStatusUpdater_UpdateCombinedCount_OngoingVerification) GetCapturedArguments() (models.Repo, models.PullRequest, models.CommitStatus, command.Name, int, int) { - repo, pull, status, command, numSuccess, numTotal := c.GetAllCapturedArguments() - return repo[len(repo)-1], pull[len(pull)-1], status[len(status)-1], command[len(command)-1], numSuccess[len(numSuccess)-1], numTotal[len(numTotal)-1] + repo, pull, status, cmdName, numSuccess, numTotal := c.GetAllCapturedArguments() + return repo[len(repo)-1], pull[len(pull)-1], status[len(status)-1], cmdName[len(cmdName)-1], numSuccess[len(numSuccess)-1], numTotal[len(numTotal)-1] } func (c *MockCommitStatusUpdater_UpdateCombinedCount_OngoingVerification) GetAllCapturedArguments() (_param0 []models.Repo, _param1 []models.PullRequest, _param2 []models.CommitStatus, _param3 []command.Name, _param4 []int, _param5 []int) { @@ -233,3 +262,89 @@ func (c *MockCommitStatusUpdater_UpdateProject_OngoingVerification) GetAllCaptur } return } + +func (verifier *VerifierMockCommitStatusUpdater) UpdatePreWorkflowHook(pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, url string) *MockCommitStatusUpdater_UpdatePreWorkflowHook_OngoingVerification { + params := []pegomock.Param{pull, status, hookDescription, runtimeDescription, url} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdatePreWorkflowHook", params, verifier.timeout) + return &MockCommitStatusUpdater_UpdatePreWorkflowHook_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockCommitStatusUpdater_UpdatePreWorkflowHook_OngoingVerification struct { + mock *MockCommitStatusUpdater + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockCommitStatusUpdater_UpdatePreWorkflowHook_OngoingVerification) GetCapturedArguments() (models.PullRequest, models.CommitStatus, string, string, string) { + pull, status, hookDescription, runtimeDescription, url := c.GetAllCapturedArguments() + return pull[len(pull)-1], status[len(status)-1], hookDescription[len(hookDescription)-1], runtimeDescription[len(runtimeDescription)-1], url[len(url)-1] +} + +func (c *MockCommitStatusUpdater_UpdatePreWorkflowHook_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest, _param1 []models.CommitStatus, _param2 []string, _param3 []string, _param4 []string) { + params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(params) > 0 { + _param0 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range params[0] { + _param0[u] = param.(models.PullRequest) + } + _param1 = make([]models.CommitStatus, len(c.methodInvocations)) + for u, param := range params[1] { + _param1[u] = param.(models.CommitStatus) + } + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range params[2] { + _param2[u] = param.(string) + } + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range params[3] { + _param3[u] = param.(string) + } + _param4 = make([]string, len(c.methodInvocations)) + for u, param := range params[4] { + _param4[u] = param.(string) + } + } + return +} + +func (verifier *VerifierMockCommitStatusUpdater) UpdatePostWorkflowHook(pull models.PullRequest, status models.CommitStatus, hookDescription string, runtimeDescription string, url string) *MockCommitStatusUpdater_UpdatePostWorkflowHook_OngoingVerification { + params := []pegomock.Param{pull, status, hookDescription, runtimeDescription, url} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UpdatePostWorkflowHook", params, verifier.timeout) + return &MockCommitStatusUpdater_UpdatePostWorkflowHook_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockCommitStatusUpdater_UpdatePostWorkflowHook_OngoingVerification struct { + mock *MockCommitStatusUpdater + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockCommitStatusUpdater_UpdatePostWorkflowHook_OngoingVerification) GetCapturedArguments() (models.PullRequest, models.CommitStatus, string, string, string) { + pull, status, hookDescription, runtimeDescription, url := c.GetAllCapturedArguments() + return pull[len(pull)-1], status[len(status)-1], hookDescription[len(hookDescription)-1], runtimeDescription[len(runtimeDescription)-1], url[len(url)-1] +} + +func (c *MockCommitStatusUpdater_UpdatePostWorkflowHook_OngoingVerification) GetAllCapturedArguments() (_param0 []models.PullRequest, _param1 []models.CommitStatus, _param2 []string, _param3 []string, _param4 []string) { + params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(params) > 0 { + _param0 = make([]models.PullRequest, len(c.methodInvocations)) + for u, param := range params[0] { + _param0[u] = param.(models.PullRequest) + } + _param1 = make([]models.CommitStatus, len(c.methodInvocations)) + for u, param := range params[1] { + _param1[u] = param.(models.CommitStatus) + } + _param2 = make([]string, len(c.methodInvocations)) + for u, param := range params[2] { + _param2[u] = param.(string) + } + _param3 = make([]string, len(c.methodInvocations)) + for u, param := range params[3] { + _param3[u] = param.(string) + } + _param4 = make([]string, len(c.methodInvocations)) + for u, param := range params[4] { + _param4[u] = param.(string) + } + } + return +} diff --git a/server/events/mocks/mock_post_workflow_hook_url_generator.go b/server/events/mocks/mock_post_workflow_hook_url_generator.go new file mode 100644 index 0000000000..63bd697ae5 --- /dev/null +++ b/server/events/mocks/mock_post_workflow_hook_url_generator.go @@ -0,0 +1,108 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/events (interfaces: PostWorkflowHookURLGenerator) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock" + "reflect" + "time" +) + +type MockPostWorkflowHookURLGenerator struct { + fail func(message string, callerSkip ...int) +} + +func NewMockPostWorkflowHookURLGenerator(options ...pegomock.Option) *MockPostWorkflowHookURLGenerator { + mock := &MockPostWorkflowHookURLGenerator{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockPostWorkflowHookURLGenerator) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockPostWorkflowHookURLGenerator) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockPostWorkflowHookURLGenerator) GenerateProjectWorkflowHookURL(hookID string) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockPostWorkflowHookURLGenerator().") + } + params := []pegomock.Param{hookID} + result := pegomock.GetGenericMockFrom(mock).Invoke("GenerateProjectWorkflowHookURL", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var ret0 string + var ret1 error + if len(result) != 0 { + if result[0] != nil { + ret0 = result[0].(string) + } + if result[1] != nil { + ret1 = result[1].(error) + } + } + return ret0, ret1 +} + +func (mock *MockPostWorkflowHookURLGenerator) VerifyWasCalledOnce() *VerifierMockPostWorkflowHookURLGenerator { + return &VerifierMockPostWorkflowHookURLGenerator{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockPostWorkflowHookURLGenerator) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockPostWorkflowHookURLGenerator { + return &VerifierMockPostWorkflowHookURLGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockPostWorkflowHookURLGenerator) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockPostWorkflowHookURLGenerator { + return &VerifierMockPostWorkflowHookURLGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockPostWorkflowHookURLGenerator) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockPostWorkflowHookURLGenerator { + return &VerifierMockPostWorkflowHookURLGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockPostWorkflowHookURLGenerator struct { + mock *MockPostWorkflowHookURLGenerator + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockPostWorkflowHookURLGenerator) GenerateProjectWorkflowHookURL(hookID string) *MockPostWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification { + params := []pegomock.Param{hookID} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GenerateProjectWorkflowHookURL", params, verifier.timeout) + return &MockPostWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockPostWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification struct { + mock *MockPostWorkflowHookURLGenerator + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockPostWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification) GetCapturedArguments() string { + hookID := c.GetAllCapturedArguments() + return hookID[len(hookID)-1] +} + +func (c *MockPostWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { + params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range params[0] { + _param0[u] = param.(string) + } + } + return +} diff --git a/server/events/mocks/mock_post_workflow_uuid_generator.go b/server/events/mocks/mock_post_workflow_uuid_generator.go new file mode 100644 index 0000000000..e782c1f8ef --- /dev/null +++ b/server/events/mocks/mock_post_workflow_uuid_generator.go @@ -0,0 +1,96 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/events (interfaces: PostWorkflowHookUUIDGenerator) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock" + "reflect" + "time" +) + +type MockPostWorkflowHookUUIDGenerator struct { + fail func(message string, callerSkip ...int) +} + +func NewMockPostWorkflowHookUUIDGenerator(options ...pegomock.Option) *MockPostWorkflowHookUUIDGenerator { + mock := &MockPostWorkflowHookUUIDGenerator{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockPostWorkflowHookUUIDGenerator) SetFailHandler(fh pegomock.FailHandler) { + mock.fail = fh +} +func (mock *MockPostWorkflowHookUUIDGenerator) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockPostWorkflowHookUUIDGenerator) GenerateUUID() string { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockPostWorkflowHookUUIDGenerator().") + } + params := []pegomock.Param{} + result := pegomock.GetGenericMockFrom(mock).Invoke("GenerateUUID", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem()}) + var ret0 string + if len(result) != 0 { + if result[0] != nil { + ret0 = result[0].(string) + } + } + return ret0 +} + +func (mock *MockPostWorkflowHookUUIDGenerator) VerifyWasCalledOnce() *VerifierMockPostWorkflowHookUUIDGenerator { + return &VerifierMockPostWorkflowHookUUIDGenerator{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockPostWorkflowHookUUIDGenerator) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockPostWorkflowHookUUIDGenerator { + return &VerifierMockPostWorkflowHookUUIDGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockPostWorkflowHookUUIDGenerator) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockPostWorkflowHookUUIDGenerator { + return &VerifierMockPostWorkflowHookUUIDGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockPostWorkflowHookUUIDGenerator) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockPostWorkflowHookUUIDGenerator { + return &VerifierMockPostWorkflowHookUUIDGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockPostWorkflowHookUUIDGenerator struct { + mock *MockPostWorkflowHookUUIDGenerator + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockPostWorkflowHookUUIDGenerator) GenerateUUID() *MockPostWorkflowHookUUIDGenerator_GenerateUUID_OngoingVerification { + params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GenerateUUID", params, verifier.timeout) + return &MockPostWorkflowHookUUIDGenerator_GenerateUUID_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockPostWorkflowHookUUIDGenerator_GenerateUUID_OngoingVerification struct { + mock *MockPostWorkflowHookUUIDGenerator + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockPostWorkflowHookUUIDGenerator_GenerateUUID_OngoingVerification) GetCapturedArguments() { +} + +func (c *MockPostWorkflowHookUUIDGenerator_GenerateUUID_OngoingVerification) GetAllCapturedArguments() { +} diff --git a/server/events/mocks/mock_post_workflows_hooks_command_runner.go b/server/events/mocks/mock_post_workflows_hooks_command_runner.go index 8bfcde7ac2..c47250a8c2 100644 --- a/server/events/mocks/mock_post_workflows_hooks_command_runner.go +++ b/server/events/mocks/mock_post_workflows_hooks_command_runner.go @@ -4,12 +4,11 @@ package mocks import ( - "reflect" - "time" - pegomock "github.com/petergtz/pegomock" events "github.com/runatlantis/atlantis/server/events" command "github.com/runatlantis/atlantis/server/events/command" + "reflect" + "time" ) type MockPostWorkflowHooksCommandRunner struct { diff --git a/server/events/mocks/mock_pre_workflow_hook_url_generator.go b/server/events/mocks/mock_pre_workflow_hook_url_generator.go new file mode 100644 index 0000000000..8db8018997 --- /dev/null +++ b/server/events/mocks/mock_pre_workflow_hook_url_generator.go @@ -0,0 +1,108 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/events (interfaces: PreWorkflowHookURLGenerator) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock" + "reflect" + "time" +) + +type MockPreWorkflowHookURLGenerator struct { + fail func(message string, callerSkip ...int) +} + +func NewMockPreWorkflowHookURLGenerator(options ...pegomock.Option) *MockPreWorkflowHookURLGenerator { + mock := &MockPreWorkflowHookURLGenerator{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockPreWorkflowHookURLGenerator) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockPreWorkflowHookURLGenerator) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockPreWorkflowHookURLGenerator) GenerateProjectWorkflowHookURL(hookID string) (string, error) { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockPreWorkflowHookURLGenerator().") + } + params := []pegomock.Param{hookID} + result := pegomock.GetGenericMockFrom(mock).Invoke("GenerateProjectWorkflowHookURL", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) + var ret0 string + var ret1 error + if len(result) != 0 { + if result[0] != nil { + ret0 = result[0].(string) + } + if result[1] != nil { + ret1 = result[1].(error) + } + } + return ret0, ret1 +} + +func (mock *MockPreWorkflowHookURLGenerator) VerifyWasCalledOnce() *VerifierMockPreWorkflowHookURLGenerator { + return &VerifierMockPreWorkflowHookURLGenerator{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockPreWorkflowHookURLGenerator) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockPreWorkflowHookURLGenerator { + return &VerifierMockPreWorkflowHookURLGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockPreWorkflowHookURLGenerator) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockPreWorkflowHookURLGenerator { + return &VerifierMockPreWorkflowHookURLGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockPreWorkflowHookURLGenerator) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockPreWorkflowHookURLGenerator { + return &VerifierMockPreWorkflowHookURLGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockPreWorkflowHookURLGenerator struct { + mock *MockPreWorkflowHookURLGenerator + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockPreWorkflowHookURLGenerator) GenerateProjectWorkflowHookURL(hookID string) *MockPreWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification { + params := []pegomock.Param{hookID} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GenerateProjectWorkflowHookURL", params, verifier.timeout) + return &MockPreWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockPreWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification struct { + mock *MockPreWorkflowHookURLGenerator + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockPreWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification) GetCapturedArguments() string { + hookID := c.GetAllCapturedArguments() + return hookID[len(hookID)-1] +} + +func (c *MockPreWorkflowHookURLGenerator_GenerateProjectWorkflowHookURL_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { + params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range params[0] { + _param0[u] = param.(string) + } + } + return +} diff --git a/server/events/mocks/mock_pre_workflow_uuid_generator.go b/server/events/mocks/mock_pre_workflow_uuid_generator.go new file mode 100644 index 0000000000..a9cd577cb1 --- /dev/null +++ b/server/events/mocks/mock_pre_workflow_uuid_generator.go @@ -0,0 +1,94 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/events (interfaces: PreWorkflowHookUUIDGenerator) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock" + "reflect" + "time" +) + +type MockPreWorkflowHookUUIDGenerator struct { + fail func(message string, callerSkip ...int) +} + +func NewMockPreWorkflowHookUUIDGenerator(options ...pegomock.Option) *MockPreWorkflowHookUUIDGenerator { + mock := &MockPreWorkflowHookUUIDGenerator{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockPreWorkflowHookUUIDGenerator) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockPreWorkflowHookUUIDGenerator) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockPreWorkflowHookUUIDGenerator) GenerateUUID() string { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockPreWorkflowHookUUIDGenerator().") + } + params := []pegomock.Param{} + result := pegomock.GetGenericMockFrom(mock).Invoke("GenerateUUID", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem()}) + var ret0 string + if len(result) != 0 { + if result[0] != nil { + ret0 = result[0].(string) + } + } + return ret0 +} + +func (mock *MockPreWorkflowHookUUIDGenerator) VerifyWasCalledOnce() *VerifierMockPreWorkflowHookUUIDGenerator { + return &VerifierMockPreWorkflowHookUUIDGenerator{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockPreWorkflowHookUUIDGenerator) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockPreWorkflowHookUUIDGenerator { + return &VerifierMockPreWorkflowHookUUIDGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockPreWorkflowHookUUIDGenerator) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockPreWorkflowHookUUIDGenerator { + return &VerifierMockPreWorkflowHookUUIDGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockPreWorkflowHookUUIDGenerator) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockPreWorkflowHookUUIDGenerator { + return &VerifierMockPreWorkflowHookUUIDGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockPreWorkflowHookUUIDGenerator struct { + mock *MockPreWorkflowHookUUIDGenerator + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockPreWorkflowHookUUIDGenerator) GenerateUUID() *MockPreWorkflowHookUUIDGenerator_GenerateUUID_OngoingVerification { + params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GenerateUUID", params, verifier.timeout) + return &MockPreWorkflowHookUUIDGenerator_GenerateUUID_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockPreWorkflowHookUUIDGenerator_GenerateUUID_OngoingVerification struct { + mock *MockPreWorkflowHookUUIDGenerator + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockPreWorkflowHookUUIDGenerator_GenerateUUID_OngoingVerification) GetCapturedArguments() { +} + +func (c *MockPreWorkflowHookUUIDGenerator_GenerateUUID_OngoingVerification) GetAllCapturedArguments() { +} diff --git a/server/events/mocks/mock_pre_workflows_hooks_command_runner.go b/server/events/mocks/mock_pre_workflows_hooks_command_runner.go index 22599a02e3..4be82acbfe 100644 --- a/server/events/mocks/mock_pre_workflows_hooks_command_runner.go +++ b/server/events/mocks/mock_pre_workflows_hooks_command_runner.go @@ -4,12 +4,11 @@ package mocks import ( - "reflect" - "time" - pegomock "github.com/petergtz/pegomock" events "github.com/runatlantis/atlantis/server/events" command "github.com/runatlantis/atlantis/server/events/command" + "reflect" + "time" ) type MockPreWorkflowHooksCommandRunner struct { diff --git a/server/events/mocks/mock_uuid_generator.go b/server/events/mocks/mock_uuid_generator.go new file mode 100644 index 0000000000..4471246e66 --- /dev/null +++ b/server/events/mocks/mock_uuid_generator.go @@ -0,0 +1,94 @@ +// Code generated by pegomock. DO NOT EDIT. +// Source: github.com/runatlantis/atlantis/server/events (interfaces: UUIDGenerator) + +package mocks + +import ( + pegomock "github.com/petergtz/pegomock" + "reflect" + "time" +) + +type MockUUIDGenerator struct { + fail func(message string, callerSkip ...int) +} + +func NewMockUUIDGenerator(options ...pegomock.Option) *MockUUIDGenerator { + mock := &MockUUIDGenerator{} + for _, option := range options { + option.Apply(mock) + } + return mock +} + +func (mock *MockUUIDGenerator) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } +func (mock *MockUUIDGenerator) FailHandler() pegomock.FailHandler { return mock.fail } + +func (mock *MockUUIDGenerator) GenerateUUID() string { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockUUIDGenerator().") + } + params := []pegomock.Param{} + result := pegomock.GetGenericMockFrom(mock).Invoke("GenerateUUID", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem()}) + var ret0 string + if len(result) != 0 { + if result[0] != nil { + ret0 = result[0].(string) + } + } + return ret0 +} + +func (mock *MockUUIDGenerator) VerifyWasCalledOnce() *VerifierMockUUIDGenerator { + return &VerifierMockUUIDGenerator{ + mock: mock, + invocationCountMatcher: pegomock.Times(1), + } +} + +func (mock *MockUUIDGenerator) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockUUIDGenerator { + return &VerifierMockUUIDGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + } +} + +func (mock *MockUUIDGenerator) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockUUIDGenerator { + return &VerifierMockUUIDGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + inOrderContext: inOrderContext, + } +} + +func (mock *MockUUIDGenerator) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockUUIDGenerator { + return &VerifierMockUUIDGenerator{ + mock: mock, + invocationCountMatcher: invocationCountMatcher, + timeout: timeout, + } +} + +type VerifierMockUUIDGenerator struct { + mock *MockUUIDGenerator + invocationCountMatcher pegomock.InvocationCountMatcher + inOrderContext *pegomock.InOrderContext + timeout time.Duration +} + +func (verifier *VerifierMockUUIDGenerator) GenerateUUID() *MockUUIDGenerator_GenerateUUID_OngoingVerification { + params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "GenerateUUID", params, verifier.timeout) + return &MockUUIDGenerator_GenerateUUID_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockUUIDGenerator_GenerateUUID_OngoingVerification struct { + mock *MockUUIDGenerator + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockUUIDGenerator_GenerateUUID_OngoingVerification) GetCapturedArguments() { +} + +func (c *MockUUIDGenerator_GenerateUUID_OngoingVerification) GetAllCapturedArguments() { +} diff --git a/server/events/models/models.go b/server/events/models/models.go index 3c6b8f5b36..0eed5b9cf7 100644 --- a/server/events/models/models.go +++ b/server/events/models/models.go @@ -526,4 +526,6 @@ type WorkflowHookCommandContext struct { // by adding a \ before each character so that they can be used within // sh -c safely, i.e. sh -c "terraform plan $(touch bad)". EscapedCommentArgs []string + // UUID for reference + HookID string } diff --git a/server/events/post_workflow_hooks_command_runner.go b/server/events/post_workflow_hooks_command_runner.go index 3be4a99273..aa0eb36aa0 100644 --- a/server/events/post_workflow_hooks_command_runner.go +++ b/server/events/post_workflow_hooks_command_runner.go @@ -1,6 +1,9 @@ package events import ( + "fmt" + + "github.com/google/uuid" "github.com/runatlantis/atlantis/server/core/config/valid" "github.com/runatlantis/atlantis/server/core/runtime" "github.com/runatlantis/atlantis/server/events/command" @@ -8,6 +11,13 @@ import ( "github.com/runatlantis/atlantis/server/events/vcs" ) +//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_post_workflow_hook_url_generator.go PostWorkflowHookURLGenerator + +// PostWorkflowHookURLGenerator generates urls to view the post workflow progress. +type PostWorkflowHookURLGenerator interface { + GenerateProjectWorkflowHookURL(hookID string) (string, error) +} + //go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_post_workflows_hooks_command_runner.go PostWorkflowHooksCommandRunner type PostWorkflowHooksCommandRunner interface { @@ -21,6 +31,8 @@ type DefaultPostWorkflowHooksCommandRunner struct { WorkingDir WorkingDir GlobalCfg valid.GlobalCfg PostWorkflowHookRunner runtime.PostWorkflowHookRunner + CommitStatusUpdater CommitStatusUpdater + Router PostWorkflowHookURLGenerator } // RunPostHooks runs post_workflow_hooks after a plan/apply has completed @@ -73,6 +85,7 @@ func (w *DefaultPostWorkflowHooksCommandRunner) RunPostHooks( User: user, Verbose: false, EscapedCommentArgs: escapedArgs, + HookID: uuid.NewString(), }, postWorkflowHooks, repoDir) @@ -89,13 +102,33 @@ func (w *DefaultPostWorkflowHooksCommandRunner) runHooks( repoDir string, ) error { - for _, hook := range postWorkflowHooks { - _, err := w.PostWorkflowHookRunner.Run(ctx, hook.RunCommand, repoDir) + for i, hook := range postWorkflowHooks { + hookDescription := hook.StepDescription + if hookDescription == "" { + hookDescription = fmt.Sprintf("Post workflow hook #%d", i) + } + url, err := w.Router.GenerateProjectWorkflowHookURL(ctx.HookID) if err != nil { return err } - } + if err := w.CommitStatusUpdater.UpdatePostWorkflowHook(ctx.Pull, models.PendingCommitStatus, hookDescription, "", url); err != nil { + ctx.Log.Warn("unable to update post workflow hook status: %s", err) + } + + _, runtimeDesc, err := w.PostWorkflowHookRunner.Run(ctx, hook.RunCommand, repoDir) + + if err != nil { + if err := w.CommitStatusUpdater.UpdatePostWorkflowHook(ctx.Pull, models.FailedCommitStatus, hookDescription, runtimeDesc, url); err != nil { + ctx.Log.Warn("unable to update post workflow hook status: %s", err) + } + return err + } + + if err := w.CommitStatusUpdater.UpdatePostWorkflowHook(ctx.Pull, models.SuccessCommitStatus, hookDescription, runtimeDesc, url); err != nil { + ctx.Log.Warn("unable to update post workflow hook status: %s", err) + } + } return nil } diff --git a/server/events/post_workflow_hooks_command_runner_test.go b/server/events/post_workflow_hooks_command_runner_test.go index 717b4de3e5..c4bf1235cb 100644 --- a/server/events/post_workflow_hooks_command_runner_test.go +++ b/server/events/post_workflow_hooks_command_runner_test.go @@ -4,7 +4,9 @@ import ( "errors" "testing" + "github.com/google/uuid" runtime_mocks "github.com/runatlantis/atlantis/server/core/runtime/mocks" + runtimematchers "github.com/runatlantis/atlantis/server/core/runtime/mocks/matchers" . "github.com/petergtz/pegomock" "github.com/runatlantis/atlantis/server/core/config/valid" @@ -22,6 +24,7 @@ var postWh events.DefaultPostWorkflowHooksCommandRunner var postWhWorkingDir *mocks.MockWorkingDir var postWhWorkingDirLocker *mocks.MockWorkingDirLocker var whPostWorkflowHookRunner *runtime_mocks.MockPostWorkflowHookRunner +var postCommitStatusUpdater *mocks.MockCommitStatusUpdater func postWorkflowHooksSetup(t *testing.T) { RegisterMockTestingT(t) @@ -29,12 +32,16 @@ func postWorkflowHooksSetup(t *testing.T) { postWhWorkingDir = mocks.NewMockWorkingDir() postWhWorkingDirLocker = mocks.NewMockWorkingDirLocker() whPostWorkflowHookRunner = runtime_mocks.NewMockPostWorkflowHookRunner() + postCommitStatusUpdater = mocks.NewMockCommitStatusUpdater() + postWorkflowHookURLGenerator := mocks.NewMockPostWorkflowHookURLGenerator() postWh = events.DefaultPostWorkflowHooksCommandRunner{ VCSClient: vcsClient, WorkingDirLocker: postWhWorkingDirLocker, WorkingDir: postWhWorkingDir, PostWorkflowHookRunner: whPostWorkflowHookRunner, + CommitStatusUpdater: postCommitStatusUpdater, + Router: postWorkflowHookURLGenerator, } } @@ -57,6 +64,10 @@ func TestRunPostHooks_Clone(t *testing.T) { RunCommand: "some command", } + repoDir := "path/to/repo" + result := "some result" + runtimeDesc := "" + pCtx := models.WorkflowHookCommandContext{ BaseRepo: fixtures.GithubRepo, HeadRepo: fixtures.GithubRepo, @@ -64,11 +75,9 @@ func TestRunPostHooks_Clone(t *testing.T) { Log: log, User: fixtures.User, Verbose: false, + HookID: uuid.NewString(), } - repoDir := "path/to/repo" - result := "some result" - t.Run("success hooks in cfg", func(t *testing.T) { postWorkflowHooksSetup(t) @@ -92,12 +101,12 @@ func TestRunPostHooks_Clone(t *testing.T) { When(postWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) When(postWhWorkingDir.Clone(log, fixtures.GithubRepo, newPull, events.DefaultWorkspace)).ThenReturn(repoDir, false, nil) - When(whPostWorkflowHookRunner.Run(pCtx, testHook.RunCommand, repoDir)).ThenReturn(result, nil) + When(whPostWorkflowHookRunner.Run(pCtx, testHook.RunCommand, repoDir)).ThenReturn(result, runtimeDesc, nil) err := postWh.RunPostHooks(ctx, nil) Ok(t, err) - whPostWorkflowHookRunner.VerifyWasCalledOnce().Run(pCtx, testHook.RunCommand, repoDir) + whPostWorkflowHookRunner.VerifyWasCalledOnce().Run(runtimematchers.AnyModelsWorkflowHookCommandContext(), EqString(testHook.RunCommand), EqString(repoDir)) Assert(t, *unlockCalled == true, "unlock function called") }) t.Run("success hooks not in cfg", func(t *testing.T) { @@ -209,7 +218,7 @@ func TestRunPostHooks_Clone(t *testing.T) { When(postWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) When(postWhWorkingDir.Clone(log, fixtures.GithubRepo, newPull, events.DefaultWorkspace)).ThenReturn(repoDir, false, nil) - When(whPostWorkflowHookRunner.Run(pCtx, testHook.RunCommand, repoDir)).ThenReturn(result, errors.New("some error")) + When(whPostWorkflowHookRunner.Run(runtimematchers.AnyModelsWorkflowHookCommandContext(), EqString(testHook.RunCommand), EqString(repoDir))).ThenReturn(result, runtimeDesc, errors.New("some error")) err := postWh.RunPostHooks(ctx, nil) @@ -247,12 +256,12 @@ func TestRunPostHooks_Clone(t *testing.T) { When(postWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) When(postWhWorkingDir.Clone(log, fixtures.GithubRepo, newPull, events.DefaultWorkspace)).ThenReturn(repoDir, false, nil) - When(whPostWorkflowHookRunner.Run(pCtx, testHook.RunCommand, repoDir)).ThenReturn(result, nil) + When(whPostWorkflowHookRunner.Run(runtimematchers.AnyModelsWorkflowHookCommandContext(), EqString(testHook.RunCommand), EqString(repoDir))).ThenReturn(result, runtimeDesc, nil) err := postWh.RunPostHooks(ctx, cmd) Ok(t, err) - whPostWorkflowHookRunner.VerifyWasCalledOnce().Run(expectedCtx, testHook.RunCommand, repoDir) + whPostWorkflowHookRunner.VerifyWasCalledOnce().Run(runtimematchers.AnyModelsWorkflowHookCommandContext(), EqString(testHook.RunCommand), EqString(repoDir)) Assert(t, *unlockCalled == true, "unlock function called") }) } diff --git a/server/events/pre_workflow_hooks_command_runner.go b/server/events/pre_workflow_hooks_command_runner.go index b5664bde0b..945f134304 100644 --- a/server/events/pre_workflow_hooks_command_runner.go +++ b/server/events/pre_workflow_hooks_command_runner.go @@ -1,6 +1,9 @@ package events import ( + "fmt" + + "github.com/google/uuid" "github.com/runatlantis/atlantis/server/core/config/valid" "github.com/runatlantis/atlantis/server/core/runtime" "github.com/runatlantis/atlantis/server/events/command" @@ -8,6 +11,13 @@ import ( "github.com/runatlantis/atlantis/server/events/vcs" ) +//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_pre_workflow_hook_url_generator.go PreWorkflowHookURLGenerator + +// PreWorkflowHookURLGenerator generates urls to view the pre workflow progress. +type PreWorkflowHookURLGenerator interface { + GenerateProjectWorkflowHookURL(hookID string) (string, error) +} + //go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_pre_workflows_hooks_command_runner.go PreWorkflowHooksCommandRunner type PreWorkflowHooksCommandRunner interface { @@ -21,6 +31,8 @@ type DefaultPreWorkflowHooksCommandRunner struct { WorkingDir WorkingDir GlobalCfg valid.GlobalCfg PreWorkflowHookRunner runtime.PreWorkflowHookRunner + CommitStatusUpdater CommitStatusUpdater + Router PreWorkflowHookURLGenerator } // RunPreHooks runs pre_workflow_hooks when PR is opened or updated. @@ -71,6 +83,7 @@ func (w *DefaultPreWorkflowHooksCommandRunner) RunPreHooks(ctx *command.Context, User: user, Verbose: false, EscapedCommentArgs: escapedArgs, + HookID: uuid.NewString(), }, preWorkflowHooks, repoDir) @@ -86,11 +99,33 @@ func (w *DefaultPreWorkflowHooksCommandRunner) runHooks( preWorkflowHooks []*valid.WorkflowHook, repoDir string, ) error { + for i, hook := range preWorkflowHooks { + hookDescription := hook.StepDescription + if hookDescription == "" { + hookDescription = fmt.Sprintf("Pre workflow hook #%d", i) + } - for _, hook := range preWorkflowHooks { - _, err := w.PreWorkflowHookRunner.Run(ctx, hook.RunCommand, repoDir) + url, err := w.Router.GenerateProjectWorkflowHookURL(ctx.HookID) + if err != nil { + return err + } + + if err := w.CommitStatusUpdater.UpdatePreWorkflowHook(ctx.Pull, models.PendingCommitStatus, hookDescription, "", url); err != nil { + ctx.Log.Warn("unable to pre workflow hook status: %s", err) + return err + } + + _, runtimeDesc, err := w.PreWorkflowHookRunner.Run(ctx, hook.RunCommand, repoDir) if err != nil { + if err := w.CommitStatusUpdater.UpdatePreWorkflowHook(ctx.Pull, models.FailedCommitStatus, hookDescription, runtimeDesc, url); err != nil { + ctx.Log.Warn("unable to pre workflow hook status: %s", err) + } + return err + } + + if err := w.CommitStatusUpdater.UpdatePreWorkflowHook(ctx.Pull, models.SuccessCommitStatus, hookDescription, runtimeDesc, url); err != nil { + ctx.Log.Warn("unable to pre workflow hook status: %s", err) return err } } diff --git a/server/events/pre_workflow_hooks_command_runner_test.go b/server/events/pre_workflow_hooks_command_runner_test.go index 13034e50a3..24d818716e 100644 --- a/server/events/pre_workflow_hooks_command_runner_test.go +++ b/server/events/pre_workflow_hooks_command_runner_test.go @@ -7,6 +7,7 @@ import ( . "github.com/petergtz/pegomock" "github.com/runatlantis/atlantis/server/core/config/valid" runtime_mocks "github.com/runatlantis/atlantis/server/core/runtime/mocks" + runtimematchers "github.com/runatlantis/atlantis/server/core/runtime/mocks/matchers" "github.com/runatlantis/atlantis/server/events" "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/events/mocks" @@ -21,6 +22,7 @@ var preWh events.DefaultPreWorkflowHooksCommandRunner var preWhWorkingDir *mocks.MockWorkingDir var preWhWorkingDirLocker *mocks.MockWorkingDirLocker var whPreWorkflowHookRunner *runtime_mocks.MockPreWorkflowHookRunner +var preCommitStatusUpdater *mocks.MockCommitStatusUpdater func preWorkflowHooksSetup(t *testing.T) { RegisterMockTestingT(t) @@ -28,12 +30,16 @@ func preWorkflowHooksSetup(t *testing.T) { preWhWorkingDir = mocks.NewMockWorkingDir() preWhWorkingDirLocker = mocks.NewMockWorkingDirLocker() whPreWorkflowHookRunner = runtime_mocks.NewMockPreWorkflowHookRunner() + preCommitStatusUpdater = mocks.NewMockCommitStatusUpdater() + preWorkflowHookURLGenerator := mocks.NewMockPreWorkflowHookURLGenerator() preWh = events.DefaultPreWorkflowHooksCommandRunner{ VCSClient: vcsClient, WorkingDirLocker: preWhWorkingDirLocker, WorkingDir: preWhWorkingDir, PreWorkflowHookRunner: whPreWorkflowHookRunner, + CommitStatusUpdater: preCommitStatusUpdater, + Router: preWorkflowHookURLGenerator, } } @@ -60,6 +66,10 @@ func TestRunPreHooks_Clone(t *testing.T) { RunCommand: "some command", } + repoDir := "path/to/repo" + result := "some result" + runtimeDesc := "" + pCtx := models.WorkflowHookCommandContext{ BaseRepo: fixtures.GithubRepo, HeadRepo: fixtures.GithubRepo, @@ -69,9 +79,6 @@ func TestRunPreHooks_Clone(t *testing.T) { Verbose: false, } - repoDir := "path/to/repo" - result := "some result" - t.Run("success hooks in cfg", func(t *testing.T) { preWorkflowHooksSetup(t) @@ -95,14 +102,15 @@ func TestRunPreHooks_Clone(t *testing.T) { When(preWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) When(preWhWorkingDir.Clone(log, fixtures.GithubRepo, newPull, events.DefaultWorkspace)).ThenReturn(repoDir, false, nil) - When(whPreWorkflowHookRunner.Run(pCtx, testHook.RunCommand, repoDir)).ThenReturn(result, nil) + When(whPreWorkflowHookRunner.Run(runtimematchers.AnyModelsWorkflowHookCommandContext(), EqString(testHook.RunCommand), EqString(repoDir))).ThenReturn(result, runtimeDesc, nil) err := preWh.RunPreHooks(ctx, nil) Ok(t, err) - whPreWorkflowHookRunner.VerifyWasCalledOnce().Run(pCtx, testHook.RunCommand, repoDir) + whPreWorkflowHookRunner.VerifyWasCalledOnce().Run(runtimematchers.AnyModelsWorkflowHookCommandContext(), EqString(testHook.RunCommand), EqString(repoDir)) Assert(t, *unlockCalled == true, "unlock function called") }) + t.Run("success hooks not in cfg", func(t *testing.T) { preWorkflowHooksSetup(t) globalCfg := valid.GlobalCfg{ @@ -128,10 +136,11 @@ func TestRunPreHooks_Clone(t *testing.T) { Ok(t, err) - whPreWorkflowHookRunner.VerifyWasCalled(Never()).Run(pCtx, testHook.RunCommand, repoDir) + whPreWorkflowHookRunner.VerifyWasCalled(Never()).Run(runtimematchers.AnyModelsWorkflowHookCommandContext(), EqString(testHook.RunCommand), EqString(repoDir)) preWhWorkingDirLocker.VerifyWasCalled(Never()).TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace) preWhWorkingDir.VerifyWasCalled(Never()).Clone(log, fixtures.GithubRepo, newPull, events.DefaultWorkspace) }) + t.Run("error locking work dir", func(t *testing.T) { preWorkflowHooksSetup(t) @@ -154,7 +163,7 @@ func TestRunPreHooks_Clone(t *testing.T) { Assert(t, err != nil, "error not nil") preWhWorkingDir.VerifyWasCalled(Never()).Clone(log, fixtures.GithubRepo, newPull, events.DefaultWorkspace) - whPreWorkflowHookRunner.VerifyWasCalled(Never()).Run(pCtx, testHook.RunCommand, repoDir) + whPreWorkflowHookRunner.VerifyWasCalled(Never()).Run(runtimematchers.AnyModelsWorkflowHookCommandContext(), EqString(testHook.RunCommand), EqString(repoDir)) }) t.Run("error cloning", func(t *testing.T) { @@ -185,7 +194,7 @@ func TestRunPreHooks_Clone(t *testing.T) { Assert(t, err != nil, "error not nil") - whPreWorkflowHookRunner.VerifyWasCalled(Never()).Run(pCtx, testHook.RunCommand, repoDir) + whPreWorkflowHookRunner.VerifyWasCalled(Never()).Run(runtimematchers.AnyModelsWorkflowHookCommandContext(), EqString(testHook.RunCommand), EqString(repoDir)) Assert(t, *unlockCalled == true, "unlock function called") }) @@ -212,7 +221,7 @@ func TestRunPreHooks_Clone(t *testing.T) { When(preWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) When(preWhWorkingDir.Clone(log, fixtures.GithubRepo, newPull, events.DefaultWorkspace)).ThenReturn(repoDir, false, nil) - When(whPreWorkflowHookRunner.Run(pCtx, testHook.RunCommand, repoDir)).ThenReturn(result, errors.New("some error")) + When(whPreWorkflowHookRunner.Run(runtimematchers.AnyModelsWorkflowHookCommandContext(), EqString(testHook.RunCommand), EqString(repoDir))).ThenReturn(result, runtimeDesc, errors.New("some error")) err := preWh.RunPreHooks(ctx, nil) @@ -250,12 +259,12 @@ func TestRunPreHooks_Clone(t *testing.T) { When(preWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil) When(preWhWorkingDir.Clone(log, fixtures.GithubRepo, newPull, events.DefaultWorkspace)).ThenReturn(repoDir, false, nil) - When(whPreWorkflowHookRunner.Run(pCtx, testHook.RunCommand, repoDir)).ThenReturn(result, nil) + When(whPreWorkflowHookRunner.Run(runtimematchers.AnyModelsWorkflowHookCommandContext(), EqString(testHook.RunCommand), EqString(repoDir))).ThenReturn(result, runtimeDesc, nil) err := preWh.RunPreHooks(ctx, cmd) Ok(t, err) - whPreWorkflowHookRunner.VerifyWasCalledOnce().Run(expectedCtx, testHook.RunCommand, repoDir) + whPreWorkflowHookRunner.VerifyWasCalledOnce().Run(runtimematchers.AnyModelsWorkflowHookCommandContext(), EqString(testHook.RunCommand), EqString(repoDir)) Assert(t, *unlockCalled == true, "unlock function called") }) } diff --git a/server/jobs/mocks/matchers/chan_of_string.go b/server/jobs/mocks/matchers/chan_of_string.go index 44526eb9bf..e1bfee5726 100644 --- a/server/jobs/mocks/matchers/chan_of_string.go +++ b/server/jobs/mocks/matchers/chan_of_string.go @@ -2,9 +2,8 @@ package matchers import ( - "reflect" - "github.com/petergtz/pegomock" + "reflect" ) func AnyChanOfString() chan string { diff --git a/server/jobs/mocks/matchers/command_projectcontext.go b/server/jobs/mocks/matchers/command_projectcontext.go new file mode 100644 index 0000000000..c25f35d932 --- /dev/null +++ b/server/jobs/mocks/matchers/command_projectcontext.go @@ -0,0 +1,33 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "github.com/petergtz/pegomock" + "reflect" + + command "github.com/runatlantis/atlantis/server/events/command" +) + +func AnyCommandProjectContext() command.ProjectContext { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(command.ProjectContext))(nil)).Elem())) + var nullValue command.ProjectContext + return nullValue +} + +func EqCommandProjectContext(value command.ProjectContext) command.ProjectContext { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue command.ProjectContext + return nullValue +} + +func NotEqCommandProjectContext(value command.ProjectContext) command.ProjectContext { + pegomock.RegisterMatcher(&pegomock.NotEqMatcher{Value: value}) + var nullValue command.ProjectContext + return nullValue +} + +func CommandProjectContextThat(matcher pegomock.ArgumentMatcher) command.ProjectContext { + pegomock.RegisterMatcher(matcher) + var nullValue command.ProjectContext + return nullValue +} diff --git a/server/jobs/mocks/matchers/jobs_pullinfo.go b/server/jobs/mocks/matchers/jobs_pullinfo.go index 64141c6b3c..95e16a16fa 100644 --- a/server/jobs/mocks/matchers/jobs_pullinfo.go +++ b/server/jobs/mocks/matchers/jobs_pullinfo.go @@ -2,9 +2,8 @@ package matchers import ( - "reflect" - "github.com/petergtz/pegomock" + "reflect" jobs "github.com/runatlantis/atlantis/server/jobs" ) diff --git a/server/jobs/mocks/matchers/models_workflowhookcommandcontext.go b/server/jobs/mocks/matchers/models_workflowhookcommandcontext.go new file mode 100644 index 0000000000..18a5a5bae9 --- /dev/null +++ b/server/jobs/mocks/matchers/models_workflowhookcommandcontext.go @@ -0,0 +1,33 @@ +// Code generated by pegomock. DO NOT EDIT. +package matchers + +import ( + "github.com/petergtz/pegomock" + "reflect" + + models "github.com/runatlantis/atlantis/server/events/models" +) + +func AnyModelsWorkflowHookCommandContext() models.WorkflowHookCommandContext { + pegomock.RegisterMatcher(pegomock.NewAnyMatcher(reflect.TypeOf((*(models.WorkflowHookCommandContext))(nil)).Elem())) + var nullValue models.WorkflowHookCommandContext + return nullValue +} + +func EqModelsWorkflowHookCommandContext(value models.WorkflowHookCommandContext) models.WorkflowHookCommandContext { + pegomock.RegisterMatcher(&pegomock.EqMatcher{Value: value}) + var nullValue models.WorkflowHookCommandContext + return nullValue +} + +func NotEqModelsWorkflowHookCommandContext(value models.WorkflowHookCommandContext) models.WorkflowHookCommandContext { + pegomock.RegisterMatcher(&pegomock.NotEqMatcher{Value: value}) + var nullValue models.WorkflowHookCommandContext + return nullValue +} + +func ModelsWorkflowHookCommandContextThat(matcher pegomock.ArgumentMatcher) models.WorkflowHookCommandContext { + pegomock.RegisterMatcher(matcher) + var nullValue models.WorkflowHookCommandContext + return nullValue +} diff --git a/server/jobs/mocks/mock_project_command_output_handler.go b/server/jobs/mocks/mock_project_command_output_handler.go index 8bc39e45e1..2ff07bc5a5 100644 --- a/server/jobs/mocks/mock_project_command_output_handler.go +++ b/server/jobs/mocks/mock_project_command_output_handler.go @@ -4,12 +4,12 @@ package mocks import ( - "reflect" - "time" - pegomock "github.com/petergtz/pegomock" - "github.com/runatlantis/atlantis/server/events/command" + command "github.com/runatlantis/atlantis/server/events/command" + models "github.com/runatlantis/atlantis/server/events/models" jobs "github.com/runatlantis/atlantis/server/jobs" + "reflect" + "time" ) type MockProjectCommandOutputHandler struct { @@ -27,35 +27,43 @@ func NewMockProjectCommandOutputHandler(options ...pegomock.Option) *MockProject func (mock *MockProjectCommandOutputHandler) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockProjectCommandOutputHandler) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockProjectCommandOutputHandler) CleanUp(_param0 jobs.PullInfo) { +func (mock *MockProjectCommandOutputHandler) Send(ctx command.ProjectContext, msg string, operationComplete bool) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockProjectCommandOutputHandler().") } - params := []pegomock.Param{_param0} - pegomock.GetGenericMockFrom(mock).Invoke("CleanUp", params, []reflect.Type{}) + params := []pegomock.Param{ctx, msg, operationComplete} + pegomock.GetGenericMockFrom(mock).Invoke("Send", params, []reflect.Type{}) } -func (mock *MockProjectCommandOutputHandler) Deregister(_param0 string, _param1 chan string) { +func (mock *MockProjectCommandOutputHandler) SendWorkflowHook(ctx models.WorkflowHookCommandContext, msg string, operationComplete bool) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockProjectCommandOutputHandler().") } - params := []pegomock.Param{_param0, _param1} - pegomock.GetGenericMockFrom(mock).Invoke("Deregister", params, []reflect.Type{}) + params := []pegomock.Param{ctx, msg, operationComplete} + pegomock.GetGenericMockFrom(mock).Invoke("SendWorkflowHook", params, []reflect.Type{}) } -func (mock *MockProjectCommandOutputHandler) Handle() { +func (mock *MockProjectCommandOutputHandler) Register(jobID string, receiver chan string) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockProjectCommandOutputHandler().") } - params := []pegomock.Param{} - pegomock.GetGenericMockFrom(mock).Invoke("Handle", params, []reflect.Type{}) + params := []pegomock.Param{jobID, receiver} + pegomock.GetGenericMockFrom(mock).Invoke("Register", params, []reflect.Type{}) } -func (mock *MockProjectCommandOutputHandler) IsKeyExists(_param0 string) bool { +func (mock *MockProjectCommandOutputHandler) Deregister(jobID string, receiver chan string) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockProjectCommandOutputHandler().") } - params := []pegomock.Param{_param0} + params := []pegomock.Param{jobID, receiver} + pegomock.GetGenericMockFrom(mock).Invoke("Deregister", params, []reflect.Type{}) +} + +func (mock *MockProjectCommandOutputHandler) IsKeyExists(key string) bool { + if mock == nil { + panic("mock must not be nil. Use myMock := NewMockProjectCommandOutputHandler().") + } + params := []pegomock.Param{key} result := pegomock.GetGenericMockFrom(mock).Invoke("IsKeyExists", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem()}) var ret0 bool if len(result) != 0 { @@ -66,20 +74,20 @@ func (mock *MockProjectCommandOutputHandler) IsKeyExists(_param0 string) bool { return ret0 } -func (mock *MockProjectCommandOutputHandler) Register(_param0 string, _param1 chan string) { +func (mock *MockProjectCommandOutputHandler) Handle() { if mock == nil { panic("mock must not be nil. Use myMock := NewMockProjectCommandOutputHandler().") } - params := []pegomock.Param{_param0, _param1} - pegomock.GetGenericMockFrom(mock).Invoke("Register", params, []reflect.Type{}) + params := []pegomock.Param{} + pegomock.GetGenericMockFrom(mock).Invoke("Handle", params, []reflect.Type{}) } -func (mock *MockProjectCommandOutputHandler) Send(_param0 command.ProjectContext, _param1 string, _param2 bool) { +func (mock *MockProjectCommandOutputHandler) CleanUp(pullInfo jobs.PullInfo) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockProjectCommandOutputHandler().") } - params := []pegomock.Param{_param0, _param1, _param2} - pegomock.GetGenericMockFrom(mock).Invoke("Send", params, []reflect.Type{}) + params := []pegomock.Param{pullInfo} + pegomock.GetGenericMockFrom(mock).Invoke("CleanUp", params, []reflect.Type{}) } func (mock *MockProjectCommandOutputHandler) VerifyWasCalledOnce() *VerifierMockProjectCommandOutputHandler { @@ -119,50 +127,93 @@ type VerifierMockProjectCommandOutputHandler struct { timeout time.Duration } -func (verifier *VerifierMockProjectCommandOutputHandler) CleanUp(_param0 jobs.PullInfo) *MockProjectCommandOutputHandler_CleanUp_OngoingVerification { - params := []pegomock.Param{_param0} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CleanUp", params, verifier.timeout) - return &MockProjectCommandOutputHandler_CleanUp_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockProjectCommandOutputHandler) Send(ctx command.ProjectContext, msg string, operationComplete bool) *MockProjectCommandOutputHandler_Send_OngoingVerification { + params := []pegomock.Param{ctx, msg, operationComplete} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Send", params, verifier.timeout) + return &MockProjectCommandOutputHandler_Send_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockProjectCommandOutputHandler_CleanUp_OngoingVerification struct { +type MockProjectCommandOutputHandler_Send_OngoingVerification struct { mock *MockProjectCommandOutputHandler methodInvocations []pegomock.MethodInvocation } -func (c *MockProjectCommandOutputHandler_CleanUp_OngoingVerification) GetCapturedArguments() jobs.PullInfo { - _param0 := c.GetAllCapturedArguments() - return _param0[len(_param0)-1] +func (c *MockProjectCommandOutputHandler_Send_OngoingVerification) GetCapturedArguments() (command.ProjectContext, string, bool) { + ctx, msg, operationComplete := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], msg[len(msg)-1], operationComplete[len(operationComplete)-1] } -func (c *MockProjectCommandOutputHandler_CleanUp_OngoingVerification) GetAllCapturedArguments() (_param0 []jobs.PullInfo) { +func (c *MockProjectCommandOutputHandler_Send_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 []string, _param2 []bool) { params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) if len(params) > 0 { - _param0 = make([]jobs.PullInfo, len(c.methodInvocations)) + _param0 = make([]command.ProjectContext, len(c.methodInvocations)) for u, param := range params[0] { - _param0[u] = param.(jobs.PullInfo) + _param0[u] = param.(command.ProjectContext) + } + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range params[1] { + _param1[u] = param.(string) + } + _param2 = make([]bool, len(c.methodInvocations)) + for u, param := range params[2] { + _param2[u] = param.(bool) } } return } -func (verifier *VerifierMockProjectCommandOutputHandler) Deregister(_param0 string, _param1 chan string) *MockProjectCommandOutputHandler_Deregister_OngoingVerification { - params := []pegomock.Param{_param0, _param1} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Deregister", params, verifier.timeout) - return &MockProjectCommandOutputHandler_Deregister_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockProjectCommandOutputHandler) SendWorkflowHook(ctx models.WorkflowHookCommandContext, msg string, operationComplete bool) *MockProjectCommandOutputHandler_SendWorkflowHook_OngoingVerification { + params := []pegomock.Param{ctx, msg, operationComplete} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "SendWorkflowHook", params, verifier.timeout) + return &MockProjectCommandOutputHandler_SendWorkflowHook_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockProjectCommandOutputHandler_Deregister_OngoingVerification struct { +type MockProjectCommandOutputHandler_SendWorkflowHook_OngoingVerification struct { mock *MockProjectCommandOutputHandler methodInvocations []pegomock.MethodInvocation } -func (c *MockProjectCommandOutputHandler_Deregister_OngoingVerification) GetCapturedArguments() (string, chan string) { - _param0, _param1 := c.GetAllCapturedArguments() - return _param0[len(_param0)-1], _param1[len(_param1)-1] +func (c *MockProjectCommandOutputHandler_SendWorkflowHook_OngoingVerification) GetCapturedArguments() (models.WorkflowHookCommandContext, string, bool) { + ctx, msg, operationComplete := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], msg[len(msg)-1], operationComplete[len(operationComplete)-1] } -func (c *MockProjectCommandOutputHandler_Deregister_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []chan string) { +func (c *MockProjectCommandOutputHandler_SendWorkflowHook_OngoingVerification) GetAllCapturedArguments() (_param0 []models.WorkflowHookCommandContext, _param1 []string, _param2 []bool) { + params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(params) > 0 { + _param0 = make([]models.WorkflowHookCommandContext, len(c.methodInvocations)) + for u, param := range params[0] { + _param0[u] = param.(models.WorkflowHookCommandContext) + } + _param1 = make([]string, len(c.methodInvocations)) + for u, param := range params[1] { + _param1[u] = param.(string) + } + _param2 = make([]bool, len(c.methodInvocations)) + for u, param := range params[2] { + _param2[u] = param.(bool) + } + } + return +} + +func (verifier *VerifierMockProjectCommandOutputHandler) Register(jobID string, receiver chan string) *MockProjectCommandOutputHandler_Register_OngoingVerification { + params := []pegomock.Param{jobID, receiver} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Register", params, verifier.timeout) + return &MockProjectCommandOutputHandler_Register_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +} + +type MockProjectCommandOutputHandler_Register_OngoingVerification struct { + mock *MockProjectCommandOutputHandler + methodInvocations []pegomock.MethodInvocation +} + +func (c *MockProjectCommandOutputHandler_Register_OngoingVerification) GetCapturedArguments() (string, chan string) { + jobID, receiver := c.GetAllCapturedArguments() + return jobID[len(jobID)-1], receiver[len(receiver)-1] +} + +func (c *MockProjectCommandOutputHandler_Register_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []chan string) { params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) if len(params) > 0 { _param0 = make([]string, len(c.methodInvocations)) @@ -177,25 +228,39 @@ func (c *MockProjectCommandOutputHandler_Deregister_OngoingVerification) GetAllC return } -func (verifier *VerifierMockProjectCommandOutputHandler) Handle() *MockProjectCommandOutputHandler_Handle_OngoingVerification { - params := []pegomock.Param{} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Handle", params, verifier.timeout) - return &MockProjectCommandOutputHandler_Handle_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockProjectCommandOutputHandler) Deregister(jobID string, receiver chan string) *MockProjectCommandOutputHandler_Deregister_OngoingVerification { + params := []pegomock.Param{jobID, receiver} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Deregister", params, verifier.timeout) + return &MockProjectCommandOutputHandler_Deregister_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockProjectCommandOutputHandler_Handle_OngoingVerification struct { +type MockProjectCommandOutputHandler_Deregister_OngoingVerification struct { mock *MockProjectCommandOutputHandler methodInvocations []pegomock.MethodInvocation } -func (c *MockProjectCommandOutputHandler_Handle_OngoingVerification) GetCapturedArguments() { +func (c *MockProjectCommandOutputHandler_Deregister_OngoingVerification) GetCapturedArguments() (string, chan string) { + jobID, receiver := c.GetAllCapturedArguments() + return jobID[len(jobID)-1], receiver[len(receiver)-1] } -func (c *MockProjectCommandOutputHandler_Handle_OngoingVerification) GetAllCapturedArguments() { +func (c *MockProjectCommandOutputHandler_Deregister_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []chan string) { + params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) + if len(params) > 0 { + _param0 = make([]string, len(c.methodInvocations)) + for u, param := range params[0] { + _param0[u] = param.(string) + } + _param1 = make([]chan string, len(c.methodInvocations)) + for u, param := range params[1] { + _param1[u] = param.(chan string) + } + } + return } -func (verifier *VerifierMockProjectCommandOutputHandler) IsKeyExists(_param0 string) *MockProjectCommandOutputHandler_IsKeyExists_OngoingVerification { - params := []pegomock.Param{_param0} +func (verifier *VerifierMockProjectCommandOutputHandler) IsKeyExists(key string) *MockProjectCommandOutputHandler_IsKeyExists_OngoingVerification { + params := []pegomock.Param{key} methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "IsKeyExists", params, verifier.timeout) return &MockProjectCommandOutputHandler_IsKeyExists_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -206,8 +271,8 @@ type MockProjectCommandOutputHandler_IsKeyExists_OngoingVerification struct { } func (c *MockProjectCommandOutputHandler_IsKeyExists_OngoingVerification) GetCapturedArguments() string { - _param0 := c.GetAllCapturedArguments() - return _param0[len(_param0)-1] + key := c.GetAllCapturedArguments() + return key[len(key)-1] } func (c *MockProjectCommandOutputHandler_IsKeyExists_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { @@ -221,67 +286,45 @@ func (c *MockProjectCommandOutputHandler_IsKeyExists_OngoingVerification) GetAll return } -func (verifier *VerifierMockProjectCommandOutputHandler) Register(_param0 string, _param1 chan string) *MockProjectCommandOutputHandler_Register_OngoingVerification { - params := []pegomock.Param{_param0, _param1} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Register", params, verifier.timeout) - return &MockProjectCommandOutputHandler_Register_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockProjectCommandOutputHandler) Handle() *MockProjectCommandOutputHandler_Handle_OngoingVerification { + params := []pegomock.Param{} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Handle", params, verifier.timeout) + return &MockProjectCommandOutputHandler_Handle_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockProjectCommandOutputHandler_Register_OngoingVerification struct { +type MockProjectCommandOutputHandler_Handle_OngoingVerification struct { mock *MockProjectCommandOutputHandler methodInvocations []pegomock.MethodInvocation } -func (c *MockProjectCommandOutputHandler_Register_OngoingVerification) GetCapturedArguments() (string, chan string) { - _param0, _param1 := c.GetAllCapturedArguments() - return _param0[len(_param0)-1], _param1[len(_param1)-1] +func (c *MockProjectCommandOutputHandler_Handle_OngoingVerification) GetCapturedArguments() { } -func (c *MockProjectCommandOutputHandler_Register_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []chan string) { - params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) - if len(params) > 0 { - _param0 = make([]string, len(c.methodInvocations)) - for u, param := range params[0] { - _param0[u] = param.(string) - } - _param1 = make([]chan string, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(chan string) - } - } - return +func (c *MockProjectCommandOutputHandler_Handle_OngoingVerification) GetAllCapturedArguments() { } -func (verifier *VerifierMockProjectCommandOutputHandler) Send(_param0 command.ProjectContext, _param1 string, _param2 bool) *MockProjectCommandOutputHandler_Send_OngoingVerification { - params := []pegomock.Param{_param0, _param1, _param2} - methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Send", params, verifier.timeout) - return &MockProjectCommandOutputHandler_Send_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} +func (verifier *VerifierMockProjectCommandOutputHandler) CleanUp(pullInfo jobs.PullInfo) *MockProjectCommandOutputHandler_CleanUp_OngoingVerification { + params := []pegomock.Param{pullInfo} + methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CleanUp", params, verifier.timeout) + return &MockProjectCommandOutputHandler_CleanUp_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } -type MockProjectCommandOutputHandler_Send_OngoingVerification struct { +type MockProjectCommandOutputHandler_CleanUp_OngoingVerification struct { mock *MockProjectCommandOutputHandler methodInvocations []pegomock.MethodInvocation } -func (c *MockProjectCommandOutputHandler_Send_OngoingVerification) GetCapturedArguments() (command.ProjectContext, string, bool) { - _param0, _param1, _param2 := c.GetAllCapturedArguments() - return _param0[len(_param0)-1], _param1[len(_param1)-1], _param2[len(_param2)-1] +func (c *MockProjectCommandOutputHandler_CleanUp_OngoingVerification) GetCapturedArguments() jobs.PullInfo { + pullInfo := c.GetAllCapturedArguments() + return pullInfo[len(pullInfo)-1] } -func (c *MockProjectCommandOutputHandler_Send_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 []string, _param2 []bool) { +func (c *MockProjectCommandOutputHandler_CleanUp_OngoingVerification) GetAllCapturedArguments() (_param0 []jobs.PullInfo) { params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) if len(params) > 0 { - _param0 = make([]command.ProjectContext, len(c.methodInvocations)) + _param0 = make([]jobs.PullInfo, len(c.methodInvocations)) for u, param := range params[0] { - _param0[u] = param.(command.ProjectContext) - } - _param1 = make([]string, len(c.methodInvocations)) - for u, param := range params[1] { - _param1[u] = param.(string) - } - _param2 = make([]bool, len(c.methodInvocations)) - for u, param := range params[2] { - _param2[u] = param.(bool) + _param0[u] = param.(jobs.PullInfo) } } return diff --git a/server/jobs/project_command_output_handler.go b/server/jobs/project_command_output_handler.go index 9b1e8ff131..6a26e4516f 100644 --- a/server/jobs/project_command_output_handler.go +++ b/server/jobs/project_command_output_handler.go @@ -4,6 +4,7 @@ import ( "sync" "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/logging" ) @@ -54,6 +55,8 @@ type ProjectCommandOutputHandler interface { // Send will enqueue the msg and wait for Handle() to receive the message. Send(ctx command.ProjectContext, msg string, operationComplete bool) + SendWorkflowHook(ctx models.WorkflowHookCommandContext, msg string, operationComplete bool) + // Register registers a channel and blocks until it is caught up. Callers should call this asynchronously when attempting // to read the channel in the same goroutine Register(jobID string, receiver chan string) @@ -107,6 +110,21 @@ func (p *AsyncProjectCommandOutputHandler) Send(ctx command.ProjectContext, msg } } +func (p *AsyncProjectCommandOutputHandler) SendWorkflowHook(ctx models.WorkflowHookCommandContext, msg string, operationComplete bool) { + p.projectCmdOutput <- &ProjectCmdOutputLine{ + JobID: ctx.HookID, + JobInfo: JobInfo{ + HeadCommit: ctx.Pull.HeadCommit, + PullInfo: PullInfo{ + PullNum: ctx.Pull.Num, + Repo: ctx.BaseRepo.Name, + }, + }, + Line: msg, + OperationComplete: operationComplete, + } +} + func (p *AsyncProjectCommandOutputHandler) Register(jobID string, receiver chan string) { p.addChan(receiver, jobID) } @@ -252,6 +270,9 @@ type NoopProjectOutputHandler struct{} func (p *NoopProjectOutputHandler) Send(ctx command.ProjectContext, msg string, isOperationComplete bool) { } +func (p *NoopProjectOutputHandler) SendWorkflowHook(ctx models.WorkflowHookCommandContext, msg string, operationComplete bool) { +} + func (p *NoopProjectOutputHandler) Register(jobID string, receiver chan string) {} func (p *NoopProjectOutputHandler) Deregister(jobID string, receiver chan string) {} diff --git a/server/router.go b/server/router.go index ce480e2567..65f72031cb 100644 --- a/server/router.go +++ b/server/router.go @@ -52,3 +52,14 @@ func (r *Router) GenerateProjectJobURL(ctx command.ProjectContext) (string, erro return r.AtlantisURL.String() + jobURL.String(), nil } + +func (r *Router) GenerateProjectWorkflowHookURL(hookID string) (string, error) { + jobURL, err := r.Underlying.Get((r.ProjectJobsViewRouteName)).URL( + "job-id", hookID, + ) + if err != nil { + return "", errors.Wrapf(err, "creating workflow hook url for %s", hookID) + } + + return r.AtlantisURL.String() + jobURL.String(), nil +} diff --git a/server/server.go b/server/server.go index c5f72b3676..2e84a37ea6 100644 --- a/server/server.go +++ b/server/server.go @@ -519,18 +519,26 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { AtlantisVersion: config.AtlantisVersion, } preWorkflowHooksCommandRunner := &events.DefaultPreWorkflowHooksCommandRunner{ - VCSClient: vcsClient, - GlobalCfg: globalCfg, - WorkingDirLocker: workingDirLocker, - WorkingDir: workingDir, - PreWorkflowHookRunner: runtime.DefaultPreWorkflowHookRunner{}, + VCSClient: vcsClient, + GlobalCfg: globalCfg, + WorkingDirLocker: workingDirLocker, + WorkingDir: workingDir, + PreWorkflowHookRunner: runtime.DefaultPreWorkflowHookRunner{ + OutputHandler: projectCmdOutputHandler, + }, + CommitStatusUpdater: commitStatusUpdater, + Router: router, } postWorkflowHooksCommandRunner := &events.DefaultPostWorkflowHooksCommandRunner{ - VCSClient: vcsClient, - GlobalCfg: globalCfg, - WorkingDirLocker: workingDirLocker, - WorkingDir: workingDir, - PostWorkflowHookRunner: runtime.DefaultPostWorkflowHookRunner{}, + VCSClient: vcsClient, + GlobalCfg: globalCfg, + WorkingDirLocker: workingDirLocker, + WorkingDir: workingDir, + PostWorkflowHookRunner: runtime.DefaultPostWorkflowHookRunner{ + OutputHandler: projectCmdOutputHandler, + }, + CommitStatusUpdater: commitStatusUpdater, + Router: router, } projectCommandBuilder := events.NewInstrumentedProjectCommandBuilder( policyChecksEnabled,