v8/tools/push-to-trunk/test_scripts.py
machenbach@chromium.org a77dfb1ac6 Refactoring: Remove more legacy from release scripts.
- Remove an unused feature that allowed to check for required
  data before each script step.
- Use a relative path to the version file. In the production
  environment, this will point to the cwd/version_file, while
  in the test environment it is fake_cwd/version_file.

TBR=tandrii@chromium.org

Review URL: https://codereview.chromium.org/591783003

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24140 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2014-09-23 09:35:49 +00:00

1550 lines
60 KiB
Python

#!/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 CheckLastPush
from auto_push import SETTINGS_LOCATION
import auto_roll
from auto_roll import CLUSTERFUZZ_API_KEY_FILE
import common_includes
from common_includes import *
import merge_to_branch
from merge_to_branch import *
import push_to_trunk
from push_to_trunk import *
import chromium_roll
from chromium_roll import CHROMIUM
from chromium_roll import ChromiumRoll
import releases
from releases import Releases
import bump_up_version
from bump_up_version import BumpUpVersion
from bump_up_version import LastChangeBailout
from bump_up_version import LKGRVersionUpToDateBailout
from auto_tag import AutoTag
TEST_CONFIG = {
"DEFAULT_CWD": None,
BRANCHNAME: "test-prepare-push",
TRUNKBRANCH: "test-trunk-push",
PERSISTFILE_BASENAME: "/tmp/test-v8-push-to-trunk-tempfile",
CHANGELOG_FILE: None,
CHANGELOG_ENTRY_FILE: "/tmp/test-v8-push-to-trunk-tempfile-changelog-entry",
PATCH_FILE: "/tmp/test-v8-push-to-trunk-tempfile-patch",
COMMITMSG_FILE: "/tmp/test-v8-push-to-trunk-tempfile-commitmsg",
CHROMIUM: "/tmp/test-v8-push-to-trunk-tempfile-chromium",
SETTINGS_LOCATION: None,
ALREADY_MERGING_SENTINEL_FILE:
"/tmp/test-merge-to-branch-tempfile-already-merging",
COMMIT_HASHES_FILE: "/tmp/test-merge-to-branch-tempfile-PATCH_COMMIT_HASHES",
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, 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 3\n")
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=PushToTrunk, 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 "100000"
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 svn 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 svn 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 svn 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 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(PushToTrunk, 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_bleeding_edge"] = "1234"
self._state["push_hash"] = "push_hash"
self._state["version"] = "3.22.5"
self.RunStep(PushToTrunk, 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(PushToTrunk, EditChangeLog)
self.assertEquals("New\n Lines",
FileToText(TEST_CONFIG[CHANGELOG_ENTRY_FILE]))
# Version on trunk: 3.22.4.0. Version on master (bleeding_edge): 3.22.6.
# Make sure that the increment is 3.22.7.0.
def testIncrementVersion(self):
self.WriteFakeVersionFile()
self._state["last_push_trunk"] = "hash1"
self._state["latest_build"] = "6"
self._state["latest_version"] = "3.22.6.0"
self.Expect([
Cmd("git checkout -f hash1 -- src/version.cc", ""),
Cmd("git checkout -f svn/bleeding_edge -- src/version.cc",
"", cb=lambda: self.WriteFakeVersionFile(22, 6)),
RL("Y"), # Increment build number.
])
self.RunStep(PushToTrunk, 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 svn/trunk hash1", "patch content"),
Cmd("git svn find-rev hash1", "123455\n"),
])
self._state["push_hash"] = "hash1"
self._state["date"] = "1999-11-11"
self.RunStep(PushToTrunk, 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 bleeding_edge revision r123455)
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 bleeding_edge revision r123455)
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 _PushToTrunk(self, force=False, manual=False):
TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
# The version file on bleeding edge has build level 5, while the version
# file from trunk has build level 4.
self.WriteFakeVersionFile(build=5)
TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile()
TEST_CONFIG[CHANGELOG_FILE] = self.MakeEmptyTempFile()
bleeding_edge_change_log = "2014-03-17: Sentinel\n"
TextToFile(bleeding_edge_change_log, TEST_CONFIG[CHANGELOG_FILE])
os.environ["EDITOR"] = "vi"
def ResetChangeLog():
"""On 'git co -b new_branch svn/trunk', and 'git checkout -- ChangeLog',
the ChangLog will be reset to its content on trunk."""
trunk_change_log = """1999-04-05: Version 3.22.4
Performance and stability improvements on all platforms.\n"""
TextToFile(trunk_change_log, TEST_CONFIG[CHANGELOG_FILE])
def ResetToTrunk():
ResetChangeLog()
self.WriteFakeVersionFile()
def CheckSVNCommit():
commit = FileToText(TEST_CONFIG[COMMITMSG_FILE])
self.assertEquals(
"""Version 3.22.5 (based on bleeding_edge revision r123455)
Log text 1 (issue 321).
Performance and stability improvements on all platforms.""", 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 trunk branch got correctly modified.
change_log = FileToText(TEST_CONFIG[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 svn fetch", ""),
Cmd("git branch", " branch1\n* branch2\n"),
Cmd("git branch", " branch1\n* branch2\n"),
Cmd("git checkout -b %s svn/bleeding_edge" % TEST_CONFIG[BRANCHNAME],
""),
Cmd("git svn find-rev r123455", "push_hash\n"),
Cmd(("git log -1 --format=%H --grep="
"\"^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]* (based\" "
"svn/trunk"), "hash2\n"),
Cmd("git log -1 hash2", "Log message\n"),
]
if manual:
expectations.append(RL("Y")) # Confirm last push.
expectations += [
Cmd("git log -1 --format=%s hash2",
"Version 3.4.5 (based on bleeding_edge revision r1234)\n"),
Cmd("git svn find-rev r1234", "hash3\n"),
Cmd("git checkout -f svn/bleeding_edge -- src/version.cc",
"", cb=self.WriteFakeVersionFile),
Cmd("git checkout -f hash2 -- src/version.cc", "",
cb=self.WriteFakeVersionFile),
]
if manual:
expectations.append(RL("")) # Increment build number.
expectations += [
Cmd("git log --format=%H hash3..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 svn fetch", "fetch result\n"),
Cmd("git checkout -f svn/bleeding_edge", ""),
Cmd("git diff svn/trunk push_hash", "patch content\n"),
Cmd("git svn find-rev push_hash", "123455\n"),
Cmd("git checkout -b %s svn/trunk" % TEST_CONFIG[TRUNKBRANCH], "",
cb=ResetToTrunk),
Cmd("git apply --index --reject \"%s\"" % TEST_CONFIG[PATCH_FILE], ""),
Cmd("git checkout -f svn/trunk -- %s" % TEST_CONFIG[CHANGELOG_FILE], "",
cb=ResetChangeLog),
Cmd("git checkout -f svn/trunk -- src/version.cc", "",
cb=self.WriteFakeVersionFile),
Cmd("git commit -aF \"%s\"" % TEST_CONFIG[COMMITMSG_FILE], "",
cb=CheckSVNCommit),
]
if manual:
expectations.append(RL("Y")) # Sanity check.
expectations += [
Cmd("git svn dcommit 2>&1",
"Some output\nCommitted r123456\nSome output\n"),
Cmd("git svn tag 3.22.5 -m \"Tagging version 3.22.5\"", ""),
Cmd("git checkout -f some_branch", ""),
Cmd("git branch -D %s" % TEST_CONFIG[BRANCHNAME], ""),
Cmd("git branch -D %s" % TEST_CONFIG[TRUNKBRANCH], ""),
]
self.Expect(expectations)
args = ["-a", "author@chromium.org", "--revision", "123455"]
if force: args.append("-f")
if manual: args.append("-m")
else: args += ["-r", "reviewer@chromium.org"]
PushToTrunk(TEST_CONFIG, self).Run(args)
cl = FileToText(TEST_CONFIG[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 the bleeding edge branch is mocked
# out.
def testPushToTrunkManual(self):
self._PushToTrunk(manual=True)
def testPushToTrunkSemiAutomatic(self):
self._PushToTrunk()
def testPushToTrunkForced(self):
self._PushToTrunk(force=True)
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 log -1 --format=%H --grep="
"\"^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]*\" "
"origin/master"), "push_hash\n"),
Cmd("git log -1 --format=%B push_hash", self.C_V8_22624_LOG),
Cmd("git log -1 --format=%s push_hash",
"Version 3.22.5 (based on bleeding_edge revision r22622)\n"),
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 checkout -b v8-roll-22624", "", cwd=chrome_dir),
Cmd("roll-dep v8 22624", "rolled", cb=WriteDeps, cwd=chrome_dir),
Cmd(("git commit -am \"Update V8 to version 3.22.5 "
"(based on bleeding_edge revision r22622).\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"]
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 log -1 --format=%H --grep="
"\"^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]* (based\" "
"svn/trunk"), "hash2\n"),
Cmd("git log -1 --format=%s hash2",
"Version 3.4.5 (based on bleeding_edge revision r99)\n"),
])
self._state["lkgr"] = "101"
self.assertRaises(Exception, lambda: self.RunStep(auto_push.AutoPush,
CheckLastPush,
AUTO_PUSH_ARGS))
def testAutoPush(self):
TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
TEST_CONFIG[SETTINGS_LOCATION] = "~/.doesnotexist"
self.Expect([
Cmd("git status -s -uno", ""),
Cmd("git status -s -b -uno", "## some_branch\n"),
Cmd("git svn fetch", ""),
URL("https://v8-status.appspot.com/current?format=json",
"{\"message\": \"Tree is throttled\"}"),
URL("https://v8-status.appspot.com/lkgr", Exception("Network problem")),
URL("https://v8-status.appspot.com/lkgr", "100"),
Cmd(("git log -1 --format=%H --grep=\""
"^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]* (based\""
" svn/trunk"), "push_hash\n"),
Cmd("git log -1 --format=%s push_hash",
"Version 3.4.5 (based on bleeding_edge revision r79)\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("100", state["lkgr"])
def testAutoPushStoppedBySettings(self):
TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
TEST_CONFIG[SETTINGS_LOCATION] = self.MakeEmptyTempFile()
TextToFile("{\"enable_auto_push\": false}", TEST_CONFIG[SETTINGS_LOCATION])
self.Expect([
Cmd("git status -s -uno", ""),
Cmd("git status -s -b -uno", "## some_branch\n"),
Cmd("git svn fetch", ""),
])
def RunAutoPush():
auto_push.AutoPush(TEST_CONFIG, self).Run(AUTO_PUSH_ARGS)
self.assertRaises(Exception, RunAutoPush)
def testAutoPushStoppedByTreeStatus(self):
TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
TEST_CONFIG[SETTINGS_LOCATION] = "~/.doesnotexist"
self.Expect([
Cmd("git status -s -uno", ""),
Cmd("git status -s -b -uno", "## some_branch\n"),
Cmd("git svn fetch", ""),
URL("https://v8-status.appspot.com/current?format=json",
"{\"message\": \"Tree is throttled (no push)\"}"),
])
def RunAutoPush():
auto_push.AutoPush(TEST_CONFIG, self).Run(AUTO_PUSH_ARGS)
self.assertRaises(Exception, RunAutoPush)
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 log -1 --format=%H --grep="
"\"^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]*\" "
"origin/master"), "push_hash\n"),
Cmd("git log -1 --format=%B push_hash", self.C_V8_22624_LOG),
Cmd("git log -1 --format=%B abcd123455", self.C_V8_123455_LOG),
])
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 log -1 --format=%H --grep="
"\"^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]*\" "
"origin/master"), "push_hash\n"),
Cmd("git log -1 --format=%B push_hash", self.C_V8_123456_LOG),
Cmd("git log -1 --format=%B abcd123455", self.C_V8_123455_LOG),
])
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 (merged r12345, r23456, r34567, r45678, r56789)
Title4
Title2
Title3
Title1
Revert "Something"
BUG=123,234,345,456,567,v8:123
LOG=N
"""
def VerifySVNCommit():
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 svn fetch", ""),
Cmd("git branch", " branch1\n* branch2\n"),
Cmd("git checkout -b %s svn/trunk" % TEST_CONFIG[BRANCHNAME], ""),
Cmd(("git log --format=%H --grep=\"Port r12345\" "
"--reverse svn/bleeding_edge"),
"hash1\nhash2"),
Cmd("git svn find-rev hash1 svn/bleeding_edge", "45678"),
Cmd("git log -1 --format=%s hash1", "Title1"),
Cmd("git svn find-rev hash2 svn/bleeding_edge", "23456"),
Cmd("git log -1 --format=%s hash2", "Title2"),
Cmd(("git log --format=%H --grep=\"Port r23456\" "
"--reverse svn/bleeding_edge"),
""),
Cmd(("git log --format=%H --grep=\"Port r34567\" "
"--reverse svn/bleeding_edge"),
"hash3"),
Cmd("git svn find-rev hash3 svn/bleeding_edge", "56789"),
Cmd("git log -1 --format=%s hash3", "Title3"),
RL("Y"), # Automatically add corresponding ports (34567, 56789)?
Cmd("git svn find-rev r12345 svn/bleeding_edge", "hash4"),
# Simulate svn being down which stops the script.
Cmd("git svn find-rev r23456 svn/bleeding_edge", None),
# Restart script in the failing step.
Cmd("git svn find-rev r12345 svn/bleeding_edge", "hash4"),
Cmd("git svn find-rev r23456 svn/bleeding_edge", "hash2"),
Cmd("git svn find-rev r34567 svn/bleeding_edge", "hash3"),
Cmd("git svn find-rev r45678 svn/bleeding_edge", "hash1"),
Cmd("git svn find-rev r56789 svn/bleeding_edge", "hash5"),
Cmd("git log -1 --format=%s hash4", "Title4"),
Cmd("git log -1 --format=%s hash2", "Title2"),
Cmd("git log -1 --format=%s hash3", "Title3"),
Cmd("git log -1 --format=%s hash1", "Title1"),
Cmd("git log -1 --format=%s hash5", "Revert \"Something\""),
Cmd("git log -1 hash4", "Title4\nBUG=123\nBUG=234"),
Cmd("git log -1 hash2", "Title2\n BUG = v8:123,345"),
Cmd("git log -1 hash3", "Title3\nLOG=n\nBUG=567, 456"),
Cmd("git log -1 hash1", "Title1\nBUG="),
Cmd("git log -1 hash5", "Revert \"Something\"\nBUG=none"),
Cmd("git log -1 -p hash4", "patch4"),
Cmd(("git apply --index --reject \"%s\"" %
TEST_CONFIG[TEMPORARY_PATCH_FILE]),
"", cb=VerifyPatch("patch4")),
Cmd("git log -1 -p hash2", "patch2"),
Cmd(("git apply --index --reject \"%s\"" %
TEST_CONFIG[TEMPORARY_PATCH_FILE]),
"", cb=VerifyPatch("patch2")),
Cmd("git log -1 -p hash3", "patch3"),
Cmd(("git apply --index --reject \"%s\"" %
TEST_CONFIG[TEMPORARY_PATCH_FILE]),
"", cb=VerifyPatch("patch3")),
Cmd("git log -1 -p hash1", "patch1"),
Cmd(("git apply --index --reject \"%s\"" %
TEST_CONFIG[TEMPORARY_PATCH_FILE]),
"", cb=VerifyPatch("patch1")),
Cmd("git log -1 -p hash5", "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", ""),
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 dcommit -f --bypass-hooks", "Closing issue\n",
cb=VerifySVNCommit),
Cmd("git svn fetch", ""),
Cmd(("git log -1 --format=%%H --grep=\"%s\" svn/trunk"
% msg.replace("\"", "\\\"")), "hash6"),
Cmd("git svn find-rev hash6", "1324"),
Cmd(("svn copy -r 1324 https://v8.googlecode.com/svn/trunk "
"https://v8.googlecode.com/svn/tags/3.22.5.1 -m "
"\"Tagging version 3.22.5.1\""), ""),
Cmd("git checkout -f some_branch", ""),
Cmd("git branch -D %s" % TEST_CONFIG[BRANCHNAME], ""),
])
# r12345 and r34567 are patches. r23456 (included) and r45678 are the MIPS
# ports of r12345. r56789 is the MIPS port of r34567.
args = ["-f", "-p", extra_patch, "--branch", "trunk", "12345", "23456",
"34567"]
# The first run of the script stops because of the svn being down.
self.assertRaises(GitFailedException,
lambda: MergeToBranch(TEST_CONFIG, self).Run(args))
# Test that state recovery after restarting the script works.
args += ["-s", "3"]
MergeToBranch(TEST_CONFIG, self).Run(args)
def testReleases(self):
tag_response_text = """
------------------------------------------------------------------------
r22631 | author1@chromium.org | 2014-07-28 02:05:29 +0200 (Mon, 28 Jul 2014)
Changed paths:
A /tags/3.28.43 (from /trunk:22630)
Tagging version 3.28.43
------------------------------------------------------------------------
r22629 | author2@chromium.org | 2014-07-26 05:09:29 +0200 (Sat, 26 Jul 2014)
Changed paths:
A /tags/3.28.41 (from /branches/bleeding_edge:22626)
Tagging version 3.28.41
------------------------------------------------------------------------
r22556 | author3@chromium.org | 2014-07-23 13:31:59 +0200 (Wed, 23 Jul 2014)
Changed paths:
A /tags/3.27.34.7 (from /branches/3.27:22555)
Tagging version 3.27.34.7
------------------------------------------------------------------------
r22627 | author4@chromium.org | 2014-07-26 01:39:15 +0200 (Sat, 26 Jul 2014)
Changed paths:
A /tags/3.28.40 (from /branches/bleeding_edge:22624)
Tagging version 3.28.40
------------------------------------------------------------------------
"""
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
"""
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(minor, build, patch=0):
return lambda: self.WriteFakeVersionFile(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 svn fetch", ""),
Cmd("git branch", " branch1\n* branch2\n"),
Cmd("git checkout -b %s" % TEST_CONFIG[BRANCHNAME], ""),
Cmd("git branch -r", " svn/3.21\n svn/3.3\n"),
Cmd("git reset --hard svn/3.3", ""),
Cmd("git log --format=%H", "hash1\nhash2"),
Cmd("git diff --name-only hash1 hash1^", ""),
Cmd("git diff --name-only hash2 hash2^", VERSION_FILE),
Cmd("git checkout -f hash2 -- %s" % VERSION_FILE, "",
cb=ResetVersion(3, 1, 1)),
Cmd("git log -1 --format=%B hash2",
"Version 3.3.1.1 (merged 12)\n\nReview URL: fake.com\n"),
Cmd("git log -1 --format=%s hash2", ""),
Cmd("git svn find-rev hash2", "234"),
Cmd("git log -1 --format=%ci hash2", "18:15"),
Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
cb=ResetVersion(22, 5)),
Cmd("git reset --hard svn/3.21", ""),
Cmd("git log --format=%H", "hash3\nhash4\nhash5\n"),
Cmd("git diff --name-only hash3 hash3^", VERSION_FILE),
Cmd("git checkout -f hash3 -- %s" % VERSION_FILE, "",
cb=ResetVersion(21, 2)),
Cmd("git log -1 --format=%B hash3", ""),
Cmd("git log -1 --format=%s hash3", ""),
Cmd("git svn find-rev hash3", "123"),
Cmd("git log -1 --format=%ci hash3", "03:15"),
Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
cb=ResetVersion(22, 5)),
Cmd("git reset --hard svn/trunk", ""),
Cmd("git log --format=%H", "hash6\n"),
Cmd("git diff --name-only hash6 hash6^", VERSION_FILE),
Cmd("git checkout -f hash6 -- %s" % VERSION_FILE, "",
cb=ResetVersion(22, 3)),
Cmd("git log -1 --format=%B hash6", ""),
Cmd("git log -1 --format=%s hash6", ""),
Cmd("git svn find-rev hash6", "345"),
Cmd("git log -1 --format=%ci hash6", ""),
Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
cb=ResetVersion(22, 5)),
Cmd("git reset --hard svn/bleeding_edge", ""),
Cmd("svn log https://v8.googlecode.com/svn/tags -v --limit 20",
tag_response_text),
Cmd("git svn find-rev r22626", "hash_22626"),
Cmd("git svn find-rev hash_22626", "22626"),
Cmd("git log -1 --format=%ci hash_22626", "01:23"),
Cmd("git svn find-rev r22624", "hash_22624"),
Cmd("git svn find-rev hash_22624", "22624"),
Cmd("git log -1 --format=%ci hash_22624", "02:34"),
Cmd("git status -s -uno", "", cwd=chrome_dir),
Cmd("git checkout -f master", "", cwd=chrome_dir),
Cmd("git pull", "", cwd=chrome_dir),
Cmd("git checkout -b %s" % TEST_CONFIG[BRANCHNAME], "", cwd=chrome_dir),
Cmd("git fetch origin", "", cwd=chrome_v8_dir),
Cmd("git log --format=%H --grep=\"V8\"", "c_hash1\nc_hash2\nc_hash3\n",
cwd=chrome_dir),
Cmd("git diff --name-only c_hash1 c_hash1^", "", 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("0123456789012345678901234567890123456789"),
cwd=chrome_dir),
Cmd("git log -1 --format=%B c_hash2", c_hash2_commit_log,
cwd=chrome_dir),
Cmd("git rev-list -n 1 0123456789012345678901234567890123456789",
"0123456789012345678901234567890123456789", cwd=chrome_v8_dir),
Cmd("git log -1 --format=%B 0123456789012345678901234567890123456789",
self.C_V8_22624_LOG, cwd=chrome_v8_dir),
Cmd("git diff --name-only c_hash3 c_hash3^", "DEPS", cwd=chrome_dir),
Cmd("git checkout -f c_hash3 -- DEPS", "", cb=ResetDEPS(345),
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(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(345),
cwd=chrome_dir),
Cmd("git checkout -f HEAD -- DEPS", "", cb=ResetDEPS(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 = ("3.28.41,bleeding_edge,22626,,\r\n"
"3.28.40,bleeding_edge,22624,4567,\r\n"
"3.22.3,trunk,345,3456:4566,\r\n"
"3.21.2,3.21,123,,\r\n"
"3.3.1.1,3.3,234,,12\r\n")
self.assertEquals(csv, FileToText(csv_output))
expected_json = [
{"bleeding_edge": "22626", "patches_merged": "", "version": "3.28.41",
"chromium_revision": "", "branch": "bleeding_edge", "revision": "22626",
"review_link": "", "date": "01:23", "chromium_branch": "",
"revision_link": "https://code.google.com/p/v8/source/detail?r=22626"},
{"bleeding_edge": "22624", "patches_merged": "", "version": "3.28.40",
"chromium_revision": "4567", "branch": "bleeding_edge",
"revision": "22624", "review_link": "", "date": "02:34",
"chromium_branch": "",
"revision_link": "https://code.google.com/p/v8/source/detail?r=22624"},
{"bleeding_edge": "", "patches_merged": "", "version": "3.22.3",
"chromium_revision": "3456:4566", "branch": "trunk", "revision": "345",
"review_link": "", "date": "", "chromium_branch": "7",
"revision_link": "https://code.google.com/p/v8/source/detail?r=345"},
{"patches_merged": "", "bleeding_edge": "", "version": "3.21.2",
"chromium_revision": "", "branch": "3.21", "revision": "123",
"review_link": "", "date": "03:15", "chromium_branch": "",
"revision_link": "https://code.google.com/p/v8/source/detail?r=123"},
{"patches_merged": "12", "bleeding_edge": "", "version": "3.3.1.1",
"chromium_revision": "", "branch": "3.3", "revision": "234",
"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)))
def _bumpUpVersion(self):
self.WriteFakeVersionFile()
def ResetVersion(minor, build, patch=0):
return lambda: self.WriteFakeVersionFile(minor=minor,
build=build,
patch=patch)
return [
Cmd("git status -s -uno", ""),
Cmd("git checkout -f bleeding_edge", "", cb=ResetVersion(11, 4)),
Cmd("git pull", ""),
Cmd("git branch", ""),
Cmd("git checkout -f bleeding_edge", ""),
Cmd("git log -1 --format=%H", "latest_hash"),
Cmd("git diff --name-only latest_hash latest_hash^", ""),
URL("https://v8-status.appspot.com/lkgr", "12345"),
Cmd("git checkout -f bleeding_edge", ""),
Cmd(("git log --format=%H --grep="
"\"^git-svn-id: [^@]*@12345 [A-Za-z0-9-]*$\""),
"lkgr_hash"),
Cmd("git checkout -b auto-bump-up-version lkgr_hash", ""),
Cmd("git checkout -f bleeding_edge", ""),
Cmd("git branch", ""),
Cmd("git diff --name-only lkgr_hash lkgr_hash^", ""),
Cmd("git checkout -f master", "", cb=ResetVersion(11, 5)),
Cmd("git pull", ""),
URL("https://v8-status.appspot.com/current?format=json",
"{\"message\": \"Tree is open\"}"),
Cmd("git checkout -b auto-bump-up-version bleeding_edge", "",
cb=ResetVersion(11, 4)),
Cmd("git commit -am \"[Auto-roll] Bump up version to 3.11.6.0\n\n"
"TBR=author@chromium.org\" "
"--author \"author@chromium.org <author@chromium.org>\"", ""),
]
def testBumpUpVersionGit(self):
expectations = self._bumpUpVersion()
expectations += [
Cmd("git cl upload --send-mail --email \"author@chromium.org\" -f "
"--bypass-hooks", ""),
Cmd("git cl dcommit -f --bypass-hooks", ""),
Cmd("git checkout -f bleeding_edge", ""),
Cmd("git branch", "auto-bump-up-version\n* bleeding_edge"),
Cmd("git branch -D auto-bump-up-version", ""),
]
self.Expect(expectations)
BumpUpVersion(TEST_CONFIG, self).Run(["-a", "author@chromium.org"])
def testBumpUpVersionSvn(self):
expectations = self._bumpUpVersion()
expectations += [
Cmd("git diff HEAD^ HEAD", "patch content"),
Cmd("svn update", "", cwd="[SVN_ROOT]"),
Cmd("svn status", "", cwd="[SVN_ROOT]"),
Cmd("patch -d branches/bleeding_edge -p1 -i %s" %
TEST_CONFIG[PATCH_FILE], "Applied patch...", cwd="[SVN_ROOT]"),
Cmd("svn commit --non-interactive --username=author@chromium.org "
"--config-dir=[CONFIG_DIR] "
"-m \"[Auto-roll] Bump up version to 3.11.6.0\"",
"", cwd="[SVN_ROOT]"),
Cmd("git checkout -f bleeding_edge", ""),
Cmd("git branch", "auto-bump-up-version\n* bleeding_edge"),
Cmd("git branch -D auto-bump-up-version", ""),
]
self.Expect(expectations)
BumpUpVersion(TEST_CONFIG, self).Run(
["-a", "author@chromium.org",
"--svn", "[SVN_ROOT]",
"--svn-config", "[CONFIG_DIR]"])
def testAutoTag(self):
self.WriteFakeVersionFile()
def ResetVersion(minor, build, patch=0):
return lambda: self.WriteFakeVersionFile(minor=minor,
build=build,
patch=patch)
self.Expect([
Cmd("git status -s -uno", ""),
Cmd("git status -s -b -uno", "## some_branch\n"),
Cmd("git svn fetch", ""),
Cmd("git branch", " branch1\n* branch2\n"),
Cmd("git checkout -f master", ""),
Cmd("git svn rebase", ""),
Cmd("git checkout -b %s" % TEST_CONFIG[BRANCHNAME], "",
cb=ResetVersion(4, 5)),
Cmd("git branch -r",
"svn/tags/3.4.2\nsvn/tags/3.2.1.0\nsvn/branches/3.4"),
Cmd(("git log --format=%H --grep="
"\"\\[Auto\\-roll\\] Bump up version to\""),
"hash125\nhash118\nhash111\nhash101"),
Cmd("git checkout -f hash125 -- %s" % VERSION_FILE, "",
cb=ResetVersion(4, 4)),
Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
cb=ResetVersion(4, 5)),
Cmd("git checkout -f hash118 -- %s" % VERSION_FILE, "",
cb=ResetVersion(4, 3)),
Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
cb=ResetVersion(4, 5)),
Cmd("git checkout -f hash111 -- %s" % VERSION_FILE, "",
cb=ResetVersion(4, 2)),
Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
cb=ResetVersion(4, 5)),
URL("https://v8-status.appspot.com/revisions?format=json",
"[{\"revision\": \"126\", \"status\": true},"
"{\"revision\": \"123\", \"status\": true},"
"{\"revision\": \"112\", \"status\": true}]"),
Cmd("git svn find-rev hash118", "118"),
Cmd("git svn find-rev hash125", "125"),
Cmd("git svn find-rev r123", "hash123"),
Cmd("git log -1 --format=%at hash123", "1"),
Cmd("git reset --hard hash123", ""),
Cmd("git svn tag 3.4.3 -m \"Tagging version 3.4.3\"", ""),
Cmd("git checkout -f some_branch", ""),
Cmd("git branch -D %s" % TEST_CONFIG[BRANCHNAME], ""),
])
AutoTag(TEST_CONFIG, self).Run(["-a", "author@chromium.org"])
# Test that we bail out if the last change was a version change.
def testBumpUpVersionBailout1(self):
self._state["latest"] = "latest_hash"
self.Expect([
Cmd("git diff --name-only latest_hash latest_hash^", VERSION_FILE),
])
self.assertEquals(0,
self.RunStep(BumpUpVersion, LastChangeBailout, ["--dry_run"]))
# Test that we bail out if the lkgr was a version change.
def testBumpUpVersionBailout2(self):
self._state["lkgr"] = "lkgr_hash"
self.Expect([
Cmd("git diff --name-only lkgr_hash lkgr_hash^", VERSION_FILE),
])
self.assertEquals(0,
self.RunStep(BumpUpVersion, LKGRVersionUpToDateBailout, ["--dry_run"]))
# Test that we bail out if the last version is already newer than the lkgr's
# version.
def testBumpUpVersionBailout3(self):
self._state["lkgr"] = "lkgr_hash"
self._state["lkgr_version"] = "3.22.4.0"
self._state["latest_version"] = "3.22.5.0"
self.Expect([
Cmd("git diff --name-only lkgr_hash lkgr_hash^", ""),
])
self.assertEquals(0,
self.RunStep(BumpUpVersion, LKGRVersionUpToDateBailout, ["--dry_run"]))
class SystemTest(unittest.TestCase):
def testReload(self):
step = MakeStep(step_class=PrepareChangeLog, number=0, state={}, config={},
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)