Skip to content

Commit 241409d

Browse files
committed
fix: resolve issue with batching MRs and forked MRs (#302)
Since all forked MRs are prepared to local branches, the MR acceptance procedure needs to be also local. * fix batching MRs when source branch has different repo url * fix unit tests * add unit test for use case forked MRs * remove credentials from debug log Changes: /tmpiq7raaob/tmpb84bjxf0 # git merge origin/dummy21 --ff --ff-only merge: origin/dummy21 - not something we can merge Into: /tmpiq7raaob/tmpb84bjxf0 # git merge dummy21 --ff --ff-only Updating b51f541..9525b89 Fast-forward 21 | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 21 Signed-off-by: Sascha Binckly <[email protected]>
1 parent 70ab3c8 commit 241409d

File tree

4 files changed

+45
-7
lines changed

4 files changed

+45
-7
lines changed

marge/batch_job.py

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# pylint: disable=too-many-branches,too-many-statements,arguments-differ
22
import logging as log
3-
from time import sleep
3+
import time
44

55
from . import git
66
from . import gitlab
@@ -110,17 +110,19 @@ def ensure_mr_not_changed(self, merge_request):
110110
if getattr(changed_mr, attr) != getattr(merge_request, attr):
111111
raise CannotMerge(error_message.format(attr.replace('_', ' ')))
112112

113-
def merge_batch(self, target_branch, source_branch, no_ff=False):
113+
def merge_batch(self, target_branch, source_branch, no_ff=False, source_repo_url=None, local=False):
114114
if no_ff:
115115
return self._repo.merge(
116116
target_branch,
117117
source_branch,
118118
'--no-ff',
119+
source_repo_url,
119120
)
120121

121122
return self._repo.fast_forward(
122123
target_branch,
123124
source_branch,
125+
local=local
124126
)
125127

126128
def update_merge_request(
@@ -166,22 +168,29 @@ def accept_mr(
166168
if new_target_sha != expected_remote_target_branch_sha:
167169
raise CannotBatch('Someone was naughty and by-passed marge')
168170

171+
log.debug("batch: accept_mr: self.update_merge_request")
169172
# Rebase and apply the trailers
170173
self.update_merge_request(
171174
merge_request,
172175
source_repo_url=source_repo_url,
173176
)
174177

175-
# This switches git to <target_branch>
178+
log.debug("batch: accept_mr: self.merge_batch")
176179
final_sha = self.merge_batch(
177180
merge_request.target_branch,
178181
merge_request.source_branch,
179182
self._options.use_no_ff_batches,
183+
source_repo_url,
184+
local=True # since we're merging multiple MRs from forks, local needs to be used
180185
)
186+
log.debug("batch: accept_mr: self._repo.push")
181187
# Don't force push in case the remote has changed.
182188
self._repo.push(merge_request.target_branch, force=False)
183189

184-
sleep(2)
190+
# delay in case Gitlab is slow to respond
191+
waiting_time_in_secs = 10
192+
log.debug('Waiting for %s secs for Gitlab to start CI after push', waiting_time_in_secs)
193+
time.sleep(waiting_time_in_secs)
185194

186195
# At this point Gitlab should have recognised the MR as being accepted.
187196
log.info('Successfully merged MR !%s', merge_request.iid)
@@ -192,6 +201,9 @@ def accept_mr(
192201
branch=merge_request.source_branch,
193202
status='running',
194203
)
204+
205+
log.debug("batch: accept_mr: canceling pipelines in Gitlab")
206+
# NOTE: this might not abort the pipeline running in external CI, it merely disconnects the pipeline
195207
for pipeline in pipelines:
196208
pipeline.cancel()
197209

@@ -225,6 +237,11 @@ def execute(self):
225237
)
226238
batch_mr_sha = batch_mr.sha
227239

240+
# delay in case Gitlab is slow to respond
241+
waiting_time_in_secs = 20
242+
log.debug('Waiting for %s secs for MR !%s to get status update', waiting_time_in_secs, batch_mr.iid)
243+
time.sleep(waiting_time_in_secs)
244+
228245
working_merge_requests = []
229246

230247
for merge_request in merge_requests:
@@ -290,6 +307,11 @@ def execute(self):
290307
for merge_request in working_merge_requests:
291308
merge_request.comment('I will attempt to batch this MR (!{})...'.format(batch_mr.iid))
292309

310+
# delay in case Gitlab is slow to respond
311+
waiting_time_in_secs = 10
312+
log.debug('Waiting for %s secs for Gitlab to start CI after push', waiting_time_in_secs)
313+
time.sleep(waiting_time_in_secs)
314+
293315
# wait for the CI of the batch MR
294316
if self._project.only_allow_merge_if_pipeline_succeeds:
295317
try:

marge/git.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ def rebase(self, branch, new_base, source_repo_url=None, local=False):
104104
def _fuse_branch(self, strategy, branch, target_branch, *fuse_args, source_repo_url=None, local=False):
105105
assert source_repo_url or branch != target_branch, branch
106106

107+
log.debug("git: _fuse_branch: %s %s %s %s", branch, target_branch, source_repo_url, local)
108+
109+
log.warning("git: _fuse_branch: local: %s", local)
107110
if not local:
108111
self.fetch('origin')
109112
target = 'origin/' + target_branch

marge/gitlab.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def call(self, command, sudo=None):
1616
headers = {'PRIVATE-TOKEN': self._auth_token}
1717
if sudo:
1818
headers['SUDO'] = '%d' % sudo
19-
log.debug('REQUEST: %s %s %r %r', method.__name__.upper(), url, headers, command.call_args)
19+
log.debug('REQUEST: %s %s %r', method.__name__.upper(), url, command.call_args)
2020
# Timeout to prevent indefinitely hanging requests. 60s is very conservative,
2121
# but should be short enough to not cause any practical annoyances. We just
2222
# crash rather than retry since marge-bot should be run in a restart loop anyway.

tests/test_batch_job.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,22 @@ def test_merge_batch(self, api, mocklab):
142142
batch_merge_job = self.get_batch_merge_job(api, mocklab)
143143
target_branch = 'master'
144144
source_branch = mocklab.merge_request_info['source_branch']
145-
batch_merge_job.merge_batch(target_branch, source_branch, no_ff=False)
145+
batch_merge_job.merge_batch(target_branch, source_branch, no_ff=False, local=False)
146146
batch_merge_job._repo.fast_forward.assert_called_once_with(
147147
target_branch,
148148
source_branch,
149+
local=False
150+
)
151+
152+
def test_merge_batch_forks(self, api, mocklab):
153+
batch_merge_job = self.get_batch_merge_job(api, mocklab)
154+
target_branch = 'master'
155+
source_branch = mocklab.merge_request_info['source_branch']
156+
batch_merge_job.merge_batch(target_branch, source_branch, no_ff=False, local=True)
157+
batch_merge_job._repo.fast_forward.assert_called_once_with(
158+
target_branch,
159+
source_branch,
160+
local=True
149161
)
150162

151163
def test_merge_batch_with_no_ff_enabled(self, api, mocklab):
@@ -156,7 +168,8 @@ def test_merge_batch_with_no_ff_enabled(self, api, mocklab):
156168
batch_merge_job._repo.merge.assert_called_once_with(
157169
target_branch,
158170
source_branch,
159-
'--no-ff'
171+
'--no-ff',
172+
None,
160173
)
161174
batch_merge_job._repo.fast_forward.assert_not_called()
162175

0 commit comments

Comments
 (0)