Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: safer re-merging with updated upstream #3499

Merged
merged 15 commits into from
Sep 25, 2023

Conversation

finnag
Copy link
Contributor

@finnag finnag commented Jun 8, 2023

what

After the initial clone, if we need to merge with an updated master, we now fetch and merge
instead of deleting the directory and cloning again.

why

We used to call forceClone() to update with upstream, but this deletes the
checked out directory. This is inefficient, can delete existing plan files,
and is very surprising if you are working manually in the working directory.

We now fetch an updated upstream, and re-do the merge operation. This
leaves any working files intact.

The previous attempted fix in #3493 reduced the issue a bit by only calling forceClone() when starting a plan, but this still causes problems for previous plans that have been created.

tests

I have tested my changes by:

  • make test-all
  • running atlantis against a test repository with many long running plans and merging in the middle of a plan run. All plans applied successfully after.

references

We used to call forceClone() to update with upstream, but this deletes the
checked out directory. This is inefficient, can delete existing plan files,
and is very surprising if you are working manually in the working directory.

We now fetch an updated upstream, and re-do the merge operation. This
leaves any working files intact.
It's never safe to clone again. But sometimes we need to check
for upstream changes to avoid reverting changes.

The flag is now used to know when we need to merge
again non-destructively with new changes.
@finnag finnag requested a review from a team as a code owner June 8, 2023 09:32
@github-actions github-actions bot added the go Pull requests that update Go code label Jun 8, 2023
@finnag
Copy link
Contributor Author

finnag commented Jun 8, 2023

The failing test is due to this renovate commit in main: 1d91dfb

return w.mergeToBaseBranch(p, runGit)
}

