From 0b0cc77fb2f6585b5a3d9f9caa4cd30752b438d4 Mon Sep 17 00:00:00 2001 From: "adam.verigin" Date: Tue, 25 Oct 2022 13:06:21 -0700 Subject: [PATCH] Add COMMENT_ARGS to pre/post-workflow hook execution environment --- runatlantis.io/docs/post-workflow-hooks.md | 2 + runatlantis.io/docs/pre-workflow-hooks.md | 2 + .../core/runtime/post_workflow_hook_runner.go | 2 + .../core/runtime/pre_workflow_hook_runner.go | 2 + server/events/command_runner.go | 8 +-- server/events/command_runner_test.go | 4 +- ...ock_post_workflows_hooks_command_runner.go | 23 +++++---- ...mock_pre_workflows_hooks_command_runner.go | 21 +++++--- server/events/models/models.go | 5 ++ .../post_workflow_hooks_command_runner.go | 22 ++++++--- ...post_workflow_hooks_command_runner_test.go | 49 +++++++++++++++++-- .../pre_workflow_hooks_command_runner.go | 24 +++++---- .../pre_workflow_hooks_command_runner_test.go | 49 +++++++++++++++++-- 13 files changed, 162 insertions(+), 51 deletions(-) diff --git a/runatlantis.io/docs/post-workflow-hooks.md b/runatlantis.io/docs/post-workflow-hooks.md index 577b677541..16e043a68e 100644 --- a/runatlantis.io/docs/post-workflow-hooks.md +++ b/runatlantis.io/docs/post-workflow-hooks.md @@ -72,4 +72,6 @@ command](custom-workflows.html#custom-run-command). * `PULL_AUTHOR` - Username of the pull request author, ex. `acme-user`. * `DIR` - The absolute path to the root of the cloned repository. * `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`. ::: diff --git a/runatlantis.io/docs/pre-workflow-hooks.md b/runatlantis.io/docs/pre-workflow-hooks.md index 33dff00b3a..b3b410f156 100644 --- a/runatlantis.io/docs/pre-workflow-hooks.md +++ b/runatlantis.io/docs/pre-workflow-hooks.md @@ -56,5 +56,7 @@ command](custom-workflows.html#custom-run-command). * `PULL_AUTHOR` - Username of the pull request author, ex. `acme-user`. * `DIR` - The absolute path to the root of the cloned repository. * `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`. ::: diff --git a/server/core/runtime/post_workflow_hook_runner.go b/server/core/runtime/post_workflow_hook_runner.go index 8f2df1d2db..11e1db429f 100644 --- a/server/core/runtime/post_workflow_hook_runner.go +++ b/server/core/runtime/post_workflow_hook_runner.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "os/exec" + "strings" "github.com/runatlantis/atlantis/server/events/models" ) @@ -24,6 +25,7 @@ func (wh DefaultPostWorkflowHookRunner) Run(ctx models.WorkflowHookCommandContex "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, diff --git a/server/core/runtime/pre_workflow_hook_runner.go b/server/core/runtime/pre_workflow_hook_runner.go index d3004c84eb..60520cfcff 100644 --- a/server/core/runtime/pre_workflow_hook_runner.go +++ b/server/core/runtime/pre_workflow_hook_runner.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "os/exec" + "strings" "github.com/runatlantis/atlantis/server/events/models" ) @@ -24,6 +25,7 @@ func (wh DefaultPreWorkflowHookRunner) Run(ctx models.WorkflowHookCommandContext "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, diff --git a/server/events/command_runner.go b/server/events/command_runner.go index 0bdf0ba88d..19eb0232a4 100644 --- a/server/events/command_runner.go +++ b/server/events/command_runner.go @@ -163,7 +163,7 @@ func (c *DefaultCommandRunner) RunAutoplanCommand(baseRepo models.Repo, headRepo return } - err = c.PreWorkflowHooksCommandRunner.RunPreHooks(ctx) + err = c.PreWorkflowHooksCommandRunner.RunPreHooks(ctx, nil) if err != nil { ctx.Log.Err("Error running pre-workflow hooks %s. Proceeding with %s command.", err, command.Plan) @@ -173,7 +173,7 @@ func (c *DefaultCommandRunner) RunAutoplanCommand(baseRepo models.Repo, headRepo autoPlanRunner.Run(ctx, nil) - err = c.PostWorkflowHooksCommandRunner.RunPostHooks(ctx) + err = c.PostWorkflowHooksCommandRunner.RunPostHooks(ctx, nil) if err != nil { ctx.Log.Err("Error running post-workflow hooks %s.", err) @@ -285,7 +285,7 @@ func (c *DefaultCommandRunner) RunCommentCommand(baseRepo models.Repo, maybeHead return } - err = c.PreWorkflowHooksCommandRunner.RunPreHooks(ctx) + err = c.PreWorkflowHooksCommandRunner.RunPreHooks(ctx, cmd) if err != nil { ctx.Log.Err("Error running pre-workflow hooks %s. Proceeding with %s command.", err, cmd.Name.String()) @@ -295,7 +295,7 @@ func (c *DefaultCommandRunner) RunCommentCommand(baseRepo models.Repo, maybeHead cmdRunner.Run(ctx, cmd) - err = c.PostWorkflowHooksCommandRunner.RunPostHooks(ctx) + err = c.PostWorkflowHooksCommandRunner.RunPostHooks(ctx, cmd) if err != nil { ctx.Log.Err("Error running post-workflow hooks %s.", err) diff --git a/server/events/command_runner_test.go b/server/events/command_runner_test.go index 1df1c8692f..c501e9fb8b 100644 --- a/server/events/command_runner_test.go +++ b/server/events/command_runner_test.go @@ -192,11 +192,11 @@ func setup(t *testing.T) *vcsmocks.MockClient { preWorkflowHooksCommandRunner = mocks.NewMockPreWorkflowHooksCommandRunner() - When(preWorkflowHooksCommandRunner.RunPreHooks(matchers.AnyPtrToEventsCommandContext())).ThenReturn(nil) + When(preWorkflowHooksCommandRunner.RunPreHooks(matchers.AnyPtrToEventsCommandContext(), matchers.AnyPtrToEventsCommentCommand())).ThenReturn(nil) postWorkflowHooksCommandRunner = mocks.NewMockPostWorkflowHooksCommandRunner() - When(postWorkflowHooksCommandRunner.RunPostHooks(matchers.AnyPtrToEventsCommandContext())).ThenReturn(nil) + When(postWorkflowHooksCommandRunner.RunPostHooks(matchers.AnyPtrToEventsCommandContext(), matchers.AnyPtrToEventsCommentCommand())).ThenReturn(nil) globalCfg := valid.NewGlobalCfgFromArgs(valid.GlobalCfgArgs{}) scope, _, _ := metrics.NewLoggingScope(logger, "atlantis") 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 9ff923e419..8bfcde7ac2 100644 --- a/server/events/mocks/mock_post_workflows_hooks_command_runner.go +++ b/server/events/mocks/mock_post_workflows_hooks_command_runner.go @@ -8,7 +8,8 @@ import ( "time" pegomock "github.com/petergtz/pegomock" - "github.com/runatlantis/atlantis/server/events/command" + events "github.com/runatlantis/atlantis/server/events" + command "github.com/runatlantis/atlantis/server/events/command" ) type MockPostWorkflowHooksCommandRunner struct { @@ -28,11 +29,11 @@ func (mock *MockPostWorkflowHooksCommandRunner) SetFailHandler(fh pegomock.FailH } func (mock *MockPostWorkflowHooksCommandRunner) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockPostWorkflowHooksCommandRunner) RunPostHooks(ctx *command.Context) error { +func (mock *MockPostWorkflowHooksCommandRunner) RunPostHooks(ctx *command.Context, cmd *events.CommentCommand) error { if mock == nil { panic("mock must not be nil. Use myMock := NewMockPostWorkflowHooksCommandRunner().") } - params := []pegomock.Param{ctx} + params := []pegomock.Param{ctx, cmd} result := pegomock.GetGenericMockFrom(mock).Invoke("RunPostHooks", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) var ret0 error if len(result) != 0 { @@ -80,8 +81,8 @@ type VerifierMockPostWorkflowHooksCommandRunner struct { timeout time.Duration } -func (verifier *VerifierMockPostWorkflowHooksCommandRunner) RunPostHooks(ctx *command.Context) *MockPostWorkflowHooksCommandRunner_RunPostHooks_OngoingVerification { - params := []pegomock.Param{ctx} +func (verifier *VerifierMockPostWorkflowHooksCommandRunner) RunPostHooks(ctx *command.Context, cmd *events.CommentCommand) *MockPostWorkflowHooksCommandRunner_RunPostHooks_OngoingVerification { + params := []pegomock.Param{ctx, cmd} methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "RunPostHooks", params, verifier.timeout) return &MockPostWorkflowHooksCommandRunner_RunPostHooks_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -91,18 +92,22 @@ type MockPostWorkflowHooksCommandRunner_RunPostHooks_OngoingVerification struct methodInvocations []pegomock.MethodInvocation } -func (c *MockPostWorkflowHooksCommandRunner_RunPostHooks_OngoingVerification) GetCapturedArguments() *command.Context { - ctx := c.GetAllCapturedArguments() - return ctx[len(ctx)-1] +func (c *MockPostWorkflowHooksCommandRunner_RunPostHooks_OngoingVerification) GetCapturedArguments() (*command.Context, *events.CommentCommand) { + ctx, cmd := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], cmd[len(cmd)-1] } -func (c *MockPostWorkflowHooksCommandRunner_RunPostHooks_OngoingVerification) GetAllCapturedArguments() (_param0 []*command.Context) { +func (c *MockPostWorkflowHooksCommandRunner_RunPostHooks_OngoingVerification) GetAllCapturedArguments() (_param0 []*command.Context, _param1 []*events.CommentCommand) { params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) if len(params) > 0 { _param0 = make([]*command.Context, len(c.methodInvocations)) for u, param := range params[0] { _param0[u] = param.(*command.Context) } + _param1 = make([]*events.CommentCommand, len(c.methodInvocations)) + for u, param := range params[1] { + _param1[u] = param.(*events.CommentCommand) + } } return } 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 9c3cb33167..22599a02e3 100644 --- a/server/events/mocks/mock_pre_workflows_hooks_command_runner.go +++ b/server/events/mocks/mock_pre_workflows_hooks_command_runner.go @@ -8,6 +8,7 @@ import ( "time" pegomock "github.com/petergtz/pegomock" + events "github.com/runatlantis/atlantis/server/events" command "github.com/runatlantis/atlantis/server/events/command" ) @@ -28,11 +29,11 @@ func (mock *MockPreWorkflowHooksCommandRunner) SetFailHandler(fh pegomock.FailHa } func (mock *MockPreWorkflowHooksCommandRunner) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockPreWorkflowHooksCommandRunner) RunPreHooks(ctx *command.Context) error { +func (mock *MockPreWorkflowHooksCommandRunner) RunPreHooks(ctx *command.Context, cmd *events.CommentCommand) error { if mock == nil { panic("mock must not be nil. Use myMock := NewMockPreWorkflowHooksCommandRunner().") } - params := []pegomock.Param{ctx} + params := []pegomock.Param{ctx, cmd} result := pegomock.GetGenericMockFrom(mock).Invoke("RunPreHooks", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) var ret0 error if len(result) != 0 { @@ -80,8 +81,8 @@ type VerifierMockPreWorkflowHooksCommandRunner struct { timeout time.Duration } -func (verifier *VerifierMockPreWorkflowHooksCommandRunner) RunPreHooks(ctx *command.Context) *MockPreWorkflowHooksCommandRunner_RunPreHooks_OngoingVerification { - params := []pegomock.Param{ctx} +func (verifier *VerifierMockPreWorkflowHooksCommandRunner) RunPreHooks(ctx *command.Context, cmd *events.CommentCommand) *MockPreWorkflowHooksCommandRunner_RunPreHooks_OngoingVerification { + params := []pegomock.Param{ctx, cmd} methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "RunPreHooks", params, verifier.timeout) return &MockPreWorkflowHooksCommandRunner_RunPreHooks_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} } @@ -91,18 +92,22 @@ type MockPreWorkflowHooksCommandRunner_RunPreHooks_OngoingVerification struct { methodInvocations []pegomock.MethodInvocation } -func (c *MockPreWorkflowHooksCommandRunner_RunPreHooks_OngoingVerification) GetCapturedArguments() *command.Context { - ctx := c.GetAllCapturedArguments() - return ctx[len(ctx)-1] +func (c *MockPreWorkflowHooksCommandRunner_RunPreHooks_OngoingVerification) GetCapturedArguments() (*command.Context, *events.CommentCommand) { + ctx, cmd := c.GetAllCapturedArguments() + return ctx[len(ctx)-1], cmd[len(cmd)-1] } -func (c *MockPreWorkflowHooksCommandRunner_RunPreHooks_OngoingVerification) GetAllCapturedArguments() (_param0 []*command.Context) { +func (c *MockPreWorkflowHooksCommandRunner_RunPreHooks_OngoingVerification) GetAllCapturedArguments() (_param0 []*command.Context, _param1 []*events.CommentCommand) { params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) if len(params) > 0 { _param0 = make([]*command.Context, len(c.methodInvocations)) for u, param := range params[0] { _param0[u] = param.(*command.Context) } + _param1 = make([]*events.CommentCommand, len(c.methodInvocations)) + for u, param := range params[1] { + _param1[u] = param.(*events.CommentCommand) + } } return } diff --git a/server/events/models/models.go b/server/events/models/models.go index 602c05035e..acc41a2e22 100644 --- a/server/events/models/models.go +++ b/server/events/models/models.go @@ -510,4 +510,9 @@ type WorkflowHookCommandContext struct { User User // Verbose is true when the user would like verbose output. Verbose bool + // EscapedCommentArgs are the extra arguments that were added to the atlantis + // command, ex. atlantis plan -- -target=resource. We then escape them + // 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 } diff --git a/server/events/post_workflow_hooks_command_runner.go b/server/events/post_workflow_hooks_command_runner.go index 83c520cfdc..3be4a99273 100644 --- a/server/events/post_workflow_hooks_command_runner.go +++ b/server/events/post_workflow_hooks_command_runner.go @@ -11,7 +11,7 @@ import ( //go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_post_workflows_hooks_command_runner.go PostWorkflowHooksCommandRunner type PostWorkflowHooksCommandRunner interface { - RunPostHooks(ctx *command.Context) error + RunPostHooks(ctx *command.Context, cmd *CommentCommand) error } // DefaultPostWorkflowHooksCommandRunner is the first step when processing a workflow hook commands. @@ -25,7 +25,7 @@ type DefaultPostWorkflowHooksCommandRunner struct { // RunPostHooks runs post_workflow_hooks after a plan/apply has completed func (w *DefaultPostWorkflowHooksCommandRunner) RunPostHooks( - ctx *command.Context, + ctx *command.Context, cmd *CommentCommand, ) error { pull := ctx.Pull baseRepo := pull.BaseRepo @@ -59,14 +59,20 @@ func (w *DefaultPostWorkflowHooksCommandRunner) RunPostHooks( return err } + var escapedArgs []string + if cmd != nil { + escapedArgs = escapeArgs(cmd.Flags) + } + err = w.runHooks( models.WorkflowHookCommandContext{ - BaseRepo: baseRepo, - HeadRepo: headRepo, - Log: log, - Pull: pull, - User: user, - Verbose: false, + BaseRepo: baseRepo, + HeadRepo: headRepo, + Log: log, + Pull: pull, + User: user, + Verbose: false, + EscapedCommentArgs: escapedArgs, }, postWorkflowHooks, repoDir) diff --git a/server/events/post_workflow_hooks_command_runner_test.go b/server/events/post_workflow_hooks_command_runner_test.go index a7ba9d8e4c..717b4de3e5 100644 --- a/server/events/post_workflow_hooks_command_runner_test.go +++ b/server/events/post_workflow_hooks_command_runner_test.go @@ -94,7 +94,7 @@ func TestRunPostHooks_Clone(t *testing.T) { When(postWhWorkingDir.Clone(log, fixtures.GithubRepo, newPull, events.DefaultWorkspace)).ThenReturn(repoDir, false, nil) When(whPostWorkflowHookRunner.Run(pCtx, testHook.RunCommand, repoDir)).ThenReturn(result, nil) - err := postWh.RunPostHooks(ctx) + err := postWh.RunPostHooks(ctx, nil) Ok(t, err) whPostWorkflowHookRunner.VerifyWasCalledOnce().Run(pCtx, testHook.RunCommand, repoDir) @@ -121,7 +121,7 @@ func TestRunPostHooks_Clone(t *testing.T) { postWh.GlobalCfg = globalCfg - err := postWh.RunPostHooks(ctx) + err := postWh.RunPostHooks(ctx, nil) Ok(t, err) @@ -147,7 +147,7 @@ func TestRunPostHooks_Clone(t *testing.T) { When(postWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, events.DefaultRepoRelDir)).ThenReturn(func() {}, errors.New("some error")) - err := postWh.RunPostHooks(ctx) + err := postWh.RunPostHooks(ctx, nil) Assert(t, err != nil, "error not nil") postWhWorkingDir.VerifyWasCalled(Never()).Clone(log, fixtures.GithubRepo, newPull, events.DefaultWorkspace) @@ -178,7 +178,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, errors.New("some error")) - err := postWh.RunPostHooks(ctx) + err := postWh.RunPostHooks(ctx, nil) Assert(t, err != nil, "error not nil") @@ -211,9 +211,48 @@ func TestRunPostHooks_Clone(t *testing.T) { 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")) - err := postWh.RunPostHooks(ctx) + err := postWh.RunPostHooks(ctx, nil) Assert(t, err != nil, "error not nil") Assert(t, *unlockCalled == true, "unlock function called") }) + + t.Run("comment args passed to webhooks", func(t *testing.T) { + postWorkflowHooksSetup(t) + + unlockCalled := newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: fixtures.GithubRepo.ID(), + PostWorkflowHooks: []*valid.WorkflowHook{ + &testHook, + }, + }, + }, + } + + cmd := &events.CommentCommand{ + Flags: []string{"comment", "args"}, + } + + expectedCtx := pCtx + expectedCtx.EscapedCommentArgs = []string{"\\c\\o\\m\\m\\e\\n\\t", "\\a\\r\\g\\s"} + + postWh.GlobalCfg = globalCfg + + 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) + + err := postWh.RunPostHooks(ctx, cmd) + + Ok(t, err) + whPostWorkflowHookRunner.VerifyWasCalledOnce().Run(expectedCtx, testHook.RunCommand, 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 370703d68b..b5664bde0b 100644 --- a/server/events/pre_workflow_hooks_command_runner.go +++ b/server/events/pre_workflow_hooks_command_runner.go @@ -11,7 +11,7 @@ import ( //go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_pre_workflows_hooks_command_runner.go PreWorkflowHooksCommandRunner type PreWorkflowHooksCommandRunner interface { - RunPreHooks(ctx *command.Context) error + RunPreHooks(ctx *command.Context, cmd *CommentCommand) error } // DefaultPreWorkflowHooksCommandRunner is the first step when processing a workflow hook commands. @@ -24,9 +24,7 @@ type DefaultPreWorkflowHooksCommandRunner struct { } // RunPreHooks runs pre_workflow_hooks when PR is opened or updated. -func (w *DefaultPreWorkflowHooksCommandRunner) RunPreHooks( - ctx *command.Context, -) error { +func (w *DefaultPreWorkflowHooksCommandRunner) RunPreHooks(ctx *command.Context, cmd *CommentCommand) error { pull := ctx.Pull baseRepo := pull.BaseRepo headRepo := ctx.HeadRepo @@ -59,14 +57,20 @@ func (w *DefaultPreWorkflowHooksCommandRunner) RunPreHooks( return err } + var escapedArgs []string + if cmd != nil { + escapedArgs = escapeArgs(cmd.Flags) + } + err = w.runHooks( models.WorkflowHookCommandContext{ - BaseRepo: baseRepo, - HeadRepo: headRepo, - Log: log, - Pull: pull, - User: user, - Verbose: false, + BaseRepo: baseRepo, + HeadRepo: headRepo, + Log: log, + Pull: pull, + User: user, + Verbose: false, + EscapedCommentArgs: escapedArgs, }, preWorkflowHooks, repoDir) diff --git a/server/events/pre_workflow_hooks_command_runner_test.go b/server/events/pre_workflow_hooks_command_runner_test.go index 6b77b3257d..13034e50a3 100644 --- a/server/events/pre_workflow_hooks_command_runner_test.go +++ b/server/events/pre_workflow_hooks_command_runner_test.go @@ -97,7 +97,7 @@ func TestRunPreHooks_Clone(t *testing.T) { When(preWhWorkingDir.Clone(log, fixtures.GithubRepo, newPull, events.DefaultWorkspace)).ThenReturn(repoDir, false, nil) When(whPreWorkflowHookRunner.Run(pCtx, testHook.RunCommand, repoDir)).ThenReturn(result, nil) - err := preWh.RunPreHooks(ctx) + err := preWh.RunPreHooks(ctx, nil) Ok(t, err) whPreWorkflowHookRunner.VerifyWasCalledOnce().Run(pCtx, testHook.RunCommand, repoDir) @@ -124,7 +124,7 @@ func TestRunPreHooks_Clone(t *testing.T) { preWh.GlobalCfg = globalCfg - err := preWh.RunPreHooks(ctx) + err := preWh.RunPreHooks(ctx, nil) Ok(t, err) @@ -150,7 +150,7 @@ func TestRunPreHooks_Clone(t *testing.T) { When(preWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, events.DefaultRepoRelDir)).ThenReturn(func() {}, errors.New("some error")) - err := preWh.RunPreHooks(ctx) + err := preWh.RunPreHooks(ctx, nil) Assert(t, err != nil, "error not nil") preWhWorkingDir.VerifyWasCalled(Never()).Clone(log, fixtures.GithubRepo, newPull, events.DefaultWorkspace) @@ -181,7 +181,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, errors.New("some error")) - err := preWh.RunPreHooks(ctx) + err := preWh.RunPreHooks(ctx, nil) Assert(t, err != nil, "error not nil") @@ -214,9 +214,48 @@ func TestRunPreHooks_Clone(t *testing.T) { 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")) - err := preWh.RunPreHooks(ctx) + err := preWh.RunPreHooks(ctx, nil) Assert(t, err != nil, "error not nil") Assert(t, *unlockCalled == true, "unlock function called") }) + + t.Run("comment args passed to webhooks", func(t *testing.T) { + preWorkflowHooksSetup(t) + + var unlockCalled = newBool(false) + unlockFn := func() { + unlockCalled = newBool(true) + } + + globalCfg := valid.GlobalCfg{ + Repos: []valid.Repo{ + { + ID: fixtures.GithubRepo.ID(), + PreWorkflowHooks: []*valid.WorkflowHook{ + &testHook, + }, + }, + }, + } + + cmd := &events.CommentCommand{ + Flags: []string{"comment", "args"}, + } + + expectedCtx := pCtx + expectedCtx.EscapedCommentArgs = []string{"\\c\\o\\m\\m\\e\\n\\t", "\\a\\r\\g\\s"} + + preWh.GlobalCfg = globalCfg + + 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) + + err := preWh.RunPreHooks(ctx, cmd) + + Ok(t, err) + whPreWorkflowHookRunner.VerifyWasCalledOnce().Run(expectedCtx, testHook.RunCommand, repoDir) + Assert(t, *unlockCalled == true, "unlock function called") + }) }