[webkit-patch] Use commit.webkit.org instead of remote SVN to compute identifier
[WebKit-https.git] / Tools / Scripts / webkitpy / tool / commands / download_unittest.py
1 # Copyright (C) 2009, 2011 Google Inc. All rights reserved.
2 # Copyright (C) 2021 Apple Inc. All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met:
7 #
8 #    * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 #    * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following disclaimer
12 # in the documentation and/or other materials provided with the
13 # distribution.
14 #    * Neither the name of Google Inc. nor the names of its
15 # contributors may be used to endorse or promote products derived from
16 # this software without specific prior written permission.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 import unittest
31
32 from webkitpy.thirdparty.mock import Mock
33 from webkitpy.tool.commands.commandtest import CommandsTest
34 from webkitpy.tool.commands.download import *
35 from webkitpy.tool.mocktool import MockOptions, MockTool
36 from webkitpy.common.checkout.checkout_mock import MockCheckout
37
38 from webkitcorepy import OutputCapture
39 from webkitcorepy import mocks
40
41
42 class AbstractRevertPrepCommandTest(unittest.TestCase):
43     def test_commit_info(self):
44         command = AbstractRevertPrepCommand()
45         tool = MockTool()
46         command.bind_to_tool(tool)
47
48         with OutputCapture(level=logging.INFO) as captured:
49             commit_info = command._commit_info(1234)
50         self.assertEqual(captured.root.log.getvalue(), 'Preparing revert for bug 50000.\n')
51         self.assertTrue(commit_info)
52
53         mock_commit_info = Mock()
54         mock_commit_info.bug_id = lambda: None
55         tool._checkout.commit_info_for_revision = lambda revision: mock_commit_info
56         with OutputCapture(level=logging.INFO) as captured:
57             commit_info = command._commit_info(1234)
58         self.assertEqual(captured.root.log.getvalue(), 'Unable to parse bug number from diff.\n')
59         self.assertEqual(commit_info, mock_commit_info)
60
61     def test_prepare_state(self):
62         command = AbstractRevertPrepCommand()
63         mock_commit_info = MockCheckout().commit_info_for_revision(123)
64         command._commit_info = lambda revision: mock_commit_info
65
66         state = command._prepare_state(None, ["124 123 125", "Reason"], None)
67         self.assertEqual(123, state["revision"])
68         self.assertEqual([123, 124, 125], state["revision_list"])
69
70         self.assertRaises(ScriptError, command._prepare_state, options=None, args=["125 r122  123", "Reason"], tool=None)
71         self.assertRaises(ScriptError, command._prepare_state, options=None, args=["125 foo 123", "Reason"], tool=None)
72
73         command._commit_info = lambda revision: None
74         state = command._prepare_state(None, ["124 123 125", "Reason"], None)
75         self.assertEqual(123, state["revision"])
76         self.assertEqual([123, 124, 125], state["revision_list"])
77
78
79 class DownloadCommandsTest(CommandsTest):
80     def _default_options(self):
81         options = MockOptions()
82         options.build = True
83         options.build_style = "release"
84         options.check_style = True
85         options.check_style_filter = None
86         options.clean = True
87         options.close_bug = True
88         options.comment_bug = True
89         options.force_clean = False
90         options.non_interactive = False
91         options.parent_command = 'MOCK parent command'
92         options.quiet = False
93         options.test = True
94         options.update = True
95         options.architecture = 'MOCK ARCH'
96         options.iterate_on_new_tests = 0
97         options.group = None
98         options.sort_xcode_project = False
99         return options
100
101     def mock_svn_remote(self):
102         return mocks.Requests('commits.webkit.org', **{
103             'r49824/json': mocks.Response.fromJson(dict(
104                 identifier='5@main',
105                 revision=49824,
106             )),
107         })
108
109     def test_build(self):
110         expected_logs = "Updating working directory\nBuilding WebKit\n"
111         self.assert_execute_outputs(Build(), [], options=self._default_options(), expected_logs=expected_logs)
112
113     def test_apply_attachment(self):
114         options = self._default_options()
115         options.update = True
116         options.local_commit = True
117         expected_logs = "Updating working directory\nProcessing 1 patch from 1 bug.\nProcessing patch 10000 from bug 50000.\n"
118         self.assert_execute_outputs(ApplyAttachment(), [10000], options=options, expected_logs=expected_logs)
119
120     def test_apply_from_bug(self):
121         options = self._default_options()
122         options.update = True
123         options.local_commit = True
124
125         expected_logs = "Updating working directory\n0 reviewed patches found on bug 50001.\nNo reviewed patches found, looking for unreviewed patches.\n1 patch found on bug 50001.\nProcessing 1 patch from 1 bug.\nProcessing patch 10002 from bug 50001.\n"
126         self.assert_execute_outputs(ApplyFromBug(), [50001], options=options, expected_logs=expected_logs)
127
128         expected_logs = "Updating working directory\n2 reviewed patches found on bug 50000.\nProcessing 2 patches from 1 bug.\nProcessing patch 10000 from bug 50000.\nProcessing patch 10001 from bug 50000.\n"
129         self.assert_execute_outputs(ApplyFromBug(), [50000], options=options, expected_logs=expected_logs)
130
131     def test_apply_watch_list(self):
132         expected_logs = """Processing 1 patch from 1 bug.
133 Updating working directory
134 MOCK run_and_throw_if_fail: ['mock-update-webkit'], cwd=/mock-checkout
135 Processing patch 10000 from bug 50000.
136 MockWatchList: determine_cc_and_messages
137 No bug was updated because no id was given.
138 Result of watchlist: cc "abarth@webkit.org, eric@webkit.org, levin@chromium.org" messages "Message1.
139
140 Message2."
141 """
142         self.assert_execute_outputs(ApplyWatchList(), [10000], options=self._default_options(), expected_logs=expected_logs, tool=MockTool(log_executive=True))
143
144     def test_land(self):
145         expected_logs = """Building WebKit
146 Committed r49824: <https://commits.webkit.org/r49824>
147 Adding comment and closing bug 50000
148 """
149         with self.mock_svn_remote():
150             mock_tool = MockTool()
151             mock_tool.scm().create_patch = Mock(return_value="Patch1\nMockPatch\n")
152             mock_tool.checkout().modified_changelogs = Mock(return_value=[])
153             self.assert_execute_outputs(Land(), [50000], options=self._default_options(), expected_logs=expected_logs, tool=mock_tool)
154             # Make sure we're not calling expensive calls too often.
155             self.assertEqual(mock_tool.scm().create_patch.call_count, 0)
156             self.assertEqual(mock_tool.checkout().modified_changelogs.call_count, 1)
157
158     def test_land_cowhand(self):
159         expected_logs = """MOCK run_and_throw_if_fail: ['mock-prepare-ChangeLog', '--email=MOCK email', '--merge-base=None', 'MockFile1'], cwd=/mock-checkout
160 MOCK run_and_throw_if_fail: ['mock-check-webkit-style', '--git-commit', 'MOCK git commit', '--diff-files', 'MockFile1', '--filter', '-changelog'], cwd=/mock-checkout
161 MOCK run_command: ['ruby', '-I', '/mock-checkout/Websites/bugs.webkit.org/PrettyPatch', '/mock-checkout/Websites/bugs.webkit.org/PrettyPatch/prettify.rb'], cwd=None, input=Patch1
162 MOCK: user.open_url: file://...
163 Was that diff correct?
164 Building WebKit
165 MOCK run_and_throw_if_fail: ['mock-build-webkit', 'ARCHS=MOCK ARCH'], cwd=/mock-checkout, env={'MOCK_ENVIRON_COPY': '1', 'TERM': 'dumb'}
166 Committed r49824: <https://commits.webkit.org/r49824>
167 Committed r49824 (5@main): <https://commits.webkit.org/5@main>
168 No bug id provided.
169 """
170         with self.mock_svn_remote():
171             mock_tool = MockTool(log_executive=True)
172             self.assert_execute_outputs(LandCowhand(), [50000], options=self._default_options(), expected_logs=expected_logs, tool=mock_tool)
173
174             expected_logs = "land-cowboy is deprecated, use land-cowhand instead.\n" + expected_logs
175             self.assert_execute_outputs(LandCowboy(), [50000], options=self._default_options(), expected_logs=expected_logs, tool=mock_tool)
176
177     def test_land_red_builders(self):
178         expected_logs = """Building WebKit
179 Committed r49824: <https://commits.webkit.org/r49824>
180 Adding comment and closing bug 50000
181 """
182         with self.mock_svn_remote():
183             mock_tool = MockTool()
184             mock_tool.buildbot.light_tree_on_fire()
185             self.assert_execute_outputs(Land(), [50000], options=self._default_options(), expected_logs=expected_logs, tool=mock_tool)
186
187     def test_check_style(self):
188         expected_logs = """Processing 1 patch from 1 bug.
189 Updating working directory
190 MOCK run_and_throw_if_fail: ['mock-update-webkit'], cwd=/mock-checkout
191 Processing patch 10000 from bug 50000.
192 MOCK run_and_throw_if_fail: ['mock-check-webkit-style', '--git-commit', 'MOCK git commit', '--diff-files', 'MockFile1'], cwd=/mock-checkout
193 """
194         self.assert_execute_outputs(CheckStyle(), [10000], options=self._default_options(), expected_logs=expected_logs, tool=MockTool(log_executive=True))
195
196     def test_build_attachment(self):
197         expected_logs = "Processing 1 patch from 1 bug.\nUpdating working directory\nProcessing patch 10000 from bug 50000.\nBuilding WebKit\n"
198         self.assert_execute_outputs(BuildAttachment(), [10000], options=self._default_options(), expected_logs=expected_logs)
199
200     def test_land_attachment(self):
201         # FIXME: This expected result is imperfect, notice how it's seeing the same patch as still there after it thought it would have cleared the flags.
202         expected_logs = """Processing 1 patch from 1 bug.
203 Updating working directory
204 Processing patch 10000 from bug 50000.
205 Building WebKit
206 Committed r49824: <https://commits.webkit.org/r49824>
207 Not closing bug 50000 as attachment 10000 has review=+.  Assuming there are more patches to land from this bug.
208 """
209         with self.mock_svn_remote():
210             self.assert_execute_outputs(LandAttachment(), [10000], options=self._default_options(), expected_logs=expected_logs)
211
212     def test_land_from_bug(self):
213         # FIXME: This expected result is imperfect, notice how it's seeing the same patch as still there after it thought it would have cleared the flags.
214         expected_logs = """2 reviewed patches found on bug 50000.
215 Processing 2 patches from 1 bug.
216 Updating working directory
217 Processing patch 10000 from bug 50000.
218 Building WebKit
219 Committed r49824: <https://commits.webkit.org/r49824>
220 Not closing bug 50000 as attachment 10000 has review=+.  Assuming there are more patches to land from this bug.
221 Updating working directory
222 Processing patch 10001 from bug 50000.
223 Building WebKit
224 Committed r49824: <https://commits.webkit.org/r49824>
225 Not closing bug 50000 as attachment 10000 has review=+.  Assuming there are more patches to land from this bug.
226 """
227         with self.mock_svn_remote():
228             self.assert_execute_outputs(LandFromBug(), [50000], options=self._default_options(), expected_logs=expected_logs)
229
230     def test_land_from_url(self):
231         # FIXME: This expected result is imperfect, notice how it's seeing the same patch as still there after it thought it would have cleared the flags.
232         expected_logs = """2 patches found on bug 50000.
233 Processing 2 patches from 1 bug.
234 Updating working directory
235 Processing patch 10000 from bug 50000.
236 Building WebKit
237 Committed r49824: <https://commits.webkit.org/r49824>
238 Not closing bug 50000 as attachment 10000 has review=+.  Assuming there are more patches to land from this bug.
239 Updating working directory
240 Processing patch 10001 from bug 50000.
241 Building WebKit
242 Committed r49824: <https://commits.webkit.org/r49824>
243 Not closing bug 50000 as attachment 10000 has review=+.  Assuming there are more patches to land from this bug.
244 """
245         with self.mock_svn_remote():
246             self.assert_execute_outputs(LandFromURL(), ["https://bugs.webkit.org/show_bug.cgi?id=50000"], options=self._default_options(), expected_logs=expected_logs)
247
248     def test_land_no_comment(self):
249         expected_logs = """Building WebKit
250 Committed r49824: <https://commits.webkit.org/r49824>
251 Not updating bug 50000
252 """
253         with self.mock_svn_remote():
254             options = self._default_options()
255             options.comment_bug = False
256             self.assert_execute_outputs(Land(), [50000], options=options, expected_logs=expected_logs)
257
258     def test_land_no_close(self):
259         expected_logs = """Building WebKit
260 Committed r49824: <https://commits.webkit.org/r49824>
261 Commenting without closing bug 50000
262 MOCK bug comment: bug_id=50000, cc=None, see_also=None
263 --- Begin comment ---
264 Committed r49824 (5@main): <https://commits.webkit.org/5@main>
265 --- End comment ---
266
267 """
268         with self.mock_svn_remote():
269             options = self._default_options()
270             options.close_bug = False
271             self.assert_execute_outputs(Land(), [50000], options=options, expected_logs=expected_logs)
272
273     def test_land_no_comment_no_close(self):
274         expected_logs = """Building WebKit
275 Committed r49824: <https://commits.webkit.org/r49824>
276 Not updating bug 50000
277 """
278         with self.mock_svn_remote():
279             options = self._default_options()
280             options.comment_bug = False
281             options.close_bug = False
282             self.assert_execute_outputs(Land(), [50000], options=options, expected_logs=expected_logs)
283
284     def test_prepare_revert(self):
285         expected_logs = "Preparing revert for bug 50000.\nUpdating working directory\n"
286         self.assert_execute_outputs(PrepareRevert(), [852, "Reason"], options=self._default_options(), expected_logs=expected_logs)
287
288         expected_logs = "prepare-rollout is deprecated, use prepare-revert instead.\n" + expected_logs
289         self.assert_execute_outputs(PrepareRollout(), [852, "Reason"], options=self._default_options(), expected_logs=expected_logs)
290
291     def test_create_revert(self):
292         expected_logs = """Preparing revert for bug 50000.
293 Updating working directory
294 MOCK create_bug
295 bug_title: REGRESSION(r852): Reason
296 bug_description: https://commits.webkit.org/r852 introduced a regression:
297 Reason
298 component: MOCK component
299 cc: MOCK cc
300 blocked: 50000
301 MOCK add_patch_to_bug: bug_id=60001, description=REVERT of r852, mark_for_review=False, mark_for_commit_queue=True, mark_for_landing=False
302 -- Begin comment --
303 Any committer can land this patch automatically by marking it commit-queue+.  The commit-queue will build and test the patch before landing to ensure that the revert will be successful.  This process takes approximately 15 minutes.
304
305 If you would like to land the revert faster, you can use the following command:
306
307   webkit-patch land-attachment ATTACHMENT_ID
308
309 where ATTACHMENT_ID is the ID of this attachment.
310 -- End comment --
311 """
312         self.assert_execute_outputs(CreateRevert(), [852, "Reason"], options=self._default_options(), expected_logs=expected_logs)
313
314         expected_logs = "create-rollout is deprecated, use create-revert instead.\n" + expected_logs
315         self.assert_execute_outputs(CreateRollout(), [852, "Reason"], options=self._default_options(), expected_logs=expected_logs)
316
317     def test_create_revert_multiple_revision(self):
318         expected_logs = """Preparing revert for bug 50000.
319 Preparing revert for bug 50000.
320 Unable to parse bug number from diff.
321 Updating working directory
322 MOCK create_bug
323 bug_title: REGRESSION(r852): Reason
324 bug_description: https://commits.webkit.org/r852 introduced a regression:
325 Reason
326 component: MOCK component
327 cc: MOCK cc
328 blocked: 50000, 50000
329 MOCK add_patch_to_bug: bug_id=60001, description=REVERT of r852, mark_for_review=False, mark_for_commit_queue=True, mark_for_landing=False
330 -- Begin comment --
331 Any committer can land this patch automatically by marking it commit-queue+.  The commit-queue will build and test the patch before landing to ensure that the revert will be successful.  This process takes approximately 15 minutes.
332
333 If you would like to land the revert faster, you can use the following command:
334
335   webkit-patch land-attachment ATTACHMENT_ID
336
337 where ATTACHMENT_ID is the ID of this attachment.
338 -- End comment --
339 """
340         self.assert_execute_outputs(CreateRevert(), ["855 852 854", "Reason"], options=self._default_options(), expected_logs=expected_logs)
341
342     def test_create_revert_multiple_revision_with_one_resolved(self):
343         expected_logs = """Preparing revert for bug 50000.
344 Unable to parse bug number from diff.
345 Preparing revert for bug 50004.
346 Updating working directory
347 MOCK create_bug
348 bug_title: REGRESSION(r852): Reason
349 bug_description: https://commits.webkit.org/r852 introduced a regression:
350 Reason
351 component: MOCK component
352 cc: MOCK cc
353 blocked: 50000, 50004
354 MOCK reopen_bug 50004 with comment 'Re-opened since this is blocked by bug 60001'
355 MOCK add_patch_to_bug: bug_id=60001, description=REVERT of r852, mark_for_review=False, mark_for_commit_queue=True, mark_for_landing=False
356 -- Begin comment --
357 Any committer can land this patch automatically by marking it commit-queue+.  The commit-queue will build and test the patch before landing to ensure that the revert will be successful.  This process takes approximately 15 minutes.
358
359 If you would like to land the revert faster, you can use the following command:
360
361   webkit-patch land-attachment ATTACHMENT_ID
362
363 where ATTACHMENT_ID is the ID of this attachment.
364 -- End comment --
365 """
366         self.assert_execute_outputs(CreateRevert(), ["855 852 3001", "Reason"], options=self._default_options(), expected_logs=expected_logs)
367
368     def test_create_revert_resolved(self):
369         expected_logs = """Preparing revert for bug 50004.
370 Updating working directory
371 MOCK create_bug
372 bug_title: REGRESSION(r3001): Reason
373 bug_description: https://commits.webkit.org/r3001 introduced a regression:
374 Reason
375 component: MOCK component
376 cc: MOCK cc
377 blocked: 50004
378 MOCK reopen_bug 50004 with comment 'Re-opened since this is blocked by bug 60001'
379 MOCK add_patch_to_bug: bug_id=60001, description=REVERT of r3001, mark_for_review=False, mark_for_commit_queue=True, mark_for_landing=False
380 -- Begin comment --
381 Any committer can land this patch automatically by marking it commit-queue+.  The commit-queue will build and test the patch before landing to ensure that the revert will be successful.  This process takes approximately 15 minutes.
382
383 If you would like to land the revert faster, you can use the following command:
384
385   webkit-patch land-attachment ATTACHMENT_ID
386
387 where ATTACHMENT_ID is the ID of this attachment.
388 -- End comment --
389 """
390         self.assert_execute_outputs(CreateRevert(), [3001, "Reason"], options=self._default_options(), expected_logs=expected_logs)
391
392     def test_create_revert_multiple_resolved(self):
393         expected_logs = """Preparing revert for bug 50005.
394 Preparing revert for bug 50006.
395 Preparing revert for bug 50004.
396 Updating working directory
397 MOCK create_bug
398 bug_title: REGRESSION(r963): Reason
399 bug_description: https://commits.webkit.org/r963 introduced a regression:
400 Reason
401 component: MOCK component
402 cc: MOCK cc
403 blocked: 50005, 50006, 50004
404 MOCK reopen_bug 50005 with comment 'Re-opened since this is blocked by bug 60001'
405 MOCK reopen_bug 50006 with comment 'Re-opened since this is blocked by bug 60001'
406 MOCK reopen_bug 50004 with comment 'Re-opened since this is blocked by bug 60001'
407 MOCK add_patch_to_bug: bug_id=60001, description=REVERT of r963, mark_for_review=False, mark_for_commit_queue=True, mark_for_landing=False
408 -- Begin comment --
409 Any committer can land this patch automatically by marking it commit-queue+.  The commit-queue will build and test the patch before landing to ensure that the revert will be successful.  This process takes approximately 15 minutes.
410
411 If you would like to land the revert faster, you can use the following command:
412
413   webkit-patch land-attachment ATTACHMENT_ID
414
415 where ATTACHMENT_ID is the ID of this attachment.
416 -- End comment --
417 """
418         self.assert_execute_outputs(CreateRevert(), ["987 3001 963", "Reason"], options=self._default_options(), expected_logs=expected_logs)
419
420     def test_revert(self):
421         expected_logs = """Preparing revert for bug 50000.
422 Updating working directory
423 MOCK: user.open_url: file://...
424 Was that diff correct?
425 Building WebKit
426 Committed r49824: <https://commits.webkit.org/r49824>
427 MOCK reopen_bug 50000 with comment 'Reverted r852 for reason:
428
429 Reason
430
431 Committed r49824 (5@main): <https://commits.webkit.org/5@main>'
432 """
433         with self.mock_svn_remote():
434             self.assert_execute_outputs(Revert(), [852, "Reason", "Description"], options=self._default_options(), expected_logs=expected_logs)
435
436             expected_logs = "rollout is deprecated, use revert instead.\n" + expected_logs
437             self.assert_execute_outputs(Rollout(), [852, "Reason", "Description"], options=self._default_options(), expected_logs=expected_logs)
438
439     def test_revert_two_revisions(self):
440         expected_logs = """Preparing revert for bug 50000.
441 Preparing revert for bug 50005.
442 Updating working directory
443 MOCK: user.open_url: file://...
444 Was that diff correct?
445 Building WebKit
446 Committed r49824: <https://commits.webkit.org/r49824>
447 MOCK reopen_bug 50000 with comment 'Reverted r852 and r963 for reason:
448
449 Reason
450
451 Committed r49824 (5@main): <https://commits.webkit.org/5@main>'
452 MOCK reopen_bug 50005 with comment 'Reverted r852 and r963 for reason:
453
454 Reason
455
456 Committed r49824 (5@main): <https://commits.webkit.org/5@main>'
457 """
458         with self.mock_svn_remote():
459             self.assert_execute_outputs(Revert(), ["852 963", "Reason", "Description"], options=self._default_options(), expected_logs=expected_logs)
460
461     def test_revert_multiple_revisions(self):
462         expected_logs = """Preparing revert for bug 50000.
463 Preparing revert for bug 50005.
464 Preparing revert for bug 50004.
465 Updating working directory
466 MOCK: user.open_url: file://...
467 Was that diff correct?
468 Building WebKit
469 Committed r49824: <https://commits.webkit.org/r49824>
470 MOCK reopen_bug 50000 with comment 'Reverted r852, r963, and r3001 for reason:
471
472 Reason
473
474 Committed r49824 (5@main): <https://commits.webkit.org/5@main>'
475 MOCK reopen_bug 50005 with comment 'Reverted r852, r963, and r3001 for reason:
476
477 Reason
478
479 Committed r49824 (5@main): <https://commits.webkit.org/5@main>'
480 MOCK reopen_bug 50004 with comment 'Reverted r852, r963, and r3001 for reason:
481
482 Reason
483
484 Committed r49824 (5@main): <https://commits.webkit.org/5@main>'
485 """
486         with self.mock_svn_remote():
487             self.assert_execute_outputs(Revert(), ["852 3001 963", "Reason", "Description"], options=self._default_options(), expected_logs=expected_logs)
488
489     def test_revert_multiple_revisions_with_a_missing_bug_id(self):
490         expected_logs = """Preparing revert for bug 50000.
491 Preparing revert for bug 50005.
492 Unable to parse bug number from diff.
493 Updating working directory
494 MOCK: user.open_url: file://...
495 Was that diff correct?
496 Building WebKit
497 Committed r49824: <https://commits.webkit.org/r49824>
498 MOCK reopen_bug 50000 with comment 'Reverted r852, r963, and r999 for reason:
499
500 Reason
501
502 Committed r49824 (5@main): <https://commits.webkit.org/5@main>'
503 MOCK reopen_bug 50005 with comment 'Reverted r852, r963, and r999 for reason:
504
505 Reason
506
507 Committed r49824 (5@main): <https://commits.webkit.org/5@main>'
508 """
509         with self.mock_svn_remote():
510             self.assert_execute_outputs(Revert(), ["852 999 963", "Reason", "Description"], options=self._default_options(), expected_logs=expected_logs)