diff --git a/runatlantis.io/docs/repo-level-atlantis-yaml.md b/runatlantis.io/docs/repo-level-atlantis-yaml.md index 04eccb3c5c..c1dc63aad7 100644 --- a/runatlantis.io/docs/repo-level-atlantis-yaml.md +++ b/runatlantis.io/docs/repo-level-atlantis-yaml.md @@ -47,6 +47,8 @@ need to be defined. version: 3 automerge: true delete_source_branch_on_merge: true +parallel_plan: true +parallel_apply: true projects: - name: my-project-name dir: . @@ -88,6 +90,22 @@ projects: This will stop Atlantis automatically running plan when `project1/` is updated in a pull request. +### Run plans and applies in parallel + +```yaml +version: 3 +parallel_plan: true +parallel_apply: true +``` + +This will run plans and applies for all of your projects in parallel. + +Enabling these options can significantly reduce the duration of plans and applies, especially for repositories with many projects. + +Use the `--parallel-pool-size` to configure the max number of plans and applies that can run in parallel. The default is 15. + +Parallel plans and applies work across both multiple directories and multiple workspaces. + ### Configuring Planning Given the directory structure: diff --git a/server/controllers/locks_controller.go b/server/controllers/locks_controller.go index 02ea561813..7d147f9f7a 100644 --- a/server/controllers/locks_controller.go +++ b/server/controllers/locks_controller.go @@ -127,7 +127,7 @@ func (l *LocksController) DeleteLock(w http.ResponseWriter, r *http.Request) { // installations of Atlantis will have locks in their DB that do not have // this field on PullRequest. We skip commenting in this case. if lock.Pull.BaseRepo != (models.Repo{}) { - unlock, err := l.WorkingDirLocker.TryLock(lock.Pull.BaseRepo.FullName, lock.Pull.Num, lock.Workspace) + unlock, err := l.WorkingDirLocker.TryLock(lock.Pull.BaseRepo.FullName, lock.Pull.Num, lock.Workspace, lock.Project.Path) if err != nil { l.Logger.Err("unable to obtain working dir lock when trying to delete old plans: %s", err) } else { diff --git a/server/events/delete_lock_command.go b/server/events/delete_lock_command.go index 9139aec7a7..98c37f8cca 100644 --- a/server/events/delete_lock_command.go +++ b/server/events/delete_lock_command.go @@ -66,7 +66,7 @@ func (l *DefaultDeleteLockCommand) deleteWorkingDir(lock models.ProjectLock) { l.Logger.Debug("Not deleting the working dir.") return } - unlock, err := l.WorkingDirLocker.TryLock(lock.Pull.BaseRepo.FullName, lock.Pull.Num, lock.Workspace) + unlock, err := l.WorkingDirLocker.TryLock(lock.Pull.BaseRepo.FullName, lock.Pull.Num, lock.Workspace, lock.Project.Path) if err != nil { l.Logger.Err("unable to obtain working dir lock when trying to delete old plans: %s", err) } else { diff --git a/server/events/mocks/mock_working_dir_locker.go b/server/events/mocks/mock_working_dir_locker.go index 2b8f628ff4..e51ef6a26a 100644 --- a/server/events/mocks/mock_working_dir_locker.go +++ b/server/events/mocks/mock_working_dir_locker.go @@ -25,11 +25,11 @@ func NewMockWorkingDirLocker(options ...pegomock.Option) *MockWorkingDirLocker { func (mock *MockWorkingDirLocker) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh } func (mock *MockWorkingDirLocker) FailHandler() pegomock.FailHandler { return mock.fail } -func (mock *MockWorkingDirLocker) TryLock(repoFullName string, pullNum int, workspace string) (func(), error) { +func (mock *MockWorkingDirLocker) TryLock(repoFullName string, pullNum int, workspace string, path string) (func(), error) { if mock == nil { panic("mock must not be nil. Use myMock := NewMockWorkingDirLocker().") } - params := []pegomock.Param{repoFullName, pullNum, workspace} + params := []pegomock.Param{repoFullName, pullNum, workspace, path} result := pegomock.GetGenericMockFrom(mock).Invoke("TryLock", params, []reflect.Type{reflect.TypeOf((*func())(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) var ret0 func() var ret1 error diff --git a/server/events/post_workflow_hooks_command_runner.go b/server/events/post_workflow_hooks_command_runner.go index 6e534e7122..83c520cfdc 100644 --- a/server/events/post_workflow_hooks_command_runner.go +++ b/server/events/post_workflow_hooks_command_runner.go @@ -47,7 +47,7 @@ func (w *DefaultPostWorkflowHooksCommandRunner) RunPostHooks( log.Debug("post-hooks configured, running...") - unlockFn, err := w.WorkingDirLocker.TryLock(baseRepo.FullName, pull.Num, DefaultWorkspace) + unlockFn, err := w.WorkingDirLocker.TryLock(baseRepo.FullName, pull.Num, DefaultWorkspace, DefaultRepoRelDir) if err != nil { return err } diff --git a/server/events/post_workflow_hooks_command_runner_test.go b/server/events/post_workflow_hooks_command_runner_test.go index b595178a30..3a57af8ffe 100644 --- a/server/events/post_workflow_hooks_command_runner_test.go +++ b/server/events/post_workflow_hooks_command_runner_test.go @@ -90,7 +90,7 @@ func TestRunPostHooks_Clone(t *testing.T) { postWh.GlobalCfg = globalCfg - When(postWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace)).ThenReturn(unlockFn, nil) + 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) @@ -145,7 +145,7 @@ func TestRunPostHooks_Clone(t *testing.T) { postWh.GlobalCfg = globalCfg - When(postWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace)).ThenReturn(func() {}, errors.New("some error")) + When(postWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, events.DefaultRepoRelDir)).ThenReturn(func() {}, errors.New("some error")) err := postWh.RunPostHooks(ctx) @@ -175,7 +175,7 @@ func TestRunPostHooks_Clone(t *testing.T) { postWh.GlobalCfg = globalCfg - When(postWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace)).ThenReturn(unlockFn, nil) + 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) @@ -207,7 +207,7 @@ func TestRunPostHooks_Clone(t *testing.T) { postWh.GlobalCfg = globalCfg - When(postWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace)).ThenReturn(unlockFn, nil) + 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")) diff --git a/server/events/pre_workflow_hooks_command_runner.go b/server/events/pre_workflow_hooks_command_runner.go index f197d8fa37..370703d68b 100644 --- a/server/events/pre_workflow_hooks_command_runner.go +++ b/server/events/pre_workflow_hooks_command_runner.go @@ -47,7 +47,7 @@ func (w *DefaultPreWorkflowHooksCommandRunner) RunPreHooks( log.Debug("pre-hooks configured, running...") - unlockFn, err := w.WorkingDirLocker.TryLock(baseRepo.FullName, pull.Num, DefaultWorkspace) + unlockFn, err := w.WorkingDirLocker.TryLock(baseRepo.FullName, pull.Num, DefaultWorkspace, DefaultRepoRelDir) if err != nil { 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 dc31c494c7..6b77b3257d 100644 --- a/server/events/pre_workflow_hooks_command_runner_test.go +++ b/server/events/pre_workflow_hooks_command_runner_test.go @@ -93,7 +93,7 @@ func TestRunPreHooks_Clone(t *testing.T) { preWh.GlobalCfg = globalCfg - When(preWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace)).ThenReturn(unlockFn, nil) + 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) @@ -148,7 +148,7 @@ func TestRunPreHooks_Clone(t *testing.T) { preWh.GlobalCfg = globalCfg - When(preWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace)).ThenReturn(func() {}, errors.New("some error")) + When(preWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace, events.DefaultRepoRelDir)).ThenReturn(func() {}, errors.New("some error")) err := preWh.RunPreHooks(ctx) @@ -178,7 +178,7 @@ func TestRunPreHooks_Clone(t *testing.T) { preWh.GlobalCfg = globalCfg - When(preWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace)).ThenReturn(unlockFn, nil) + 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) @@ -210,7 +210,7 @@ func TestRunPreHooks_Clone(t *testing.T) { preWh.GlobalCfg = globalCfg - When(preWhWorkingDirLocker.TryLock(fixtures.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace)).ThenReturn(unlockFn, nil) + 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")) diff --git a/server/events/project_command_builder.go b/server/events/project_command_builder.go index 04feca8a62..d0ed9f39c7 100644 --- a/server/events/project_command_builder.go +++ b/server/events/project_command_builder.go @@ -247,7 +247,7 @@ func (p *DefaultProjectCommandBuilder) buildPlanAllCommands(ctx *command.Context // Need to lock the workspace we're about to clone to. workspace := DefaultWorkspace - unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, workspace) + unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, workspace, DefaultRepoRelDir) if err != nil { ctx.Log.Warn("workspace was locked") return nil, err @@ -342,7 +342,7 @@ func (p *DefaultProjectCommandBuilder) buildProjectPlanCommand(ctx *command.Cont var pcc []command.ProjectContext ctx.Log.Debug("building plan command") - unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, workspace) + unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, workspace, DefaultRepoRelDir) if err != nil { return pcc, err } @@ -478,7 +478,7 @@ func (p *DefaultProjectCommandBuilder) buildProjectApplyCommand(ctx *command.Con } var projCtx []command.ProjectContext - unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, workspace) + unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, workspace, DefaultRepoRelDir) if err != nil { return projCtx, err } @@ -519,7 +519,7 @@ func (p *DefaultProjectCommandBuilder) buildProjectVersionCommand(ctx *command.C } var projCtx []command.ProjectContext - unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, workspace) + unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, workspace, DefaultRepoRelDir) if err != nil { return projCtx, err } diff --git a/server/events/project_command_runner.go b/server/events/project_command_runner.go index 82debf548c..ead5e85eff 100644 --- a/server/events/project_command_runner.go +++ b/server/events/project_command_runner.go @@ -294,7 +294,7 @@ func (p *DefaultProjectCommandRunner) doPolicyCheck(ctx command.ProjectContext) // Acquire internal lock for the directory we're going to operate in. // We should refactor this to keep the lock for the duration of plan and policy check since as of now // there is a small gap where we don't have the lock and if we can't get this here, we should just unlock the PR. - unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, ctx.Workspace) + unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, ctx.Workspace, ctx.RepoRelDir) if err != nil { return nil, "", err } @@ -357,7 +357,7 @@ func (p *DefaultProjectCommandRunner) doPlan(ctx command.ProjectContext) (*model ctx.Log.Debug("acquired lock for project") // Acquire internal lock for the directory we're going to operate in. - unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, ctx.Workspace) + unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, ctx.Workspace, ctx.RepoRelDir) if err != nil { return nil, "", err } @@ -413,7 +413,7 @@ func (p *DefaultProjectCommandRunner) doApply(ctx command.ProjectContext) (apply } // Acquire internal lock for the directory we're going to operate in. - unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, ctx.Workspace) + unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, ctx.Workspace, ctx.RepoRelDir) if err != nil { return "", "", err } @@ -451,7 +451,7 @@ func (p *DefaultProjectCommandRunner) doVersion(ctx command.ProjectContext) (ver } // Acquire internal lock for the directory we're going to operate in. - unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, ctx.Workspace) + unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, ctx.Workspace, ctx.RepoRelDir) if err != nil { return "", "", err } diff --git a/server/events/working_dir_locker.go b/server/events/working_dir_locker.go index 7642e0ca28..44563c0cb3 100644 --- a/server/events/working_dir_locker.go +++ b/server/events/working_dir_locker.go @@ -27,11 +27,11 @@ import ( // on disk and we haven't written Atlantis (yet) to handle concurrent execution // within this workspace. type WorkingDirLocker interface { - // TryLock tries to acquire a lock for this repo, workspace and pull. + // TryLock tries to acquire a lock for this repo, pull, workspace, and path. // It returns a function that should be used to unlock the workspace and // an error if the workspace is already locked. The error is expected to // be printed to the pull request. - TryLock(repoFullName string, pullNum int, workspace string) (func(), error) + TryLock(repoFullName string, pullNum int, workspace string, path string) (func(), error) // TryLockPull tries to acquire a lock for all the workspaces in this repo // and pull. // It returns a function that should be used to unlock the workspace and @@ -74,31 +74,31 @@ func (d *DefaultWorkingDirLocker) TryLockPull(repoFullName string, pullNum int) }, nil } -func (d *DefaultWorkingDirLocker) TryLock(repoFullName string, pullNum int, workspace string) (func(), error) { +func (d *DefaultWorkingDirLocker) TryLock(repoFullName string, pullNum int, workspace string, path string) (func(), error) { d.mutex.Lock() defer d.mutex.Unlock() pullKey := d.pullKey(repoFullName, pullNum) - workspaceKey := d.workspaceKey(repoFullName, pullNum, workspace) + workspaceKey := d.workspaceKey(repoFullName, pullNum, workspace, path) for _, l := range d.locks { if l == pullKey || l == workspaceKey { - return func() {}, fmt.Errorf("The %s workspace is currently locked by another"+ + return func() {}, fmt.Errorf("The %s workspace at path %s is currently locked by another"+ " command that is running for this pull request.\n"+ - "Wait until the previous command is complete and try again.", workspace) + "Wait until the previous command is complete and try again.", workspace, path) } } d.locks = append(d.locks, workspaceKey) return func() { - d.unlock(repoFullName, pullNum, workspace) + d.unlock(repoFullName, pullNum, workspace, path) }, nil } // Unlock unlocks the workspace for this pull. -func (d *DefaultWorkingDirLocker) unlock(repoFullName string, pullNum int, workspace string) { +func (d *DefaultWorkingDirLocker) unlock(repoFullName string, pullNum int, workspace string, path string) { d.mutex.Lock() defer d.mutex.Unlock() - workspaceKey := d.workspaceKey(repoFullName, pullNum, workspace) + workspaceKey := d.workspaceKey(repoFullName, pullNum, workspace, path) d.removeLock(workspaceKey) } @@ -121,8 +121,8 @@ func (d *DefaultWorkingDirLocker) removeLock(key string) { d.locks = newLocks } -func (d *DefaultWorkingDirLocker) workspaceKey(repo string, pull int, workspace string) string { - return fmt.Sprintf("%s/%s", d.pullKey(repo, pull), workspace) +func (d *DefaultWorkingDirLocker) workspaceKey(repo string, pull int, workspace string, path string) string { + return fmt.Sprintf("%s/%s/%s", d.pullKey(repo, pull), workspace, path) } func (d *DefaultWorkingDirLocker) pullKey(repo string, pull int) string { diff --git a/server/events/working_dir_locker_test.go b/server/events/working_dir_locker_test.go index 49450e69dc..d786582588 100644 --- a/server/events/working_dir_locker_test.go +++ b/server/events/working_dir_locker_test.go @@ -27,18 +27,18 @@ func TestTryLock(t *testing.T) { locker := events.NewDefaultWorkingDirLocker() // The first lock should succeed. - unlockFn, err := locker.TryLock(repo, 1, workspace) + unlockFn, err := locker.TryLock(repo, 1, workspace, "") Ok(t, err) // Now another lock for the same repo, workspace, and pull should fail - _, err = locker.TryLock(repo, 1, workspace) + _, err = locker.TryLock(repo, 1, workspace, "") ErrEquals(t, "The default workspace is currently locked by another"+ " command that is running for this pull request.\n"+ "Wait until the previous command is complete and try again.", err) // Unlock should work. unlockFn() - _, err = locker.TryLock(repo, 1, workspace) + _, err = locker.TryLock(repo, 1, workspace, "") Ok(t, err) } @@ -46,15 +46,15 @@ func TestTryLockDifferentWorkspaces(t *testing.T) { locker := events.NewDefaultWorkingDirLocker() t.Log("a lock for the same repo and pull but different workspace should succeed") - _, err := locker.TryLock(repo, 1, workspace) + _, err := locker.TryLock(repo, 1, workspace, "") Ok(t, err) - _, err = locker.TryLock(repo, 1, "new-workspace") + _, err = locker.TryLock(repo, 1, "new-workspace", "") Ok(t, err) t.Log("and both should now be locked") - _, err = locker.TryLock(repo, 1, workspace) + _, err = locker.TryLock(repo, 1, workspace, "") Assert(t, err != nil, "exp err") - _, err = locker.TryLock(repo, 1, "new-workspace") + _, err = locker.TryLock(repo, 1, "new-workspace", "") Assert(t, err != nil, "exp err") } @@ -62,16 +62,16 @@ func TestTryLockDifferentRepo(t *testing.T) { locker := events.NewDefaultWorkingDirLocker() t.Log("a lock for a different repo but the same workspace and pull should succeed") - _, err := locker.TryLock(repo, 1, workspace) + _, err := locker.TryLock(repo, 1, workspace, "") Ok(t, err) newRepo := "owner/newrepo" - _, err = locker.TryLock(newRepo, 1, workspace) + _, err = locker.TryLock(newRepo, 1, workspace, "") Ok(t, err) t.Log("and both should now be locked") - _, err = locker.TryLock(repo, 1, workspace) + _, err = locker.TryLock(repo, 1, workspace, "") ErrContains(t, "currently locked", err) - _, err = locker.TryLock(newRepo, 1, workspace) + _, err = locker.TryLock(newRepo, 1, workspace, "") ErrContains(t, "currently locked", err) } @@ -79,16 +79,33 @@ func TestTryLockDifferentPulls(t *testing.T) { locker := events.NewDefaultWorkingDirLocker() t.Log("a lock for a different pull but the same repo and workspace should succeed") - _, err := locker.TryLock(repo, 1, workspace) + _, err := locker.TryLock(repo, 1, workspace, "") Ok(t, err) newPull := 2 - _, err = locker.TryLock(repo, newPull, workspace) + _, err = locker.TryLock(repo, newPull, workspace, "") Ok(t, err) t.Log("and both should now be locked") - _, err = locker.TryLock(repo, 1, workspace) + _, err = locker.TryLock(repo, 1, workspace, "") ErrContains(t, "currently locked", err) - _, err = locker.TryLock(repo, newPull, workspace) + _, err = locker.TryLock(repo, newPull, workspace, "") + ErrContains(t, "currently locked", err) +} + +func TestTryLockDifferentPaths(t *testing.T) { + locker := events.NewDefaultWorkingDirLocker() + + t.Log("a lock for a different path but the same repo, pull, and workspace should succeed") + _, err := locker.TryLock(repo, 1, workspace, "") + Ok(t, err) + newPath := "new-path" + _, err = locker.TryLock(repo, 1, workspace, newPath) + Ok(t, err) + + t.Log("and both should now be locked") + _, err = locker.TryLock(repo, 1, workspace, "") + ErrContains(t, "currently locked", err) + _, err = locker.TryLock(repo, 1, workspace, newPath) ErrContains(t, "currently locked", err) } @@ -96,60 +113,60 @@ func TestUnlock(t *testing.T) { locker := events.NewDefaultWorkingDirLocker() t.Log("unlocking should work") - unlockFn, err := locker.TryLock(repo, 1, workspace) + unlockFn, err := locker.TryLock(repo, 1, workspace, "") Ok(t, err) unlockFn() - _, err = locker.TryLock(repo, 1, workspace) + _, err = locker.TryLock(repo, 1, workspace, "") Ok(t, err) } func TestUnlockDifferentWorkspaces(t *testing.T) { locker := events.NewDefaultWorkingDirLocker() t.Log("unlocking should work for different workspaces") - unlockFn1, err1 := locker.TryLock(repo, 1, workspace) + unlockFn1, err1 := locker.TryLock(repo, 1, workspace, "") Ok(t, err1) - unlockFn2, err2 := locker.TryLock(repo, 1, "new-workspace") + unlockFn2, err2 := locker.TryLock(repo, 1, "new-workspace", "") Ok(t, err2) unlockFn1() unlockFn2() - _, err := locker.TryLock(repo, 1, workspace) + _, err := locker.TryLock(repo, 1, workspace, "") Ok(t, err) - _, err = locker.TryLock(repo, 1, "new-workspace") + _, err = locker.TryLock(repo, 1, "new-workspace", "") Ok(t, err) } func TestUnlockDifferentRepos(t *testing.T) { locker := events.NewDefaultWorkingDirLocker() t.Log("unlocking should work for different repos") - unlockFn1, err1 := locker.TryLock(repo, 1, workspace) + unlockFn1, err1 := locker.TryLock(repo, 1, workspace, "") Ok(t, err1) newRepo := "owner/newrepo" - unlockFn2, err2 := locker.TryLock(newRepo, 1, workspace) + unlockFn2, err2 := locker.TryLock(newRepo, 1, workspace, "") Ok(t, err2) unlockFn1() unlockFn2() - _, err := locker.TryLock(repo, 1, workspace) + _, err := locker.TryLock(repo, 1, workspace, "") Ok(t, err) - _, err = locker.TryLock(newRepo, 1, workspace) + _, err = locker.TryLock(newRepo, 1, workspace, "") Ok(t, err) } func TestUnlockDifferentPulls(t *testing.T) { locker := events.NewDefaultWorkingDirLocker() t.Log("unlocking should work for different pulls") - unlockFn1, err1 := locker.TryLock(repo, 1, workspace) + unlockFn1, err1 := locker.TryLock(repo, 1, workspace, "") Ok(t, err1) newPull := 2 - unlockFn2, err2 := locker.TryLock(repo, newPull, workspace) + unlockFn2, err2 := locker.TryLock(repo, newPull, workspace, "") Ok(t, err2) unlockFn1() unlockFn2() - _, err := locker.TryLock(repo, 1, workspace) + _, err := locker.TryLock(repo, 1, workspace, "") Ok(t, err) - _, err = locker.TryLock(repo, newPull, workspace) + _, err = locker.TryLock(repo, newPull, workspace, "") Ok(t, err) } @@ -161,13 +178,13 @@ func TestLockPull(t *testing.T) { // Now a lock for the same pull or for a workspace should fail. _, err = locker.TryLockPull("owner/repo", 1) Assert(t, err != nil, "exp err") - _, err = locker.TryLock("owner/repo", 1, "workspace") + _, err = locker.TryLock("owner/repo", 1, "workspace", "") Assert(t, err != nil, "exp err") // Lock for a different pull and workspace should succeed. _, err = locker.TryLockPull("owner/repo", 2) Ok(t, err) - _, err = locker.TryLock("owner/repo", 3, "workspace") + _, err = locker.TryLock("owner/repo", 3, "workspace", "") Ok(t, err) // After unlocking, should be able to get a pull lock. @@ -177,7 +194,7 @@ func TestLockPull(t *testing.T) { // If we unlock that too, should be able to get the workspace lock. unlock() - _, err = locker.TryLock("owner/repo", 1, "workspace") + _, err = locker.TryLock("owner/repo", 1, "workspace", "") Ok(t, err) unlock() } @@ -185,7 +202,7 @@ func TestLockPull(t *testing.T) { // If the workspace was locked first, we shouldn't be able to get the pull lock. func TestLockPull_WorkspaceFirst(t *testing.T) { locker := events.NewDefaultWorkingDirLocker() - unlock, err := locker.TryLock("owner/repo", 1, "workspace") + unlock, err := locker.TryLock("owner/repo", 1, "workspace", "") Ok(t, err) _, err = locker.TryLockPull("owner/repo", 1)