summaryrefslogtreecommitdiff
path: root/deps/v8/tools/release/test_scripts.py
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/tools/release/test_scripts.py')
-rw-r--r--deps/v8/tools/release/test_scripts.py1558
1 files changed, 1558 insertions, 0 deletions
diff --git a/deps/v8/tools/release/test_scripts.py b/deps/v8/tools/release/test_scripts.py
new file mode 100644
index 0000000000..3beddfd936
--- /dev/null
+++ b/deps/v8/tools/release/test_scripts.py
@@ -0,0 +1,1558 @@
+#!/usr/bin/env python
+# Copyright 2013 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import shutil
+import tempfile
+import traceback
+import unittest
+
+import auto_push
+from auto_push import LastReleaseBailout
+import auto_roll
+import common_includes
+from common_includes import *
+import create_release
+from create_release import CreateRelease
+import merge_to_branch
+from merge_to_branch import *
+import push_to_candidates
+from push_to_candidates import *
+import chromium_roll
+from chromium_roll import ChromiumRoll
+import releases
+from releases import Releases
+from auto_tag import AutoTag
+
+
+TEST_CONFIG = {
+ "DEFAULT_CWD": None,
+ "BRANCHNAME": "test-prepare-push",
+ "CANDIDATESBRANCH": "test-candidates-push",
+ "PERSISTFILE_BASENAME": "/tmp/test-v8-push-to-candidates-tempfile",
+ "CHANGELOG_ENTRY_FILE":
+ "/tmp/test-v8-push-to-candidates-tempfile-changelog-entry",
+ "PATCH_FILE": "/tmp/test-v8-push-to-candidates-tempfile-patch",
+ "COMMITMSG_FILE": "/tmp/test-v8-push-to-candidates-tempfile-commitmsg",
+ "CHROMIUM": "/tmp/test-v8-push-to-candidates-tempfile-chromium",
+ "SETTINGS_LOCATION": None,
+ "ALREADY_MERGING_SENTINEL_FILE":
+ "/tmp/test-merge-to-branch-tempfile-already-merging",
+ "TEMPORARY_PATCH_FILE": "/tmp/test-merge-to-branch-tempfile-temporary-patch",
+ "CLUSTERFUZZ_API_KEY_FILE": "/tmp/test-fake-cf-api-key",
+}
+
+
+AUTO_PUSH_ARGS = [
+ "-a", "author@chromium.org",
+ "-r", "reviewer@chromium.org",
+]
+
+
+class ToplevelTest(unittest.TestCase):
+ def testSortBranches(self):
+ S = releases.SortBranches
+ self.assertEquals(["3.1", "2.25"], S(["2.25", "3.1"])[0:2])
+ self.assertEquals(["3.0", "2.25"], S(["2.25", "3.0", "2.24"])[0:2])
+ self.assertEquals(["3.11", "3.2"], S(["3.11", "3.2", "2.24"])[0:2])
+
+ def testFilterDuplicatesAndReverse(self):
+ F = releases.FilterDuplicatesAndReverse
+ self.assertEquals([], F([]))
+ self.assertEquals([["100", "10"]], F([["100", "10"]]))
+ self.assertEquals([["99", "9"], ["100", "10"]],
+ F([["100", "10"], ["99", "9"]]))
+ self.assertEquals([["98", "9"], ["100", "10"]],
+ F([["100", "10"], ["99", "9"], ["98", "9"]]))
+ self.assertEquals([["98", "9"], ["99", "10"]],
+ F([["100", "10"], ["99", "10"], ["98", "9"]]))
+
+ def testBuildRevisionRanges(self):
+ B = releases.BuildRevisionRanges
+ self.assertEquals({}, B([]))
+ self.assertEquals({"10": "100"}, B([["100", "10"]]))
+ self.assertEquals({"10": "100", "9": "99:99"},
+ B([["100", "10"], ["99", "9"]]))
+ self.assertEquals({"10": "100", "9": "97:99"},
+ B([["100", "10"], ["98", "9"], ["97", "9"]]))
+ self.assertEquals({"10": "100", "9": "99:99", "3": "91:98"},
+ B([["100", "10"], ["99", "9"], ["91", "3"]]))
+ self.assertEquals({"13": "101", "12": "100:100", "9": "94:97",
+ "3": "91:93, 98:99"},
+ B([["101", "13"], ["100", "12"], ["98", "3"],
+ ["94", "9"], ["91", "3"]]))
+
+ def testMakeComment(self):
+ self.assertEquals("# Line 1\n# Line 2\n#",
+ MakeComment(" Line 1\n Line 2\n"))
+ self.assertEquals("#Line 1\n#Line 2",
+ MakeComment("Line 1\n Line 2"))
+
+ def testStripComments(self):
+ self.assertEquals(" Line 1\n Line 3\n",
+ StripComments(" Line 1\n# Line 2\n Line 3\n#\n"))
+ self.assertEquals("\nLine 2 ### Test\n #",
+ StripComments("###\n# \n\n# Line 1\nLine 2 ### Test\n #"))
+
+ def testMakeChangeLogBodySimple(self):
+ commits = [
+ ["Title text 1",
+ "Title text 1\n\nBUG=\n",
+ "author1@chromium.org"],
+ ["Title text 2.",
+ "Title text 2\n\nBUG=1234\n",
+ "author2@chromium.org"],
+ ]
+ self.assertEquals(" Title text 1.\n"
+ " (author1@chromium.org)\n\n"
+ " Title text 2 (Chromium issue 1234).\n"
+ " (author2@chromium.org)\n\n",
+ MakeChangeLogBody(commits))
+
+ def testMakeChangeLogBodyEmpty(self):
+ self.assertEquals("", MakeChangeLogBody([]))
+
+ def testMakeChangeLogBodyAutoFormat(self):
+ commits = [
+ ["Title text 1!",
+ "Title text 1\nLOG=y\nBUG=\n",
+ "author1@chromium.org"],
+ ["Title text 2",
+ "Title text 2\n\nBUG=1234\n",
+ "author2@chromium.org"],
+ ["Title text 3",
+ "Title text 3\n\nBUG=1234\nLOG = Yes\n",
+ "author3@chromium.org"],
+ ["Title text 3",
+ "Title text 4\n\nBUG=1234\nLOG=\n",
+ "author4@chromium.org"],
+ ]
+ self.assertEquals(" Title text 1.\n\n"
+ " Title text 3 (Chromium issue 1234).\n\n",
+ MakeChangeLogBody(commits, True))
+
+ def testRegressWrongLogEntryOnTrue(self):
+ body = """
+Check elimination: Learn from if(CompareMap(x)) on true branch.
+
+BUG=
+R=verwaest@chromium.org
+
+Committed: https://code.google.com/p/v8/source/detail?r=18210
+"""
+ self.assertEquals("", MakeChangeLogBody([["title", body, "author"]], True))
+
+ def testMakeChangeLogBugReferenceEmpty(self):
+ self.assertEquals("", MakeChangeLogBugReference(""))
+ self.assertEquals("", MakeChangeLogBugReference("LOG="))
+ self.assertEquals("", MakeChangeLogBugReference(" BUG ="))
+ self.assertEquals("", MakeChangeLogBugReference("BUG=none\t"))
+
+ def testMakeChangeLogBugReferenceSimple(self):
+ self.assertEquals("(issue 987654)",
+ MakeChangeLogBugReference("BUG = v8:987654"))
+ self.assertEquals("(Chromium issue 987654)",
+ MakeChangeLogBugReference("BUG=987654 "))
+
+ def testMakeChangeLogBugReferenceFromBody(self):
+ self.assertEquals("(Chromium issue 1234567)",
+ MakeChangeLogBugReference("Title\n\nTBR=\nBUG=\n"
+ " BUG=\tchromium:1234567\t\n"
+ "R=somebody\n"))
+
+ def testMakeChangeLogBugReferenceMultiple(self):
+ # All issues should be sorted and grouped. Multiple references to the same
+ # issue should be filtered.
+ self.assertEquals("(issues 123, 234, Chromium issue 345)",
+ MakeChangeLogBugReference("Title\n\n"
+ "BUG=v8:234\n"
+ " BUG\t= 345, \tv8:234,\n"
+ "BUG=v8:123\n"
+ "R=somebody\n"))
+ self.assertEquals("(Chromium issues 123, 234)",
+ MakeChangeLogBugReference("Title\n\n"
+ "BUG=234,,chromium:123 \n"
+ "R=somebody\n"))
+ self.assertEquals("(Chromium issues 123, 234)",
+ MakeChangeLogBugReference("Title\n\n"
+ "BUG=chromium:234, , 123\n"
+ "R=somebody\n"))
+ self.assertEquals("(issues 345, 456)",
+ MakeChangeLogBugReference("Title\n\n"
+ "\t\tBUG=v8:345,v8:456\n"
+ "R=somebody\n"))
+ self.assertEquals("(issue 123, Chromium issues 345, 456)",
+ MakeChangeLogBugReference("Title\n\n"
+ "BUG=chromium:456\n"
+ "BUG = none\n"
+ "R=somebody\n"
+ "BUG=456,v8:123, 345"))
+
+ # TODO(machenbach): These test don't make much sense when the formatting is
+ # done later.
+ def testMakeChangeLogBugReferenceLong(self):
+ # -----------------00--------10--------20--------30--------
+ self.assertEquals("(issues 234, 1234567890, 1234567"
+ "8901234567890, Chromium issues 12345678,"
+ " 123456789)",
+ MakeChangeLogBugReference("BUG=v8:234\n"
+ "BUG=v8:1234567890\n"
+ "BUG=v8:12345678901234567890\n"
+ "BUG=123456789\n"
+ "BUG=12345678\n"))
+ # -----------------00--------10--------20--------30--------
+ self.assertEquals("(issues 234, 1234567890, 1234567"
+ "8901234567890, Chromium issues"
+ " 123456789, 1234567890)",
+ MakeChangeLogBugReference("BUG=v8:234\n"
+ "BUG=v8:12345678901234567890\n"
+ "BUG=v8:1234567890\n"
+ "BUG=123456789\n"
+ "BUG=1234567890\n"))
+ # -----------------00--------10--------20--------30--------
+ self.assertEquals("(Chromium issues 234, 1234567890"
+ ", 12345678901234567, "
+ "1234567890123456789)",
+ MakeChangeLogBugReference("BUG=234\n"
+ "BUG=12345678901234567\n"
+ "BUG=1234567890123456789\n"
+ "BUG=1234567890\n"))
+
+
+def Cmd(*args, **kwargs):
+ """Convenience function returning a shell command test expectation."""
+ return {
+ "name": "command",
+ "args": args,
+ "ret": args[-1],
+ "cb": kwargs.get("cb"),
+ "cwd": kwargs.get("cwd", TEST_CONFIG["DEFAULT_CWD"]),
+ }
+
+
+def RL(text, cb=None):
+ """Convenience function returning a readline test expectation."""
+ return {
+ "name": "readline",
+ "args": [],
+ "ret": text,
+ "cb": cb,
+ "cwd": None,
+ }
+
+
+def URL(*args, **kwargs):
+ """Convenience function returning a readurl test expectation."""
+ return {
+ "name": "readurl",
+ "args": args[:-1],
+ "ret": args[-1],
+ "cb": kwargs.get("cb"),
+ "cwd": None,
+ }
+
+
+class SimpleMock(object):
+ def __init__(self):
+ self._recipe = []
+ self._index = -1
+
+ def Expect(self, recipe):
+ self._recipe = recipe
+
+ def Call(self, name, *args, **kwargs): # pragma: no cover
+ self._index += 1
+ try:
+ expected_call = self._recipe[self._index]
+ except IndexError:
+ raise NoRetryException("Calling %s %s" % (name, " ".join(args)))
+
+ if not isinstance(expected_call, dict):
+ raise NoRetryException("Found wrong expectation type for %s %s" %
+ (name, " ".join(args)))
+
+ if expected_call["name"] != name:
+ raise NoRetryException("Expected action: %s %s - Actual: %s" %
+ (expected_call["name"], expected_call["args"], name))
+
+ # Check if the given working directory matches the expected one.
+ if expected_call["cwd"] != kwargs.get("cwd"):
+ raise NoRetryException("Expected cwd: %s in %s %s - Actual: %s" %
+ (expected_call["cwd"],
+ expected_call["name"],
+ expected_call["args"],
+ kwargs.get("cwd")))
+
+ # The number of arguments in the expectation must match the actual
+ # arguments.
+ if len(args) > len(expected_call['args']):
+ raise NoRetryException("When calling %s with arguments, the "
+ "expectations must consist of at least as many arguments." %
+ name)
+
+ # Compare expected and actual arguments.
+ for (expected_arg, actual_arg) in zip(expected_call['args'], args):
+ if expected_arg != actual_arg:
+ raise NoRetryException("Expected: %s - Actual: %s" %
+ (expected_arg, actual_arg))
+
+ # The expected call contains an optional callback for checking the context
+ # at the time of the call.
+ if expected_call['cb']:
+ try:
+ expected_call['cb']()
+ except:
+ tb = traceback.format_exc()
+ raise NoRetryException("Caught exception from callback: %s" % tb)
+
+ # If the return value is an exception, raise it instead of returning.
+ if isinstance(expected_call['ret'], Exception):
+ raise expected_call['ret']
+ return expected_call['ret']
+
+ def AssertFinished(self): # pragma: no cover
+ if self._index < len(self._recipe) -1:
+ raise NoRetryException("Called mock too seldom: %d vs. %d" %
+ (self._index, len(self._recipe)))
+
+
+class ScriptTest(unittest.TestCase):
+ def MakeEmptyTempFile(self):
+ handle, name = tempfile.mkstemp()
+ os.close(handle)
+ self._tmp_files.append(name)
+ return name
+
+ def MakeEmptyTempDirectory(self):
+ name = tempfile.mkdtemp()
+ self._tmp_files.append(name)
+ return name
+
+
+ def WriteFakeVersionFile(self, major=3, minor=22, build=4, patch=0):
+ version_file = os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE)
+ if not os.path.exists(os.path.dirname(version_file)):
+ os.makedirs(os.path.dirname(version_file))
+ with open(version_file, "w") as f:
+ f.write(" // Some line...\n")
+ f.write("\n")
+ f.write("#define MAJOR_VERSION %s\n" % major)
+ f.write("#define MINOR_VERSION %s\n" % minor)
+ f.write("#define BUILD_NUMBER %s\n" % build)
+ f.write("#define PATCH_LEVEL %s\n" % patch)
+ f.write(" // Some line...\n")
+ f.write("#define IS_CANDIDATE_VERSION 0\n")
+
+ def MakeStep(self):
+ """Convenience wrapper."""
+ options = ScriptsBase(TEST_CONFIG, self, self._state).MakeOptions([])
+ return MakeStep(step_class=Step, state=self._state,
+ config=TEST_CONFIG, side_effect_handler=self,
+ options=options)
+
+ def RunStep(self, script=PushToCandidates, step_class=Step, args=None):
+ """Convenience wrapper."""
+ args = args if args is not None else ["-m"]
+ return script(TEST_CONFIG, self, self._state).RunSteps([step_class], args)
+
+ def Call(self, fun, *args, **kwargs):
+ print "Calling %s with %s and %s" % (str(fun), str(args), str(kwargs))
+
+ def Command(self, cmd, args="", prefix="", pipe=True, cwd=None):
+ print "%s %s" % (cmd, args)
+ print "in %s" % cwd
+ return self._mock.Call("command", cmd + " " + args, cwd=cwd)
+
+ def ReadLine(self):
+ return self._mock.Call("readline")
+
+ def ReadURL(self, url, params):
+ if params is not None:
+ return self._mock.Call("readurl", url, params)
+ else:
+ return self._mock.Call("readurl", url)
+
+ def ReadClusterFuzzAPI(self, api_key, **params):
+ # TODO(machenbach): Use a mock for this and add a test that stops rolling
+ # due to clustefuzz results.
+ return []
+
+ def Sleep(self, seconds):
+ pass
+
+ def GetDate(self):
+ return "1999-07-31"
+
+ def GetUTCStamp(self):
+ return "1000000"
+
+ def Expect(self, *args):
+ """Convenience wrapper."""
+ self._mock.Expect(*args)
+
+ def setUp(self):
+ self._mock = SimpleMock()
+ self._tmp_files = []
+ self._state = {}
+ TEST_CONFIG["DEFAULT_CWD"] = self.MakeEmptyTempDirectory()
+
+ def tearDown(self):
+ if os.path.exists(TEST_CONFIG["PERSISTFILE_BASENAME"]):
+ shutil.rmtree(TEST_CONFIG["PERSISTFILE_BASENAME"])
+
+ # Clean up temps. Doesn't work automatically.
+ for name in self._tmp_files:
+ if os.path.isfile(name):
+ os.remove(name)
+ if os.path.isdir(name):
+ shutil.rmtree(name)
+
+ self._mock.AssertFinished()
+
+ def testGitMock(self):
+ self.Expect([Cmd("git --version", "git version 1.2.3"),
+ Cmd("git dummy", "")])
+ self.assertEquals("git version 1.2.3", self.MakeStep().Git("--version"))
+ self.assertEquals("", self.MakeStep().Git("dummy"))
+
+ def testCommonPrepareDefault(self):
+ self.Expect([
+ Cmd("git status -s -uno", ""),
+ Cmd("git status -s -b -uno", "## some_branch"),
+ Cmd("git fetch", ""),
+ Cmd("git branch", " branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]),
+ RL("Y"),
+ Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
+ ])
+ self.MakeStep().CommonPrepare()
+ self.MakeStep().PrepareBranch()
+ self.assertEquals("some_branch", self._state["current_branch"])
+
+ def testCommonPrepareNoConfirm(self):
+ self.Expect([
+ Cmd("git status -s -uno", ""),
+ Cmd("git status -s -b -uno", "## some_branch"),
+ Cmd("git fetch", ""),
+ Cmd("git branch", " branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]),
+ RL("n"),
+ ])
+ self.MakeStep().CommonPrepare()
+ self.assertRaises(Exception, self.MakeStep().PrepareBranch)
+ self.assertEquals("some_branch", self._state["current_branch"])
+
+ def testCommonPrepareDeleteBranchFailure(self):
+ self.Expect([
+ Cmd("git status -s -uno", ""),
+ Cmd("git status -s -b -uno", "## some_branch"),
+ Cmd("git fetch", ""),
+ Cmd("git branch", " branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]),
+ RL("Y"),
+ Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], None),
+ ])
+ self.MakeStep().CommonPrepare()
+ self.assertRaises(Exception, self.MakeStep().PrepareBranch)
+ self.assertEquals("some_branch", self._state["current_branch"])
+
+ def testInitialEnvironmentChecks(self):
+ TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
+ os.environ["EDITOR"] = "vi"
+ self.Expect([
+ Cmd("which vi", "/usr/bin/vi"),
+ ])
+ self.MakeStep().InitialEnvironmentChecks(TEST_CONFIG["DEFAULT_CWD"])
+
+ def testTagTimeout(self):
+ self.Expect([
+ Cmd("git fetch", ""),
+ Cmd("git log -1 --format=%H --grep=\"Title\" origin/candidates", ""),
+ Cmd("git fetch", ""),
+ Cmd("git log -1 --format=%H --grep=\"Title\" origin/candidates", ""),
+ Cmd("git fetch", ""),
+ Cmd("git log -1 --format=%H --grep=\"Title\" origin/candidates", ""),
+ Cmd("git fetch", ""),
+ Cmd("git log -1 --format=%H --grep=\"Title\" origin/candidates", ""),
+ ])
+ args = ["--branch", "candidates", "ab12345"]
+ self._state["version"] = "tag_name"
+ self._state["commit_title"] = "Title"
+ self.assertRaises(Exception,
+ lambda: self.RunStep(MergeToBranch, TagRevision, args))
+
+ def testReadAndPersistVersion(self):
+ self.WriteFakeVersionFile(build=5)
+ step = self.MakeStep()
+ step.ReadAndPersistVersion()
+ self.assertEquals("3", step["major"])
+ self.assertEquals("22", step["minor"])
+ self.assertEquals("5", step["build"])
+ self.assertEquals("0", step["patch"])
+
+ def testRegex(self):
+ self.assertEqual("(issue 321)",
+ re.sub(r"BUG=v8:(.*)$", r"(issue \1)", "BUG=v8:321"))
+ self.assertEqual("(Chromium issue 321)",
+ re.sub(r"BUG=(.*)$", r"(Chromium issue \1)", "BUG=321"))
+
+ cl = " too little\n\ttab\ttab\n too much\n trailing "
+ cl = MSub(r"\t", r" ", cl)
+ cl = MSub(r"^ {1,7}([^ ])", r" \1", cl)
+ cl = MSub(r"^ {9,80}([^ ])", r" \1", cl)
+ cl = MSub(r" +$", r"", cl)
+ self.assertEqual(" too little\n"
+ " tab tab\n"
+ " too much\n"
+ " trailing", cl)
+
+ self.assertEqual("//\n#define BUILD_NUMBER 3\n",
+ MSub(r"(?<=#define BUILD_NUMBER)(?P<space>\s+)\d*$",
+ r"\g<space>3",
+ "//\n#define BUILD_NUMBER 321\n"))
+
+ def testPreparePushRevision(self):
+ # Tests the default push hash used when the --revision option is not set.
+ self.Expect([
+ Cmd("git log -1 --format=%H HEAD", "push_hash")
+ ])
+
+ self.RunStep(PushToCandidates, PreparePushRevision)
+ self.assertEquals("push_hash", self._state["push_hash"])
+
+ def testPrepareChangeLog(self):
+ self.WriteFakeVersionFile()
+ TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile()
+
+ self.Expect([
+ Cmd("git log --format=%H 1234..push_hash", "rev1\nrev2\nrev3\nrev4"),
+ Cmd("git log -1 --format=%s rev1", "Title text 1"),
+ Cmd("git log -1 --format=%B rev1", "Title\n\nBUG=\nLOG=y\n"),
+ Cmd("git log -1 --format=%an rev1", "author1@chromium.org"),
+ Cmd("git log -1 --format=%s rev2", "Title text 2."),
+ Cmd("git log -1 --format=%B rev2", "Title\n\nBUG=123\nLOG= \n"),
+ Cmd("git log -1 --format=%an rev2", "author2@chromium.org"),
+ Cmd("git log -1 --format=%s rev3", "Title text 3"),
+ Cmd("git log -1 --format=%B rev3", "Title\n\nBUG=321\nLOG=true\n"),
+ Cmd("git log -1 --format=%an rev3", "author3@chromium.org"),
+ Cmd("git log -1 --format=%s rev4", "Title text 4"),
+ Cmd("git log -1 --format=%B rev4",
+ ("Title\n\nBUG=456\nLOG=Y\n\n"
+ "Review URL: https://codereview.chromium.org/9876543210\n")),
+ URL("https://codereview.chromium.org/9876543210/description",
+ "Title\n\nBUG=456\nLOG=N\n\n"),
+ Cmd("git log -1 --format=%an rev4", "author4@chromium.org"),
+ ])
+
+ self._state["last_push_master"] = "1234"
+ self._state["push_hash"] = "push_hash"
+ self._state["version"] = "3.22.5"
+ self.RunStep(PushToCandidates, PrepareChangeLog)
+
+ actual_cl = FileToText(TEST_CONFIG["CHANGELOG_ENTRY_FILE"])
+
+ expected_cl = """1999-07-31: Version 3.22.5
+
+ Title text 1.
+
+ Title text 3 (Chromium issue 321).
+
+ Performance and stability improvements on all platforms.
+#
+# The change log above is auto-generated. Please review if all relevant
+# commit messages from the list below are included.
+# All lines starting with # will be stripped.
+#
+# Title text 1.
+# (author1@chromium.org)
+#
+# Title text 2 (Chromium issue 123).
+# (author2@chromium.org)
+#
+# Title text 3 (Chromium issue 321).
+# (author3@chromium.org)
+#
+# Title text 4 (Chromium issue 456).
+# (author4@chromium.org)
+#
+#"""
+
+ self.assertEquals(expected_cl, actual_cl)
+
+ def testEditChangeLog(self):
+ TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile()
+ TextToFile(" New \n\tLines \n", TEST_CONFIG["CHANGELOG_ENTRY_FILE"])
+ os.environ["EDITOR"] = "vi"
+ self.Expect([
+ RL(""), # Open editor.
+ Cmd("vi %s" % TEST_CONFIG["CHANGELOG_ENTRY_FILE"], ""),
+ ])
+
+ self.RunStep(PushToCandidates, EditChangeLog)
+
+ self.assertEquals("New\n Lines",
+ FileToText(TEST_CONFIG["CHANGELOG_ENTRY_FILE"]))
+
+ TAGS = """
+4425.0
+0.0.0.0
+3.9.6
+3.22.4
+test_tag
+"""
+
+ # Version as tag: 3.22.4.0. Version on master: 3.22.6.
+ # Make sure that the latest version is 3.22.6.0.
+ def testIncrementVersion(self):
+ self.Expect([
+ Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
+ Cmd("git tag", self.TAGS),
+ Cmd("git checkout -f origin/master -- src/version.cc",
+ "", cb=lambda: self.WriteFakeVersionFile(3, 22, 6)),
+ ])
+
+ self.RunStep(PushToCandidates, IncrementVersion)
+
+ self.assertEquals("3", self._state["new_major"])
+ self.assertEquals("22", self._state["new_minor"])
+ self.assertEquals("7", self._state["new_build"])
+ self.assertEquals("0", self._state["new_patch"])
+
+ def _TestSquashCommits(self, change_log, expected_msg):
+ TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile()
+ with open(TEST_CONFIG["CHANGELOG_ENTRY_FILE"], "w") as f:
+ f.write(change_log)
+
+ self.Expect([
+ Cmd("git diff origin/candidates hash1", "patch content"),
+ ])
+
+ self._state["push_hash"] = "hash1"
+ self._state["date"] = "1999-11-11"
+
+ self.RunStep(PushToCandidates, SquashCommits)
+ self.assertEquals(FileToText(TEST_CONFIG["COMMITMSG_FILE"]), expected_msg)
+
+ patch = FileToText(TEST_CONFIG["PATCH_FILE"])
+ self.assertTrue(re.search(r"patch content", patch))
+
+ def testSquashCommitsUnformatted(self):
+ change_log = """1999-11-11: Version 3.22.5
+
+ Log text 1.
+ Chromium issue 12345
+
+ Performance and stability improvements on all platforms.\n"""
+ commit_msg = """Version 3.22.5 (based on hash1)
+
+Log text 1. Chromium issue 12345
+
+Performance and stability improvements on all platforms."""
+ self._TestSquashCommits(change_log, commit_msg)
+
+ def testSquashCommitsFormatted(self):
+ change_log = """1999-11-11: Version 3.22.5
+
+ Long commit message that fills more than 80 characters (Chromium issue
+ 12345).
+
+ Performance and stability improvements on all platforms.\n"""
+ commit_msg = """Version 3.22.5 (based on hash1)
+
+Long commit message that fills more than 80 characters (Chromium issue 12345).
+
+Performance and stability improvements on all platforms."""
+ self._TestSquashCommits(change_log, commit_msg)
+
+ def testSquashCommitsQuotationMarks(self):
+ change_log = """Line with "quotation marks".\n"""
+ commit_msg = """Line with "quotation marks"."""
+ self._TestSquashCommits(change_log, commit_msg)
+
+ def testBootstrapper(self):
+ work_dir = self.MakeEmptyTempDirectory()
+ class FakeScript(ScriptsBase):
+ def _Steps(self):
+ return []
+
+ # Use the test configuration without the fake testing default work dir.
+ fake_config = dict(TEST_CONFIG)
+ del(fake_config["DEFAULT_CWD"])
+
+ self.Expect([
+ Cmd("fetch v8", "", cwd=work_dir),
+ ])
+ FakeScript(fake_config, self).Run(["--work-dir", work_dir])
+
+ def _PushToCandidates(self, force=False, manual=False):
+ TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
+
+ # The version file on master has build level 5, while the version
+ # file from candidates has build level 4.
+ self.WriteFakeVersionFile(build=5)
+
+ TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile()
+ master_change_log = "2014-03-17: Sentinel\n"
+ TextToFile(master_change_log,
+ os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
+ os.environ["EDITOR"] = "vi"
+
+ commit_msg_squashed = """Version 3.22.5 (squashed - based on push_hash)
+
+Log text 1 (issue 321).
+
+Performance and stability improvements on all platforms."""
+
+ commit_msg = """Version 3.22.5 (based on push_hash)
+
+Log text 1 (issue 321).
+
+Performance and stability improvements on all platforms."""
+
+ def ResetChangeLog():
+ """On 'git co -b new_branch origin/candidates',
+ and 'git checkout -- ChangeLog',
+ the ChangLog will be reset to its content on candidates."""
+ candidates_change_log = """1999-04-05: Version 3.22.4
+
+ Performance and stability improvements on all platforms.\n"""
+ TextToFile(candidates_change_log,
+ os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
+
+ def ResetToCandidates():
+ ResetChangeLog()
+ self.WriteFakeVersionFile()
+
+ def CheckVersionCommit():
+ commit = FileToText(TEST_CONFIG["COMMITMSG_FILE"])
+ self.assertEquals(commit_msg, commit)
+ version = FileToText(
+ os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE))
+ self.assertTrue(re.search(r"#define MINOR_VERSION\s+22", version))
+ self.assertTrue(re.search(r"#define BUILD_NUMBER\s+5", version))
+ self.assertFalse(re.search(r"#define BUILD_NUMBER\s+6", version))
+ self.assertTrue(re.search(r"#define PATCH_LEVEL\s+0", version))
+ self.assertTrue(re.search(r"#define IS_CANDIDATE_VERSION\s+0", version))
+
+ # Check that the change log on the candidates branch got correctly
+ # modified.
+ change_log = FileToText(
+ os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
+ self.assertEquals(
+"""1999-07-31: Version 3.22.5
+
+ Log text 1 (issue 321).
+
+ Performance and stability improvements on all platforms.
+
+
+1999-04-05: Version 3.22.4
+
+ Performance and stability improvements on all platforms.\n""",
+ change_log)
+
+ force_flag = " -f" if not manual else ""
+ expectations = []
+ if not force:
+ expectations.append(Cmd("which vi", "/usr/bin/vi"))
+ expectations += [
+ Cmd("git status -s -uno", ""),
+ Cmd("git status -s -b -uno", "## some_branch\n"),
+ Cmd("git fetch", ""),
+ Cmd("git branch", " branch1\n* branch2\n"),
+ Cmd("git branch", " branch1\n* branch2\n"),
+ Cmd(("git new-branch %s --upstream origin/master" %
+ TEST_CONFIG["BRANCHNAME"]), ""),
+ Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
+ Cmd("git tag", self.TAGS),
+ Cmd("git checkout -f origin/master -- src/version.cc",
+ "", cb=self.WriteFakeVersionFile),
+ Cmd("git log -1 --format=%H 3.22.4", "release_hash\n"),
+ Cmd("git log -1 --format=%s release_hash",
+ "Version 3.22.4 (based on abc3)\n"),
+ Cmd("git log --format=%H abc3..push_hash", "rev1\n"),
+ Cmd("git log -1 --format=%s rev1", "Log text 1.\n"),
+ Cmd("git log -1 --format=%B rev1", "Text\nLOG=YES\nBUG=v8:321\nText\n"),
+ Cmd("git log -1 --format=%an rev1", "author1@chromium.org\n"),
+ ]
+ if manual:
+ expectations.append(RL("")) # Open editor.
+ if not force:
+ expectations.append(
+ Cmd("vi %s" % TEST_CONFIG["CHANGELOG_ENTRY_FILE"], ""))
+ expectations += [
+ Cmd("git fetch", ""),
+ Cmd("git checkout -f origin/master", ""),
+ Cmd("git diff origin/candidates push_hash", "patch content\n"),
+ Cmd(("git new-branch %s --upstream origin/candidates" %
+ TEST_CONFIG["CANDIDATESBRANCH"]), "", cb=ResetToCandidates),
+ Cmd("git apply --index --reject \"%s\"" % TEST_CONFIG["PATCH_FILE"], ""),
+ Cmd("git checkout -f origin/candidates -- ChangeLog", "",
+ cb=ResetChangeLog),
+ Cmd("git checkout -f origin/candidates -- src/version.cc", "",
+ cb=self.WriteFakeVersionFile),
+ Cmd("git commit -am \"%s\"" % commit_msg_squashed, ""),
+ ]
+ if manual:
+ expectations.append(RL("Y")) # Sanity check.
+ expectations += [
+ Cmd("git cl land -f --bypass-hooks", ""),
+ Cmd("git checkout -f master", ""),
+ Cmd("git fetch", ""),
+ Cmd("git branch -D %s" % TEST_CONFIG["CANDIDATESBRANCH"], ""),
+ Cmd(("git new-branch %s --upstream origin/candidates" %
+ TEST_CONFIG["CANDIDATESBRANCH"]), "", cb=ResetToCandidates),
+ Cmd("git commit -aF \"%s\"" % TEST_CONFIG["COMMITMSG_FILE"], "",
+ cb=CheckVersionCommit),
+ Cmd("git cl land -f --bypass-hooks", ""),
+ Cmd("git fetch", ""),
+ Cmd("git log -1 --format=%H --grep="
+ "\"Version 3.22.5 (based on push_hash)\""
+ " origin/candidates", "hsh_to_tag"),
+ Cmd("git tag 3.22.5 hsh_to_tag", ""),
+ Cmd("git push origin 3.22.5", ""),
+ Cmd("git checkout -f some_branch", ""),
+ Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
+ Cmd("git branch -D %s" % TEST_CONFIG["CANDIDATESBRANCH"], ""),
+ ]
+ self.Expect(expectations)
+
+ args = ["-a", "author@chromium.org", "--revision", "push_hash"]
+ if force: args.append("-f")
+ if manual: args.append("-m")
+ else: args += ["-r", "reviewer@chromium.org"]
+ PushToCandidates(TEST_CONFIG, self).Run(args)
+
+ cl = FileToText(os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
+ self.assertTrue(re.search(r"^\d\d\d\d\-\d+\-\d+: Version 3\.22\.5", cl))
+ self.assertTrue(re.search(r" Log text 1 \(issue 321\).", cl))
+ self.assertTrue(re.search(r"1999\-04\-05: Version 3\.22\.4", cl))
+
+ # Note: The version file is on build number 5 again in the end of this test
+ # since the git command that merges to master is mocked out.
+
+ def testPushToCandidatesManual(self):
+ self._PushToCandidates(manual=True)
+
+ def testPushToCandidatesSemiAutomatic(self):
+ self._PushToCandidates()
+
+ def testPushToCandidatesForced(self):
+ self._PushToCandidates(force=True)
+
+ def testCreateRelease(self):
+ TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
+
+ # The version file on master has build level 5.
+ self.WriteFakeVersionFile(build=5)
+
+ master_change_log = "2014-03-17: Sentinel\n"
+ TextToFile(master_change_log,
+ os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
+
+ commit_msg = """Version 3.22.5
+
+Log text 1 (issue 321).
+
+Performance and stability improvements on all platforms."""
+
+ def ResetChangeLog():
+ last_change_log = """1999-04-05: Version 3.22.4
+
+ Performance and stability improvements on all platforms.\n"""
+ TextToFile(last_change_log,
+ os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
+
+
+ def CheckVersionCommit():
+ commit = FileToText(TEST_CONFIG["COMMITMSG_FILE"])
+ self.assertEquals(commit_msg, commit)
+ version = FileToText(
+ os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE))
+ self.assertTrue(re.search(r"#define MINOR_VERSION\s+22", version))
+ self.assertTrue(re.search(r"#define BUILD_NUMBER\s+5", version))
+ self.assertFalse(re.search(r"#define BUILD_NUMBER\s+6", version))
+ self.assertTrue(re.search(r"#define PATCH_LEVEL\s+0", version))
+ self.assertTrue(re.search(r"#define IS_CANDIDATE_VERSION\s+0", version))
+
+ # Check that the change log on the candidates branch got correctly
+ # modified.
+ change_log = FileToText(
+ os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
+ self.assertEquals(
+"""1999-07-31: Version 3.22.5
+
+ Log text 1 (issue 321).
+
+ Performance and stability improvements on all platforms.
+
+
+1999-04-05: Version 3.22.4
+
+ Performance and stability improvements on all platforms.\n""",
+ change_log)
+
+ expectations = [
+ Cmd("git fetch origin "
+ "+refs/heads/*:refs/heads/* "
+ "+refs/pending/*:refs/pending/* "
+ "+refs/pending-tags/*:refs/pending-tags/*", ""),
+ Cmd("git checkout -f origin/master", ""),
+ Cmd("git branch", ""),
+ Cmd("git log -1 --format=\"%H %T\" push_hash", "push_hash tree_hash"),
+ Cmd("git log -200 --format=\"%H %T\" refs/pending/heads/master",
+ "not_right wrong\npending_hash tree_hash\nsome other\n"),
+ Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
+ Cmd("git tag", self.TAGS),
+ Cmd("git checkout -f origin/master -- src/version.cc",
+ "", cb=self.WriteFakeVersionFile),
+ Cmd("git log -1 --format=%H 3.22.4", "release_hash\n"),
+ Cmd("git log -1 --format=%s release_hash", "Version 3.22.4\n"),
+ Cmd("git log -1 --format=%H release_hash^", "abc3\n"),
+ Cmd("git log --format=%H abc3..push_hash", "rev1\n"),
+ Cmd("git log -1 --format=%s rev1", "Log text 1.\n"),
+ Cmd("git log -1 --format=%B rev1", "Text\nLOG=YES\nBUG=v8:321\nText\n"),
+ Cmd("git log -1 --format=%an rev1", "author1@chromium.org\n"),
+ Cmd("git reset --hard origin/master", ""),
+ Cmd("git checkout -b work-branch pending_hash", ""),
+ Cmd("git checkout -f 3.22.4 -- ChangeLog", "", cb=ResetChangeLog),
+ Cmd("git checkout -f 3.22.4 -- src/version.cc", "",
+ cb=self.WriteFakeVersionFile),
+ Cmd("git commit -aF \"%s\"" % TEST_CONFIG["COMMITMSG_FILE"], "",
+ cb=CheckVersionCommit),
+ Cmd("git push origin "
+ "refs/heads/work-branch:refs/pending/heads/3.22.5 "
+ "pending_hash:refs/pending-tags/heads/3.22.5 "
+ "push_hash:refs/heads/3.22.5", ""),
+ Cmd("git fetch", ""),
+ Cmd("git log -1 --format=%H --grep="
+ "\"Version 3.22.5\" origin/3.22.5", "hsh_to_tag"),
+ Cmd("git tag 3.22.5 hsh_to_tag", ""),
+ Cmd("git push origin 3.22.5", ""),
+ Cmd("git checkout -f origin/master", ""),
+ Cmd("git branch", "* master\n work-branch\n"),
+ Cmd("git branch -D work-branch", ""),
+ Cmd("git gc", ""),
+ ]
+ self.Expect(expectations)
+
+ args = ["-a", "author@chromium.org",
+ "-r", "reviewer@chromium.org",
+ "--revision", "push_hash"]
+ CreateRelease(TEST_CONFIG, self).Run(args)
+
+ cl = FileToText(os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
+ self.assertTrue(re.search(r"^\d\d\d\d\-\d+\-\d+: Version 3\.22\.5", cl))
+ self.assertTrue(re.search(r" Log text 1 \(issue 321\).", cl))
+ self.assertTrue(re.search(r"1999\-04\-05: Version 3\.22\.4", cl))
+
+ # Note: The version file is on build number 5 again in the end of this test
+ # since the git command that merges to master is mocked out.
+
+ C_V8_22624_LOG = """V8 CL.
+
+git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22624 123
+
+"""
+
+ C_V8_123455_LOG = """V8 CL.
+
+git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@123455 123
+
+"""
+
+ C_V8_123456_LOG = """V8 CL.
+
+git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@123456 123
+
+"""
+
+ def testChromiumRoll(self):
+ googlers_mapping_py = "%s-mapping.py" % TEST_CONFIG["PERSISTFILE_BASENAME"]
+ with open(googlers_mapping_py, "w") as f:
+ f.write("""
+def list_to_dict(entries):
+ return {"g_name@google.com": "c_name@chromium.org"}
+def get_list():
+ pass""")
+
+ # Setup fake directory structures.
+ TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory()
+ TextToFile("", os.path.join(TEST_CONFIG["CHROMIUM"], ".git"))
+ chrome_dir = TEST_CONFIG["CHROMIUM"]
+ os.makedirs(os.path.join(chrome_dir, "v8"))
+
+ # Write fake deps file.
+ TextToFile("Some line\n \"v8_revision\": \"123444\",\n some line",
+ os.path.join(chrome_dir, "DEPS"))
+ def WriteDeps():
+ TextToFile("Some line\n \"v8_revision\": \"22624\",\n some line",
+ os.path.join(chrome_dir, "DEPS"))
+
+ expectations = [
+ Cmd("git fetch origin", ""),
+ Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
+ Cmd("git tag", self.TAGS),
+ Cmd("git log -1 --format=%H 3.22.4", "push_hash\n"),
+ Cmd("git log -1 --format=%s push_hash",
+ "Version 3.22.4 (based on abc)\n"),
+ Cmd("git log -1 --format=%H 3.22.4", "push_hash\n"),
+ Cmd("git log -1 --format=%s push_hash",
+ "Version 3.22.4 (based on abc)"),
+ Cmd("git describe --tags last_roll_hsh", "3.22.2.1"),
+ Cmd("git log -1 --format=%H 3.22.2", "last_roll_base_hash"),
+ Cmd("git log -1 --format=%s last_roll_base_hash", "Version 3.22.2"),
+ Cmd("git log -1 --format=%H last_roll_base_hash^",
+ "last_roll_master_hash"),
+ URL("https://chromium-build.appspot.com/p/chromium/sheriff_v8.js",
+ "document.write('g_name')"),
+ Cmd("git status -s -uno", "", cwd=chrome_dir),
+ Cmd("git checkout -f master", "", cwd=chrome_dir),
+ Cmd("gclient sync --nohooks", "syncing...", cwd=chrome_dir),
+ Cmd("git pull", "", cwd=chrome_dir),
+ Cmd("git fetch origin", ""),
+ Cmd("git new-branch v8-roll-push_hash", "", cwd=chrome_dir),
+ Cmd("roll-dep v8 push_hash", "rolled", cb=WriteDeps, cwd=chrome_dir),
+ Cmd(("git commit -am \"Update V8 to version 3.22.4 "
+ "(based on abc).\n\n"
+ "Summary of changes available at:\n"
+ "https://chromium.googlesource.com/v8/v8/+log/last_rol..abc\n\n"
+ "Please reply to the V8 sheriff c_name@chromium.org in "
+ "case of problems.\n\nTBR=c_name@chromium.org\" "
+ "--author \"author@chromium.org <author@chromium.org>\""),
+ "", cwd=chrome_dir),
+ Cmd("git cl upload --send-mail --email \"author@chromium.org\" -f", "",
+ cwd=chrome_dir),
+ ]
+ self.Expect(expectations)
+
+ args = ["-a", "author@chromium.org", "-c", chrome_dir,
+ "--sheriff", "--googlers-mapping", googlers_mapping_py,
+ "-r", "reviewer@chromium.org",
+ "--last-roll", "last_roll_hsh"]
+ ChromiumRoll(TEST_CONFIG, self).Run(args)
+
+ deps = FileToText(os.path.join(chrome_dir, "DEPS"))
+ self.assertTrue(re.search("\"v8_revision\": \"22624\"", deps))
+
+ def testCheckLastPushRecently(self):
+ self.Expect([
+ Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
+ Cmd("git tag", self.TAGS),
+ Cmd("git log -1 --format=%H 3.22.4", "release_hash\n"),
+ Cmd("git log -1 --format=%s release_hash",
+ "Version 3.22.4 (based on abc3)\n"),
+ Cmd("git log --format=%H abc3..abc123", "\n"),
+ ])
+
+ self._state["candidate"] = "abc123"
+ self.assertEquals(0, self.RunStep(
+ auto_push.AutoPush, LastReleaseBailout, AUTO_PUSH_ARGS))
+
+ def testAutoPush(self):
+ TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
+
+ self.Expect([
+ Cmd("git status -s -uno", ""),
+ Cmd("git status -s -b -uno", "## some_branch\n"),
+ Cmd("git fetch", ""),
+ Cmd("git fetch origin +refs/heads/roll:refs/heads/roll", ""),
+ Cmd("git show-ref -s refs/heads/roll", "abc123\n"),
+ Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
+ Cmd("git tag", self.TAGS),
+ Cmd("git log -1 --format=%H 3.22.4", "release_hash\n"),
+ Cmd("git log -1 --format=%s release_hash",
+ "Version 3.22.4 (based on abc3)\n"),
+ Cmd("git log --format=%H abc3..abc123", "some_stuff\n"),
+ ])
+
+ auto_push.AutoPush(TEST_CONFIG, self).Run(AUTO_PUSH_ARGS + ["--push"])
+
+ state = json.loads(FileToText("%s-state.json"
+ % TEST_CONFIG["PERSISTFILE_BASENAME"]))
+
+ self.assertEquals("abc123", state["candidate"])
+
+ def testAutoRollExistingRoll(self):
+ self.Expect([
+ URL("https://codereview.chromium.org/search",
+ "owner=author%40chromium.org&limit=30&closed=3&format=json",
+ ("{\"results\": [{\"subject\": \"different\"},"
+ "{\"subject\": \"Update V8 to Version...\"}]}")),
+ ])
+
+ result = auto_roll.AutoRoll(TEST_CONFIG, self).Run(
+ AUTO_PUSH_ARGS + ["-c", TEST_CONFIG["CHROMIUM"]])
+ self.assertEquals(0, result)
+
+ # Snippet from the original DEPS file.
+ FAKE_DEPS = """
+vars = {
+ "v8_revision": "abcd123455",
+}
+deps = {
+ "src/v8":
+ (Var("googlecode_url") % "v8") + "/" + Var("v8_branch") + "@" +
+ Var("v8_revision"),
+}
+"""
+
+ def testAutoRollUpToDate(self):
+ TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory()
+ TextToFile(self.FAKE_DEPS, os.path.join(TEST_CONFIG["CHROMIUM"], "DEPS"))
+ self.Expect([
+ URL("https://codereview.chromium.org/search",
+ "owner=author%40chromium.org&limit=30&closed=3&format=json",
+ ("{\"results\": [{\"subject\": \"different\"}]}")),
+ Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
+ Cmd("git tag", self.TAGS),
+ Cmd("git log -1 --format=%H 3.22.4", "push_hash\n"),
+ ])
+
+ result = auto_roll.AutoRoll(TEST_CONFIG, self).Run(
+ AUTO_PUSH_ARGS + ["-c", TEST_CONFIG["CHROMIUM"]])
+ self.assertEquals(0, result)
+
+ def testAutoRoll(self):
+ TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory()
+ TextToFile(self.FAKE_DEPS, os.path.join(TEST_CONFIG["CHROMIUM"], "DEPS"))
+ TEST_CONFIG["CLUSTERFUZZ_API_KEY_FILE"] = self.MakeEmptyTempFile()
+ TextToFile("fake key", TEST_CONFIG["CLUSTERFUZZ_API_KEY_FILE"])
+
+ self.Expect([
+ URL("https://codereview.chromium.org/search",
+ "owner=author%40chromium.org&limit=30&closed=3&format=json",
+ ("{\"results\": [{\"subject\": \"different\"}]}")),
+ Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
+ Cmd("git tag", self.TAGS),
+ Cmd("git log -1 --format=%H 3.22.4", "push_hash\n"),
+ ])
+
+ result = auto_roll.AutoRoll(TEST_CONFIG, self).Run(
+ AUTO_PUSH_ARGS + ["-c", TEST_CONFIG["CHROMIUM"], "--roll"])
+ self.assertEquals(0, result)
+
+ def testMergeToBranch(self):
+ TEST_CONFIG["ALREADY_MERGING_SENTINEL_FILE"] = self.MakeEmptyTempFile()
+ TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
+ self.WriteFakeVersionFile(build=5)
+ os.environ["EDITOR"] = "vi"
+ extra_patch = self.MakeEmptyTempFile()
+
+ def VerifyPatch(patch):
+ return lambda: self.assertEquals(patch,
+ FileToText(TEST_CONFIG["TEMPORARY_PATCH_FILE"]))
+
+ msg = """Version 3.22.5.1 (cherry-pick)
+
+Merged ab12345
+Merged ab23456
+Merged ab34567
+Merged ab45678
+Merged ab56789
+
+Title4
+
+Title2
+
+Title3
+
+Title1
+
+Revert "Something"
+
+BUG=123,234,345,456,567,v8:123
+LOG=N
+"""
+
+ def VerifyLand():
+ commit = FileToText(TEST_CONFIG["COMMITMSG_FILE"])
+ self.assertEquals(msg, commit)
+ version = FileToText(
+ os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE))
+ self.assertTrue(re.search(r"#define MINOR_VERSION\s+22", version))
+ self.assertTrue(re.search(r"#define BUILD_NUMBER\s+5", version))
+ self.assertTrue(re.search(r"#define PATCH_LEVEL\s+1", version))
+ self.assertTrue(re.search(r"#define IS_CANDIDATE_VERSION\s+0", version))
+
+ self.Expect([
+ Cmd("git status -s -uno", ""),
+ Cmd("git status -s -b -uno", "## some_branch\n"),
+ Cmd("git fetch", ""),
+ Cmd("git branch", " branch1\n* branch2\n"),
+ Cmd("git new-branch %s --upstream refs/remotes/origin/candidates" %
+ TEST_CONFIG["BRANCHNAME"], ""),
+ Cmd(("git log --format=%H --grep=\"Port ab12345\" "
+ "--reverse origin/master"),
+ "ab45678\nab23456"),
+ Cmd("git log -1 --format=%s ab45678", "Title1"),
+ Cmd("git log -1 --format=%s ab23456", "Title2"),
+ Cmd(("git log --format=%H --grep=\"Port ab23456\" "
+ "--reverse origin/master"),
+ ""),
+ Cmd(("git log --format=%H --grep=\"Port ab34567\" "
+ "--reverse origin/master"),
+ "ab56789"),
+ Cmd("git log -1 --format=%s ab56789", "Title3"),
+ RL("Y"), # Automatically add corresponding ports (ab34567, ab56789)?
+ # Simulate git being down which stops the script.
+ Cmd("git log -1 --format=%s ab12345", None),
+ # Restart script in the failing step.
+ Cmd("git log -1 --format=%s ab12345", "Title4"),
+ Cmd("git log -1 --format=%s ab23456", "Title2"),
+ Cmd("git log -1 --format=%s ab34567", "Title3"),
+ Cmd("git log -1 --format=%s ab45678", "Title1"),
+ Cmd("git log -1 --format=%s ab56789", "Revert \"Something\""),
+ Cmd("git log -1 ab12345", "Title4\nBUG=123\nBUG=234"),
+ Cmd("git log -1 ab23456", "Title2\n BUG = v8:123,345"),
+ Cmd("git log -1 ab34567", "Title3\nLOG=n\nBUG=567, 456"),
+ Cmd("git log -1 ab45678", "Title1\nBUG="),
+ Cmd("git log -1 ab56789", "Revert \"Something\"\nBUG=none"),
+ Cmd("git log -1 -p ab12345", "patch4"),
+ Cmd(("git apply --index --reject \"%s\"" %
+ TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
+ "", cb=VerifyPatch("patch4")),
+ Cmd("git log -1 -p ab23456", "patch2"),
+ Cmd(("git apply --index --reject \"%s\"" %
+ TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
+ "", cb=VerifyPatch("patch2")),
+ Cmd("git log -1 -p ab34567", "patch3"),
+ Cmd(("git apply --index --reject \"%s\"" %
+ TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
+ "", cb=VerifyPatch("patch3")),
+ Cmd("git log -1 -p ab45678", "patch1"),
+ Cmd(("git apply --index --reject \"%s\"" %
+ TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
+ "", cb=VerifyPatch("patch1")),
+ Cmd("git log -1 -p ab56789", "patch5\n"),
+ Cmd(("git apply --index --reject \"%s\"" %
+ TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
+ "", cb=VerifyPatch("patch5\n")),
+ Cmd("git apply --index --reject \"%s\"" % extra_patch, ""),
+ RL("Y"), # Automatically increment patch level?
+ Cmd("git commit -aF \"%s\"" % TEST_CONFIG["COMMITMSG_FILE"], ""),
+ RL("reviewer@chromium.org"), # V8 reviewer.
+ Cmd("git cl upload --send-mail -r \"reviewer@chromium.org\" "
+ "--bypass-hooks --cc \"ulan@chromium.org\"", ""),
+ Cmd("git checkout -f %s" % TEST_CONFIG["BRANCHNAME"], ""),
+ RL("LGTM"), # Enter LGTM for V8 CL.
+ Cmd("git cl presubmit", "Presubmit successfull\n"),
+ Cmd("git cl land -f --bypass-hooks", "Closing issue\n",
+ cb=VerifyLand),
+ Cmd("git fetch", ""),
+ Cmd("git log -1 --format=%H --grep=\""
+ "Version 3.22.5.1 (cherry-pick)"
+ "\" refs/remotes/origin/candidates",
+ ""),
+ Cmd("git fetch", ""),
+ Cmd("git log -1 --format=%H --grep=\""
+ "Version 3.22.5.1 (cherry-pick)"
+ "\" refs/remotes/origin/candidates",
+ "hsh_to_tag"),
+ Cmd("git tag 3.22.5.1 hsh_to_tag", ""),
+ Cmd("git push origin 3.22.5.1", ""),
+ Cmd("git checkout -f some_branch", ""),
+ Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
+ ])
+
+ # ab12345 and ab34567 are patches. ab23456 (included) and ab45678 are the
+ # MIPS ports of ab12345. ab56789 is the MIPS port of ab34567.
+ args = ["-f", "-p", extra_patch, "--branch", "candidates",
+ "ab12345", "ab23456", "ab34567"]
+
+ # The first run of the script stops because of git being down.
+ self.assertRaises(GitFailedException,
+ lambda: MergeToBranch(TEST_CONFIG, self).Run(args))
+
+ # Test that state recovery after restarting the script works.
+ args += ["-s", "4"]
+ MergeToBranch(TEST_CONFIG, self).Run(args)
+
+ def testReleases(self):
+ c_hash1_commit_log = """Update V8 to Version 4.2.71.
+
+Cr-Commit-Position: refs/heads/master@{#5678}
+"""
+ c_hash2_commit_log = """Revert something.
+
+BUG=12345
+
+Reason:
+> Some reason.
+> Cr-Commit-Position: refs/heads/master@{#12345}
+> git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12345 003-1c4
+
+Review URL: https://codereview.chromium.org/12345
+
+Cr-Commit-Position: refs/heads/master@{#4567}
+git-svn-id: svn://svn.chromium.org/chrome/trunk/src@4567 0039-1c4b
+
+"""
+ c_hash3_commit_log = """Simple.
+
+git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3456 0039-1c4b
+
+"""
+ c_hash_234_commit_log = """Version 3.3.1.1 (cherry-pick).
+
+Merged abc12.
+
+Review URL: fake.com
+
+Cr-Commit-Position: refs/heads/candidates@{#234}
+"""
+ c_hash_123_commit_log = """Version 3.3.1.0
+
+git-svn-id: googlecode@123 0039-1c4b
+"""
+ c_hash_345_commit_log = """Version 3.4.0.
+
+Cr-Commit-Position: refs/heads/candidates@{#345}
+"""
+ c_hash_456_commit_log = """Version 4.2.71.
+
+Cr-Commit-Position: refs/heads/4.2.71@{#1}
+"""
+
+ json_output = self.MakeEmptyTempFile()
+ csv_output = self.MakeEmptyTempFile()
+ self.WriteFakeVersionFile()
+
+ TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory()
+ chrome_dir = TEST_CONFIG["CHROMIUM"]
+ chrome_v8_dir = os.path.join(chrome_dir, "v8")
+ os.makedirs(chrome_v8_dir)
+ def WriteDEPS(revision):
+ TextToFile("Line\n \"v8_revision\": \"%s\",\n line\n" % revision,
+ os.path.join(chrome_dir, "DEPS"))
+ WriteDEPS(567)
+
+ def ResetVersion(major, minor, build, patch=0):
+ return lambda: self.WriteFakeVersionFile(major=major,
+ minor=minor,
+ build=build,
+ patch=patch)
+
+ def ResetDEPS(revision):
+ return lambda: WriteDEPS(revision)
+
+ self.Expect([
+ Cmd("git status -s -uno", ""),
+ Cmd("git status -s -b -uno", "## some_branch\n"),
+ Cmd("git fetch", ""),
+ Cmd("git branch", " branch1\n* branch2\n"),
+ Cmd("git new-branch %s" % TEST_CONFIG["BRANCHNAME"], ""),
+ Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
+ Cmd("git rev-list --max-age=395200 --tags",
+ "bad_tag\nhash_234\nhash_123\nhash_345\nhash_456\n"),
+ Cmd("git describe --tags bad_tag", "3.23.42-1-deadbeef"),
+ Cmd("git describe --tags hash_234", "3.3.1.1"),
+ Cmd("git describe --tags hash_123", "3.21.2"),
+ Cmd("git describe --tags hash_345", "3.22.3"),
+ Cmd("git describe --tags hash_456", "4.2.71"),
+ Cmd("git diff --name-only hash_234 hash_234^", VERSION_FILE),
+ Cmd("git checkout -f hash_234 -- %s" % VERSION_FILE, "",
+ cb=ResetVersion(3, 3, 1, 1)),
+ Cmd("git branch -r --contains hash_234", " branch-heads/3.3\n"),
+ Cmd("git log -1 --format=%B hash_234", c_hash_234_commit_log),
+ Cmd("git log -1 --format=%s hash_234", ""),
+ Cmd("git log -1 --format=%B hash_234", c_hash_234_commit_log),
+ Cmd("git log -1 --format=%ci hash_234", "18:15"),
+ Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
+ cb=ResetVersion(3, 22, 5)),
+ Cmd("git diff --name-only hash_123 hash_123^", VERSION_FILE),
+ Cmd("git checkout -f hash_123 -- %s" % VERSION_FILE, "",
+ cb=ResetVersion(3, 21, 2)),
+ Cmd("git branch -r --contains hash_123", " branch-heads/3.21\n"),
+ Cmd("git log -1 --format=%B hash_123", c_hash_123_commit_log),
+ Cmd("git log -1 --format=%s hash_123", ""),
+ Cmd("git log -1 --format=%B hash_123", c_hash_123_commit_log),
+ Cmd("git log -1 --format=%ci hash_123", "03:15"),
+ Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
+ cb=ResetVersion(3, 22, 5)),
+ Cmd("git diff --name-only hash_345 hash_345^", VERSION_FILE),
+ Cmd("git checkout -f hash_345 -- %s" % VERSION_FILE, "",
+ cb=ResetVersion(3, 22, 3)),
+ Cmd("git branch -r --contains hash_345", " origin/candidates\n"),
+ Cmd("git log -1 --format=%B hash_345", c_hash_345_commit_log),
+ Cmd("git log -1 --format=%s hash_345", ""),
+ Cmd("git log -1 --format=%B hash_345", c_hash_345_commit_log),
+ Cmd("git log -1 --format=%ci hash_345", ""),
+ Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
+ cb=ResetVersion(3, 22, 5)),
+ Cmd("git diff --name-only hash_456 hash_456^", VERSION_FILE),
+ Cmd("git checkout -f hash_456 -- %s" % VERSION_FILE, "",
+ cb=ResetVersion(4, 2, 71)),
+ Cmd("git branch -r --contains hash_456", " origin/4.2.71\n"),
+ Cmd("git log -1 --format=%B hash_456", c_hash_456_commit_log),
+ Cmd("git log -1 --format=%H 4.2.71", "hash_456"),
+ Cmd("git log -1 --format=%s hash_456", "Version 4.2.71"),
+ Cmd("git log -1 --format=%H hash_456^", "master_456"),
+ Cmd("git log -1 --format=%B master_456",
+ "Cr-Commit-Position: refs/heads/master@{#456}"),
+ Cmd("git log -1 --format=%B hash_456", c_hash_456_commit_log),
+ Cmd("git log -1 --format=%ci hash_456", "02:15"),
+ Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
+ cb=ResetVersion(3, 22, 5)),
+ Cmd("git status -s -uno", "", cwd=chrome_dir),
+ Cmd("git checkout -f master", "", cwd=chrome_dir),
+ Cmd("git pull", "", cwd=chrome_dir),
+ Cmd("git new-branch %s" % TEST_CONFIG["BRANCHNAME"], "",
+ cwd=chrome_dir),
+ Cmd("git fetch origin", "", cwd=chrome_v8_dir),
+ Cmd("git log --format=%H --grep=\"V8\"",
+ "c_hash0\nc_hash1\nc_hash2\nc_hash3\n",
+ cwd=chrome_dir),
+ Cmd("git diff --name-only c_hash0 c_hash0^", "", cwd=chrome_dir),
+ Cmd("git diff --name-only c_hash1 c_hash1^", "DEPS", cwd=chrome_dir),
+ Cmd("git checkout -f c_hash1 -- DEPS", "",
+ cb=ResetDEPS("hash_456"),
+ cwd=chrome_dir),
+ Cmd("git log -1 --format=%B c_hash1", c_hash1_commit_log,
+ cwd=chrome_dir),
+ Cmd("git diff --name-only c_hash2 c_hash2^", "DEPS", cwd=chrome_dir),
+ Cmd("git checkout -f c_hash2 -- DEPS", "",
+ cb=ResetDEPS("hash_345"),
+ cwd=chrome_dir),
+ Cmd("git log -1 --format=%B c_hash2", c_hash2_commit_log,
+ cwd=chrome_dir),
+ Cmd("git diff --name-only c_hash3 c_hash3^", "DEPS", cwd=chrome_dir),
+ Cmd("git checkout -f c_hash3 -- DEPS", "", cb=ResetDEPS("deadbeef"),
+ cwd=chrome_dir),
+ Cmd("git log -1 --format=%B c_hash3", c_hash3_commit_log,
+ cwd=chrome_dir),
+ Cmd("git checkout -f HEAD -- DEPS", "", cb=ResetDEPS("hash_567"),
+ cwd=chrome_dir),
+ Cmd("git branch -r", " weird/123\n branch-heads/7\n", cwd=chrome_dir),
+ Cmd("git checkout -f branch-heads/7 -- DEPS", "",
+ cb=ResetDEPS("hash_345"),
+ cwd=chrome_dir),
+ Cmd("git checkout -f HEAD -- DEPS", "", cb=ResetDEPS("hash_567"),
+ cwd=chrome_dir),
+ Cmd("git checkout -f master", "", cwd=chrome_dir),
+ Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], "", cwd=chrome_dir),
+ Cmd("git checkout -f some_branch", ""),
+ Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
+ ])
+
+ args = ["-c", TEST_CONFIG["CHROMIUM"],
+ "--json", json_output,
+ "--csv", csv_output,
+ "--max-releases", "1"]
+ Releases(TEST_CONFIG, self).Run(args)
+
+ # Check expected output.
+ csv = ("4.2.71,4.2.71,1,5678,\r\n"
+ "3.22.3,candidates,345,4567:5677,\r\n"
+ "3.21.2,3.21,123,,\r\n"
+ "3.3.1.1,3.3,234,,abc12\r\n")
+ self.assertEquals(csv, FileToText(csv_output))
+
+ expected_json = [
+ {
+ "revision": "1",
+ "revision_git": "hash_456",
+ "master_position": "456",
+ "master_hash": "master_456",
+ "patches_merged": "",
+ "version": "4.2.71",
+ "chromium_revision": "5678",
+ "branch": "4.2.71",
+ "review_link": "",
+ "date": "02:15",
+ "chromium_branch": "",
+ # FIXME(machenbach): Fix revisions link for git.
+ "revision_link": "https://code.google.com/p/v8/source/detail?r=1",
+ },
+ {
+ "revision": "345",
+ "revision_git": "hash_345",
+ "master_position": "",
+ "master_hash": "",
+ "patches_merged": "",
+ "version": "3.22.3",
+ "chromium_revision": "4567:5677",
+ "branch": "candidates",
+ "review_link": "",
+ "date": "",
+ "chromium_branch": "7",
+ "revision_link": "https://code.google.com/p/v8/source/detail?r=345",
+ },
+ {
+ "revision": "123",
+ "revision_git": "hash_123",
+ "patches_merged": "",
+ "master_position": "",
+ "master_hash": "",
+ "version": "3.21.2",
+ "chromium_revision": "",
+ "branch": "3.21",
+ "review_link": "",
+ "date": "03:15",
+ "chromium_branch": "",
+ "revision_link": "https://code.google.com/p/v8/source/detail?r=123",
+ },
+ {
+ "revision": "234",
+ "revision_git": "hash_234",
+ "patches_merged": "abc12",
+ "master_position": "",
+ "master_hash": "",
+ "version": "3.3.1.1",
+ "chromium_revision": "",
+ "branch": "3.3",
+ "review_link": "fake.com",
+ "date": "18:15",
+ "chromium_branch": "",
+ "revision_link": "https://code.google.com/p/v8/source/detail?r=234",
+ },
+ ]
+ self.assertEquals(expected_json, json.loads(FileToText(json_output)))
+
+
+class SystemTest(unittest.TestCase):
+ def testReload(self):
+ options = ScriptsBase(
+ TEST_CONFIG, DEFAULT_SIDE_EFFECT_HANDLER, {}).MakeOptions([])
+ step = MakeStep(step_class=PrepareChangeLog, number=0, state={}, config={},
+ options=options,
+ side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER)
+ body = step.Reload(
+"""------------------------------------------------------------------------
+r17997 | machenbach@chromium.org | 2013-11-22 11:04:04 +0100 (...) | 6 lines
+
+Prepare push to trunk. Now working on version 3.23.11.
+
+R=danno@chromium.org
+
+Review URL: https://codereview.chromium.org/83173002
+
+------------------------------------------------------------------------""")
+ self.assertEquals(
+"""Prepare push to trunk. Now working on version 3.23.11.
+
+R=danno@chromium.org
+
+Committed: https://code.google.com/p/v8/source/detail?r=17997""", body)