fix: parallel plan and apply also in a single workspace (rebased) (#5264)

Signed-off-by: Andrew Carter <andrew@emailcarter.com>
Signed-off-by: Luke Massa <lukefrederickmassa@gmail.com>
Co-authored-by: Finn Arne Gangstad <finnag@gmail.com>
Co-authored-by: Rui Chen <rui@chenrui.dev>
Co-authored-by: PePe Amengual <2208324+jamengual@users.noreply.github.com>
Co-authored-by: Luke Massa <lukefrederickmassa@gmail.com>
This commit is contained in:
Andrew Carter
2025-04-22 12:57:17 -05:00
committed by GitHub
parent 5b93200fbf
commit dcae47bddb
21 changed files with 308 additions and 363 deletions

View File

@@ -222,7 +222,7 @@ func (a *APIController) apiSetup(ctx *command.Context) error {
defer unlockFn()
// ensure workingDir is present
_, _, err = a.WorkingDir.Clone(ctx.Log, headRepo, pull, events.DefaultWorkspace)
_, err = a.WorkingDir.Clone(ctx.Log, headRepo, pull, events.DefaultWorkspace)
if err != nil {
return err
}

View File

@@ -20,7 +20,7 @@ type GithubAppWorkingDir struct {
}
// Clone writes a fresh token for Github App authentication
func (g *GithubAppWorkingDir) Clone(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (string, bool, error) {
func (g *GithubAppWorkingDir) Clone(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (string, error) {
baseRepo := &p.BaseRepo
// Realistically, this is a super brittle way of supporting clones using gh app installation tokens

View File

@@ -45,7 +45,7 @@ func TestClone_GithubAppNoneExisting(t *testing.T) {
GithubHostname: testServer,
}
cloneDir, _, err := gwd.Clone(logger, models.Repo{}, models.PullRequest{
cloneDir, err := gwd.Clone(logger, models.Repo{}, models.PullRequest{
BaseRepo: models.Repo{},
HeadBranch: "branch",
}, "default")
@@ -90,11 +90,11 @@ func TestClone_GithubAppSetsCorrectUrl(t *testing.T) {
When(credentials.GetToken()).ThenReturn("token", nil)
When(workingDir.Clone(Any[logging.SimpleLogging](), Eq(modifiedBaseRepo), Eq(models.PullRequest{BaseRepo: modifiedBaseRepo}),
Eq("default"))).ThenReturn("", true, nil)
Eq("default"))).ThenReturn("", nil)
_, success, _ := ghAppWorkingDir.Clone(logger, headRepo, models.PullRequest{BaseRepo: baseRepo}, "default")
_, err := ghAppWorkingDir.Clone(logger, headRepo, models.PullRequest{BaseRepo: baseRepo}, "default")
workingDir.VerifyWasCalledOnce().Clone(logger, modifiedBaseRepo, models.PullRequest{BaseRepo: modifiedBaseRepo}, "default")
Assert(t, success == true, "clone url mutation error")
Ok(t, err)
}

View File

@@ -4,11 +4,12 @@
package events
import (
"reflect"
"time"
pegomock "github.com/petergtz/pegomock/v4"
models "github.com/runatlantis/atlantis/server/events/models"
logging "github.com/runatlantis/atlantis/server/logging"
"reflect"
"time"
)
type MockWorkingDir struct {
@@ -26,27 +27,23 @@ func NewMockWorkingDir(options ...pegomock.Option) *MockWorkingDir {
func (mock *MockWorkingDir) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh }
func (mock *MockWorkingDir) FailHandler() pegomock.FailHandler { return mock.fail }
func (mock *MockWorkingDir) Clone(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (string, bool, error) {
func (mock *MockWorkingDir) Clone(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (string, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockWorkingDir().")
}
_params := []pegomock.Param{logger, headRepo, p, workspace}
_result := pegomock.GetGenericMockFrom(mock).Invoke("Clone", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
_result := pegomock.GetGenericMockFrom(mock).Invoke("Clone", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var _ret0 string
var _ret1 bool
var _ret2 error
var _ret1 error
if len(_result) != 0 {
if _result[0] != nil {
_ret0 = _result[0].(string)
}
if _result[1] != nil {
_ret1 = _result[1].(bool)
}
if _result[2] != nil {
_ret2 = _result[2].(error)
_ret1 = _result[1].(error)
}
}
return _ret0, _ret1, _ret2
return _ret0, _ret1
}
func (mock *MockWorkingDir) Delete(logger logging.SimpleLogging, r models.Repo, p models.PullRequest) error {
@@ -166,12 +163,23 @@ func (mock *MockWorkingDir) HasDiverged(logger logging.SimpleLogging, cloneDir s
return _ret0
}
func (mock *MockWorkingDir) SetCheckForUpstreamChanges() {
func (mock *MockWorkingDir) MergeAgain(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (bool, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockWorkingDir().")
}
_params := []pegomock.Param{}
pegomock.GetGenericMockFrom(mock).Invoke("SetCheckForUpstreamChanges", _params, []reflect.Type{})
_params := []pegomock.Param{logger, headRepo, p, workspace}
_result := pegomock.GetGenericMockFrom(mock).Invoke("MergeAgain", _params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var _ret0 bool
var _ret1 error
if len(_result) != 0 {
if _result[0] != nil {
_ret0 = _result[0].(bool)
}
if _result[1] != nil {
_ret1 = _result[1].(error)
}
}
return _ret0, _ret1
}
func (mock *MockWorkingDir) VerifyWasCalledOnce() *VerifierMockWorkingDir {
@@ -563,19 +571,49 @@ func (c *MockWorkingDir_HasDiverged_OngoingVerification) GetAllCapturedArguments
return
}
func (verifier *VerifierMockWorkingDir) SetCheckForUpstreamChanges() *MockWorkingDir_SetCheckForUpstreamChanges_OngoingVerification {
_params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "SetCheckForUpstreamChanges", _params, verifier.timeout)
return &MockWorkingDir_SetCheckForUpstreamChanges_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
func (verifier *VerifierMockWorkingDir) MergeAgain(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_MergeAgain_OngoingVerification {
_params := []pegomock.Param{logger, headRepo, p, workspace}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "MergeAgain", _params, verifier.timeout)
return &MockWorkingDir_MergeAgain_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type MockWorkingDir_SetCheckForUpstreamChanges_OngoingVerification struct {
type MockWorkingDir_MergeAgain_OngoingVerification struct {
mock *MockWorkingDir
methodInvocations []pegomock.MethodInvocation
}
func (c *MockWorkingDir_SetCheckForUpstreamChanges_OngoingVerification) GetCapturedArguments() {
func (c *MockWorkingDir_MergeAgain_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest, string) {
logger, headRepo, p, workspace := c.GetAllCapturedArguments()
return logger[len(logger)-1], headRepo[len(headRepo)-1], p[len(p)-1], workspace[len(workspace)-1]
}
func (c *MockWorkingDir_SetCheckForUpstreamChanges_OngoingVerification) GetAllCapturedArguments() {
func (c *MockWorkingDir_MergeAgain_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []string) {
_params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(_params) > 0 {
if len(_params) > 0 {
_param0 = make([]logging.SimpleLogging, len(c.methodInvocations))
for u, param := range _params[0] {
_param0[u] = param.(logging.SimpleLogging)
}
}
if len(_params) > 1 {
_param1 = make([]models.Repo, len(c.methodInvocations))
for u, param := range _params[1] {
_param1[u] = param.(models.Repo)
}
}
if len(_params) > 2 {
_param2 = make([]models.PullRequest, len(c.methodInvocations))
for u, param := range _params[2] {
_param2[u] = param.(models.PullRequest)
}
}
if len(_params) > 3 {
_param3 = make([]string, len(c.methodInvocations))
for u, param := range _params[3] {
_param3[u] = param.(string)
}
}
}
return
}

View File

@@ -11,7 +11,7 @@ import (
models "github.com/runatlantis/atlantis/server/events/models"
gitea0 "github.com/runatlantis/atlantis/server/events/vcs/gitea"
logging "github.com/runatlantis/atlantis/server/logging"
go_gitlab "gitlab.com/gitlab-org/api/client-go"
client_go "gitlab.com/gitlab-org/api/client-go"
"reflect"
"time"
)
@@ -490,7 +490,7 @@ func (mock *MockEventParsing) ParseGithubRepo(ghRepo *github.Repository) (models
return _ret0, _ret1
}
func (mock *MockEventParsing) ParseGitlabMergeRequest(mr *go_gitlab.MergeRequest, baseRepo models.Repo) models.PullRequest {
func (mock *MockEventParsing) ParseGitlabMergeRequest(mr *client_go.MergeRequest, baseRepo models.Repo) models.PullRequest {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockEventParsing().")
}
@@ -505,7 +505,7 @@ func (mock *MockEventParsing) ParseGitlabMergeRequest(mr *go_gitlab.MergeRequest
return _ret0
}
func (mock *MockEventParsing) ParseGitlabMergeRequestCommentEvent(event go_gitlab.MergeCommentEvent) (models.Repo, models.Repo, int, models.User, error) {
func (mock *MockEventParsing) ParseGitlabMergeRequestCommentEvent(event client_go.MergeCommentEvent) (models.Repo, models.Repo, int, models.User, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockEventParsing().")
}
@@ -536,7 +536,7 @@ func (mock *MockEventParsing) ParseGitlabMergeRequestCommentEvent(event go_gitla
return _ret0, _ret1, _ret2, _ret3, _ret4
}
func (mock *MockEventParsing) ParseGitlabMergeRequestEvent(event go_gitlab.MergeEvent) (models.PullRequest, models.PullRequestEventType, models.Repo, models.Repo, models.User, error) {
func (mock *MockEventParsing) ParseGitlabMergeRequestEvent(event client_go.MergeEvent) (models.PullRequest, models.PullRequestEventType, models.Repo, models.Repo, models.User, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockEventParsing().")
}
@@ -571,7 +571,7 @@ func (mock *MockEventParsing) ParseGitlabMergeRequestEvent(event go_gitlab.Merge
return _ret0, _ret1, _ret2, _ret3, _ret4, _ret5
}
func (mock *MockEventParsing) ParseGitlabMergeRequestUpdateEvent(event go_gitlab.MergeEvent) models.PullRequestEventType {
func (mock *MockEventParsing) ParseGitlabMergeRequestUpdateEvent(event client_go.MergeEvent) models.PullRequestEventType {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockEventParsing().")
}
@@ -1158,7 +1158,7 @@ func (c *MockEventParsing_ParseGithubRepo_OngoingVerification) GetAllCapturedArg
return
}
func (verifier *VerifierMockEventParsing) ParseGitlabMergeRequest(mr *go_gitlab.MergeRequest, baseRepo models.Repo) *MockEventParsing_ParseGitlabMergeRequest_OngoingVerification {
func (verifier *VerifierMockEventParsing) ParseGitlabMergeRequest(mr *client_go.MergeRequest, baseRepo models.Repo) *MockEventParsing_ParseGitlabMergeRequest_OngoingVerification {
_params := []pegomock.Param{mr, baseRepo}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGitlabMergeRequest", _params, verifier.timeout)
return &MockEventParsing_ParseGitlabMergeRequest_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
@@ -1169,18 +1169,18 @@ type MockEventParsing_ParseGitlabMergeRequest_OngoingVerification struct {
methodInvocations []pegomock.MethodInvocation
}
func (c *MockEventParsing_ParseGitlabMergeRequest_OngoingVerification) GetCapturedArguments() (*go_gitlab.MergeRequest, models.Repo) {
func (c *MockEventParsing_ParseGitlabMergeRequest_OngoingVerification) GetCapturedArguments() (*client_go.MergeRequest, models.Repo) {
mr, baseRepo := c.GetAllCapturedArguments()
return mr[len(mr)-1], baseRepo[len(baseRepo)-1]
}
func (c *MockEventParsing_ParseGitlabMergeRequest_OngoingVerification) GetAllCapturedArguments() (_param0 []*go_gitlab.MergeRequest, _param1 []models.Repo) {
func (c *MockEventParsing_ParseGitlabMergeRequest_OngoingVerification) GetAllCapturedArguments() (_param0 []*client_go.MergeRequest, _param1 []models.Repo) {
_params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(_params) > 0 {
if len(_params) > 0 {
_param0 = make([]*go_gitlab.MergeRequest, len(c.methodInvocations))
_param0 = make([]*client_go.MergeRequest, len(c.methodInvocations))
for u, param := range _params[0] {
_param0[u] = param.(*go_gitlab.MergeRequest)
_param0[u] = param.(*client_go.MergeRequest)
}
}
if len(_params) > 1 {
@@ -1193,7 +1193,7 @@ func (c *MockEventParsing_ParseGitlabMergeRequest_OngoingVerification) GetAllCap
return
}
func (verifier *VerifierMockEventParsing) ParseGitlabMergeRequestCommentEvent(event go_gitlab.MergeCommentEvent) *MockEventParsing_ParseGitlabMergeRequestCommentEvent_OngoingVerification {
func (verifier *VerifierMockEventParsing) ParseGitlabMergeRequestCommentEvent(event client_go.MergeCommentEvent) *MockEventParsing_ParseGitlabMergeRequestCommentEvent_OngoingVerification {
_params := []pegomock.Param{event}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGitlabMergeRequestCommentEvent", _params, verifier.timeout)
return &MockEventParsing_ParseGitlabMergeRequestCommentEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
@@ -1204,25 +1204,25 @@ type MockEventParsing_ParseGitlabMergeRequestCommentEvent_OngoingVerification st
methodInvocations []pegomock.MethodInvocation
}
func (c *MockEventParsing_ParseGitlabMergeRequestCommentEvent_OngoingVerification) GetCapturedArguments() go_gitlab.MergeCommentEvent {
func (c *MockEventParsing_ParseGitlabMergeRequestCommentEvent_OngoingVerification) GetCapturedArguments() client_go.MergeCommentEvent {
event := c.GetAllCapturedArguments()
return event[len(event)-1]
}
func (c *MockEventParsing_ParseGitlabMergeRequestCommentEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []go_gitlab.MergeCommentEvent) {
func (c *MockEventParsing_ParseGitlabMergeRequestCommentEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []client_go.MergeCommentEvent) {
_params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(_params) > 0 {
if len(_params) > 0 {
_param0 = make([]go_gitlab.MergeCommentEvent, len(c.methodInvocations))
_param0 = make([]client_go.MergeCommentEvent, len(c.methodInvocations))
for u, param := range _params[0] {
_param0[u] = param.(go_gitlab.MergeCommentEvent)
_param0[u] = param.(client_go.MergeCommentEvent)
}
}
}
return
}
func (verifier *VerifierMockEventParsing) ParseGitlabMergeRequestEvent(event go_gitlab.MergeEvent) *MockEventParsing_ParseGitlabMergeRequestEvent_OngoingVerification {
func (verifier *VerifierMockEventParsing) ParseGitlabMergeRequestEvent(event client_go.MergeEvent) *MockEventParsing_ParseGitlabMergeRequestEvent_OngoingVerification {
_params := []pegomock.Param{event}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGitlabMergeRequestEvent", _params, verifier.timeout)
return &MockEventParsing_ParseGitlabMergeRequestEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
@@ -1233,25 +1233,25 @@ type MockEventParsing_ParseGitlabMergeRequestEvent_OngoingVerification struct {
methodInvocations []pegomock.MethodInvocation
}
func (c *MockEventParsing_ParseGitlabMergeRequestEvent_OngoingVerification) GetCapturedArguments() go_gitlab.MergeEvent {
func (c *MockEventParsing_ParseGitlabMergeRequestEvent_OngoingVerification) GetCapturedArguments() client_go.MergeEvent {
event := c.GetAllCapturedArguments()
return event[len(event)-1]
}
func (c *MockEventParsing_ParseGitlabMergeRequestEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []go_gitlab.MergeEvent) {
func (c *MockEventParsing_ParseGitlabMergeRequestEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []client_go.MergeEvent) {
_params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(_params) > 0 {
if len(_params) > 0 {
_param0 = make([]go_gitlab.MergeEvent, len(c.methodInvocations))
_param0 = make([]client_go.MergeEvent, len(c.methodInvocations))
for u, param := range _params[0] {
_param0[u] = param.(go_gitlab.MergeEvent)
_param0[u] = param.(client_go.MergeEvent)
}
}
}
return
}
func (verifier *VerifierMockEventParsing) ParseGitlabMergeRequestUpdateEvent(event go_gitlab.MergeEvent) *MockEventParsing_ParseGitlabMergeRequestUpdateEvent_OngoingVerification {
func (verifier *VerifierMockEventParsing) ParseGitlabMergeRequestUpdateEvent(event client_go.MergeEvent) *MockEventParsing_ParseGitlabMergeRequestUpdateEvent_OngoingVerification {
_params := []pegomock.Param{event}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ParseGitlabMergeRequestUpdateEvent", _params, verifier.timeout)
return &MockEventParsing_ParseGitlabMergeRequestUpdateEvent_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
@@ -1262,18 +1262,18 @@ type MockEventParsing_ParseGitlabMergeRequestUpdateEvent_OngoingVerification str
methodInvocations []pegomock.MethodInvocation
}
func (c *MockEventParsing_ParseGitlabMergeRequestUpdateEvent_OngoingVerification) GetCapturedArguments() go_gitlab.MergeEvent {
func (c *MockEventParsing_ParseGitlabMergeRequestUpdateEvent_OngoingVerification) GetCapturedArguments() client_go.MergeEvent {
event := c.GetAllCapturedArguments()
return event[len(event)-1]
}
func (c *MockEventParsing_ParseGitlabMergeRequestUpdateEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []go_gitlab.MergeEvent) {
func (c *MockEventParsing_ParseGitlabMergeRequestUpdateEvent_OngoingVerification) GetAllCapturedArguments() (_param0 []client_go.MergeEvent) {
_params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(_params) > 0 {
if len(_params) > 0 {
_param0 = make([]go_gitlab.MergeEvent, len(c.methodInvocations))
_param0 = make([]client_go.MergeEvent, len(c.methodInvocations))
for u, param := range _params[0] {
_param0[u] = param.(go_gitlab.MergeEvent)
_param0[u] = param.(client_go.MergeEvent)
}
}
}

View File

@@ -6,7 +6,7 @@ package mocks
import (
pegomock "github.com/petergtz/pegomock/v4"
logging "github.com/runatlantis/atlantis/server/logging"
go_gitlab "gitlab.com/gitlab-org/api/client-go"
client_go "gitlab.com/gitlab-org/api/client-go"
"reflect"
"time"
)
@@ -26,17 +26,17 @@ func NewMockGitlabMergeRequestGetter(options ...pegomock.Option) *MockGitlabMerg
func (mock *MockGitlabMergeRequestGetter) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh }
func (mock *MockGitlabMergeRequestGetter) FailHandler() pegomock.FailHandler { return mock.fail }
func (mock *MockGitlabMergeRequestGetter) GetMergeRequest(logger logging.SimpleLogging, repoFullName string, pullNum int) (*go_gitlab.MergeRequest, error) {
func (mock *MockGitlabMergeRequestGetter) GetMergeRequest(logger logging.SimpleLogging, repoFullName string, pullNum int) (*client_go.MergeRequest, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockGitlabMergeRequestGetter().")
}
_params := []pegomock.Param{logger, repoFullName, pullNum}
_result := pegomock.GetGenericMockFrom(mock).Invoke("GetMergeRequest", _params, []reflect.Type{reflect.TypeOf((**go_gitlab.MergeRequest)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var _ret0 *go_gitlab.MergeRequest
_result := pegomock.GetGenericMockFrom(mock).Invoke("GetMergeRequest", _params, []reflect.Type{reflect.TypeOf((**client_go.MergeRequest)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var _ret0 *client_go.MergeRequest
var _ret1 error
if len(_result) != 0 {
if _result[0] != nil {
_ret0 = _result[0].(*go_gitlab.MergeRequest)
_ret0 = _result[0].(*client_go.MergeRequest)
}
if _result[1] != nil {
_ret1 = _result[1].(error)

View File

@@ -26,27 +26,23 @@ func NewMockWorkingDir(options ...pegomock.Option) *MockWorkingDir {
func (mock *MockWorkingDir) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh }
func (mock *MockWorkingDir) FailHandler() pegomock.FailHandler { return mock.fail }
func (mock *MockWorkingDir) Clone(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (string, bool, error) {
func (mock *MockWorkingDir) Clone(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (string, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockWorkingDir().")
}
_params := []pegomock.Param{logger, headRepo, p, workspace}
_result := pegomock.GetGenericMockFrom(mock).Invoke("Clone", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
_result := pegomock.GetGenericMockFrom(mock).Invoke("Clone", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var _ret0 string
var _ret1 bool
var _ret2 error
var _ret1 error
if len(_result) != 0 {
if _result[0] != nil {
_ret0 = _result[0].(string)
}
if _result[1] != nil {
_ret1 = _result[1].(bool)
}
if _result[2] != nil {
_ret2 = _result[2].(error)
_ret1 = _result[1].(error)
}
}
return _ret0, _ret1, _ret2
return _ret0, _ret1
}
func (mock *MockWorkingDir) Delete(logger logging.SimpleLogging, r models.Repo, p models.PullRequest) error {
@@ -166,12 +162,23 @@ func (mock *MockWorkingDir) HasDiverged(logger logging.SimpleLogging, cloneDir s
return _ret0
}
func (mock *MockWorkingDir) SetCheckForUpstreamChanges() {
func (mock *MockWorkingDir) MergeAgain(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (bool, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockWorkingDir().")
}
_params := []pegomock.Param{}
pegomock.GetGenericMockFrom(mock).Invoke("SetCheckForUpstreamChanges", _params, []reflect.Type{})
_params := []pegomock.Param{logger, headRepo, p, workspace}
_result := pegomock.GetGenericMockFrom(mock).Invoke("MergeAgain", _params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var _ret0 bool
var _ret1 error
if len(_result) != 0 {
if _result[0] != nil {
_ret0 = _result[0].(bool)
}
if _result[1] != nil {
_ret1 = _result[1].(error)
}
}
return _ret0, _ret1
}
func (mock *MockWorkingDir) VerifyWasCalledOnce() *VerifierMockWorkingDir {
@@ -563,19 +570,49 @@ func (c *MockWorkingDir_HasDiverged_OngoingVerification) GetAllCapturedArguments
return
}
func (verifier *VerifierMockWorkingDir) SetCheckForUpstreamChanges() *MockWorkingDir_SetCheckForUpstreamChanges_OngoingVerification {
_params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "SetCheckForUpstreamChanges", _params, verifier.timeout)
return &MockWorkingDir_SetCheckForUpstreamChanges_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
func (verifier *VerifierMockWorkingDir) MergeAgain(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) *MockWorkingDir_MergeAgain_OngoingVerification {
_params := []pegomock.Param{logger, headRepo, p, workspace}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "MergeAgain", _params, verifier.timeout)
return &MockWorkingDir_MergeAgain_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type MockWorkingDir_SetCheckForUpstreamChanges_OngoingVerification struct {
type MockWorkingDir_MergeAgain_OngoingVerification struct {
mock *MockWorkingDir
methodInvocations []pegomock.MethodInvocation
}
func (c *MockWorkingDir_SetCheckForUpstreamChanges_OngoingVerification) GetCapturedArguments() {
func (c *MockWorkingDir_MergeAgain_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, models.Repo, models.PullRequest, string) {
logger, headRepo, p, workspace := c.GetAllCapturedArguments()
return logger[len(logger)-1], headRepo[len(headRepo)-1], p[len(p)-1], workspace[len(workspace)-1]
}
func (c *MockWorkingDir_SetCheckForUpstreamChanges_OngoingVerification) GetAllCapturedArguments() {
func (c *MockWorkingDir_MergeAgain_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []models.Repo, _param2 []models.PullRequest, _param3 []string) {
_params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(_params) > 0 {
if len(_params) > 0 {
_param0 = make([]logging.SimpleLogging, len(c.methodInvocations))
for u, param := range _params[0] {
_param0[u] = param.(logging.SimpleLogging)
}
}
if len(_params) > 1 {
_param1 = make([]models.Repo, len(c.methodInvocations))
for u, param := range _params[1] {
_param1[u] = param.(models.Repo)
}
}
if len(_params) > 2 {
_param2 = make([]models.PullRequest, len(c.methodInvocations))
for u, param := range _params[2] {
_param2[u] = param.(models.PullRequest)
}
}
if len(_params) > 3 {
_param3 = make([]string, len(c.methodInvocations))
for u, param := range _params[3] {
_param3[u] = param.(string)
}
}
}
return
}

View File

@@ -43,25 +43,6 @@ func (mock *MockWorkingDirLocker) TryLock(repoFullName string, pullNum int, work
return _ret0, _ret1
}
func (mock *MockWorkingDirLocker) TryLockPull(repoFullName string, pullNum int) (func(), error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockWorkingDirLocker().")
}
_params := []pegomock.Param{repoFullName, pullNum}
_result := pegomock.GetGenericMockFrom(mock).Invoke("TryLockPull", _params, []reflect.Type{reflect.TypeOf((*func())(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var _ret0 func()
var _ret1 error
if len(_result) != 0 {
if _result[0] != nil {
_ret0 = _result[0].(func())
}
if _result[1] != nil {
_ret1 = _result[1].(error)
}
}
return _ret0, _ret1
}
func (mock *MockWorkingDirLocker) VerifyWasCalledOnce() *VerifierMockWorkingDirLocker {
return &VerifierMockWorkingDirLocker{
mock: mock,
@@ -145,38 +126,3 @@ func (c *MockWorkingDirLocker_TryLock_OngoingVerification) GetAllCapturedArgumen
}
return
}
func (verifier *VerifierMockWorkingDirLocker) TryLockPull(repoFullName string, pullNum int) *MockWorkingDirLocker_TryLockPull_OngoingVerification {
_params := []pegomock.Param{repoFullName, pullNum}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "TryLockPull", _params, verifier.timeout)
return &MockWorkingDirLocker_TryLockPull_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type MockWorkingDirLocker_TryLockPull_OngoingVerification struct {
mock *MockWorkingDirLocker
methodInvocations []pegomock.MethodInvocation
}
func (c *MockWorkingDirLocker_TryLockPull_OngoingVerification) GetCapturedArguments() (string, int) {
repoFullName, pullNum := c.GetAllCapturedArguments()
return repoFullName[len(repoFullName)-1], pullNum[len(pullNum)-1]
}
func (c *MockWorkingDirLocker_TryLockPull_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []int) {
_params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(_params) > 0 {
if len(_params) > 0 {
_param0 = make([]string, len(c.methodInvocations))
for u, param := range _params[0] {
_param0[u] = param.(string)
}
}
if len(_params) > 1 {
_param1 = make([]int, len(c.methodInvocations))
for u, param := range _params[1] {
_param1[u] = param.(int)
}
}
}
return
}

View File

@@ -59,7 +59,7 @@ func (w *DefaultPostWorkflowHooksCommandRunner) RunPostHooks(ctx *command.Contex
ctx.Log.Debug("got workspace lock")
defer unlockFn()
repoDir, _, err := w.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, DefaultWorkspace)
repoDir, err := w.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, DefaultWorkspace)
if err != nil {
return err
}

View File

@@ -168,7 +168,7 @@ func TestRunPostHooks_Clone(t *testing.T) {
When(postWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(postWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, nil)
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil)
When(whPostWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand), Any[string](),
Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil)
@@ -209,7 +209,7 @@ func TestRunPostHooks_Clone(t *testing.T) {
When(postWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(postWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, nil)
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil)
When(whPostWorkflowHookRunner.Run(
ArgThat[models.WorkflowHookCommandContext](WorkflowHookCommandContextMatcher{expected: expectedCtx}),
Eq(testHook.RunCommand),
@@ -312,7 +312,7 @@ func TestRunPostHooks_Clone(t *testing.T) {
When(postWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(postWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, errors.New("some error"))
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, errors.New("some error"))
err := postWh.RunPostHooks(ctx, planCmd)
@@ -347,7 +347,7 @@ func TestRunPostHooks_Clone(t *testing.T) {
When(postWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(postWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, nil)
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil)
When(whPostWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand),
Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, errors.New("some error"))
@@ -389,7 +389,7 @@ func TestRunPostHooks_Clone(t *testing.T) {
When(postWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(postWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, nil)
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil)
When(whPostWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand),
Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil)
@@ -425,7 +425,7 @@ func TestRunPostHooks_Clone(t *testing.T) {
When(postWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(postWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, nil)
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil)
When(whPostWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHookWithShell.RunCommand),
Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil)
@@ -461,7 +461,7 @@ func TestRunPostHooks_Clone(t *testing.T) {
When(postWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(postWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, nil)
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil)
When(whPostWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand),
Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil)
@@ -497,7 +497,7 @@ func TestRunPostHooks_Clone(t *testing.T) {
When(postWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(postWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, nil)
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil)
When(whPostWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHookWithShellandShellArgs.RunCommand),
Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil)
@@ -534,7 +534,7 @@ func TestRunPostHooks_Clone(t *testing.T) {
When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, nil)
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil)
When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](),
Eq(testHookWithPlanCommand.RunCommand), Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil)
@@ -570,7 +570,7 @@ func TestRunPostHooks_Clone(t *testing.T) {
When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, nil)
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil)
When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHookWithPlanCommand.RunCommand),
Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil)
@@ -606,7 +606,7 @@ func TestRunPostHooks_Clone(t *testing.T) {
When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, nil)
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil)
When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHookWithPlanApplyCommands.RunCommand),
Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil)

View File

@@ -59,7 +59,7 @@ func (w *DefaultPreWorkflowHooksCommandRunner) RunPreHooks(ctx *command.Context,
ctx.Log.Debug("got workspace lock")
defer unlockFn()
repoDir, _, err := w.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, DefaultWorkspace)
repoDir, err := w.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, DefaultWorkspace)
if err != nil {
return err
}

View File

@@ -145,7 +145,7 @@ func TestRunPreHooks_Clone(t *testing.T) {
When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, nil)
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil)
When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand),
Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil)
@@ -241,7 +241,7 @@ func TestRunPreHooks_Clone(t *testing.T) {
When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, errors.New("some error"))
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, errors.New("some error"))
err := preWh.RunPreHooks(ctx, planCmd)
@@ -276,7 +276,7 @@ func TestRunPreHooks_Clone(t *testing.T) {
When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, nil)
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil)
When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand),
Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, errors.New("some error"))
@@ -318,7 +318,7 @@ func TestRunPreHooks_Clone(t *testing.T) {
When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, nil)
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil)
When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand), Any[string](),
Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil)
@@ -354,7 +354,7 @@ func TestRunPreHooks_Clone(t *testing.T) {
When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, nil)
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil)
When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHookWithShell.RunCommand),
Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil)
@@ -390,7 +390,7 @@ func TestRunPreHooks_Clone(t *testing.T) {
When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, nil)
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil)
When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHook.RunCommand),
Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil)
@@ -426,7 +426,7 @@ func TestRunPreHooks_Clone(t *testing.T) {
When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, nil)
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil)
When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHookWithShellandShellArgs.RunCommand),
Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil)
@@ -463,7 +463,7 @@ func TestRunPreHooks_Clone(t *testing.T) {
When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, nil)
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil)
When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHookWithPlanCommand.RunCommand),
Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil)
@@ -499,7 +499,7 @@ func TestRunPreHooks_Clone(t *testing.T) {
When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, nil)
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil)
When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHookWithPlanCommand.RunCommand),
Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil)
@@ -535,7 +535,7 @@ func TestRunPreHooks_Clone(t *testing.T) {
When(preWhWorkingDirLocker.TryLock(testdata.GithubRepo.FullName, newPull.Num, events.DefaultWorkspace,
events.DefaultRepoRelDir)).ThenReturn(unlockFn, nil)
When(preWhWorkingDir.Clone(Any[logging.SimpleLogging](), Eq(testdata.GithubRepo), Eq(newPull),
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, false, nil)
Eq(events.DefaultWorkspace))).ThenReturn(repoDir, nil)
When(whPreWorkflowHookRunner.Run(Any[models.WorkflowHookCommandContext](), Eq(testHookWithPlanApplyCommands.RunCommand),
Any[string](), Any[string](), Eq(repoDir))).ThenReturn(result, runtimeDesc, nil)

View File

@@ -479,7 +479,7 @@ func (p *DefaultProjectCommandBuilder) buildAllCommandsByCfg(ctx *command.Contex
ctx.Log.Debug("got workspace lock")
defer unlockFn()
repoDir, _, err := p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, workspace)
repoDir, err := p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, workspace)
if err != nil {
return nil, err
}
@@ -604,7 +604,7 @@ func (p *DefaultProjectCommandBuilder) buildProjectPlanCommand(ctx *command.Cont
defer unlockFn()
ctx.Log.Debug("cloning repository")
_, _, err = p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, DefaultWorkspace)
_, err = p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, DefaultWorkspace)
if err != nil {
return pcc, err
}
@@ -682,7 +682,7 @@ func (p *DefaultProjectCommandBuilder) buildProjectPlanCommand(ctx *command.Cont
if DefaultWorkspace != workspace {
ctx.Log.Debug("cloning repository with workspace %s", workspace)
_, _, err = p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, workspace)
_, err = p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, workspace)
if err != nil {
return pcc, err
}
@@ -766,14 +766,6 @@ func (p *DefaultProjectCommandBuilder) getCfg(ctx *command.Context, projectName
// buildAllProjectCommandsByPlan builds contexts for a command for every project that has
// pending plans in this ctx.
func (p *DefaultProjectCommandBuilder) buildAllProjectCommandsByPlan(ctx *command.Context, commentCmd *CommentCommand) ([]command.ProjectContext, error) {
// Lock all dirs in this pull request (instead of a single dir) because we
// don't know how many dirs we'll need to run the command in.
unlockFn, err := p.WorkingDirLocker.TryLockPull(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num)
if err != nil {
return nil, err
}
defer unlockFn()
pullDir, err := p.WorkingDir.GetPullDir(ctx.Pull.BaseRepo, ctx.Pull)
if err != nil {
return nil, err
@@ -793,6 +785,12 @@ func (p *DefaultProjectCommandBuilder) buildAllProjectCommandsByPlan(ctx *comman
var cmds []command.ProjectContext
for _, plan := range plans {
// Lock all the directories we need to run the command in
unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, plan.Workspace, plan.RepoRelDir)
if err != nil {
return nil, err
}
defer unlockFn()
commentCmds, err := p.buildProjectCommandCtx(ctx, commentCmd.CommandName(), commentCmd.SubName, plan.ProjectName, commentCmd.Flags, defaultRepoDir, plan.RepoRelDir, plan.Workspace, commentCmd.Verbose)
if err != nil {
return nil, errors.Wrapf(err, "building command for dir '%s'", plan.RepoRelDir)

View File

@@ -631,7 +631,7 @@ projects:
workingDir := NewMockWorkingDir()
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(tmp, false, nil)
Any[string]())).ThenReturn(tmp, nil)
vcsClient := vcsmocks.NewMockClient()
When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](),
Any[models.PullRequest]())).ThenReturn([]string{"modules/module/main.tf"}, nil)
@@ -846,7 +846,7 @@ projects:
workingDir := NewMockWorkingDir()
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(tmp, false, nil)
Any[string]())).ThenReturn(tmp, nil)
vcsClient := vcsmocks.NewMockClient()
When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](),
Any[models.PullRequest]())).ThenReturn([]string{"modules/module/main.tf"}, nil)
@@ -1091,7 +1091,7 @@ workflows:
workingDir := NewMockWorkingDir()
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(tmp, false, nil)
Any[string]())).ThenReturn(tmp, nil)
vcsClient := vcsmocks.NewMockClient()
When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](),
Any[models.PullRequest]())).ThenReturn([]string{"modules/module/main.tf"}, nil)
@@ -1245,7 +1245,7 @@ projects:
workingDir := NewMockWorkingDir()
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(tmp, false, nil)
Any[string]())).ThenReturn(tmp, nil)
vcsClient := vcsmocks.NewMockClient()
When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](),
Any[models.PullRequest]())).ThenReturn([]string{"modules/module/main.tf"}, nil)
@@ -1385,7 +1385,7 @@ projects:
workingDir := NewMockWorkingDir()
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(tmp, false, nil)
Any[string]())).ThenReturn(tmp, nil)
vcsClient := vcsmocks.NewMockClient()
When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](),
Any[models.PullRequest]())).ThenReturn(c.modifiedFiles, nil)

View File

@@ -241,7 +241,7 @@ terraform {
tmpDir := DirStructure(t, c.TestDirStructure)
workingDir := mocks.NewMockWorkingDir()
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(tmpDir, false, nil)
Any[string]())).ThenReturn(tmpDir, nil)
vcsClient := vcsmocks.NewMockClient()
When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](),
Any[models.PullRequest]())).ThenReturn(ChangedFiles(c.TestDirStructure, ""), nil)
@@ -602,7 +602,7 @@ projects:
workingDir := mocks.NewMockWorkingDir()
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(tmpDir, false, nil)
Any[string]())).ThenReturn(tmpDir, nil)
When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, nil)
vcsClient := vcsmocks.NewMockClient()
When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](),
@@ -790,7 +790,7 @@ projects:
workingDir := mocks.NewMockWorkingDir()
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(tmpDir, false, nil)
Any[string]())).ThenReturn(tmpDir, nil)
When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, nil)
vcsClient := vcsmocks.NewMockClient()
When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](),
@@ -1191,7 +1191,7 @@ projects:
workingDir := mocks.NewMockWorkingDir()
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(tmpDir, false, nil)
Any[string]())).ThenReturn(tmpDir, nil)
When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, nil)
vcsClient := vcsmocks.NewMockClient()
When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](),
@@ -1379,7 +1379,7 @@ projects:
Ok(t, err)
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(repoDir, false, nil)
Any[string]())).ThenReturn(repoDir, nil)
When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(repoDir, nil)
globalCfgArgs := valid.GlobalCfgArgs{
@@ -1467,7 +1467,7 @@ func TestDefaultProjectCommandBuilder_EscapeArgs(t *testing.T) {
workingDir := mocks.NewMockWorkingDir()
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(tmpDir, false, nil)
Any[string]())).ThenReturn(tmpDir, nil)
When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, nil)
vcsClient := vcsmocks.NewMockClient()
When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](),
@@ -1623,7 +1623,7 @@ projects:
Any[models.PullRequest]())).ThenReturn(testCase.ModifiedFiles, nil)
workingDir := mocks.NewMockWorkingDir()
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(tmpDir, false, nil)
Any[string]())).ThenReturn(tmpDir, nil)
When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, nil)
globalCfgArgs := valid.GlobalCfgArgs{
@@ -1821,7 +1821,7 @@ func TestDefaultProjectCommandBuilder_WithPolicyCheckEnabled_BuildAutoplanComman
workingDir := mocks.NewMockWorkingDir()
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(tmpDir, false, nil)
Any[string]())).ThenReturn(tmpDir, nil)
vcsClient := vcsmocks.NewMockClient()
When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](),
Any[models.PullRequest]())).ThenReturn([]string{"main.tf"}, nil)
@@ -2038,7 +2038,7 @@ func TestDefaultProjectCommandBuilder_BuildPlanCommands_Single_With_RestrictFile
workingDir := mocks.NewMockWorkingDir()
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(tmpDir, false, nil)
Any[string]())).ThenReturn(tmpDir, nil)
When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, nil)
When(workingDir.GetGitUntrackedFiles(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(c.UntrackedFiles, nil)
@@ -2149,7 +2149,7 @@ func TestDefaultProjectCommandBuilder_BuildPlanCommands_with_IncludeGitUntracked
workingDir := mocks.NewMockWorkingDir()
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(tmpDir, false, nil)
Any[string]())).ThenReturn(tmpDir, nil)
When(workingDir.GetWorkingDir(Any[models.Repo](), Any[models.PullRequest](), Any[string]())).ThenReturn(tmpDir, nil)
When(workingDir.GetGitUntrackedFiles(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(c.UntrackedFiles, nil)

View File

@@ -580,15 +580,22 @@ func (p *DefaultProjectCommandRunner) doPlan(ctx command.ProjectContext) (*model
}
defer unlockFn()
p.WorkingDir.SetCheckForUpstreamChanges()
// Clone is idempotent so okay to run even if the repo was already cloned.
repoDir, mergedAgain, cloneErr := p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, ctx.Workspace)
if cloneErr != nil {
repoDir, err := p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, ctx.Workspace)
if err != nil {
if unlockErr := lockAttempt.UnlockFn(); unlockErr != nil {
ctx.Log.Err("error unlocking state after plan error: %v", unlockErr)
}
return nil, "", cloneErr
return nil, "", err
}
mergedAgain, err := p.WorkingDir.MergeAgain(ctx.Log, ctx.HeadRepo, ctx.Pull, ctx.Workspace)
if err != nil {
if unlockErr := lockAttempt.UnlockFn(); unlockErr != nil {
ctx.Log.Err("error unlocking state after plan error: %v", unlockErr)
}
return nil, "", err
}
projAbsPath := filepath.Join(repoDir, ctx.RepoRelDir)
if _, err = os.Stat(projAbsPath); os.IsNotExist(err) {
return nil, "", DirNotExistErr{RepoRelDir: ctx.RepoRelDir}
@@ -706,7 +713,7 @@ func (p *DefaultProjectCommandRunner) doVersion(ctx command.ProjectContext) (ver
func (p *DefaultProjectCommandRunner) doImport(ctx command.ProjectContext) (out *models.ImportSuccess, failure string, err error) {
// Clone is idempotent so okay to run even if the repo was already cloned.
repoDir, _, cloneErr := p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, ctx.Workspace)
repoDir, cloneErr := p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, ctx.Workspace)
if cloneErr != nil {
return nil, "", cloneErr
}
@@ -752,7 +759,7 @@ func (p *DefaultProjectCommandRunner) doImport(ctx command.ProjectContext) (out
func (p *DefaultProjectCommandRunner) doStateRm(ctx command.ProjectContext) (out *models.StateRmSuccess, failure string, err error) {
// Clone is idempotent so okay to run even if the repo was already cloned.
repoDir, _, cloneErr := p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, ctx.Workspace)
repoDir, cloneErr := p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, ctx.Workspace)
if cloneErr != nil {
return nil, "", cloneErr
}

View File

@@ -66,7 +66,7 @@ func TestDefaultProjectCommandRunner_Plan(t *testing.T) {
repoDir := t.TempDir()
When(mockWorkingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(repoDir, false, nil)
Any[string]())).ThenReturn(repoDir, nil)
When(mockLocker.TryLock(Any[logging.SimpleLogging](), Any[models.PullRequest](), Any[models.User](), Any[string](),
Any[models.Project](), AnyBool())).ThenReturn(&events.TryLockResponse{LockAcquired: true, LockKey: "lock-key"}, nil)
@@ -106,6 +106,7 @@ func TestDefaultProjectCommandRunner_Plan(t *testing.T) {
Assert(t, res.PlanSuccess != nil, "exp plan success")
Equals(t, "https://lock-key", res.PlanSuccess.LockURL)
t.Logf("output is %s", res.PlanSuccess.TerraformOutput)
Equals(t, "run\napply\nplan\ninit", res.PlanSuccess.TerraformOutput)
expSteps := []string{"run", "apply", "plan", "init", "env"}
for _, step := range expSteps {
@@ -575,7 +576,7 @@ func TestDefaultProjectCommandRunner_RunEnvSteps(t *testing.T) {
repoDir := t.TempDir()
When(mockWorkingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(repoDir, false, nil)
Any[string]())).ThenReturn(repoDir, nil)
When(mockLocker.TryLock(Any[logging.SimpleLogging](), Any[models.PullRequest](), Any[models.User](), Any[string](),
Any[models.Project](), AnyBool())).ThenReturn(&events.TryLockResponse{LockAcquired: true, LockKey: "lock-key"}, nil)
@@ -717,7 +718,7 @@ func TestDefaultProjectCommandRunner_Import(t *testing.T) {
}
repoDir := t.TempDir()
When(mockWorkingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
Any[string]())).ThenReturn(repoDir, false, nil)
Any[string]())).ThenReturn(repoDir, nil)
if c.setup != nil {
c.setup(repoDir, ctx, mockLocker, mockInit, mockImport)
}

View File

@@ -32,6 +32,7 @@ import (
const workingDirPrefix = "repos"
var cloneLocks sync.Map
var recheckRequiredMap sync.Map
//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package mocks -o mocks/mock_working_dir.go WorkingDir
//go:generate pegomock generate github.com/runatlantis/atlantis/server/events --package events WorkingDir
@@ -39,10 +40,11 @@ var cloneLocks sync.Map
// WorkingDir handles the workspace on disk for running commands.
type WorkingDir interface {
// Clone git clones headRepo, checks out the branch and then returns the
// absolute path to the root of the cloned repo. It also returns
// a boolean indicating if we should warn users that the branch we're
// merging into has been updated since we cloned it.
Clone(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (string, bool, error)
// absolute path to the root of the cloned repo.
Clone(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (string, error)
// MergeAgain merges again with upstream if upstream has been modified, returns
// whether it actually did a new merge
MergeAgain(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (bool, error)
// GetWorkingDir returns the path to the workspace for this repo and pull.
// If workspace does not exist on disk, error will be of type os.IsNotExist.
GetWorkingDir(r models.Repo, p models.PullRequest, workspace string) (string, error)
@@ -51,10 +53,6 @@ type WorkingDir interface {
// Delete deletes the workspace for this repo and pull.
Delete(logger logging.SimpleLogging, r models.Repo, p models.PullRequest) error
DeleteForWorkspace(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string) error
// Set a flag in the workingdir so Clone() can know that it is safe to re-clone the workingdir if
// the upstream branch has been modified. This is only safe after grabbing the project lock
// and before running any plans
SetCheckForUpstreamChanges()
// DeletePlan deletes the plan for this repo, pull, workspace path and project name
DeletePlan(logger logging.SimpleLogging, r models.Repo, p models.PullRequest, workspace string, path string, projectName string) error
// GetGitUntrackedFiles returns a list of Git untracked files in the working dir.
@@ -90,14 +88,19 @@ type FileWorkspace struct {
}
// Clone git clones headRepo, checks out the branch and then returns the absolute
// path to the root of the cloned repo. It also returns
// a boolean indicating whether we had to merge with upstream again.
// path to the root of the cloned repo.
// If the repo already exists and is at
// the right commit it does nothing. This is to support running commands in
// multiple dirs of the same repo without deleting existing plans.
func (w *FileWorkspace) Clone(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (string, bool, error) {
func (w *FileWorkspace) Clone(logger logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (string, error) {
cloneDir := w.cloneDir(p.BaseRepo, p, workspace)
defer func() { w.CheckForUpstreamChanges = false }()
// Unconditionally wait for the clone lock here, if anyone else is doing any clone
// operation in this directory, we wait for it to finish before we check anything.
value, _ := cloneLocks.LoadOrStore(cloneDir, new(sync.Mutex))
mutex := value.(*sync.Mutex)
mutex.Lock()
defer mutex.Unlock()
c := wrappedGitContext{cloneDir, headRepo, p}
// If the directory already exists, check if it's at the right commit.
@@ -119,27 +122,62 @@ func (w *FileWorkspace) Clone(logger logging.SimpleLogging, headRepo models.Repo
outputRevParseCmd, err := revParseCmd.CombinedOutput()
if err != nil {
logger.Warn("will re-clone repo, could not determine if was at correct commit: %s: %s: %s", strings.Join(revParseCmd.Args, " "), err, string(outputRevParseCmd))
return cloneDir, false, w.forceClone(logger, c)
return cloneDir, w.forceClone(logger, c)
}
currCommit := strings.Trim(string(outputRevParseCmd), "\n")
// We're prefix matching here because BitBucket doesn't give us the full
// commit, only a 12 character prefix.
if strings.HasPrefix(currCommit, p.HeadCommit) {
if w.CheckForUpstreamChanges && w.CheckoutMerge && w.recheckDiverged(logger, p, headRepo, cloneDir) {
logger.Info("base branch has been updated, using merge strategy and will clone again")
return cloneDir, true, w.mergeAgain(logger, c)
}
logger.Debug("repo is at correct commit '%s' so will not re-clone", p.HeadCommit)
return cloneDir, false, nil
} else {
logger.Debug("repo was already cloned but is not at correct commit, wanted '%s' got '%s'", p.HeadCommit, currCommit)
logger.Debug("repo is at correct commit %q so will not re-clone", p.HeadCommit)
return cloneDir, nil
}
logger.Debug("repo was already cloned but is not at correct commit, wanted %q got %q", p.HeadCommit, currCommit)
// We'll fall through to re-clone.
}
// Otherwise we clone the repo.
return cloneDir, false, w.forceClone(logger, c)
return cloneDir, w.forceClone(logger, c)
}
// MergeAgain merges again with upstream if we are using the merge checkout strategy,
// and upstream has been modified since we last checked.
// It returns a flag indicating whether we had to merge with upstream again.
func (w *FileWorkspace) MergeAgain(
logger logging.SimpleLogging,
headRepo models.Repo,
p models.PullRequest,
workspace string) (bool, error) {
if !w.CheckoutMerge {
return false, nil
}
cloneDir := w.cloneDir(p.BaseRepo, p, workspace)
// We atomically set the recheckRequiredMap flag here before grabbing the clone lock.
// If the flag is cleared after we grab the lock, it means some other thread
// did the necessary work late enough that we do not have to do it again.
recheckRequiredMap.Store(cloneDir, struct{}{})
// Unconditionally wait for the clone lock here, if anyone else is doing any clone
// operation in this directory, we wait for it to finish before we check anything.
value, _ := cloneLocks.LoadOrStore(cloneDir, new(sync.Mutex))
mutex := value.(*sync.Mutex)
mutex.Lock()
defer mutex.Unlock()
if _, exists := recheckRequiredMap.Load(cloneDir); !exists {
logger.Debug("Skipping upstream check. Some other thread has done this for us")
return false, nil
}
recheckRequiredMap.Delete(cloneDir)
c := wrappedGitContext{cloneDir, headRepo, p}
if w.recheckDiverged(logger, p, headRepo, cloneDir) {
logger.Info("base branch has been updated, using merge strategy and will merge again")
return true, w.mergeAgain(logger, c)
}
return false, nil
}
// recheckDiverged returns true if the branch we're merging into has diverged
@@ -217,15 +255,6 @@ func (w *FileWorkspace) HasDiverged(logger logging.SimpleLogging, cloneDir strin
}
func (w *FileWorkspace) forceClone(logger logging.SimpleLogging, c wrappedGitContext) error {
value, _ := cloneLocks.LoadOrStore(c.dir, new(sync.Mutex))
mutex := value.(*sync.Mutex)
defer mutex.Unlock()
if locked := mutex.TryLock(); !locked {
mutex.Lock()
return nil
}
err := os.RemoveAll(c.dir)
if err != nil {
return errors.Wrapf(err, "deleting dir '%s' before cloning", c.dir)
@@ -280,15 +309,6 @@ func (w *FileWorkspace) forceClone(logger logging.SimpleLogging, c wrappedGitCon
// There is a new upstream update that we need, and we want to update to it
// without deleting any existing plans
func (w *FileWorkspace) mergeAgain(logger logging.SimpleLogging, c wrappedGitContext) error {
value, _ := cloneLocks.LoadOrStore(c.dir, new(sync.Mutex))
mutex := value.(*sync.Mutex)
defer mutex.Unlock()
if locked := mutex.TryLock(); !locked {
mutex.Lock()
return nil
}
// Reset branch as if it was cloned again
if err := w.wrappedGit(logger, c, "reset", "--hard", fmt.Sprintf("refs/remotes/origin/%s", c.pr.BaseBranch)); err != nil {
return err

View File

@@ -15,7 +15,6 @@ package events
import (
"fmt"
"strings"
"sync"
)
@@ -32,12 +31,6 @@ type WorkingDirLocker interface {
// 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, 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
// an error if the workspace is already locked. The error is expected to
// be printed to the pull request.
TryLockPull(repoFullName string, pullNum int) (func(), error)
}
// DefaultWorkingDirLocker implements WorkingDirLocker.
@@ -45,49 +38,26 @@ type DefaultWorkingDirLocker struct {
// mutex prevents against multiple threads calling functions on this struct
// concurrently. It's only used for entry/exit to each function.
mutex sync.Mutex
// locks is a list of the keys that are locked. We then use prefix
// matching to determine if something is locked. It's naive but that's okay
// because there won't be many locks at one time.
locks []string
// locks is a set of the keys that are locked.
locks map[string]struct{}
}
// NewDefaultWorkingDirLocker is a constructor.
func NewDefaultWorkingDirLocker() *DefaultWorkingDirLocker {
return &DefaultWorkingDirLocker{}
}
func (d *DefaultWorkingDirLocker) TryLockPull(repoFullName string, pullNum int) (func(), error) {
d.mutex.Lock()
defer d.mutex.Unlock()
pullKey := d.pullKey(repoFullName, pullNum)
for _, l := range d.locks {
if l == pullKey || strings.HasPrefix(l, pullKey+"/") {
return func() {}, fmt.Errorf("the Atlantis working dir is currently locked by another" +
" command that is running for this pull request.\n" +
"Wait until the previous command is complete and try again")
}
}
d.locks = append(d.locks, pullKey)
return func() {
d.UnlockPull(repoFullName, pullNum)
}, nil
return &DefaultWorkingDirLocker{locks: make(map[string]struct{})}
}
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, path)
for _, l := range d.locks {
if l == pullKey || l == workspaceKey {
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, path)
}
if _, exists := d.locks[workspaceKey]; exists {
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, path)
}
d.locks = append(d.locks, workspaceKey)
d.locks[workspaceKey] = struct{}{}
return func() {
d.unlock(repoFullName, pullNum, workspace, path)
}, nil
@@ -99,32 +69,9 @@ func (d *DefaultWorkingDirLocker) unlock(repoFullName string, pullNum int, works
defer d.mutex.Unlock()
workspaceKey := d.workspaceKey(repoFullName, pullNum, workspace, path)
d.removeLock(workspaceKey)
}
// Unlock unlocks all workspaces for this pull.
func (d *DefaultWorkingDirLocker) UnlockPull(repoFullName string, pullNum int) {
d.mutex.Lock()
defer d.mutex.Unlock()
pullKey := d.pullKey(repoFullName, pullNum)
d.removeLock(pullKey)
}
func (d *DefaultWorkingDirLocker) removeLock(key string) {
var newLocks []string
for _, l := range d.locks {
if l != key {
newLocks = append(newLocks, l)
}
}
d.locks = newLocks
delete(d.locks, workspaceKey)
}
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 {
return fmt.Sprintf("%s/%d", repo, pull)
return fmt.Sprintf("%s/%d/%s/%s", repo, pull, workspace, path)
}

View File

@@ -170,47 +170,3 @@ func TestUnlockDifferentPulls(t *testing.T) {
_, err = locker.TryLock(repo, newPull, workspace, path)
Ok(t, err)
}
func TestLockPull(t *testing.T) {
locker := events.NewDefaultWorkingDirLocker()
unlock, err := locker.TryLockPull("owner/repo", 1)
Ok(t, err)
// 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", path)
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", path)
Ok(t, err)
// After unlocking, should be able to get a pull lock.
unlock()
unlock, err = locker.TryLockPull("owner/repo", 1)
Ok(t, err)
// If we unlock that too, should be able to get the workspace lock.
unlock()
_, err = locker.TryLock("owner/repo", 1, "workspace", path)
Ok(t, err)
unlock()
}
// 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", path)
Ok(t, err)
_, err = locker.TryLockPull("owner/repo", 1)
Assert(t, err != nil, "exp err")
// After unlocking the workspace, should be able to get the lock.
unlock()
_, err = locker.TryLockPull("owner/repo", 1)
Ok(t, err)
}

View File

@@ -45,7 +45,7 @@ func TestClone_NoneExisting(t *testing.T) {
GpgNoSigningEnabled: true,
}
cloneDir, _, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
cloneDir, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
BaseRepo: models.Repo{},
HeadBranch: "branch",
}, "default")
@@ -97,13 +97,12 @@ func TestClone_CheckoutMergeNoneExisting(t *testing.T) {
GpgNoSigningEnabled: true,
}
cloneDir, mergedAgain, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
cloneDir, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
BaseRepo: models.Repo{},
HeadBranch: "branch",
BaseBranch: "main",
}, "default")
Ok(t, err)
Equals(t, false, mergedAgain)
// Check the commits.
actBaseCommit := runCmd(t, cloneDir, "git", "rev-parse", "HEAD~1")
@@ -148,25 +147,23 @@ func TestClone_CheckoutMergeNoReclone(t *testing.T) {
GpgNoSigningEnabled: true,
}
_, mergedAgain, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
_, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
BaseRepo: models.Repo{},
HeadBranch: "branch",
BaseBranch: "main",
}, "default")
Ok(t, err)
Equals(t, false, mergedAgain)
// Create a file that we can use to check if the repo was recloned.
runCmd(t, dataDir, "touch", "repos/0/default/proof")
// Now run the clone again.
cloneDir, mergedAgain, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
cloneDir, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
BaseRepo: models.Repo{},
HeadBranch: "branch",
BaseBranch: "main",
}, "default")
Ok(t, err)
Equals(t, false, mergedAgain)
// Check that our proof file is still there, proving that we didn't reclone.
_, err = os.Stat(filepath.Join(cloneDir, "proof"))
@@ -200,25 +197,23 @@ func TestClone_CheckoutMergeNoRecloneFastForward(t *testing.T) {
GpgNoSigningEnabled: true,
}
_, mergedAgain, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
_, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
BaseRepo: models.Repo{},
HeadBranch: "branch",
BaseBranch: "main",
}, "default")
Ok(t, err)
Equals(t, false, mergedAgain)
// Create a file that we can use to check if the repo was recloned.
runCmd(t, dataDir, "touch", "repos/0/default/proof")
// Now run the clone again.
cloneDir, mergedAgain, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
cloneDir, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
BaseRepo: models.Repo{},
HeadBranch: "branch",
BaseBranch: "main",
}, "default")
Ok(t, err)
Equals(t, false, mergedAgain)
// Check that our proof file is still there, proving that we didn't reclone.
_, err = os.Stat(filepath.Join(cloneDir, "proof"))
@@ -257,7 +252,7 @@ func TestClone_CheckoutMergeConflict(t *testing.T) {
GpgNoSigningEnabled: true,
}
_, _, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
_, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
BaseRepo: models.Repo{},
HeadBranch: "branch",
BaseBranch: "main",
@@ -316,13 +311,12 @@ func TestClone_CheckoutMergeShallow(t *testing.T) {
GpgNoSigningEnabled: true,
}
cloneDir, mergedAgain, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
cloneDir, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
BaseRepo: models.Repo{},
HeadBranch: "branch",
BaseBranch: "main",
}, "default")
Ok(t, err)
Equals(t, false, mergedAgain)
gotBaseCommitType := runCmd(t, cloneDir, "git", "cat-file", "-t", baseCommit)
Assert(t, gotBaseCommitType == "commit\n", "should have merge-base in shallow repo")
@@ -346,13 +340,12 @@ func TestClone_CheckoutMergeShallow(t *testing.T) {
GpgNoSigningEnabled: true,
}
cloneDir, mergedAgain, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
cloneDir, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
BaseRepo: models.Repo{},
HeadBranch: "branch",
BaseBranch: "main",
}, "default")
Ok(t, err)
Equals(t, false, mergedAgain)
gotBaseCommitType := runCmd(t, cloneDir, "git", "cat-file", "-t", baseCommit)
Assert(t, gotBaseCommitType == "commit\n", "should have merge-base in full repo")
@@ -381,12 +374,11 @@ func TestClone_NoReclone(t *testing.T) {
TestingOverrideHeadCloneURL: fmt.Sprintf("file://%s", repoDir),
GpgNoSigningEnabled: true,
}
cloneDir, mergedAgain, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
cloneDir, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
BaseRepo: models.Repo{},
HeadBranch: "branch",
}, "default")
Ok(t, err)
Equals(t, false, mergedAgain)
// Check that our proof file is still there.
_, err = os.Stat(filepath.Join(cloneDir, "proof"))
@@ -425,13 +417,12 @@ func TestClone_RecloneWrongCommit(t *testing.T) {
TestingOverrideHeadCloneURL: fmt.Sprintf("file://%s", repoDir),
GpgNoSigningEnabled: true,
}
cloneDir, mergedAgain, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
cloneDir, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
BaseRepo: models.Repo{},
HeadBranch: "branch",
HeadCommit: expCommit,
}, "default")
Ok(t, err)
Equals(t, false, mergedAgain)
assert.NoFileExists(t, planFile, "Plan file should have been wiped out by Clone")
// Use rev-parse to verify at correct commit.
@@ -506,23 +497,28 @@ func TestClone_MasterHasDiverged(t *testing.T) {
Assert(t, err == nil, "creating plan file: %v", err)
assert.FileExists(t, planFile)
// Run the clone without the checkout merge strategy. It should return
// Run MergeAgain without the checkout merge strategy. It should return
// false for mergedAgain
_, mergedAgain, err := wd.Clone(logger, models.Repo{}, models.PullRequest{
_, err = wd.Clone(logger, models.Repo{}, models.PullRequest{
BaseRepo: models.Repo{},
HeadBranch: "second-pr",
BaseBranch: "main",
}, "default")
Ok(t, err)
Assert(t, mergedAgain == false, "Clone with CheckoutMerge=false should not merge")
assert.FileExists(t, planFile, "Existing plan file should not be deleted by Clone with merge disabled")
mergedAgain, err := wd.MergeAgain(logger, models.Repo{CloneURL: repoDir}, models.PullRequest{
BaseRepo: models.Repo{CloneURL: repoDir},
HeadBranch: "second-pr",
BaseBranch: "main",
}, "default")
Ok(t, err)
assert.FileExists(t, planFile, "Existing plan file should not be deleted by merging again")
Assert(t, mergedAgain == false, "MergeAgain with CheckoutMerge=false should not merge")
wd.CheckoutMerge = true
wd.SetCheckForUpstreamChanges()
// Run the clone twice with the merge strategy, the first run should
// return true for mergedAgain, subsequent runs should
// return false since the first call is supposed to merge.
_, mergedAgain, err = wd.Clone(logger, models.Repo{CloneURL: repoDir}, models.PullRequest{
mergedAgain, err = wd.MergeAgain(logger, models.Repo{CloneURL: repoDir}, models.PullRequest{
BaseRepo: models.Repo{CloneURL: repoDir},
HeadBranch: "second-pr",
BaseBranch: "main",
@@ -531,8 +527,7 @@ func TestClone_MasterHasDiverged(t *testing.T) {
assert.FileExists(t, planFile, "Existing plan file should not be deleted by merging again")
Assert(t, mergedAgain == true, "First clone with CheckoutMerge=true with diverged base should have merged")
wd.SetCheckForUpstreamChanges()
_, mergedAgain, err = wd.Clone(logger, models.Repo{CloneURL: repoDir}, models.PullRequest{
mergedAgain, err = wd.MergeAgain(logger, models.Repo{CloneURL: repoDir}, models.PullRequest{
BaseRepo: models.Repo{CloneURL: repoDir},
HeadBranch: "second-pr",
BaseBranch: "main",