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