blob: 4a3cb5b24a1f049772a85be0d29cee3fadc26722 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001#!/usr/bin/env python
2# Copyright 2013 the V8 project authors. All rights reserved.
3# Redistribution and use in source and binary forms, with or without
4# modification, are permitted provided that the following conditions are
5# met:
6#
7# * Redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer.
9# * Redistributions in binary form must reproduce the above
10# copyright notice, this list of conditions and the following
11# disclaimer in the documentation and/or other materials provided
12# with the distribution.
13# * Neither the name of Google Inc. nor the names of its
14# contributors may be used to endorse or promote products derived
15# from this software without specific prior written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29import os
30import shutil
31import tempfile
32import traceback
33import unittest
34
35import auto_push
36from auto_push import LastReleaseBailout
37import auto_roll
38import common_includes
39from common_includes import *
40import create_release
41from create_release import CreateRelease
42import merge_to_branch
43from merge_to_branch import *
44import push_to_candidates
45from push_to_candidates import *
46import chromium_roll
47from chromium_roll import ChromiumRoll
48import releases
49from releases import Releases
50from auto_tag import AutoTag
51
52
53TEST_CONFIG = {
54 "DEFAULT_CWD": None,
55 "BRANCHNAME": "test-prepare-push",
56 "CANDIDATESBRANCH": "test-candidates-push",
57 "PERSISTFILE_BASENAME": "/tmp/test-v8-push-to-candidates-tempfile",
58 "CHANGELOG_ENTRY_FILE":
59 "/tmp/test-v8-push-to-candidates-tempfile-changelog-entry",
60 "PATCH_FILE": "/tmp/test-v8-push-to-candidates-tempfile-patch",
61 "COMMITMSG_FILE": "/tmp/test-v8-push-to-candidates-tempfile-commitmsg",
62 "CHROMIUM": "/tmp/test-v8-push-to-candidates-tempfile-chromium",
63 "SETTINGS_LOCATION": None,
64 "ALREADY_MERGING_SENTINEL_FILE":
65 "/tmp/test-merge-to-branch-tempfile-already-merging",
66 "TEMPORARY_PATCH_FILE": "/tmp/test-merge-to-branch-tempfile-temporary-patch",
67}
68
69
70AUTO_PUSH_ARGS = [
71 "-a", "author@chromium.org",
72 "-r", "reviewer@chromium.org",
73]
74
75
76class ToplevelTest(unittest.TestCase):
77 def testSaniniziteVersionTags(self):
78 self.assertEquals("4.8.230", SanitizeVersionTag("4.8.230"))
79 self.assertEquals("4.8.230", SanitizeVersionTag("tags/4.8.230"))
80 self.assertEquals(None, SanitizeVersionTag("candidate"))
81
82 def testNormalizeVersionTags(self):
83 input = ["4.8.230",
84 "tags/4.8.230",
85 "tags/4.8.224.1",
86 "4.8.224.1",
87 "4.8.223.1",
88 "tags/4.8.223",
89 "tags/4.8.231",
90 "candidates"]
91 expected = ["4.8.230",
92 "4.8.230",
93 "4.8.224.1",
94 "4.8.224.1",
95 "4.8.223.1",
96 "4.8.223",
97 "4.8.231",
98 ]
99 self.assertEquals(expected, NormalizeVersionTags(input))
100
101 def testSortBranches(self):
102 S = releases.SortBranches
103 self.assertEquals(["3.1", "2.25"], S(["2.25", "3.1"])[0:2])
104 self.assertEquals(["3.0", "2.25"], S(["2.25", "3.0", "2.24"])[0:2])
105 self.assertEquals(["3.11", "3.2"], S(["3.11", "3.2", "2.24"])[0:2])
106
107 def testFilterDuplicatesAndReverse(self):
108 F = releases.FilterDuplicatesAndReverse
109 self.assertEquals([], F([]))
110 self.assertEquals([["100", "10"]], F([["100", "10"]]))
111 self.assertEquals([["99", "9"], ["100", "10"]],
112 F([["100", "10"], ["99", "9"]]))
113 self.assertEquals([["98", "9"], ["100", "10"]],
114 F([["100", "10"], ["99", "9"], ["98", "9"]]))
115 self.assertEquals([["98", "9"], ["99", "10"]],
116 F([["100", "10"], ["99", "10"], ["98", "9"]]))
117
118 def testBuildRevisionRanges(self):
119 B = releases.BuildRevisionRanges
120 self.assertEquals({}, B([]))
121 self.assertEquals({"10": "100"}, B([["100", "10"]]))
122 self.assertEquals({"10": "100", "9": "99:99"},
123 B([["100", "10"], ["99", "9"]]))
124 self.assertEquals({"10": "100", "9": "97:99"},
125 B([["100", "10"], ["98", "9"], ["97", "9"]]))
126 self.assertEquals({"10": "100", "9": "99:99", "3": "91:98"},
127 B([["100", "10"], ["99", "9"], ["91", "3"]]))
128 self.assertEquals({"13": "101", "12": "100:100", "9": "94:97",
129 "3": "91:93, 98:99"},
130 B([["101", "13"], ["100", "12"], ["98", "3"],
131 ["94", "9"], ["91", "3"]]))
132
133 def testMakeComment(self):
134 self.assertEquals("# Line 1\n# Line 2\n#",
135 MakeComment(" Line 1\n Line 2\n"))
136 self.assertEquals("#Line 1\n#Line 2",
137 MakeComment("Line 1\n Line 2"))
138
139 def testStripComments(self):
140 self.assertEquals(" Line 1\n Line 3\n",
141 StripComments(" Line 1\n# Line 2\n Line 3\n#\n"))
142 self.assertEquals("\nLine 2 ### Test\n #",
143 StripComments("###\n# \n\n# Line 1\nLine 2 ### Test\n #"))
144
145 def testMakeChangeLogBodySimple(self):
146 commits = [
147 ["Title text 1",
148 "Title text 1\n\nBUG=\n",
149 "author1@chromium.org"],
150 ["Title text 2.",
151 "Title text 2\n\nBUG=1234\n",
152 "author2@chromium.org"],
153 ]
154 self.assertEquals(" Title text 1.\n"
155 " (author1@chromium.org)\n\n"
156 " Title text 2 (Chromium issue 1234).\n"
157 " (author2@chromium.org)\n\n",
158 MakeChangeLogBody(commits))
159
160 def testMakeChangeLogBodyEmpty(self):
161 self.assertEquals("", MakeChangeLogBody([]))
162
163 def testMakeChangeLogBodyAutoFormat(self):
164 commits = [
165 ["Title text 1!",
166 "Title text 1\nLOG=y\nBUG=\n",
167 "author1@chromium.org"],
168 ["Title text 2",
169 "Title text 2\n\nBUG=1234\n",
170 "author2@chromium.org"],
171 ["Title text 3",
172 "Title text 3\n\nBUG=1234\nLOG = Yes\n",
173 "author3@chromium.org"],
174 ["Title text 3",
175 "Title text 4\n\nBUG=1234\nLOG=\n",
176 "author4@chromium.org"],
177 ]
178 self.assertEquals(" Title text 1.\n\n"
179 " Title text 3 (Chromium issue 1234).\n\n",
180 MakeChangeLogBody(commits, True))
181
182 def testRegressWrongLogEntryOnTrue(self):
183 body = """
184Check elimination: Learn from if(CompareMap(x)) on true branch.
185
186BUG=
187R=verwaest@chromium.org
188
189Committed: https://code.google.com/p/v8/source/detail?r=18210
190"""
191 self.assertEquals("", MakeChangeLogBody([["title", body, "author"]], True))
192
193 def testMakeChangeLogBugReferenceEmpty(self):
194 self.assertEquals("", MakeChangeLogBugReference(""))
195 self.assertEquals("", MakeChangeLogBugReference("LOG="))
196 self.assertEquals("", MakeChangeLogBugReference(" BUG ="))
197 self.assertEquals("", MakeChangeLogBugReference("BUG=none\t"))
198
199 def testMakeChangeLogBugReferenceSimple(self):
200 self.assertEquals("(issue 987654)",
201 MakeChangeLogBugReference("BUG = v8:987654"))
202 self.assertEquals("(Chromium issue 987654)",
203 MakeChangeLogBugReference("BUG=987654 "))
204
205 def testMakeChangeLogBugReferenceFromBody(self):
206 self.assertEquals("(Chromium issue 1234567)",
207 MakeChangeLogBugReference("Title\n\nTBR=\nBUG=\n"
208 " BUG=\tchromium:1234567\t\n"
209 "R=somebody\n"))
210
211 def testMakeChangeLogBugReferenceMultiple(self):
212 # All issues should be sorted and grouped. Multiple references to the same
213 # issue should be filtered.
214 self.assertEquals("(issues 123, 234, Chromium issue 345)",
215 MakeChangeLogBugReference("Title\n\n"
216 "BUG=v8:234\n"
217 " BUG\t= 345, \tv8:234,\n"
218 "BUG=v8:123\n"
219 "R=somebody\n"))
220 self.assertEquals("(Chromium issues 123, 234)",
221 MakeChangeLogBugReference("Title\n\n"
222 "BUG=234,,chromium:123 \n"
223 "R=somebody\n"))
224 self.assertEquals("(Chromium issues 123, 234)",
225 MakeChangeLogBugReference("Title\n\n"
226 "BUG=chromium:234, , 123\n"
227 "R=somebody\n"))
228 self.assertEquals("(issues 345, 456)",
229 MakeChangeLogBugReference("Title\n\n"
230 "\t\tBUG=v8:345,v8:456\n"
231 "R=somebody\n"))
232 self.assertEquals("(issue 123, Chromium issues 345, 456)",
233 MakeChangeLogBugReference("Title\n\n"
234 "BUG=chromium:456\n"
235 "BUG = none\n"
236 "R=somebody\n"
237 "BUG=456,v8:123, 345"))
238
239 # TODO(machenbach): These test don't make much sense when the formatting is
240 # done later.
241 def testMakeChangeLogBugReferenceLong(self):
242 # -----------------00--------10--------20--------30--------
243 self.assertEquals("(issues 234, 1234567890, 1234567"
244 "8901234567890, Chromium issues 12345678,"
245 " 123456789)",
246 MakeChangeLogBugReference("BUG=v8:234\n"
247 "BUG=v8:1234567890\n"
248 "BUG=v8:12345678901234567890\n"
249 "BUG=123456789\n"
250 "BUG=12345678\n"))
251 # -----------------00--------10--------20--------30--------
252 self.assertEquals("(issues 234, 1234567890, 1234567"
253 "8901234567890, Chromium issues"
254 " 123456789, 1234567890)",
255 MakeChangeLogBugReference("BUG=v8:234\n"
256 "BUG=v8:12345678901234567890\n"
257 "BUG=v8:1234567890\n"
258 "BUG=123456789\n"
259 "BUG=1234567890\n"))
260 # -----------------00--------10--------20--------30--------
261 self.assertEquals("(Chromium issues 234, 1234567890"
262 ", 12345678901234567, "
263 "1234567890123456789)",
264 MakeChangeLogBugReference("BUG=234\n"
265 "BUG=12345678901234567\n"
266 "BUG=1234567890123456789\n"
267 "BUG=1234567890\n"))
268
269
270def Cmd(*args, **kwargs):
271 """Convenience function returning a shell command test expectation."""
272 return {
273 "name": "command",
274 "args": args,
275 "ret": args[-1],
276 "cb": kwargs.get("cb"),
277 "cwd": kwargs.get("cwd", TEST_CONFIG["DEFAULT_CWD"]),
278 }
279
280
281def RL(text, cb=None):
282 """Convenience function returning a readline test expectation."""
283 return {
284 "name": "readline",
285 "args": [],
286 "ret": text,
287 "cb": cb,
288 "cwd": None,
289 }
290
291
292def URL(*args, **kwargs):
293 """Convenience function returning a readurl test expectation."""
294 return {
295 "name": "readurl",
296 "args": args[:-1],
297 "ret": args[-1],
298 "cb": kwargs.get("cb"),
299 "cwd": None,
300 }
301
302
303class SimpleMock(object):
304 def __init__(self):
305 self._recipe = []
306 self._index = -1
307
308 def Expect(self, recipe):
309 self._recipe = recipe
310
311 def Call(self, name, *args, **kwargs): # pragma: no cover
312 self._index += 1
313 try:
314 expected_call = self._recipe[self._index]
315 except IndexError:
316 raise NoRetryException("Calling %s %s" % (name, " ".join(args)))
317
318 if not isinstance(expected_call, dict):
319 raise NoRetryException("Found wrong expectation type for %s %s" %
320 (name, " ".join(args)))
321
322 if expected_call["name"] != name:
323 raise NoRetryException("Expected action: %s %s - Actual: %s" %
324 (expected_call["name"], expected_call["args"], name))
325
326 # Check if the given working directory matches the expected one.
327 if expected_call["cwd"] != kwargs.get("cwd"):
328 raise NoRetryException("Expected cwd: %s in %s %s - Actual: %s" %
329 (expected_call["cwd"],
330 expected_call["name"],
331 expected_call["args"],
332 kwargs.get("cwd")))
333
334 # The number of arguments in the expectation must match the actual
335 # arguments.
336 if len(args) > len(expected_call['args']):
337 raise NoRetryException("When calling %s with arguments, the "
338 "expectations must consist of at least as many arguments." %
339 name)
340
341 # Compare expected and actual arguments.
342 for (expected_arg, actual_arg) in zip(expected_call['args'], args):
343 if expected_arg != actual_arg:
344 raise NoRetryException("Expected: %s - Actual: %s" %
345 (expected_arg, actual_arg))
346
347 # The expected call contains an optional callback for checking the context
348 # at the time of the call.
349 if expected_call['cb']:
350 try:
351 expected_call['cb']()
352 except:
353 tb = traceback.format_exc()
354 raise NoRetryException("Caught exception from callback: %s" % tb)
355
356 # If the return value is an exception, raise it instead of returning.
357 if isinstance(expected_call['ret'], Exception):
358 raise expected_call['ret']
359 return expected_call['ret']
360
361 def AssertFinished(self): # pragma: no cover
362 if self._index < len(self._recipe) -1:
363 raise NoRetryException("Called mock too seldom: %d vs. %d" %
364 (self._index, len(self._recipe)))
365
366
367class ScriptTest(unittest.TestCase):
368 def MakeEmptyTempFile(self):
369 handle, name = tempfile.mkstemp()
370 os.close(handle)
371 self._tmp_files.append(name)
372 return name
373
374 def MakeEmptyTempDirectory(self):
375 name = tempfile.mkdtemp()
376 self._tmp_files.append(name)
377 return name
378
379
380 def WriteFakeVersionFile(self, major=3, minor=22, build=4, patch=0):
381 version_file = os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE)
382 if not os.path.exists(os.path.dirname(version_file)):
383 os.makedirs(os.path.dirname(version_file))
384 with open(version_file, "w") as f:
385 f.write(" // Some line...\n")
386 f.write("\n")
387 f.write("#define V8_MAJOR_VERSION %s\n" % major)
388 f.write("#define V8_MINOR_VERSION %s\n" % minor)
389 f.write("#define V8_BUILD_NUMBER %s\n" % build)
390 f.write("#define V8_PATCH_LEVEL %s\n" % patch)
391 f.write(" // Some line...\n")
392 f.write("#define V8_IS_CANDIDATE_VERSION 0\n")
393
394 def MakeStep(self):
395 """Convenience wrapper."""
396 options = ScriptsBase(TEST_CONFIG, self, self._state).MakeOptions([])
397 return MakeStep(step_class=Step, state=self._state,
398 config=TEST_CONFIG, side_effect_handler=self,
399 options=options)
400
401 def RunStep(self, script=PushToCandidates, step_class=Step, args=None):
402 """Convenience wrapper."""
403 args = args if args is not None else ["-m"]
404 return script(TEST_CONFIG, self, self._state).RunSteps([step_class], args)
405
406 def Call(self, fun, *args, **kwargs):
407 print "Calling %s with %s and %s" % (str(fun), str(args), str(kwargs))
408
409 def Command(self, cmd, args="", prefix="", pipe=True, cwd=None):
410 print "%s %s" % (cmd, args)
411 print "in %s" % cwd
412 return self._mock.Call("command", cmd + " " + args, cwd=cwd)
413
414 def ReadLine(self):
415 return self._mock.Call("readline")
416
417 def ReadURL(self, url, params):
418 if params is not None:
419 return self._mock.Call("readurl", url, params)
420 else:
421 return self._mock.Call("readurl", url)
422
423 def Sleep(self, seconds):
424 pass
425
426 def GetDate(self):
427 return "1999-07-31"
428
429 def GetUTCStamp(self):
430 return "1000000"
431
432 def Expect(self, *args):
433 """Convenience wrapper."""
434 self._mock.Expect(*args)
435
436 def setUp(self):
437 self._mock = SimpleMock()
438 self._tmp_files = []
439 self._state = {}
440 TEST_CONFIG["DEFAULT_CWD"] = self.MakeEmptyTempDirectory()
441
442 def tearDown(self):
443 if os.path.exists(TEST_CONFIG["PERSISTFILE_BASENAME"]):
444 shutil.rmtree(TEST_CONFIG["PERSISTFILE_BASENAME"])
445
446 # Clean up temps. Doesn't work automatically.
447 for name in self._tmp_files:
448 if os.path.isfile(name):
449 os.remove(name)
450 if os.path.isdir(name):
451 shutil.rmtree(name)
452
453 self._mock.AssertFinished()
454
455 def testGitMock(self):
456 self.Expect([Cmd("git --version", "git version 1.2.3"),
457 Cmd("git dummy", "")])
458 self.assertEquals("git version 1.2.3", self.MakeStep().Git("--version"))
459 self.assertEquals("", self.MakeStep().Git("dummy"))
460
461 def testCommonPrepareDefault(self):
462 self.Expect([
463 Cmd("git status -s -uno", ""),
464 Cmd("git checkout -f origin/master", ""),
465 Cmd("git fetch", ""),
466 Cmd("git branch", " branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]),
467 RL("Y"),
468 Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
469 ])
470 self.MakeStep().CommonPrepare()
471 self.MakeStep().PrepareBranch()
472
473 def testCommonPrepareNoConfirm(self):
474 self.Expect([
475 Cmd("git status -s -uno", ""),
476 Cmd("git checkout -f origin/master", ""),
477 Cmd("git fetch", ""),
478 Cmd("git branch", " branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]),
479 RL("n"),
480 ])
481 self.MakeStep().CommonPrepare()
482 self.assertRaises(Exception, self.MakeStep().PrepareBranch)
483
484 def testCommonPrepareDeleteBranchFailure(self):
485 self.Expect([
486 Cmd("git status -s -uno", ""),
487 Cmd("git checkout -f origin/master", ""),
488 Cmd("git fetch", ""),
489 Cmd("git branch", " branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]),
490 RL("Y"),
491 Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], None),
492 ])
493 self.MakeStep().CommonPrepare()
494 self.assertRaises(Exception, self.MakeStep().PrepareBranch)
495
496 def testInitialEnvironmentChecks(self):
497 TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
498 os.environ["EDITOR"] = "vi"
499 self.Expect([
500 Cmd("which vi", "/usr/bin/vi"),
501 ])
502 self.MakeStep().InitialEnvironmentChecks(TEST_CONFIG["DEFAULT_CWD"])
503
504 def testTagTimeout(self):
505 self.Expect([
506 Cmd("git fetch", ""),
507 Cmd("git log -1 --format=%H --grep=\"Title\" origin/candidates", ""),
508 Cmd("git fetch", ""),
509 Cmd("git log -1 --format=%H --grep=\"Title\" origin/candidates", ""),
510 Cmd("git fetch", ""),
511 Cmd("git log -1 --format=%H --grep=\"Title\" origin/candidates", ""),
512 Cmd("git fetch", ""),
513 Cmd("git log -1 --format=%H --grep=\"Title\" origin/candidates", ""),
514 ])
515 args = ["--branch", "candidates", "ab12345"]
516 self._state["version"] = "tag_name"
517 self._state["commit_title"] = "Title"
518 self.assertRaises(Exception,
519 lambda: self.RunStep(MergeToBranch, TagRevision, args))
520
521 def testReadAndPersistVersion(self):
522 self.WriteFakeVersionFile(build=5)
523 step = self.MakeStep()
524 step.ReadAndPersistVersion()
525 self.assertEquals("3", step["major"])
526 self.assertEquals("22", step["minor"])
527 self.assertEquals("5", step["build"])
528 self.assertEquals("0", step["patch"])
529
530 def testRegex(self):
531 self.assertEqual("(issue 321)",
532 re.sub(r"BUG=v8:(.*)$", r"(issue \1)", "BUG=v8:321"))
533 self.assertEqual("(Chromium issue 321)",
534 re.sub(r"BUG=(.*)$", r"(Chromium issue \1)", "BUG=321"))
535
536 cl = " too little\n\ttab\ttab\n too much\n trailing "
537 cl = MSub(r"\t", r" ", cl)
538 cl = MSub(r"^ {1,7}([^ ])", r" \1", cl)
539 cl = MSub(r"^ {9,80}([^ ])", r" \1", cl)
540 cl = MSub(r" +$", r"", cl)
541 self.assertEqual(" too little\n"
542 " tab tab\n"
543 " too much\n"
544 " trailing", cl)
545
546 self.assertEqual("//\n#define V8_BUILD_NUMBER 3\n",
547 MSub(r"(?<=#define V8_BUILD_NUMBER)(?P<space>\s+)\d*$",
548 r"\g<space>3",
549 "//\n#define V8_BUILD_NUMBER 321\n"))
550
551 def testPreparePushRevision(self):
552 # Tests the default push hash used when the --revision option is not set.
553 self.Expect([
554 Cmd("git log -1 --format=%H HEAD", "push_hash")
555 ])
556
557 self.RunStep(PushToCandidates, PreparePushRevision)
558 self.assertEquals("push_hash", self._state["push_hash"])
559
560 def testPrepareChangeLog(self):
561 self.WriteFakeVersionFile()
562 TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile()
563
564 self.Expect([
565 Cmd("git log --format=%H 1234..push_hash", "rev1\nrev2\nrev3\nrev4"),
566 Cmd("git log -1 --format=%s rev1", "Title text 1"),
567 Cmd("git log -1 --format=%B rev1", "Title\n\nBUG=\nLOG=y\n"),
568 Cmd("git log -1 --format=%an rev1", "author1@chromium.org"),
569 Cmd("git log -1 --format=%s rev2", "Title text 2."),
570 Cmd("git log -1 --format=%B rev2", "Title\n\nBUG=123\nLOG= \n"),
571 Cmd("git log -1 --format=%an rev2", "author2@chromium.org"),
572 Cmd("git log -1 --format=%s rev3", "Title text 3"),
573 Cmd("git log -1 --format=%B rev3", "Title\n\nBUG=321\nLOG=true\n"),
574 Cmd("git log -1 --format=%an rev3", "author3@chromium.org"),
575 Cmd("git log -1 --format=%s rev4", "Title text 4"),
576 Cmd("git log -1 --format=%B rev4",
577 ("Title\n\nBUG=456\nLOG=Y\n\n"
578 "Review URL: https://codereview.chromium.org/9876543210\n")),
579 URL("https://codereview.chromium.org/9876543210/description",
580 "Title\n\nBUG=456\nLOG=N\n\n"),
581 Cmd("git log -1 --format=%an rev4", "author4@chromium.org"),
582 ])
583
584 self._state["last_push_master"] = "1234"
585 self._state["push_hash"] = "push_hash"
586 self._state["version"] = "3.22.5"
587 self.RunStep(PushToCandidates, PrepareChangeLog)
588
589 actual_cl = FileToText(TEST_CONFIG["CHANGELOG_ENTRY_FILE"])
590
591 expected_cl = """1999-07-31: Version 3.22.5
592
593 Title text 1.
594
595 Title text 3 (Chromium issue 321).
596
597 Performance and stability improvements on all platforms.
598#
599# The change log above is auto-generated. Please review if all relevant
600# commit messages from the list below are included.
601# All lines starting with # will be stripped.
602#
603# Title text 1.
604# (author1@chromium.org)
605#
606# Title text 2 (Chromium issue 123).
607# (author2@chromium.org)
608#
609# Title text 3 (Chromium issue 321).
610# (author3@chromium.org)
611#
612# Title text 4 (Chromium issue 456).
613# (author4@chromium.org)
614#
615#"""
616
617 self.assertEquals(expected_cl, actual_cl)
618
619 def testEditChangeLog(self):
620 TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile()
621 TextToFile(" New \n\tLines \n", TEST_CONFIG["CHANGELOG_ENTRY_FILE"])
622 os.environ["EDITOR"] = "vi"
623 self.Expect([
624 RL(""), # Open editor.
625 Cmd("vi %s" % TEST_CONFIG["CHANGELOG_ENTRY_FILE"], ""),
626 ])
627
628 self.RunStep(PushToCandidates, EditChangeLog)
629
630 self.assertEquals("New\n Lines",
631 FileToText(TEST_CONFIG["CHANGELOG_ENTRY_FILE"]))
632
633 TAGS = """
6344425.0
6350.0.0.0
6363.9.6
6373.22.4
638test_tag
639"""
640
641 # Version as tag: 3.22.4.0. Version on master: 3.22.6.
642 # Make sure that the latest version is 3.22.6.0.
643 def testIncrementVersion(self):
644 self.Expect([
645 Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
646 Cmd("git tag", self.TAGS),
647 Cmd("git checkout -f origin/master -- include/v8-version.h",
648 "", cb=lambda: self.WriteFakeVersionFile(3, 22, 6)),
649 ])
650
651 self.RunStep(PushToCandidates, IncrementVersion)
652
653 self.assertEquals("3", self._state["new_major"])
654 self.assertEquals("22", self._state["new_minor"])
655 self.assertEquals("7", self._state["new_build"])
656 self.assertEquals("0", self._state["new_patch"])
657
658 def _TestSquashCommits(self, change_log, expected_msg):
659 TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile()
660 with open(TEST_CONFIG["CHANGELOG_ENTRY_FILE"], "w") as f:
661 f.write(change_log)
662
663 self.Expect([
664 Cmd("git diff origin/candidates hash1", "patch content"),
665 ])
666
667 self._state["push_hash"] = "hash1"
668 self._state["date"] = "1999-11-11"
669
670 self.RunStep(PushToCandidates, SquashCommits)
671 self.assertEquals(FileToText(TEST_CONFIG["COMMITMSG_FILE"]), expected_msg)
672
673 patch = FileToText(TEST_CONFIG["PATCH_FILE"])
674 self.assertTrue(re.search(r"patch content", patch))
675
676 def testSquashCommitsUnformatted(self):
677 change_log = """1999-11-11: Version 3.22.5
678
679 Log text 1.
680 Chromium issue 12345
681
682 Performance and stability improvements on all platforms.\n"""
683 commit_msg = """Version 3.22.5 (based on hash1)
684
685Log text 1. Chromium issue 12345
686
687Performance and stability improvements on all platforms."""
688 self._TestSquashCommits(change_log, commit_msg)
689
690 def testSquashCommitsFormatted(self):
691 change_log = """1999-11-11: Version 3.22.5
692
693 Long commit message that fills more than 80 characters (Chromium issue
694 12345).
695
696 Performance and stability improvements on all platforms.\n"""
697 commit_msg = """Version 3.22.5 (based on hash1)
698
699Long commit message that fills more than 80 characters (Chromium issue 12345).
700
701Performance and stability improvements on all platforms."""
702 self._TestSquashCommits(change_log, commit_msg)
703
704 def testSquashCommitsQuotationMarks(self):
705 change_log = """Line with "quotation marks".\n"""
706 commit_msg = """Line with "quotation marks"."""
707 self._TestSquashCommits(change_log, commit_msg)
708
709 def testBootstrapper(self):
710 work_dir = self.MakeEmptyTempDirectory()
711 class FakeScript(ScriptsBase):
712 def _Steps(self):
713 return []
714
715 # Use the test configuration without the fake testing default work dir.
716 fake_config = dict(TEST_CONFIG)
717 del(fake_config["DEFAULT_CWD"])
718
719 self.Expect([
720 Cmd("fetch v8", "", cwd=work_dir),
721 ])
722 FakeScript(fake_config, self).Run(["--work-dir", work_dir])
723
724 def _PushToCandidates(self, force=False, manual=False):
725 TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
726
727 # The version file on master has build level 5, while the version
728 # file from candidates has build level 4.
729 self.WriteFakeVersionFile(build=5)
730
731 TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile()
732 master_change_log = "2014-03-17: Sentinel\n"
733 TextToFile(master_change_log,
734 os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
735 os.environ["EDITOR"] = "vi"
736
737 commit_msg_squashed = """Version 3.22.5 (squashed - based on push_hash)
738
739Log text 1 (issue 321).
740
741Performance and stability improvements on all platforms."""
742
743 commit_msg = """Version 3.22.5 (based on push_hash)
744
745Log text 1 (issue 321).
746
747Performance and stability improvements on all platforms."""
748
749 def ResetChangeLog():
750 """On 'git co -b new_branch origin/candidates',
751 and 'git checkout -- ChangeLog',
752 the ChangLog will be reset to its content on candidates."""
753 candidates_change_log = """1999-04-05: Version 3.22.4
754
755 Performance and stability improvements on all platforms.\n"""
756 TextToFile(candidates_change_log,
757 os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
758
759 def ResetToCandidates():
760 ResetChangeLog()
761 self.WriteFakeVersionFile()
762
763 def CheckVersionCommit():
764 commit = FileToText(TEST_CONFIG["COMMITMSG_FILE"])
765 self.assertEquals(commit_msg, commit)
766 version = FileToText(
767 os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE))
768 self.assertTrue(re.search(r"#define V8_MINOR_VERSION\s+22", version))
769 self.assertTrue(re.search(r"#define V8_BUILD_NUMBER\s+5", version))
770 self.assertFalse(re.search(r"#define V8_BUILD_NUMBER\s+6", version))
771 self.assertTrue(re.search(r"#define V8_PATCH_LEVEL\s+0", version))
772 self.assertTrue(
773 re.search(r"#define V8_IS_CANDIDATE_VERSION\s+0", version))
774
775 # Check that the change log on the candidates branch got correctly
776 # modified.
777 change_log = FileToText(
778 os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
779 self.assertEquals(
780"""1999-07-31: Version 3.22.5
781
782 Log text 1 (issue 321).
783
784 Performance and stability improvements on all platforms.
785
786
7871999-04-05: Version 3.22.4
788
789 Performance and stability improvements on all platforms.\n""",
790 change_log)
791
792 force_flag = " -f" if not manual else ""
793 expectations = []
794 if not force:
795 expectations.append(Cmd("which vi", "/usr/bin/vi"))
796 expectations += [
797 Cmd("git status -s -uno", ""),
798 Cmd("git checkout -f origin/master", ""),
799 Cmd("git fetch", ""),
800 Cmd("git branch", " branch1\n* branch2\n"),
801 Cmd("git branch", " branch1\n* branch2\n"),
802 Cmd(("git new-branch %s --upstream origin/master" %
803 TEST_CONFIG["BRANCHNAME"]), ""),
804 Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
805 Cmd("git tag", self.TAGS),
806 Cmd("git checkout -f origin/master -- include/v8-version.h",
807 "", cb=self.WriteFakeVersionFile),
808 Cmd("git log -1 --format=%H 3.22.4", "release_hash\n"),
809 Cmd("git log -1 --format=%s release_hash",
810 "Version 3.22.4 (based on abc3)\n"),
811 Cmd("git log --format=%H abc3..push_hash", "rev1\n"),
812 Cmd("git log -1 --format=%s rev1", "Log text 1.\n"),
813 Cmd("git log -1 --format=%B rev1", "Text\nLOG=YES\nBUG=v8:321\nText\n"),
814 Cmd("git log -1 --format=%an rev1", "author1@chromium.org\n"),
815 ]
816 if manual:
817 expectations.append(RL("")) # Open editor.
818 if not force:
819 expectations.append(
820 Cmd("vi %s" % TEST_CONFIG["CHANGELOG_ENTRY_FILE"], ""))
821 expectations += [
822 Cmd("git fetch", ""),
823 Cmd("git checkout -f origin/master", ""),
824 Cmd("git diff origin/candidates push_hash", "patch content\n"),
825 Cmd(("git new-branch %s --upstream origin/candidates" %
826 TEST_CONFIG["CANDIDATESBRANCH"]), "", cb=ResetToCandidates),
827 Cmd("git apply --index --reject \"%s\"" % TEST_CONFIG["PATCH_FILE"], ""),
828 Cmd("git checkout -f origin/candidates -- ChangeLog", "",
829 cb=ResetChangeLog),
830 Cmd("git checkout -f origin/candidates -- include/v8-version.h", "",
831 cb=self.WriteFakeVersionFile),
832 Cmd("git commit -am \"%s\"" % commit_msg_squashed, ""),
833 ]
834 if manual:
835 expectations.append(RL("Y")) # Sanity check.
836 expectations += [
837 Cmd("git cl land -f --bypass-hooks", ""),
838 Cmd("git checkout -f master", ""),
839 Cmd("git fetch", ""),
840 Cmd("git branch -D %s" % TEST_CONFIG["CANDIDATESBRANCH"], ""),
841 Cmd(("git new-branch %s --upstream origin/candidates" %
842 TEST_CONFIG["CANDIDATESBRANCH"]), "", cb=ResetToCandidates),
843 Cmd("git commit -aF \"%s\"" % TEST_CONFIG["COMMITMSG_FILE"], "",
844 cb=CheckVersionCommit),
845 Cmd("git cl land -f --bypass-hooks", ""),
846 Cmd("git fetch", ""),
847 Cmd("git log -1 --format=%H --grep="
848 "\"Version 3.22.5 (based on push_hash)\""
849 " origin/candidates", "hsh_to_tag"),
850 Cmd("git tag 3.22.5 hsh_to_tag", ""),
851 Cmd("git push origin 3.22.5", ""),
852 Cmd("git checkout -f origin/master", ""),
853 Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
854 Cmd("git branch -D %s" % TEST_CONFIG["CANDIDATESBRANCH"], ""),
855 ]
856 self.Expect(expectations)
857
858 args = ["-a", "author@chromium.org", "--revision", "push_hash"]
859 if force: args.append("-f")
860 if manual: args.append("-m")
861 else: args += ["-r", "reviewer@chromium.org"]
862 PushToCandidates(TEST_CONFIG, self).Run(args)
863
864 cl = FileToText(os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
865 self.assertTrue(re.search(r"^\d\d\d\d\-\d+\-\d+: Version 3\.22\.5", cl))
866 self.assertTrue(re.search(r" Log text 1 \(issue 321\).", cl))
867 self.assertTrue(re.search(r"1999\-04\-05: Version 3\.22\.4", cl))
868
869 # Note: The version file is on build number 5 again in the end of this test
870 # since the git command that merges to master is mocked out.
871
872 def testPushToCandidatesManual(self):
873 self._PushToCandidates(manual=True)
874
875 def testPushToCandidatesSemiAutomatic(self):
876 self._PushToCandidates()
877
878 def testPushToCandidatesForced(self):
879 self._PushToCandidates(force=True)
880
881 def testCreateRelease(self):
882 TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
883
884 # The version file on master has build level 5.
885 self.WriteFakeVersionFile(build=5)
886
887 master_change_log = "2014-03-17: Sentinel\n"
888 TextToFile(master_change_log,
889 os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
890
891 commit_msg = """Version 3.22.5
892
893Log text 1 (issue 321).
894
895Performance and stability improvements on all platforms."""
896
897 def ResetChangeLog():
898 last_change_log = """1999-04-05: Version 3.22.4
899
900 Performance and stability improvements on all platforms.\n"""
901 TextToFile(last_change_log,
902 os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
903
904
905 def CheckVersionCommit():
906 commit = FileToText(TEST_CONFIG["COMMITMSG_FILE"])
907 self.assertEquals(commit_msg, commit)
908 version = FileToText(
909 os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE))
910 self.assertTrue(re.search(r"#define V8_MINOR_VERSION\s+22", version))
911 self.assertTrue(re.search(r"#define V8_BUILD_NUMBER\s+5", version))
912 self.assertFalse(re.search(r"#define V8_BUILD_NUMBER\s+6", version))
913 self.assertTrue(re.search(r"#define V8_PATCH_LEVEL\s+0", version))
914 self.assertTrue(
915 re.search(r"#define V8_IS_CANDIDATE_VERSION\s+0", version))
916
917 # Check that the change log on the candidates branch got correctly
918 # modified.
919 change_log = FileToText(
920 os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
921 self.assertEquals(
922"""1999-07-31: Version 3.22.5
923
924 Log text 1 (issue 321).
925
926 Performance and stability improvements on all platforms.
927
928
9291999-04-05: Version 3.22.4
930
931 Performance and stability improvements on all platforms.\n""",
932 change_log)
933
934 expectations = [
935 Cmd("git fetch origin "
936 "+refs/heads/*:refs/heads/* "
937 "+refs/pending/*:refs/pending/* "
938 "+refs/pending-tags/*:refs/pending-tags/*", ""),
939 Cmd("git checkout -f origin/master", ""),
940 Cmd("git branch", ""),
941 Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
942 Cmd("git tag", self.TAGS),
943 Cmd("git checkout -f origin/master -- include/v8-version.h",
944 "", cb=self.WriteFakeVersionFile),
945 Cmd("git log -1 --format=%H 3.22.4", "release_hash\n"),
946 Cmd("git log -1 --format=%s release_hash", "Version 3.22.4\n"),
947 Cmd("git log -1 --format=%H release_hash^", "abc3\n"),
948 Cmd("git log --format=%H abc3..push_hash", "rev1\n"),
949 Cmd("git log -1 --format=%s rev1", "Log text 1.\n"),
950 Cmd("git log -1 --format=%B rev1", "Text\nLOG=YES\nBUG=v8:321\nText\n"),
951 Cmd("git log -1 --format=%an rev1", "author1@chromium.org\n"),
952 Cmd("git reset --hard origin/master", ""),
953 Cmd("git checkout -b work-branch push_hash", ""),
954 Cmd("git checkout -f 3.22.4 -- ChangeLog", "", cb=ResetChangeLog),
955 Cmd("git checkout -f 3.22.4 -- include/v8-version.h", "",
956 cb=self.WriteFakeVersionFile),
957 Cmd("git commit -aF \"%s\"" % TEST_CONFIG["COMMITMSG_FILE"], "",
958 cb=CheckVersionCommit),
959 Cmd("git push origin "
960 "refs/heads/work-branch:refs/pending/heads/3.22.5 "
961 "push_hash:refs/pending-tags/heads/3.22.5 "
962 "push_hash:refs/heads/3.22.5", ""),
963 Cmd("git fetch", ""),
964 Cmd("git log -1 --format=%H --grep="
965 "\"Version 3.22.5\" origin/3.22.5", "hsh_to_tag"),
966 Cmd("git tag 3.22.5 hsh_to_tag", ""),
967 Cmd("git push origin 3.22.5", ""),
968 Cmd("git checkout -f origin/master", ""),
969 Cmd("git branch", "* master\n work-branch\n"),
970 Cmd("git branch -D work-branch", ""),
971 Cmd("git gc", ""),
972 ]
973 self.Expect(expectations)
974
975 args = ["-a", "author@chromium.org",
976 "-r", "reviewer@chromium.org",
977 "--revision", "push_hash"]
978 CreateRelease(TEST_CONFIG, self).Run(args)
979
980 cl = FileToText(os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
981 self.assertTrue(re.search(r"^\d\d\d\d\-\d+\-\d+: Version 3\.22\.5", cl))
982 self.assertTrue(re.search(r" Log text 1 \(issue 321\).", cl))
983 self.assertTrue(re.search(r"1999\-04\-05: Version 3\.22\.4", cl))
984
985 # Note: The version file is on build number 5 again in the end of this test
986 # since the git command that merges to master is mocked out.
987
988 C_V8_22624_LOG = """V8 CL.
989
990git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22624 123
991
992"""
993
994 C_V8_123455_LOG = """V8 CL.
995
996git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@123455 123
997
998"""
999
1000 C_V8_123456_LOG = """V8 CL.
1001
1002git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@123456 123
1003
1004"""
1005
1006 ROLL_COMMIT_MSG = """Update V8 to version 3.22.4.
1007
1008Summary of changes available at:
1009https://chromium.googlesource.com/v8/v8/+log/last_rol..roll_hsh
1010
1011Please follow these instructions for assigning/CC'ing issues:
1012https://github.com/v8/v8/wiki/Triaging%20issues
1013
1014Please close rolling in case of a roll revert:
1015https://v8-roll.appspot.com/
1016This only works with a Google account.
1017
1018TBR=reviewer@chromium.org"""
1019
1020 # Snippet from the original DEPS file.
1021 FAKE_DEPS = """
1022vars = {
1023 "v8_revision": "last_roll_hsh",
1024}
1025deps = {
1026 "src/v8":
1027 (Var("googlecode_url") % "v8") + "/" + Var("v8_branch") + "@" +
1028 Var("v8_revision"),
1029}
1030"""
1031
1032 def testChromiumRollUpToDate(self):
1033 TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory()
1034 json_output_file = os.path.join(TEST_CONFIG["CHROMIUM"], "out.json")
1035 TextToFile(self.FAKE_DEPS, os.path.join(TEST_CONFIG["CHROMIUM"], "DEPS"))
1036 self.Expect([
1037 Cmd("git fetch origin", ""),
1038 Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
1039 Cmd("git describe --tags last_roll_hsh", "3.22.4"),
1040 Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
1041 Cmd("git rev-list --max-age=395200 --tags",
1042 "bad_tag\nroll_hsh\nhash_123"),
1043 Cmd("git describe --tags bad_tag", ""),
1044 Cmd("git describe --tags roll_hsh", "3.22.4"),
1045 Cmd("git describe --tags hash_123", "3.22.3"),
1046 Cmd("git describe --tags roll_hsh", "3.22.4"),
1047 Cmd("git describe --tags hash_123", "3.22.3"),
1048 ])
1049
1050 result = auto_roll.AutoRoll(TEST_CONFIG, self).Run(
1051 AUTO_PUSH_ARGS + [
1052 "-c", TEST_CONFIG["CHROMIUM"],
1053 "--json-output", json_output_file])
1054 self.assertEquals(0, result)
1055 json_output = json.loads(FileToText(json_output_file))
1056 self.assertEquals("up_to_date", json_output["monitoring_state"])
1057
1058
1059 def testChromiumRoll(self):
1060 # Setup fake directory structures.
1061 TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory()
1062 json_output_file = os.path.join(TEST_CONFIG["CHROMIUM"], "out.json")
1063 TextToFile(self.FAKE_DEPS, os.path.join(TEST_CONFIG["CHROMIUM"], "DEPS"))
1064 TextToFile("", os.path.join(TEST_CONFIG["CHROMIUM"], ".git"))
1065 chrome_dir = TEST_CONFIG["CHROMIUM"]
1066 os.makedirs(os.path.join(chrome_dir, "v8"))
1067
1068 def WriteDeps():
1069 TextToFile("Some line\n \"v8_revision\": \"22624\",\n some line",
1070 os.path.join(chrome_dir, "DEPS"))
1071
1072 expectations = [
1073 Cmd("git fetch origin", ""),
1074 Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
1075 Cmd("git describe --tags last_roll_hsh", "3.22.3.1"),
1076 Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
1077 Cmd("git rev-list --max-age=395200 --tags",
1078 "bad_tag\nroll_hsh\nhash_123"),
1079 Cmd("git describe --tags bad_tag", ""),
1080 Cmd("git describe --tags roll_hsh", "3.22.4"),
1081 Cmd("git describe --tags hash_123", "3.22.3"),
1082 Cmd("git describe --tags roll_hsh", "3.22.4"),
1083 Cmd("git log -1 --format=%s roll_hsh", "Version 3.22.4\n"),
1084 Cmd("git describe --tags roll_hsh", "3.22.4"),
1085 Cmd("git describe --tags last_roll_hsh", "3.22.2.1"),
1086 Cmd("git status -s -uno", "", cwd=chrome_dir),
1087 Cmd("git checkout -f master", "", cwd=chrome_dir),
1088 Cmd("git branch", "", cwd=chrome_dir),
1089 Cmd("gclient sync --nohooks", "syncing...", cwd=chrome_dir),
1090 Cmd("git pull", "", cwd=chrome_dir),
1091 Cmd("git fetch origin", ""),
1092 Cmd("git new-branch work-branch", "", cwd=chrome_dir),
1093 Cmd("roll-dep-svn v8 roll_hsh", "rolled", cb=WriteDeps, cwd=chrome_dir),
1094 Cmd(("git commit -am \"%s\" "
1095 "--author \"author@chromium.org <author@chromium.org>\"" %
1096 self.ROLL_COMMIT_MSG),
1097 "", cwd=chrome_dir),
1098 Cmd("git cl upload --send-mail --email \"author@chromium.org\" -f "
1099 "--use-commit-queue", "", cwd=chrome_dir),
1100 Cmd("git checkout -f master", "", cwd=chrome_dir),
1101 Cmd("git branch -D work-branch", "", cwd=chrome_dir),
1102 ]
1103 self.Expect(expectations)
1104
1105 args = ["-a", "author@chromium.org", "-c", chrome_dir,
1106 "-r", "reviewer@chromium.org", "--json-output", json_output_file]
1107 auto_roll.AutoRoll(TEST_CONFIG, self).Run(args)
1108
1109 deps = FileToText(os.path.join(chrome_dir, "DEPS"))
1110 self.assertTrue(re.search("\"v8_revision\": \"22624\"", deps))
1111
1112 json_output = json.loads(FileToText(json_output_file))
1113 self.assertEquals("success", json_output["monitoring_state"])
1114
1115 def testCheckLastPushRecently(self):
1116 self.Expect([
1117 Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
1118 Cmd("git tag", self.TAGS),
1119 Cmd("git log -1 --format=%H 3.22.4", "release_hash\n"),
1120 Cmd("git log -1 --format=%s release_hash",
1121 "Version 3.22.4 (based on abc3)\n"),
1122 Cmd("git log --format=%H abc3..abc123", "\n"),
1123 ])
1124
1125 self._state["candidate"] = "abc123"
1126 self.assertEquals(0, self.RunStep(
1127 auto_push.AutoPush, LastReleaseBailout, AUTO_PUSH_ARGS))
1128
1129 def testAutoPush(self):
1130 self.Expect([
1131 Cmd("git fetch", ""),
1132 Cmd("git fetch origin +refs/heads/lkgr:refs/heads/lkgr", ""),
1133 Cmd("git show-ref -s refs/heads/lkgr", "abc123\n"),
1134 Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
1135 Cmd("git tag", self.TAGS),
1136 Cmd("git log -1 --format=%H 3.22.4", "release_hash\n"),
1137 Cmd("git log -1 --format=%s release_hash",
1138 "Version 3.22.4 (based on abc3)\n"),
1139 Cmd("git log --format=%H abc3..abc123", "some_stuff\n"),
1140 ])
1141
1142 auto_push.AutoPush(TEST_CONFIG, self).Run(AUTO_PUSH_ARGS + ["--push"])
1143
1144 state = json.loads(FileToText("%s-state.json"
1145 % TEST_CONFIG["PERSISTFILE_BASENAME"]))
1146
1147 self.assertEquals("abc123", state["candidate"])
1148
1149 def testMergeToBranch(self):
1150 TEST_CONFIG["ALREADY_MERGING_SENTINEL_FILE"] = self.MakeEmptyTempFile()
1151 TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
1152 self.WriteFakeVersionFile(build=5)
1153 os.environ["EDITOR"] = "vi"
1154 extra_patch = self.MakeEmptyTempFile()
1155
1156 def VerifyPatch(patch):
1157 return lambda: self.assertEquals(patch,
1158 FileToText(TEST_CONFIG["TEMPORARY_PATCH_FILE"]))
1159
1160 msg = """Version 3.22.5.1 (cherry-pick)
1161
1162Merged ab12345
1163Merged ab23456
1164Merged ab34567
1165Merged ab45678
1166Merged ab56789
1167
1168Title4
1169
1170Title2
1171
1172Title3
1173
1174Title1
1175
1176Revert "Something"
1177
1178BUG=123,234,345,456,567,v8:123
1179LOG=N
1180"""
1181
1182 def VerifyLand():
1183 commit = FileToText(TEST_CONFIG["COMMITMSG_FILE"])
1184 self.assertEquals(msg, commit)
1185 version = FileToText(
1186 os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE))
1187 self.assertTrue(re.search(r"#define V8_MINOR_VERSION\s+22", version))
1188 self.assertTrue(re.search(r"#define V8_BUILD_NUMBER\s+5", version))
1189 self.assertTrue(re.search(r"#define V8_PATCH_LEVEL\s+1", version))
1190 self.assertTrue(
1191 re.search(r"#define V8_IS_CANDIDATE_VERSION\s+0", version))
1192
1193 self.Expect([
1194 Cmd("git status -s -uno", ""),
1195 Cmd("git checkout -f origin/master", ""),
1196 Cmd("git fetch", ""),
1197 Cmd("git branch", " branch1\n* branch2\n"),
1198 Cmd("git new-branch %s --upstream refs/remotes/origin/candidates" %
1199 TEST_CONFIG["BRANCHNAME"], ""),
1200 Cmd(("git log --format=%H --grep=\"Port ab12345\" "
1201 "--reverse origin/master"),
1202 "ab45678\nab23456"),
1203 Cmd("git log -1 --format=%s ab45678", "Title1"),
1204 Cmd("git log -1 --format=%s ab23456", "Title2"),
1205 Cmd(("git log --format=%H --grep=\"Port ab23456\" "
1206 "--reverse origin/master"),
1207 ""),
1208 Cmd(("git log --format=%H --grep=\"Port ab34567\" "
1209 "--reverse origin/master"),
1210 "ab56789"),
1211 Cmd("git log -1 --format=%s ab56789", "Title3"),
1212 RL("Y"), # Automatically add corresponding ports (ab34567, ab56789)?
1213 # Simulate git being down which stops the script.
1214 Cmd("git log -1 --format=%s ab12345", None),
1215 # Restart script in the failing step.
1216 Cmd("git log -1 --format=%s ab12345", "Title4"),
1217 Cmd("git log -1 --format=%s ab23456", "Title2"),
1218 Cmd("git log -1 --format=%s ab34567", "Title3"),
1219 Cmd("git log -1 --format=%s ab45678", "Title1"),
1220 Cmd("git log -1 --format=%s ab56789", "Revert \"Something\""),
1221 Cmd("git log -1 ab12345", "Title4\nBUG=123\nBUG=234"),
1222 Cmd("git log -1 ab23456", "Title2\n BUG = v8:123,345"),
1223 Cmd("git log -1 ab34567", "Title3\nLOG=n\nBUG=567, 456"),
1224 Cmd("git log -1 ab45678", "Title1\nBUG="),
1225 Cmd("git log -1 ab56789", "Revert \"Something\"\nBUG=none"),
1226 Cmd("git log -1 -p ab12345", "patch4"),
1227 Cmd(("git apply --index --reject \"%s\"" %
1228 TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
1229 "", cb=VerifyPatch("patch4")),
1230 Cmd("git log -1 -p ab23456", "patch2"),
1231 Cmd(("git apply --index --reject \"%s\"" %
1232 TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
1233 "", cb=VerifyPatch("patch2")),
1234 Cmd("git log -1 -p ab34567", "patch3"),
1235 Cmd(("git apply --index --reject \"%s\"" %
1236 TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
1237 "", cb=VerifyPatch("patch3")),
1238 Cmd("git log -1 -p ab45678", "patch1"),
1239 Cmd(("git apply --index --reject \"%s\"" %
1240 TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
1241 "", cb=VerifyPatch("patch1")),
1242 Cmd("git log -1 -p ab56789", "patch5\n"),
1243 Cmd(("git apply --index --reject \"%s\"" %
1244 TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
1245 "", cb=VerifyPatch("patch5\n")),
1246 Cmd("git apply --index --reject \"%s\"" % extra_patch, ""),
1247 RL("Y"), # Automatically increment patch level?
1248 Cmd("git commit -aF \"%s\"" % TEST_CONFIG["COMMITMSG_FILE"], ""),
1249 RL("reviewer@chromium.org"), # V8 reviewer.
1250 Cmd("git cl upload --send-mail -r \"reviewer@chromium.org\" "
1251 "--bypass-hooks --cc \"ulan@chromium.org\"", ""),
1252 Cmd("git checkout -f %s" % TEST_CONFIG["BRANCHNAME"], ""),
1253 RL("LGTM"), # Enter LGTM for V8 CL.
1254 Cmd("git cl presubmit", "Presubmit successfull\n"),
1255 Cmd("git cl land -f --bypass-hooks", "Closing issue\n",
1256 cb=VerifyLand),
1257 Cmd("git fetch", ""),
1258 Cmd("git log -1 --format=%H --grep=\""
1259 "Version 3.22.5.1 (cherry-pick)"
1260 "\" refs/remotes/origin/candidates",
1261 ""),
1262 Cmd("git fetch", ""),
1263 Cmd("git log -1 --format=%H --grep=\""
1264 "Version 3.22.5.1 (cherry-pick)"
1265 "\" refs/remotes/origin/candidates",
1266 "hsh_to_tag"),
1267 Cmd("git tag 3.22.5.1 hsh_to_tag", ""),
1268 Cmd("git push origin 3.22.5.1", ""),
1269 Cmd("git checkout -f origin/master", ""),
1270 Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
1271 ])
1272
1273 # ab12345 and ab34567 are patches. ab23456 (included) and ab45678 are the
1274 # MIPS ports of ab12345. ab56789 is the MIPS port of ab34567.
1275 args = ["-f", "-p", extra_patch, "--branch", "candidates",
1276 "ab12345", "ab23456", "ab34567"]
1277
1278 # The first run of the script stops because of git being down.
1279 self.assertRaises(GitFailedException,
1280 lambda: MergeToBranch(TEST_CONFIG, self).Run(args))
1281
1282 # Test that state recovery after restarting the script works.
1283 args += ["-s", "4"]
1284 MergeToBranch(TEST_CONFIG, self).Run(args)
1285
1286 def testReleases(self):
1287 c_hash1_commit_log = """Update V8 to Version 4.2.71.
1288
1289Cr-Commit-Position: refs/heads/master@{#5678}
1290"""
1291 c_hash2_commit_log = """Revert something.
1292
1293BUG=12345
1294
1295Reason:
1296> Some reason.
1297> Cr-Commit-Position: refs/heads/master@{#12345}
1298> git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12345 003-1c4
1299
1300Review URL: https://codereview.chromium.org/12345
1301
1302Cr-Commit-Position: refs/heads/master@{#4567}
1303git-svn-id: svn://svn.chromium.org/chrome/trunk/src@4567 0039-1c4b
1304
1305"""
1306 c_hash3_commit_log = """Simple.
1307
1308git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3456 0039-1c4b
1309
1310"""
1311 c_hash_234_commit_log = """Version 3.3.1.1 (cherry-pick).
1312
1313Merged abc12.
1314
1315Review URL: fake.com
1316
1317Cr-Commit-Position: refs/heads/candidates@{#234}
1318"""
1319 c_hash_123_commit_log = """Version 3.3.1.0
1320
1321git-svn-id: googlecode@123 0039-1c4b
1322"""
1323 c_hash_345_commit_log = """Version 3.4.0.
1324
1325Cr-Commit-Position: refs/heads/candidates@{#345}
1326"""
1327 c_hash_456_commit_log = """Version 4.2.71.
1328
1329Cr-Commit-Position: refs/heads/4.2.71@{#1}
1330"""
1331 c_deps = "Line\n \"v8_revision\": \"%s\",\n line\n"
1332
1333 json_output = self.MakeEmptyTempFile()
1334 csv_output = self.MakeEmptyTempFile()
1335 self.WriteFakeVersionFile()
1336
1337 TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory()
1338 chrome_dir = TEST_CONFIG["CHROMIUM"]
1339 chrome_v8_dir = os.path.join(chrome_dir, "v8")
1340 os.makedirs(chrome_v8_dir)
1341
1342 def ResetVersion(major, minor, build, patch=0):
1343 return lambda: self.WriteFakeVersionFile(major=major,
1344 minor=minor,
1345 build=build,
1346 patch=patch)
1347
1348 self.Expect([
1349 Cmd("git status -s -uno", ""),
1350 Cmd("git checkout -f origin/master", ""),
1351 Cmd("git fetch", ""),
1352 Cmd("git branch", " branch1\n* branch2\n"),
1353 Cmd("git new-branch %s" % TEST_CONFIG["BRANCHNAME"], ""),
1354 Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
1355 Cmd("git rev-list --max-age=395200 --tags",
1356 "bad_tag\nhash_234\nhash_123\nhash_345\nhash_456\n"),
1357 Cmd("git describe --tags bad_tag", "3.23.42-1-deadbeef"),
1358 Cmd("git describe --tags hash_234", "3.3.1.1"),
1359 Cmd("git describe --tags hash_123", "3.21.2"),
1360 Cmd("git describe --tags hash_345", "3.22.3"),
1361 Cmd("git describe --tags hash_456", "4.2.71"),
1362 Cmd("git diff --name-only hash_234 hash_234^", VERSION_FILE),
1363 Cmd("git checkout -f hash_234 -- %s" % VERSION_FILE, "",
1364 cb=ResetVersion(3, 3, 1, 1)),
1365 Cmd("git branch -r --contains hash_234", " branch-heads/3.3\n"),
1366 Cmd("git log -1 --format=%B hash_234", c_hash_234_commit_log),
1367 Cmd("git log -1 --format=%s hash_234", ""),
1368 Cmd("git log -1 --format=%B hash_234", c_hash_234_commit_log),
1369 Cmd("git log -1 --format=%ci hash_234", "18:15"),
1370 Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
1371 cb=ResetVersion(3, 22, 5)),
1372 Cmd("git diff --name-only hash_123 hash_123^", VERSION_FILE),
1373 Cmd("git checkout -f hash_123 -- %s" % VERSION_FILE, "",
1374 cb=ResetVersion(3, 21, 2)),
1375 Cmd("git branch -r --contains hash_123", " branch-heads/3.21\n"),
1376 Cmd("git log -1 --format=%B hash_123", c_hash_123_commit_log),
1377 Cmd("git log -1 --format=%s hash_123", ""),
1378 Cmd("git log -1 --format=%B hash_123", c_hash_123_commit_log),
1379 Cmd("git log -1 --format=%ci hash_123", "03:15"),
1380 Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
1381 cb=ResetVersion(3, 22, 5)),
1382 Cmd("git diff --name-only hash_345 hash_345^", VERSION_FILE),
1383 Cmd("git checkout -f hash_345 -- %s" % VERSION_FILE, "",
1384 cb=ResetVersion(3, 22, 3)),
1385 Cmd("git branch -r --contains hash_345", " origin/candidates\n"),
1386 Cmd("git log -1 --format=%B hash_345", c_hash_345_commit_log),
1387 Cmd("git log -1 --format=%s hash_345", ""),
1388 Cmd("git log -1 --format=%B hash_345", c_hash_345_commit_log),
1389 Cmd("git log -1 --format=%ci hash_345", ""),
1390 Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
1391 cb=ResetVersion(3, 22, 5)),
1392 Cmd("git diff --name-only hash_456 hash_456^", VERSION_FILE),
1393 Cmd("git checkout -f hash_456 -- %s" % VERSION_FILE, "",
1394 cb=ResetVersion(4, 2, 71)),
1395 Cmd("git branch -r --contains hash_456", " origin/4.2.71\n"),
1396 Cmd("git log -1 --format=%B hash_456", c_hash_456_commit_log),
1397 Cmd("git log -1 --format=%H 4.2.71", "hash_456"),
1398 Cmd("git log -1 --format=%s hash_456", "Version 4.2.71"),
1399 Cmd("git log -1 --format=%H hash_456^", "master_456"),
1400 Cmd("git log -1 --format=%B master_456",
1401 "Cr-Commit-Position: refs/heads/master@{#456}"),
1402 Cmd("git log -1 --format=%B hash_456", c_hash_456_commit_log),
1403 Cmd("git log -1 --format=%ci hash_456", "02:15"),
1404 Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
1405 cb=ResetVersion(3, 22, 5)),
1406 Cmd("git fetch origin +refs/heads/*:refs/remotes/origin/* "
1407 "+refs/branch-heads/*:refs/remotes/branch-heads/*", "",
1408 cwd=chrome_dir),
1409 Cmd("git fetch origin", "", cwd=chrome_v8_dir),
1410 Cmd("git log --format=%H --grep=\"V8\" origin/master -- DEPS",
1411 "c_hash1\nc_hash2\nc_hash3\n",
1412 cwd=chrome_dir),
1413 Cmd("git show c_hash1:DEPS", c_deps % "hash_456", cwd=chrome_dir),
1414 Cmd("git log -1 --format=%B c_hash1", c_hash1_commit_log,
1415 cwd=chrome_dir),
1416 Cmd("git show c_hash2:DEPS", c_deps % "hash_345", cwd=chrome_dir),
1417 Cmd("git log -1 --format=%B c_hash2", c_hash2_commit_log,
1418 cwd=chrome_dir),
1419 Cmd("git show c_hash3:DEPS", c_deps % "deadbeef", cwd=chrome_dir),
1420 Cmd("git log -1 --format=%B c_hash3", c_hash3_commit_log,
1421 cwd=chrome_dir),
1422 Cmd("git branch -r", " weird/123\n branch-heads/7\n", cwd=chrome_dir),
1423 Cmd("git show refs/branch-heads/7:DEPS", c_deps % "hash_345",
1424 cwd=chrome_dir),
1425 URL("http://omahaproxy.appspot.com/all.json", """[{
1426 "os": "win",
1427 "versions": [{
1428 "version": "2.2.2.2",
1429 "v8_version": "22.2.2.2",
1430 "current_reldate": "04/09/15",
1431 "os": "win",
1432 "channel": "canary",
1433 "previous_version": "1.1.1.0"
1434 }]
1435 }]"""),
1436 URL("http://omahaproxy.appspot.com/v8.json?version=1.1.1.0", """{
1437 "chromium_version": "1.1.1.0",
1438 "v8_version": "11.1.1.0"
1439 }"""),
1440 Cmd("git rev-list -1 11.1.1", "v8_previous_version_hash"),
1441 Cmd("git rev-list -1 22.2.2.2", "v8_version_hash"),
1442 Cmd("git checkout -f origin/master", ""),
1443 Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], "")
1444 ])
1445
1446 args = ["-c", TEST_CONFIG["CHROMIUM"],
1447 "--json", json_output,
1448 "--csv", csv_output,
1449 "--max-releases", "1"]
1450 Releases(TEST_CONFIG, self).Run(args)
1451
1452 # Check expected output.
1453 csv = ("4.2.71,4.2.71,1,5678,\r\n"
1454 "3.22.3,candidates,345,4567:5677,\r\n"
1455 "3.21.2,3.21,123,,\r\n"
1456 "3.3.1.1,3.3,234,,abc12\r\n")
1457 self.assertEquals(csv, FileToText(csv_output))
1458
1459 expected_json = {"chrome_releases":{
1460 "canaries": [
1461 {
1462 "chrome_version": "2.2.2.2",
1463 "os": "win",
1464 "release_date": "04/09/15",
1465 "v8_version": "22.2.2.2",
1466 "v8_version_hash": "v8_version_hash",
1467 "v8_previous_version": "11.1.1.0",
1468 "v8_previous_version_hash": "v8_previous_version_hash"
1469 }]},
1470 "releases":[
1471 {
1472 "revision": "1",
1473 "revision_git": "hash_456",
1474 "master_position": "456",
1475 "master_hash": "master_456",
1476 "patches_merged": "",
1477 "version": "4.2.71",
1478 "chromium_revision": "5678",
1479 "branch": "4.2.71",
1480 "review_link": "",
1481 "date": "02:15",
1482 "chromium_branch": "",
1483 # FIXME(machenbach): Fix revisions link for git.
1484 "revision_link": "https://code.google.com/p/v8/source/detail?r=1",
1485 },
1486 {
1487 "revision": "345",
1488 "revision_git": "hash_345",
1489 "master_position": "",
1490 "master_hash": "",
1491 "patches_merged": "",
1492 "version": "3.22.3",
1493 "chromium_revision": "4567:5677",
1494 "branch": "candidates",
1495 "review_link": "",
1496 "date": "",
1497 "chromium_branch": "7",
1498 "revision_link": "https://code.google.com/p/v8/source/detail?r=345",
1499 },
1500 {
1501 "revision": "123",
1502 "revision_git": "hash_123",
1503 "patches_merged": "",
1504 "master_position": "",
1505 "master_hash": "",
1506 "version": "3.21.2",
1507 "chromium_revision": "",
1508 "branch": "3.21",
1509 "review_link": "",
1510 "date": "03:15",
1511 "chromium_branch": "",
1512 "revision_link": "https://code.google.com/p/v8/source/detail?r=123",
1513 },
1514 {
1515 "revision": "234",
1516 "revision_git": "hash_234",
1517 "patches_merged": "abc12",
1518 "master_position": "",
1519 "master_hash": "",
1520 "version": "3.3.1.1",
1521 "chromium_revision": "",
1522 "branch": "3.3",
1523 "review_link": "fake.com",
1524 "date": "18:15",
1525 "chromium_branch": "",
1526 "revision_link": "https://code.google.com/p/v8/source/detail?r=234",
1527 },],
1528 }
1529 self.assertEquals(expected_json, json.loads(FileToText(json_output)))
1530
1531
1532class SystemTest(unittest.TestCase):
1533 def testReload(self):
1534 options = ScriptsBase(
1535 TEST_CONFIG, DEFAULT_SIDE_EFFECT_HANDLER, {}).MakeOptions([])
1536 step = MakeStep(step_class=PrepareChangeLog, number=0, state={}, config={},
1537 options=options,
1538 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER)
1539 body = step.Reload(
1540"""------------------------------------------------------------------------
1541r17997 | machenbach@chromium.org | 2013-11-22 11:04:04 +0100 (...) | 6 lines
1542
1543Prepare push to trunk. Now working on version 3.23.11.
1544
1545R=danno@chromium.org
1546
1547Review URL: https://codereview.chromium.org/83173002
1548
1549------------------------------------------------------------------------""")
1550 self.assertEquals(
1551"""Prepare push to trunk. Now working on version 3.23.11.
1552
1553R=danno@chromium.org
1554
1555Committed: https://code.google.com/p/v8/source/detail?r=17997""", body)