1#!/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) 1556