Skip to content

Commit d5e1a02

Browse files
finnagjamengualnitrocode
authored andcommitted
fix: Check for upstream changes to merge only when planning (runatlantis#3493)
* whitespace fixes * Only re-clone on upstream updates just before planning When using the merge checkout strategy, we would peviously re-clone on upstream updates on any call to Clone(), for example when running workflow hooks or runing import commands. If we had already ran a plan, and master was updated, this would delete the plan and apply would not have anything to apply. Modified to only re-clone on upstream updates in doPlan() * Apply suggestions from code review --------- Co-authored-by: PePe Amengual <[email protected]> Co-authored-by: nitrocode <[email protected]>
1 parent 5d2b3c2 commit d5e1a02

File tree

6 files changed

+115
-15
lines changed

6 files changed

+115
-15
lines changed

server/events/mock_workingdir_test.go

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/events/mocks/mock_comment_building.go

Lines changed: 35 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/events/mocks/mock_working_dir.go

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/events/project_command_runner.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,7 @@ func (p *DefaultProjectCommandRunner) doPlan(ctx command.ProjectContext) (*model
528528
}
529529
defer unlockFn()
530530

531+
p.WorkingDir.SetSafeToReClone()
531532
// Clone is idempotent so okay to run even if the repo was already cloned.
532533
repoDir, hasDiverged, cloneErr := p.WorkingDir.Clone(ctx.Log, ctx.HeadRepo, ctx.Pull, ctx.Workspace, []string{})
533534
if cloneErr != nil {

server/events/working_dir.go

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ type WorkingDir interface {
4949
// Delete deletes the workspace for this repo and pull.
5050
Delete(r models.Repo, p models.PullRequest) error
5151
DeleteForWorkspace(r models.Repo, p models.PullRequest, workspace string) error
52+
// Set a flag in the workingdir so Clone() can know that it is safe to re-clone the workingdir if
53+
// the upstream branch has been modified. This is only safe after grabbing the project lock
54+
// and before running any plans
55+
SetSafeToReClone()
5256
}
5357

5458
// FileWorkspace implements WorkingDir with the file system.
@@ -75,6 +79,8 @@ type FileWorkspace struct {
7579
GithubAppEnabled bool
7680
// use the global setting without overriding
7781
GpgNoSigningEnabled bool
82+
// flag indicating if a re-clone will be safe (project lock held, about to run plan)
83+
SafeToReClone bool
7884
}
7985

8086
// Clone git clones headRepo, checks out the branch and then returns the absolute
@@ -94,6 +100,7 @@ func (w *FileWorkspace) Clone(
94100
additionalBranches []string) (string, bool, error) {
95101
cloneDir := w.cloneDir(p.BaseRepo, p, workspace)
96102
hasDiverged := false
103+
defer func() { w.SafeToReClone = false }()
97104

98105
if !w.alreadyClonedHEAD(log, cloneDir, p) {
99106
if err := w.forceClone(log, cloneDir, headRepo, p); err != nil {
@@ -111,7 +118,7 @@ func (w *FileWorkspace) Clone(
111118
// We're prefix matching here because BitBucket doesn't give us the full
112119
// commit, only a 12 character prefix.
113120
if strings.HasPrefix(currCommit, p.HeadCommit) {
114-
if w.CheckoutMerge && w.recheckDiverged(log, p, headRepo, cloneDir) {
121+
if w.SafeToReClone && w.CheckoutMerge && w.recheckDiverged(log, p, headRepo, cloneDir) {
115122
log.Info("base branch has been updated, using merge strategy and will clone again")
116123
hasDiverged = true
117124
} else {
@@ -254,17 +261,17 @@ func (w *FileWorkspace) forceClone(log logging.SimpleLogging,
254261
if !w.CheckoutMerge {
255262
return runGit("clone", "--depth=1", "--branch", p.HeadBranch, "--single-branch", headCloneURL, cloneDir)
256263
}
257-
264+
258265
// if merge strategy...
259266

260267
// if no checkout depth, omit depth arg
261268
if w.CheckoutDepth == 0 {
262269
if err := runGit("clone", "--branch", p.BaseBranch, "--single-branch", baseCloneURL, cloneDir); err != nil {
263-
return err
270+
return err
264271
}
265272
} else {
266-
if err := runGit("clone", "--depth", fmt.Sprint(w.CheckoutDepth), "--branch", p.BaseBranch, "--single-branch", baseCloneURL, cloneDir); err != nil {
267-
return err
273+
if err := runGit("clone", "--depth", fmt.Sprint(w.CheckoutDepth), "--branch", p.BaseBranch, "--single-branch", baseCloneURL, cloneDir); err != nil {
274+
return err
268275
}
269276
}
270277

@@ -279,16 +286,16 @@ func (w *FileWorkspace) forceClone(log logging.SimpleLogging,
279286
fetchRemote = "origin"
280287
}
281288

282-
// if no checkout depth, omit depth arg
283-
if w.CheckoutDepth == 0 {
284-
if err := runGit("fetch", fetchRemote, fetchRef); err != nil {
285-
return err
286-
}
287-
} else {
288-
if err := runGit("fetch", "--depth", fmt.Sprint(w.CheckoutDepth), fetchRemote, fetchRef); err != nil {
289-
return err
290-
}
291-
}
289+
// if no checkout depth, omit depth arg
290+
if w.CheckoutDepth == 0 {
291+
if err := runGit("fetch", fetchRemote, fetchRef); err != nil {
292+
return err
293+
}
294+
} else {
295+
if err := runGit("fetch", "--depth", fmt.Sprint(w.CheckoutDepth), fetchRemote, fetchRef); err != nil {
296+
return err
297+
}
298+
}
292299

293300
if w.GpgNoSigningEnabled {
294301
if err := runGit("config", "--local", "commit.gpgsign", "false"); err != nil {
@@ -355,3 +362,8 @@ func (w *FileWorkspace) sanitizeGitCredentials(s string, base models.Repo, head
355362
baseReplaced := strings.Replace(s, base.CloneURL, base.SanitizedCloneURL, -1)
356363
return strings.Replace(baseReplaced, head.CloneURL, head.SanitizedCloneURL, -1)
357364
}
365+
366+
// Set the flag that indicates it is safe to re-clone if necessary
367+
func (w *FileWorkspace) SetSafeToReClone() {
368+
w.SafeToReClone = true
369+
}

server/events/working_dir_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,7 @@ func TestClone_MasterHasDiverged(t *testing.T) {
480480
Assert(t, hasDiverged == false, "Clone with CheckoutMerge=false should not merge")
481481

482482
wd.CheckoutMerge = true
483+
wd.SetSafeToReClone()
483484
// Run the clone twice with the merge strategy, the first run should
484485
// return true for hasDiverged, subsequent runs should
485486
// return false since the first call is supposed to merge.
@@ -491,6 +492,7 @@ func TestClone_MasterHasDiverged(t *testing.T) {
491492
Ok(t, err)
492493
Assert(t, hasDiverged == true, "First clone with CheckoutMerge=true with diverged base should have merged")
493494

495+
wd.SetSafeToReClone()
494496
_, hasDiverged, err = wd.Clone(logging.NewNoopLogger(t), models.Repo{CloneURL: repoDir}, models.PullRequest{
495497
BaseRepo: models.Repo{CloneURL: repoDir},
496498
HeadBranch: "second-pr",

0 commit comments

Comments
 (0)