Files
atlantis/server/events/post_workflow_hooks_command_runner.go
KevinSnyderCodes 5288389897 fix: allow projects in separate directories to run in parallel (#2131)
* fix: add path to DefaultWorkingDirLocker.TryLock()

In the release notes for v0.13.0: https://github.com/runatlantis/atlantis/blob/master/CHANGELOG.md#features-4

> Running in parallel is only supported if you're using workspaces to separate your projects. Projects in separate directories can not be run in parallel currently.

This commit adds `path` as an argument to `DefaultWorkingDirLocker.TryLock()` and includes `path` in the `workspaceKey` used to check if a project is locked. This should allow projects in separate directories to run in parallel.

To my knowledge, there is no functional reason that projects in separate directories cannot run in parallel.

All calls to `DefaultWorkingDirLocker.TryLock()` have been updated. A new unit test `TestTryLockWithDifferentPaths` has been added to test the behavior of locking two separate directories with the same workspace name.

* Add documntation for parallel_plan and parallel_apply options

Co-authored-by: Kevin Snyder <kevinsnyder@ip-192-168-4-61.ec2.internal>
Co-authored-by: Kevin Snyder <kevinsnyder@ip-10-60-10-94.ec2.internal>
2022-03-21 16:08:52 -07:00

96 lines
2.5 KiB
Go

package events
import (
"github.com/runatlantis/atlantis/server/core/config/valid"
"github.com/runatlantis/atlantis/server/core/runtime"
"github.com/runatlantis/atlantis/server/events/command"
"github.com/runatlantis/atlantis/server/events/models"
"github.com/runatlantis/atlantis/server/events/vcs"
)
//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
}
// DefaultPostWorkflowHooksCommandRunner is the first step when processing a workflow hook commands.
type DefaultPostWorkflowHooksCommandRunner struct {
VCSClient vcs.Client
WorkingDirLocker WorkingDirLocker
WorkingDir WorkingDir
GlobalCfg valid.GlobalCfg
PostWorkflowHookRunner runtime.PostWorkflowHookRunner
}
// RunPostHooks runs post_workflow_hooks after a plan/apply has completed
func (w *DefaultPostWorkflowHooksCommandRunner) RunPostHooks(
ctx *command.Context,
) error {
pull := ctx.Pull
baseRepo := pull.BaseRepo
headRepo := ctx.HeadRepo
user := ctx.User
log := ctx.Log
postWorkflowHooks := make([]*valid.WorkflowHook, 0)
for _, repo := range w.GlobalCfg.Repos {
if repo.IDMatches(baseRepo.ID()) && repo.BranchMatches(pull.BaseBranch) && len(repo.PostWorkflowHooks) > 0 {
postWorkflowHooks = append(postWorkflowHooks, repo.PostWorkflowHooks...)
}
}
// short circuit any other calls if there are no post-hooks configured
if len(postWorkflowHooks) == 0 {
return nil
}
log.Debug("post-hooks configured, running...")
unlockFn, err := w.WorkingDirLocker.TryLock(baseRepo.FullName, pull.Num, DefaultWorkspace, DefaultRepoRelDir)
if err != nil {
return err
}
log.Debug("got workspace lock")
defer unlockFn()
repoDir, _, err := w.WorkingDir.Clone(log, headRepo, pull, DefaultWorkspace)
if err != nil {
return err
}
err = w.runHooks(
models.WorkflowHookCommandContext{
BaseRepo: baseRepo,
HeadRepo: headRepo,
Log: log,
Pull: pull,
User: user,
Verbose: false,
},
postWorkflowHooks, repoDir)
if err != nil {
return err
}
return nil
}
func (w *DefaultPostWorkflowHooksCommandRunner) runHooks(
ctx models.WorkflowHookCommandContext,
postWorkflowHooks []*valid.WorkflowHook,
repoDir string,
) error {
for _, hook := range postWorkflowHooks {
_, err := w.PostWorkflowHookRunner.Run(ctx, hook.RunCommand, repoDir)
if err != nil {
return err
}
}
return nil
}