aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/llvm.py86
-rw-r--r--scripts/llvm.py25
-rw-r--r--tests/cli/llvmtestcase.py29
-rw-r--r--tests/cli/testllvmprojects.py4
-rw-r--r--tests/cli/testllvmpush.py166
-rw-r--r--tests/unittests/testllvmsourceconfig.py85
-rw-r--r--tests/unittests/testpush.py200
7 files changed, 557 insertions, 38 deletions
diff --git a/modules/llvm.py b/modules/llvm.py
index 34cd02c..2e7c44f 100644
--- a/modules/llvm.py
+++ b/modules/llvm.py
@@ -1,4 +1,5 @@
import os
+import re
from linaropy.git.worktree import Worktree
@@ -146,6 +147,24 @@ class LLVMSourceConfig(object):
for subproj in remove:
self.__remove_subproject(subproj)
+ def for_each_enabled(self, action):
+ """Perform the given action for each enabled subproject including LLVM.
+
+ The action must be a callable object receiving the path to the
+ subproject's directory as its only parameter.
+
+ If the action throws an exception, it will be rethrown as a
+ RuntimeError. Note that this does not have transactional behaviour.
+ """
+ for subproj in self.get_enabled_subprojects():
+ try:
+ action(self.__get_subproj_cmake_path(subproj))
+ except Exception as exc:
+ raise RuntimeError("Error while processing {}".format(subproj)) from exc
+
+ # Visit LLVM last, in case getting the enabled subprojects errors out.
+ action(self.llvmSourceTree.repodir)
+
def __get_subproj_object(self, subprojName):
"""Get the LLVMSubproject object corresponding to subprojName."""
if not subprojName in list(self.subprojs.keys()):
@@ -160,18 +179,22 @@ class LLVMSourceConfig(object):
def __is_enabled(self, subprojName):
"""
Check if subproj is enabled in this configuration. A subproj is
- considered to be enabled if it is a worktree on the correct branch.
+ considered to be enabled if it is a worktree on the correct branch. If
+ a directory for the subproject exists but does not satisfy those
+ conditions, an EnvironmentError is thrown.
"""
- try:
- # If this succeeds, the subproject has already been added.
- existing = Worktree(self.proj,
- self.__get_subproj_cmake_path(subprojName))
- except EnvironmentError:
- # If it's not a worktree (for whatever reason), it's not enabled.
+ subprojPath = self.__get_subproj_cmake_path(subprojName)
+
+ if not os.path.isdir(subprojPath):
return False
- # If it is a worktree, but on the wrong branch, it is not enabled.
- return existing.getbranch() == self.llvmSourceTree.getbranch()
+ existing = Worktree(self.proj, subprojPath)
+
+ if existing.getbranch() != self.llvmSourceTree.getbranch():
+ raise EnvironmentError("{} is on branch {}, but should be on {}".format(
+ subprojName, existing.getbranch(), self.llvmSourceTree.getbranch()))
+
+ return True
# TODO: add_subproject, remove_subproject and is_enabled should live in
# another object (AddRemoveStrategy?) that would know what we want to add
@@ -222,3 +245,48 @@ class LLVMSourceConfig(object):
worktree = Worktree(self.proj, path)
worktree.clean(False)
+
+
+# FIXME: repo.pushToBranch doesn't work, because it doesn't handle remote
+# branches properly. Furthermore, there's no support for getting the remote URL,
+# so we need to resort to raw git commands. We may also consider moving the
+# functionality for parsing info out of the remote URL into the repo object.
+from sh import git
+from linaropy.cd import cd
+
+
+def get_user_from_remote(url):
+ """Get the username used as part of the remote URL, or None.
+
+ The remote URLs that we expect to see look like $protocol://$user@$location.
+ If they look any different, we won't be able to parse them.
+ """
+ pattern = re.compile("(.*://)?(?P<user>.*)@(.*)\n?")
+ match = pattern.match(str(url))
+ if match is None:
+ return None
+ return match.group('user')
+
+
+def push_current_branch(proj, pathToRepo):
+ """Push the current branch to origin.
+
+ It will be pushed into linaro-local/$user/$branch, where $branch is the
+ current branch and $user is the username used as part of the remote URL.
+ """
+ repo = Worktree(proj, pathToRepo)
+
+ with cd(repo.repodir):
+ remote = git("remote", "get-url", "--push", "origin").strip()
+ user = get_user_from_remote(remote)
+ if not user:
+ raise EnvironmentError("Couldn't parse user from {}.".format(remote))
+
+ local_branch = repo.getbranch()
+ remote_branch = "linaro-local/{}/{}".format(user, local_branch)
+ if not repo.is_valid_branch_name(remote_branch):
+ raise EnvironmentError(
+ "{} is not a valid branch name.".format(remote_branch))
+
+ with cd(repo.repodir):
+ git("push", "-u", "origin", "+{}:{}".format(local_branch, remote_branch))
diff --git a/scripts/llvm.py b/scripts/llvm.py
index 829c720..2252ab2 100644
--- a/scripts/llvm.py
+++ b/scripts/llvm.py
@@ -3,11 +3,12 @@
import os
from sys import exit
-from modules.llvm import LLVMSubproject, LLVMSourceConfig
+from modules.llvm import LLVMSubproject, LLVMSourceConfig, push_current_branch
from linaropy.git.clone import Clone
from linaropy.proj import Proj
from argparse import Action, ArgumentParser, RawTextHelpFormatter
+from functools import partial
def die(message, config_to_dump=None):
@@ -64,6 +65,22 @@ def projects(args):
dump_config(config)
+
+def push_branch(args):
+ """Push current branch to origin."""
+
+ proj = Proj()
+
+ llvm_worktree_root = get_worktree_root(args.env)
+ config = LLVMSourceConfig(proj, llvm_worktree_root)
+
+ llvmBranch = Clone(proj, llvm_worktree_root).getbranch()
+
+ try:
+ config.for_each_enabled(partial(push_current_branch, proj))
+ except RuntimeError as exc:
+ die("Failed to push branch because: " + str(exc) + str(exc.__cause__))
+
##########################################################################
# Command line parsing #
##########################################################################
@@ -106,5 +123,11 @@ projs.add_argument(
metavar='subproject',
help="Unlink given subprojects.")
+# Subcommand for pushing the current branch to origin
+push = subcommands.add_parser(
+ "push",
+ help="Push current branch to origin linaro-local/<user>/<branch>, for all linked subprojects.")
+push.set_defaults(run_command=push_branch)
+
args = options.parse_args()
args.run_command(args)
diff --git a/tests/cli/llvmtestcase.py b/tests/cli/llvmtestcase.py
index b2fc765..9b4ac3e 100644
--- a/tests/cli/llvmtestcase.py
+++ b/tests/cli/llvmtestcase.py
@@ -34,19 +34,28 @@ class LLVMTestCase(unittest.TestCase):
script = os.path.join("scripts", "llvm.py")
@classmethod
- def create_dummy_commit(cls):
- filename = "filethatshouldntexist"
+ def create_dummy_commit(cls, commitMessage="Dummy commit"):
+ filename = "filethatshouldntexist" + str(uuid4())
cls.run_quietly(["touch", filename])
- cls.run_quietly(["git", "add", filename])
- cls.run_quietly(["git", "commit", "-m", "Dummy commit"])
+ try:
+ cls.run_quietly(["git", "add", filename])
+ cls.run_quietly(["git", "commit", "-m", commitMessage])
+ except subprocess.CalledProcessError as exc:
+ print("Command {} exited with error code {}:\n{}".format(
+ exc.cmd, exc.returncode, exc.output))
@classmethod
- def create_dummy_repo(cls, repopath):
- if not os.path.isdir(repopath):
- os.makedirs(repopath)
+ def create_dummy_repo(cls, repopath, originpath=None):
+ if originpath is not None:
+ cls.run_quietly(["git", "clone", originpath, repopath])
+ else:
+ if not os.path.isdir(repopath):
+ os.makedirs(repopath)
+
+ with cd(repopath):
+ cls.run_quietly(["git", "init"])
with cd(repopath):
- cls.run_quietly(["git", "init"])
cls.create_dummy_commit()
@classmethod
@@ -55,10 +64,6 @@ class LLVMTestCase(unittest.TestCase):
cls.run_quietly(["git", "worktree", "add", worktreepath,
"-b", branch])
- @classmethod
- def get_subproj_repo(cls, subproj):
- return os.path.join(cls.repos, subproj)
-
@staticmethod
def run_with_output(*args, **kwargs):
"""Helper for running a command and capturing stdout and stderr"""
diff --git a/tests/cli/testllvmprojects.py b/tests/cli/testllvmprojects.py
index 394f3ac..30f7ff2 100644
--- a/tests/cli/testllvmprojects.py
+++ b/tests/cli/testllvmprojects.py
@@ -24,6 +24,10 @@ class Testllvmprojs(LLVMTestCase):
return cls.command_with_defaults("projects", *args, **kwargs)
@classmethod
+ def get_subproj_repo(cls, subproj):
+ return os.path.join(cls.repos, subproj)
+
+ @classmethod
def setUpClass(cls):
"""Create the file structure and environment that llvmprojs expects"""
cls.llvm_root = mkdtemp()
diff --git a/tests/cli/testllvmpush.py b/tests/cli/testllvmpush.py
new file mode 100644
index 0000000..769aa18
--- /dev/null
+++ b/tests/cli/testllvmpush.py
@@ -0,0 +1,166 @@
+"""Command line interface tests for llvm.py push.
+
+Note that although this uses the unittest framework, it does *not* contain unit
+tests.
+
+"""
+
+import shutil
+import os
+import subprocess
+import unittest
+
+from tempfile import mkdtemp
+from uuid import uuid4
+
+from linaropy.cd import cd
+from linaropy.git.clone import Clone
+from llvmtestcase import LLVMTestCase, debug
+
+
+class Testllvmpush(LLVMTestCase):
+
+ @classmethod
+ def llvm_push(cls, *args, **kwargs):
+ return cls.command_with_defaults("push", *args, **kwargs)
+
+ @classmethod
+ def get_origin_path(cls, subproj):
+ return os.path.join(cls.origins, subproj)
+
+ @classmethod
+ def get_clone_path(cls, subproj):
+ return os.path.join(cls.repos, subproj)
+
+ @classmethod
+ def setUpClass(cls):
+ """Create the file structure and environment for testing llvm push."""
+ cls.all_repos = ("llvm", "clang", "compiler-rt", "lld", "lldb",
+ "libcxx", "libcxxabi", "libunwind", "test-suite")
+
+ cls.origins = mkdtemp()
+ cls.repos = mkdtemp()
+ cls.llvm_root = mkdtemp()
+
+ cls.user = "llvm-developer"
+
+ # Create dummy repos - one origin that we will push to, and one clone
+ # that we will create worktrees from
+ for reponame in cls.all_repos:
+ origin = cls.get_origin_path(reponame)
+ cls.create_dummy_repo(origin)
+
+ clone = cls.get_clone_path(reponame)
+ cls.create_dummy_repo(
+ clone, "file://{}@{}".format(cls.user, origin))
+
+ @classmethod
+ def tearDownClass(cls):
+ shutil.rmtree(cls.origins)
+ shutil.rmtree(cls.repos)
+
+ @classmethod
+ def setUp(cls):
+ cls.env = os.path.join(cls.llvm_root, "env" + str(uuid4()))
+ cls.llvm_src = os.path.join(cls.env, "llvm")
+
+ # Create LLVM worktree
+ cls.branch = "br" + str(uuid4())
+ cls.add_worktree(cls.get_clone_path("llvm"), cls.llvm_src,
+ cls.branch)
+
+ @classmethod
+ def tearDown(cls):
+ # Clean up the directories where we might have added subprojects.
+ # This isn't 100% clean, because we don't clean up the repos between
+ # tests (so any branches will remain), but it's good enough for the
+ # current tests.
+ for subprojdir in (os.path.join(cls.llvm_src, "projects"),
+ os.path.join(cls.llvm_src, "tools")):
+ if os.path.isdir(subprojdir):
+ shutil.rmtree(subprojdir)
+ os.makedirs(subprojdir)
+
+ # Run prune on the original repos, to remove any dangling worktrees.
+ for reponame in cls.all_repos:
+ repopath = cls.get_clone_path(reponame)
+ with cd(repopath):
+ cls.run_quietly(["git", "worktree", "prune"])
+
+ def test_push(self):
+ with cd(self.llvm_src):
+ self.create_dummy_commit("Test llvm push")
+
+ enabled = ["clang", "lld"]
+
+ for subproj in enabled:
+ worktreePath = os.path.join(self.llvm_src, "tools", subproj)
+ self.add_worktree(self.get_clone_path(subproj),
+ worktreePath,
+ self.branch)
+ with cd(worktreePath):
+ self.create_dummy_commit("Test {} push".format(subproj))
+
+ self.run_quietly(self.llvm_push())
+ remote_branch = "linaro-local/{}/{}".format(self.user, self.branch)
+
+ for subproj in self.all_repos:
+ origin = self.get_origin_path(subproj)
+
+ with cd(origin):
+ if subproj == "llvm" or subproj in enabled:
+ output = self.run_with_output(["git", "log", "--oneline",
+ "-1", remote_branch])
+
+ self.assertRegex(
+ output, ".*Test {} push.*".format(subproj))
+ else:
+ with self.assertRaises(subprocess.CalledProcessError) as context:
+ output = self.run_with_output(
+ ["git", "log", "--oneline", "-1", remote_branch])
+
+ self.assertRegex(
+ str(context.exception.output),
+ "(.*\n)*.*unknown revision or path not in the working tree(.*\n)*")
+
+ def test_push_mismatched_branches(self):
+ with cd(self.llvm_src):
+ self.create_dummy_commit("Test llvm push")
+
+ enabled = ["clang", "lld"]
+
+ for subproj in enabled:
+ branch = self.branch
+
+ # Move only lld to a different branch
+ if subproj == "lld":
+ branch = branch + "-different"
+
+ worktreePath = os.path.join(self.llvm_src, "tools", subproj)
+ self.add_worktree(self.get_clone_path(subproj),
+ worktreePath,
+ branch)
+ with cd(worktreePath):
+ self.create_dummy_commit("Test {} push".format(subproj))
+
+ with self.assertRaises(subprocess.CalledProcessError) as context:
+ output = self.run_with_output(self.llvm_push())
+
+ # Check that we error out because lld is on a different branch
+ self.assertRegex(str(context.exception.output),
+ "(.*\n)*.*lld is on branch {}, but should be on {}".format(
+ self.branch + "-different", self.branch))
+
+ # Check that we haven't pushed llvm or clang either, even if they're on
+ # the same branch
+ remote_branch = "linaro-local/{}/{}".format(self.user, self.branch)
+
+ for subproj in ["llvm", "clang"]:
+ with cd(self.get_origin_path(subproj)):
+ with self.assertRaises(subprocess.CalledProcessError) as context:
+ self.run_with_output(["git", "log", "--oneline", "-1",
+ remote_branch])
+
+ self.assertRegex(
+ str(context.exception.output),
+ "(.*\n)*.*unknown revision or path not in the working tree(.*\n)*")
diff --git a/tests/unittests/testllvmsourceconfig.py b/tests/unittests/testllvmsourceconfig.py
index 3ad93b1..8a60065 100644
--- a/tests/unittests/testllvmsourceconfig.py
+++ b/tests/unittests/testllvmsourceconfig.py
@@ -3,6 +3,7 @@ import unittest
import uuid
from sh import git
+from unittest.mock import MagicMock, call
from linaropy.cd import cd
from linaropy.proj import Proj
@@ -130,13 +131,12 @@ class TestLLVMSourceConfig(unittest.TestCase):
os.makedirs(path)
config = LLVMSourceConfig(self.proj, sourcePath)
- enabled = config.get_enabled_subprojects()
+ with self.assertRaises(EnvironmentError) as context:
+ config.get_enabled_subprojects()
- # Check that if it's not a worktree, it's not enabled.
- self.assertEqual(
- enabled,
- [],
- "Detected unexpected projects %s" % str(enabled)
+ self.assertRegex(
+ str(context.exception),
+ ".*compiler-rt is not a worktree.*"
)
def test_detect_enabled_wrong_branch(self):
@@ -153,14 +153,12 @@ class TestLLVMSourceConfig(unittest.TestCase):
self.assertTrue(os.path.isdir(path), "Failed to create worktree")
config = LLVMSourceConfig(self.proj, sourcePath)
- enabled = config.get_enabled_subprojects()
+ with self.assertRaises(EnvironmentError) as context:
+ config.get_enabled_subprojects()
- # Check that if it's a worktree on the wrong branch, it's not enabled.
- self.assertEqual(
- enabled,
- [],
- "Detected unexpected projects %s" % str(enabled)
- )
+ self.assertRegex(str(context.exception),
+ "compiler-rt is on branch {}, but should be on {}".format(branch,
+ self.temporaryLLVMbranch))
def test_add_invalid_subproject(self):
config = LLVMSourceConfig(self.proj, self.temporaryLLVM.repodir)
@@ -284,7 +282,7 @@ class TestLLVMSourceConfig(unittest.TestCase):
config.update({ "lldb" : self.__get_subproj_repo("lldb")})
self.assertRegex(str(context.exception),
- "{} already exists but is not a valid subproject directory.*"
+ "{} is not a worktree.*"
.format(existingPath))
# If we got this far, we're probably ok, but let's be pedantic and check
@@ -314,8 +312,8 @@ class TestLLVMSourceConfig(unittest.TestCase):
config.update({ "lldb" : self.__get_subproj_repo("lldb")})
self.assertRegex(str(context.exception),
- "{} already exists but is not a valid subproject directory.*"
- .format(existingPath))
+ "lldb is on branch {}, but should be on {}.*"
+ .format(branch, self.temporaryLLVMbranch))
# If we got this far, we're probably ok, but let's be pedantic and check
# that the subproject is still there
@@ -568,5 +566,60 @@ class TestLLVMSourceConfig(unittest.TestCase):
# TODO: test that CMake gets our layout
+ def test_for_each_enabled(self):
+ sourcePath = self.temporaryLLVM.repodir
+
+ config = LLVMSourceConfig(self.proj, sourcePath)
+
+ logPath = unittest.mock.MagicMock()
+ config.for_each_enabled(logPath)
+
+ logPath.assert_called_with(self.temporaryLLVM.repodir)
+
+ subprojs = LLVMSubproject.get_all_subprojects()
+ enabled = ["clang", "compiler-rt", "lld", "lldb", "libunwind"]
+ calls = []
+
+ for subproj in enabled:
+ path = subprojs[subproj].get_cmake_path(sourcePath)
+ worktree = Worktree.create(
+ self.proj,
+ self.__get_subproj_repo(subproj),
+ path,
+ self.temporaryLLVMbranch)
+ calls.append(call(path)) # Expect our mock to be called with path
+
+ logPath = unittest.mock.MagicMock()
+ config.for_each_enabled(logPath)
+
+ logPath.assert_has_calls(calls, any_order=True)
+
+ def _throw(self, projPath):
+ if "lld" in projPath:
+ raise ValueError("An error has been!!1")
+
+ def test_for_each_enabled_error(self):
+ """Test that we rethrow exceptions correctly."""
+ sourcePath = self.temporaryLLVM.repodir
+
+ config = LLVMSourceConfig(self.proj, sourcePath)
+ subprojs = LLVMSubproject.get_all_subprojects()
+ enabled = ["clang", "compiler-rt", "lld", "lldb", "libunwind"]
+
+ for subproj in enabled:
+ path = subprojs[subproj].get_cmake_path(sourcePath)
+ worktree = Worktree.create(
+ self.proj,
+ self.__get_subproj_repo(subproj),
+ path,
+ self.temporaryLLVMbranch)
+
+ with self.assertRaises(RuntimeError) as context:
+ config.for_each_enabled(self._throw)
+ self.assertRegex(str(context.exception),
+ "(.*\n?)*Error while processing lld(.*\n)*")
+ self.assertRegex(str(context.exception.__cause__),
+ "(.*\n?)*An error has been!!1(.*\n)*")
+
if __name__ == "__main__":
unittest.main()
diff --git a/tests/unittests/testpush.py b/tests/unittests/testpush.py
new file mode 100644
index 0000000..0046e2b
--- /dev/null
+++ b/tests/unittests/testpush.py
@@ -0,0 +1,200 @@
+import os
+import unittest
+import uuid
+
+from sh import git
+
+from linaropy.cd import cd
+from linaropy.proj import Proj
+from linaropy.git.clone import Clone
+from linaropy.git.worktree import Worktree
+
+from modules.llvm import get_user_from_remote, push_current_branch
+
+
+class TestGetUser(unittest.TestCase):
+ testdirprefix = "GetUserUT"
+
+ def test_full_remote(self):
+ user = get_user_from_remote("https://user1@remote.url:1234")
+ self.assertEqual(user, "user1")
+
+ user = get_user_from_remote("ssh://user2@remote.url:1234")
+ self.assertEqual(user, "user2")
+
+ def test_no_protocol_remote(self):
+ user = get_user_from_remote("user.name@remote.url:1234")
+ self.assertEqual(user, "user.name")
+
+ def test_no_user(self):
+ user = get_user_from_remote("https://remote.url:1234:")
+ self.assertEqual(user, None)
+
+
+class TestPush(unittest.TestCase):
+ testdirprefix = "PushUT"
+
+ def __create_dummy_commit(
+ self,
+ message="Branches without commits confuse git"):
+ filename = "file" + str(uuid.uuid4())
+ open(filename, "a").close()
+ git("add", filename)
+ git("commit", "-m", message)
+
+ def __get_last_commit_message(self, branch=""):
+ return str(git("rev-list", "-1", "--oneline", branch)).strip()
+
+ def __create_dummy_repo(self, path):
+ if not os.path.exists(path):
+ os.makedirs(path)
+
+ with cd(path):
+ git("init")
+ self.__create_dummy_commit()
+
+ def setUp(self):
+ # We're going to create a hierarchy with an origin repo, a clone repo
+ # and a worktree of the clone. When pushing through the worktree, we
+ # expect to see things in origin.
+ self.proj = Proj(prefix=self.testdirprefix)
+ self.user = "llvm-developer"
+
+ path = os.path.join(self.proj.projdir, "origin")
+ self.__create_dummy_repo(path)
+ self.origin = Clone(self.proj, path)
+
+ path = os.path.join(self.proj.projdir, "clone")
+ git("clone", "file://" + self.user + "@" + self.origin.repodir, path)
+ self.clone = Clone(self.proj, path)
+
+ self.worktreeBranch = "a-branch"
+ self.worktree = Worktree.create(
+ self.proj, self.clone, os.path.join(
+ self.proj.projdir, "worktree"), self.worktreeBranch)
+
+ def tearDown(self):
+ self.proj.cleanup()
+
+ def test_push_new_branch(self):
+ """Test that we can push a new branch to origin."""
+
+ with cd(self.worktree.repodir):
+ self.__create_dummy_commit("This should make it to origin")
+
+ push_current_branch(self.proj, self.worktree.repodir)
+
+ with cd(self.origin.repodir):
+ self.assertRegex(
+ self.__get_last_commit_message(
+ "linaro-local/{}/{}".format(
+ self.user,
+ self.worktreeBranch)),
+ ".*This should make it to origin")
+
+ def test_push_existing_branch(self):
+ """Test that we can push to a branch that already exists in origin."""
+
+ remoteBranch = "linaro-local/{}/{}".format(
+ self.user, self.worktreeBranch)
+
+ with cd(self.worktree.repodir):
+ self.__create_dummy_commit("This already exists in origin")
+ git("push", "origin", "{}:{}".format(
+ self.worktreeBranch, remoteBranch))
+
+ self.__create_dummy_commit("This should make it to origin too")
+
+ push_current_branch(self.proj, self.worktree.repodir)
+
+ with cd(self.origin.repodir):
+ self.assertRegex(self.__get_last_commit_message(remoteBranch),
+ ".*This should make it to origin too")
+
+ def test_push_squashed_update(self):
+ """
+ Test that we can push again after squashing some fixes into a commit
+ that has already been pushed to origin. This isn't a nice thing to do,
+ but we need to support it because Gerrit requires squashes.
+ """
+ remoteBranch = "linaro-local/{}/{}".format(self.user,
+ self.worktreeBranch)
+ with cd(self.worktree.repodir):
+ self.__create_dummy_commit("First version of the patch")
+
+ push_current_branch(self.proj, self.worktree.repodir)
+
+ with cd(self.origin.repodir):
+ self.assertRegex(
+ self.__get_last_commit_message(remoteBranch),
+ ".*First version of the patch")
+
+ with cd(self.worktree.repodir):
+ git("commit", "--amend", "-m", "Second version of the patch")
+
+ push_current_branch(self.proj, self.worktree.repodir)
+
+ with cd(self.origin.repodir):
+ self.assertRegex(
+ self.__get_last_commit_message(remoteBranch),
+ "/*Second version of the patch")
+
+ def test_push_rebased_branch(self):
+ """ Test that we can push again with new updates after a rebase."""
+ remoteBranch = "linaro-local/{}/{}".format(self.user,
+ self.worktreeBranch)
+ with cd(self.worktree.repodir):
+ self.__create_dummy_commit("First change")
+
+ push_current_branch(self.proj, self.worktree.repodir)
+
+ with cd(self.origin.repodir):
+ self.assertRegex(
+ self.__get_last_commit_message(remoteBranch),
+ ".*First change")
+
+ with cd(self.origin.repodir):
+ self.__create_dummy_commit("Master moving forward")
+
+ with cd(self.worktree.repodir):
+ self.__create_dummy_commit("Second change")
+ git("fetch", "origin", "master")
+ git("rebase", "origin/master")
+
+ push_current_branch(self.proj, self.worktree.repodir)
+
+ with cd(self.origin.repodir):
+ self.assertRegex(self.__get_last_commit_message(remoteBranch),
+ ".*Second change")
+
+ def test_push_no_user(self):
+ """Test that we error out when we can't parse a user in the remote name."""
+ remote = "file://" + self.origin.repodir
+ with cd(self.worktree.repodir):
+ git("remote", "set-url", "origin", remote)
+ self.__create_dummy_commit("Make it look like a real branch")
+
+ with self.assertRaises(EnvironmentError) as context:
+ push_current_branch(self.proj, self.worktree.repodir)
+
+ self.assertEqual(str(context.exception),
+ "Couldn't parse user from {}.".format(remote))
+
+ def test_push_invalid_user(self):
+ """Test that we error out when the value of LLVM_GITUSER wouldn't look good in a branch name (e.g. if it contains spaces)."""
+
+ badUser = "LLVM Developer"
+ with cd(self.worktree.repodir):
+ git("remote", "set-url", "origin",
+ "file://{}@{}".format(badUser, self.origin.repodir))
+ self.__create_dummy_commit("Make it look like a real branch")
+
+ with self.assertRaises(EnvironmentError) as context:
+ push_current_branch(self.proj, self.worktree.repodir)
+
+ self.assertEqual(str(context.exception),
+ "linaro-local/{}/{} is not a valid branch name.".format(badUser,
+ self.worktreeBranch))
+
+if __name__ == "__main__":
+ unittest.main()