func (w *FileWorkspace) makeGitRunner(log logging.SimpleLogging, cloneDir string, headRepo models.Repo, p models.PullRequest) func(args ...string) error {
Copy link
Member

@nitrocode nitrocode Jun 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why return a function? It's already a function.

Previously it was returning a function because it was onlyb used within one scope. Now that's it's broken out, you might as well use it as a function instead of a function of a function

Suggested change
func (w *FileWorkspace) makeGitRunner(log logging.SimpleLogging, cloneDir string, headRepo models.Repo, p models.PullRequest) func(args ...string) error {
func (w *FileWorkspace) runGit(log logging.SimpleLogging, cloneDir string, headRepo models.Repo, p models.PullRequest) error {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @nitrocode here. This is needlessly complicating the call stack. See my comments on how to properly refactor this.

@nitrocode nitrocode added the needs tests Change requires tests label Jun 8, 2023
@nitrocode nitrocode mentioned this pull request Jun 8, 2023
1 task
finnag and others added 5 commits June 8, 2023 16:01
As long as the branch itself has not been updated, plans
should be kept. Even if upstream has changed.
This flag was only set to true in case a call to Clone()
ended up merging with an updated upstream, so the
new name better represents what it means.
This complements the test that Clone with unmodified
branch but modified upstream does _not_ wipe plans.
@finnag
Copy link
Contributor Author

finnag commented Jun 14, 2023

@nitrocode added some tests and tried to clean up the comments here, does it look resaonable now?

@edbighead
Copy link
Contributor

hopefully this gets merged, it's the only thing that holds us from updating atlantis

@GenPage
Copy link
Member

GenPage commented Jul 28, 2023

I'm reviewing today

Copy link
Member

@GenPage GenPage left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this might bloat the PR a bit. But I think this is an excellent opportunity to refactor the git code a bit better.

I draw the line at trying to create a puesdo git client with a recursive function "runner" creating functions. The proper to do this would be to refactor all the Git code into a util package that initializes a client.

Let's create a proper Git interface that moves the git related functions like Clone() out of the WorkingDir interface. Can you do that?

return w.mergeToBaseBranch(p, runGit)
}

func (w *FileWorkspace) makeGitRunner(log logging.SimpleLogging, cloneDir string, headRepo models.Repo, p models.PullRequest) func(args ...string) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @nitrocode here. This is needlessly complicating the call stack. See my comments on how to properly refactor this.

server/events/templates/diverged.tmpl Outdated Show resolved Hide resolved
server/events/working_dir.go Fixed Show fixed Hide fixed
server/events/working_dir.go Fixed Show fixed Hide fixed
server/events/working_dir.go Fixed Show fixed Hide fixed
@finnag finnag requested a review from GenPage August 11, 2023 18:39
Every call to wrappedGit for the same PR uses identical setup
for directory, head repo and PR, so passing the
server/events/working_dir.go Dismissed Show dismissed Hide dismissed
server/events/working_dir.go Dismissed Show dismissed Hide dismissed
server/events/working_dir.go Dismissed Show dismissed Hide dismissed
@grimm26
Copy link
Contributor

grimm26 commented Sep 11, 2023

I know this might bloat the PR a bit. But I think this is an excellent opportunity to refactor the git code a bit better.

I draw the line at trying to create a puesdo git client with a recursive function "runner" creating functions. The proper to do this would be to refactor all the Git code into a util package that initializes a client.

Let's create a proper Git interface that moves the git related functions like Clone() out of the WorkingDir interface. Can you do that?

It seems like this scope creep has stalled this PR. Can we push the git refactor to another effort so we can get this bugfix in?

@GenPage
Copy link
Member

GenPage commented Sep 11, 2023

I know this might bloat the PR a bit. But I think this is an excellent opportunity to refactor the git code a bit better.
I draw the line at trying to create a puesdo git client with a recursive function "runner" creating functions. The proper to do this would be to refactor all the Git code into a util package that initializes a client.
Let's create a proper Git interface that moves the git related functions like Clone() out of the WorkingDir interface. Can you do that?

It seems like this scope creep has stalled this PR. Can we push the git refactor to another effort so we can get this bugfix in?

The PR isn't stalled, I just haven't been able to review @finnag changes. My main concern was the recursive function calls which they seemed to have addressed. I will be re-reviewing here shortly.

@grimm26
Copy link
Contributor

grimm26 commented Sep 11, 2023

@GenPage ok, thanks for your time!

@GenPage GenPage merged commit 078af70 into runatlantis:main Sep 25, 2023
15 checks passed
@finnag finnag deleted the safer-re-merge branch September 27, 2023 10:07
ijames-gc pushed a commit to gocardless/atlantis that referenced this pull request Feb 13, 2024
* Safer handling of merging with an updated upstream.

We used to call forceClone() to update with upstream, but this deletes the
checked out directory. This is inefficient, can delete existing plan files,
and is very surprising if you are working manually in the working directory.

We now fetch an updated upstream, and re-do the merge operation. This
leaves any working files intact.

* Rename SafeToReClone -> CheckForUpstreamChanges

It's never safe to clone again. But sometimes we need to check
for upstream changes to avoid reverting changes.

The flag is now used to know when we need to merge
again non-destructively with new changes.

* Update fixtures.go

* Add test to make sure plans are not wiped out

As long as the branch itself has not been updated, plans
should be kept. Even if upstream has changed.

* renamed HasDiverged to MergedAgain in PlanResult and from Clone()

This flag was only set to true in case a call to Clone()
ended up merging with an updated upstream, so the
new name better represents what it means.

* Test that Clone on branch update wipes old plans

This complements the test that Clone with unmodified
branch but modified upstream does _not_ wipe plans.

* runGit now runs git instead of returning a function that runs git

* Updated template to merged again instead of diverged

This is no longer a warning, but expected behavior in merge chekout mode

* Rename git wrapper to wrappedGit, add a type for static config

Every call to wrappedGit for the same PR uses identical setup
for directory, head repo and PR, so passing the

---------

Co-authored-by: nitrocode <[email protected]>
Co-authored-by: PePe Amengual <[email protected]>
ijames-gc pushed a commit to gocardless/atlantis that referenced this pull request Feb 13, 2024
* Safer handling of merging with an updated upstream.

We used to call forceClone() to update with upstream, but this deletes the
checked out directory. This is inefficient, can delete existing plan files,
and is very surprising if you are working manually in the working directory.

We now fetch an updated upstream, and re-do the merge operation. This
leaves any working files intact.

* Rename SafeToReClone -> CheckForUpstreamChanges

It's never safe to clone again. But sometimes we need to check
for upstream changes to avoid reverting changes.

The flag is now used to know when we need to merge
again non-destructively with new changes.

* Update fixtures.go

* Add test to make sure plans are not wiped out

As long as the branch itself has not been updated, plans
should be kept. Even if upstream has changed.

* renamed HasDiverged to MergedAgain in PlanResult and from Clone()

This flag was only set to true in case a call to Clone()
ended up merging with an updated upstream, so the
new name better represents what it means.

* Test that Clone on branch update wipes old plans

This complements the test that Clone with unmodified
branch but modified upstream does _not_ wipe plans.

* runGit now runs git instead of returning a function that runs git

* Updated template to merged again instead of diverged

This is no longer a warning, but expected behavior in merge chekout mode

* Rename git wrapper to wrappedGit, add a type for static config

Every call to wrappedGit for the same PR uses identical setup
for directory, head repo and PR, so passing the

---------

Co-authored-by: nitrocode <[email protected]>
Co-authored-by: PePe Amengual <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
go Pull requests that update Go code needs tests Change requires tests
Projects
None yet
6 participants