a8f77a54cf
Preliminary version. TODO: Add wrapper script in tools dir. TODO: Some refactoring. R=jkummerow@chromium.org Review URL: https://codereview.chromium.org/49653002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17600 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
429 lines
17 KiB
Python
429 lines
17 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 tempfile
|
|
import unittest
|
|
|
|
import common_includes
|
|
from common_includes import *
|
|
import push_to_trunk
|
|
from push_to_trunk import *
|
|
|
|
|
|
TEST_CONFIG = {
|
|
BRANCHNAME: "test-prepare-push",
|
|
TRUNKBRANCH: "test-trunk-push",
|
|
PERSISTFILE_BASENAME: "/tmp/test-v8-push-to-trunk-tempfile",
|
|
TEMP_BRANCH: "test-prepare-push-temporary-branch-created-by-script",
|
|
DOT_GIT_LOCATION: None,
|
|
VERSION_FILE: None,
|
|
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",
|
|
DEPS_FILE: "/tmp/test-v8-push-to-trunk-tempfile-chromium/DEPS",
|
|
}
|
|
|
|
|
|
class ScriptTest(unittest.TestCase):
|
|
def MakeEmptyTempFile(self):
|
|
handle, name = tempfile.mkstemp()
|
|
os.close(handle)
|
|
self._tmp_files.append(name)
|
|
return name
|
|
|
|
def MakeTempVersionFile(self):
|
|
name = self.MakeEmptyTempFile()
|
|
with open(name, "w") as f:
|
|
f.write(" // Some line...\n")
|
|
f.write("\n")
|
|
f.write("#define MAJOR_VERSION 3\n")
|
|
f.write("#define MINOR_VERSION 22\n")
|
|
f.write("#define BUILD_NUMBER 5\n")
|
|
f.write("#define PATCH_LEVEL 0\n")
|
|
f.write(" // Some line...\n")
|
|
f.write("#define IS_CANDIDATE_VERSION 0\n")
|
|
return name
|
|
|
|
def MakeStep(self, step_class=Step, state=None):
|
|
state = state or {}
|
|
step = step_class()
|
|
step.SetConfig(TEST_CONFIG)
|
|
step.SetState(state)
|
|
step.SetNumber(0)
|
|
step.SetSideEffectHandler(self)
|
|
return step
|
|
|
|
def GitMock(self, cmd, args="", pipe=True):
|
|
self._git_index += 1
|
|
try:
|
|
git_invocation = self._git_recipe[self._git_index]
|
|
except IndexError:
|
|
raise Exception("Calling git %s" % args)
|
|
if git_invocation[0] != args:
|
|
raise Exception("Expected: %s - Actual: %s" % (git_invocation[0], args))
|
|
if len(git_invocation) == 3:
|
|
# Run optional function checking the context during this git command.
|
|
git_invocation[2]()
|
|
return git_invocation[1]
|
|
|
|
def LogMock(self, cmd, args=""):
|
|
print "Log: %s %s" % (cmd, args)
|
|
|
|
MOCKS = {
|
|
"git": GitMock,
|
|
"vi": LogMock,
|
|
}
|
|
|
|
def Command(self, cmd, args="", prefix="", pipe=True):
|
|
return ScriptTest.MOCKS[cmd](self, cmd, args)
|
|
|
|
def ReadLine(self):
|
|
self._rl_index += 1
|
|
try:
|
|
return self._rl_recipe[self._rl_index]
|
|
except IndexError:
|
|
raise Exception("Calling readline too often")
|
|
|
|
def setUp(self):
|
|
self._git_recipe = []
|
|
self._git_index = -1
|
|
self._rl_recipe = []
|
|
self._rl_index = -1
|
|
self._tmp_files = []
|
|
|
|
def tearDown(self):
|
|
Command("rm", "-rf %s*" % TEST_CONFIG[PERSISTFILE_BASENAME])
|
|
|
|
# Clean up temps. Doesn't work automatically.
|
|
for name in self._tmp_files:
|
|
if os.path.exists(name):
|
|
os.remove(name)
|
|
|
|
if self._git_index < len(self._git_recipe) -1:
|
|
raise Exception("Called git too seldom: %d vs. %d" %
|
|
(self._git_index, len(self._git_recipe)))
|
|
if self._rl_index < len(self._rl_recipe) -1:
|
|
raise Exception("Too little input: %d vs. %d" %
|
|
(self._rl_index, len(self._rl_recipe)))
|
|
|
|
def testPersistRestore(self):
|
|
self.MakeStep().Persist("test1", "")
|
|
self.assertEquals("", self.MakeStep().Restore("test1"))
|
|
self.MakeStep().Persist("test2", "AB123")
|
|
self.assertEquals("AB123", self.MakeStep().Restore("test2"))
|
|
|
|
def testGitOrig(self):
|
|
self.assertTrue(Command("git", "--version").startswith("git version"))
|
|
|
|
def testGitMock(self):
|
|
self._git_recipe = [["--version", "git version 1.2.3"], ["dummy", ""]]
|
|
self.assertEquals("git version 1.2.3", self.MakeStep().Git("--version"))
|
|
self.assertEquals("", self.MakeStep().Git("dummy"))
|
|
|
|
def testCommonPrepareDefault(self):
|
|
self._git_recipe = [
|
|
["status -s -uno", ""],
|
|
["status -s -b -uno", "## some_branch"],
|
|
["svn fetch", ""],
|
|
["branch", " branch1\n* %s" % TEST_CONFIG[TEMP_BRANCH]],
|
|
["branch -D %s" % TEST_CONFIG[TEMP_BRANCH], ""],
|
|
["checkout -b %s" % TEST_CONFIG[TEMP_BRANCH], ""],
|
|
["branch", ""],
|
|
]
|
|
self._rl_recipe = ["Y"]
|
|
self.MakeStep().CommonPrepare()
|
|
self.assertEquals("some_branch", self.MakeStep().Restore("current_branch"))
|
|
|
|
def testCommonPrepareNoConfirm(self):
|
|
self._git_recipe = [
|
|
["status -s -uno", ""],
|
|
["status -s -b -uno", "## some_branch"],
|
|
["svn fetch", ""],
|
|
["branch", " branch1\n* %s" % TEST_CONFIG[TEMP_BRANCH]],
|
|
]
|
|
self._rl_recipe = ["n"]
|
|
self.assertRaises(Exception, self.MakeStep().CommonPrepare)
|
|
self.assertEquals("some_branch", self.MakeStep().Restore("current_branch"))
|
|
|
|
def testCommonPrepareDeleteBranchFailure(self):
|
|
self._git_recipe = [
|
|
["status -s -uno", ""],
|
|
["status -s -b -uno", "## some_branch"],
|
|
["svn fetch", ""],
|
|
["branch", " branch1\n* %s" % TEST_CONFIG[TEMP_BRANCH]],
|
|
["branch -D %s" % TEST_CONFIG[TEMP_BRANCH], None],
|
|
]
|
|
self._rl_recipe = ["Y"]
|
|
self.assertRaises(Exception, self.MakeStep().CommonPrepare)
|
|
self.assertEquals("some_branch", self.MakeStep().Restore("current_branch"))
|
|
|
|
def testInitialEnvironmentChecks(self):
|
|
TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile()
|
|
os.environ["EDITOR"] = "vi"
|
|
self.MakeStep().InitialEnvironmentChecks()
|
|
|
|
def testReadAndPersistVersion(self):
|
|
TEST_CONFIG[VERSION_FILE] = self.MakeTempVersionFile()
|
|
step = self.MakeStep()
|
|
step.ReadAndPersistVersion()
|
|
self.assertEquals("3", self.MakeStep().Restore("major"))
|
|
self.assertEquals("22", self.MakeStep().Restore("minor"))
|
|
self.assertEquals("5", self.MakeStep().Restore("build"))
|
|
self.assertEquals("0", self.MakeStep().Restore("patch"))
|
|
self.assertEquals("3", step._state["major"])
|
|
self.assertEquals("22", step._state["minor"])
|
|
self.assertEquals("5", step._state["build"])
|
|
self.assertEquals("0", step._state["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 testPrepareChangeLog(self):
|
|
TEST_CONFIG[VERSION_FILE] = self.MakeTempVersionFile()
|
|
TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile()
|
|
|
|
self._git_recipe = [
|
|
["log 1234..HEAD --format=%H", "rev1\nrev2"],
|
|
["log -1 rev1 --format=\"%w(80,8,8)%s\"", " Title text 1"],
|
|
["log -1 rev1 --format=\"%B\"", "Title\n\nBUG=\n"],
|
|
["log -1 rev1 --format=\"%w(80,8,8)(%an)\"",
|
|
" author1@chromium.org"],
|
|
["log -1 rev2 --format=\"%w(80,8,8)%s\"", " Title text 2"],
|
|
["log -1 rev2 --format=\"%B\"", "Title\n\nBUG=321\n"],
|
|
["log -1 rev2 --format=\"%w(80,8,8)(%an)\"",
|
|
" author2@chromium.org"],
|
|
]
|
|
|
|
self.MakeStep().Persist("last_push", "1234")
|
|
self.MakeStep(PrepareChangeLog).Run()
|
|
|
|
cl = FileToText(TEST_CONFIG[CHANGELOG_ENTRY_FILE])
|
|
self.assertTrue(re.search(r"\d+\-\d+\-\d+: Version 3\.22\.5", cl))
|
|
self.assertTrue(re.search(r" Title text 1", cl))
|
|
self.assertTrue(re.search(r" Title text 2", cl))
|
|
self.assertTrue(re.search(r" author1@chromium.org", cl))
|
|
self.assertTrue(re.search(r" author2@chromium.org", cl))
|
|
self.assertTrue(re.search(r" \(Chromium issue 321\)", cl))
|
|
self.assertFalse(re.search(r"BUG=", cl))
|
|
self.assertEquals("3", self.MakeStep().Restore("major"))
|
|
self.assertEquals("22", self.MakeStep().Restore("minor"))
|
|
self.assertEquals("5", self.MakeStep().Restore("build"))
|
|
self.assertEquals("0", self.MakeStep().Restore("patch"))
|
|
|
|
def testEditChangeLog(self):
|
|
TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile()
|
|
TEST_CONFIG[CHANGELOG_FILE] = self.MakeEmptyTempFile()
|
|
TextToFile(" Original CL", TEST_CONFIG[CHANGELOG_FILE])
|
|
TextToFile(" New \n\tLines \n", TEST_CONFIG[CHANGELOG_ENTRY_FILE])
|
|
os.environ["EDITOR"] = "vi"
|
|
|
|
self._rl_recipe = [
|
|
"", # Open editor.
|
|
]
|
|
|
|
self.MakeStep(EditChangeLog).Run()
|
|
|
|
self.assertEquals(" New\n Lines\n\n\n Original CL",
|
|
FileToText(TEST_CONFIG[CHANGELOG_FILE]))
|
|
|
|
def testIncrementVersion(self):
|
|
TEST_CONFIG[VERSION_FILE] = self.MakeTempVersionFile()
|
|
self.MakeStep().Persist("build", "5")
|
|
|
|
self._rl_recipe = [
|
|
"Y", # Increment build number.
|
|
]
|
|
|
|
self.MakeStep(IncrementVersion).Run()
|
|
|
|
self.assertEquals("3", self.MakeStep().Restore("new_major"))
|
|
self.assertEquals("22", self.MakeStep().Restore("new_minor"))
|
|
self.assertEquals("6", self.MakeStep().Restore("new_build"))
|
|
self.assertEquals("0", self.MakeStep().Restore("new_patch"))
|
|
|
|
def testSquashCommits(self):
|
|
TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile()
|
|
with open(TEST_CONFIG[CHANGELOG_ENTRY_FILE], "w") as f:
|
|
f.write("1999-11-11: Version 3.22.5\n")
|
|
f.write("\n")
|
|
f.write(" Log text 1.\n")
|
|
f.write(" Chromium issue 12345\n")
|
|
f.write("\n")
|
|
f.write(" Performance and stability improvements on all "
|
|
"platforms.\n")
|
|
|
|
self._git_recipe = [
|
|
["diff svn/trunk hash1", "patch content"],
|
|
]
|
|
|
|
self.MakeStep().Persist("prepare_commit_hash", "hash1")
|
|
self.MakeStep().Persist("date", "1999-11-11")
|
|
|
|
self.MakeStep(SquashCommits).Run()
|
|
|
|
msg = FileToText(TEST_CONFIG[COMMITMSG_FILE])
|
|
self.assertTrue(re.search(r"Version 3\.22\.5", msg))
|
|
self.assertTrue(re.search(r"Performance and stability", msg))
|
|
self.assertTrue(re.search(r"Log text 1\. Chromium issue 12345", msg))
|
|
self.assertFalse(re.search(r"\d+\-\d+\-\d+", msg))
|
|
|
|
patch = FileToText(TEST_CONFIG[ PATCH_FILE])
|
|
self.assertTrue(re.search(r"patch content", patch))
|
|
|
|
def testPushToTrunk(self):
|
|
TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile()
|
|
TEST_CONFIG[VERSION_FILE] = self.MakeTempVersionFile()
|
|
TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile()
|
|
TEST_CONFIG[CHANGELOG_FILE] = self.MakeEmptyTempFile()
|
|
if not os.path.exists(TEST_CONFIG[CHROMIUM]):
|
|
os.makedirs(TEST_CONFIG[CHROMIUM])
|
|
TextToFile("1999-04-05: Version 3.22.4", TEST_CONFIG[CHANGELOG_FILE])
|
|
TextToFile("Some line\n \"v8_revision\": \"123444\",\n some line",
|
|
TEST_CONFIG[DEPS_FILE])
|
|
os.environ["EDITOR"] = "vi"
|
|
|
|
def CheckPreparePush():
|
|
cl = FileToText(TEST_CONFIG[CHANGELOG_FILE])
|
|
self.assertTrue(re.search(r"Version 3.22.5", cl))
|
|
self.assertTrue(re.search(r" Log text 1", cl))
|
|
self.assertTrue(re.search(r" \(issue 321\)", cl))
|
|
version = FileToText(TEST_CONFIG[VERSION_FILE])
|
|
self.assertTrue(re.search(r"#define BUILD_NUMBER\s+6", version))
|
|
|
|
def CheckSVNCommit():
|
|
commit = FileToText(TEST_CONFIG[COMMITMSG_FILE])
|
|
self.assertTrue(re.search(r"Version 3.22.5", commit))
|
|
self.assertTrue(re.search(r"Log text 1. \(issue 321\)", commit))
|
|
version = FileToText(TEST_CONFIG[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))
|
|
|
|
self._git_recipe = [
|
|
["status -s -uno", ""],
|
|
["status -s -b -uno", "## some_branch\n"],
|
|
["svn fetch", ""],
|
|
["branch", " branch1\n* branch2\n"],
|
|
["checkout -b %s" % TEST_CONFIG[TEMP_BRANCH], ""],
|
|
["branch", " branch1\n* branch2\n"],
|
|
["branch", " branch1\n* branch2\n"],
|
|
["checkout -b %s svn/bleeding_edge" % TEST_CONFIG[BRANCHNAME], ""],
|
|
["log -1 --format=%H ChangeLog", "1234\n"],
|
|
["log -1 1234", "Last push ouput\n"],
|
|
["log 1234..HEAD --format=%H", "rev1\n"],
|
|
["log -1 rev1 --format=\"%w(80,8,8)%s\"", " Log text 1.\n"],
|
|
["log -1 rev1 --format=\"%B\"", "Text\nBUG=v8:321\nText\n"],
|
|
["log -1 rev1 --format=\"%w(80,8,8)(%an)\"",
|
|
" author1@chromium.org\n"],
|
|
[("commit -a -m \"Prepare push to trunk. "
|
|
"Now working on version 3.22.6.\""),
|
|
" 2 files changed\n",
|
|
CheckPreparePush],
|
|
["cl upload -r \"reviewer@chromium.org\" --send-mail", "done\n"],
|
|
["cl dcommit", "Closing issue\n"],
|
|
["svn fetch", "fetch result\n"],
|
|
["checkout svn/bleeding_edge", ""],
|
|
[("log -1 --format=%H --grep=\"Prepare push to trunk. "
|
|
"Now working on version 3.22.6.\""),
|
|
"hash1\n"],
|
|
["diff svn/trunk hash1", "patch content\n"],
|
|
["checkout -b %s svn/trunk" % TEST_CONFIG[TRUNKBRANCH], ""],
|
|
["apply --index --reject \"%s\"" % TEST_CONFIG[PATCH_FILE], ""],
|
|
["add \"%s\"" % TEST_CONFIG[VERSION_FILE], ""],
|
|
["commit -F \"%s\"" % TEST_CONFIG[COMMITMSG_FILE], "", CheckSVNCommit],
|
|
["svn dcommit 2>&1", "Some output\nCommitted r123456\nSome output\n"],
|
|
["svn tag 3.22.5 -m \"Tagging version 3.22.5\"", ""],
|
|
["status -s -uno", ""],
|
|
["checkout master", ""],
|
|
["pull", ""],
|
|
["checkout -b v8-roll-123456", ""],
|
|
[("commit -am \"Update V8 to version 3.22.5.\n\n"
|
|
"TBR=reviewer@chromium.org\""),
|
|
""],
|
|
["cl upload --send-mail", ""],
|
|
["checkout -f some_branch", ""],
|
|
["branch -D %s" % TEST_CONFIG[TEMP_BRANCH], ""],
|
|
["branch -D %s" % TEST_CONFIG[BRANCHNAME], ""],
|
|
["branch -D %s" % TEST_CONFIG[TRUNKBRANCH], ""],
|
|
]
|
|
self._rl_recipe = [
|
|
"Y", # Confirm last push.
|
|
"", # Open editor.
|
|
"Y", # Increment build number.
|
|
"reviewer@chromium.org", # V8 reviewer.
|
|
"LGTX", # Enter LGTM for V8 CL (wrong).
|
|
"LGTM", # Enter LGTM for V8 CL.
|
|
"Y", # Sanity check.
|
|
"reviewer@chromium.org", # Chromium reviewer.
|
|
]
|
|
|
|
class Options( object ):
|
|
pass
|
|
|
|
options = Options()
|
|
options.s = 0
|
|
options.l = None
|
|
options.c = TEST_CONFIG[CHROMIUM]
|
|
RunScript(TEST_CONFIG, options, self)
|
|
|
|
deps = FileToText(TEST_CONFIG[DEPS_FILE])
|
|
self.assertTrue(re.search("\"v8_revision\": \"123456\"", deps))
|
|
|
|
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", cl))
|
|
self.assertTrue(re.search(r" \(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.
|