aboutsummaryrefslogtreecommitdiff
path: root/tests/cli
diff options
context:
space:
mode:
authorDiana Picus <diana.picus@linaro.org>2017-06-09 19:14:08 +0200
committerDiana Picus <diana.picus@linaro.org>2017-07-07 18:08:56 +0200
commitefc7bdaf3f4e53b0b9c15c4b1100dcf2e9d30b09 (patch)
tree50ab59c5106a23a2f11ee9478407f278afc520b4 /tests/cli
parent3601bea50533d4ba06fafac16664183cdb250ab0 (diff)
[llvmpush] Add llvm push
Add support for pushing the current branch in all linked subprojects in a given config. If they are not on the same branch, an error is thrown. The branches are pushed as linaro-local/$user/$branch, where $branch is the local name of the branch and $user is the user as seen in LLVM_GITUSER (we might want to change to a more intelligent way to get the user in the future). We achieve this by adding a new method to LLVMSourceConfig: for_each_enabled, which takes an action and applies it to all the enabled subprojects. If an exception is thrown by the action, it is rethrown by the action as a RuntimeError specifying which project the action was being applied to. Note that this does not behave like a transaction - the action may have been applied to some of the projects already, and there's no way to undo it. It's also a bit difficult to tell which projects the action was applied on (in the future we should probably log that info). We also provide an action that simply pushes the current branch to origin with the updated name. This makes sure the remote branch will live in an isolated namespace where it won't conflict with other people's branches. We also update some of the internals of LLVMSourceConfig to throw exceptions if some of the subprojects that are linked are not worktrees on the same branch as LLVM. In the past they were just ignored, but that doesn't seem like a sane default anymore. Change-Id: I9c917658d65b5d0e7bad3310efce07a0fe5bce5e
Diffstat (limited to 'tests/cli')
-rw-r--r--tests/cli/llvmtestcase.py29
-rw-r--r--tests/cli/testllvmprojects.py4
-rw-r--r--tests/cli/testllvmpush.py166
3 files changed, 187 insertions, 12 deletions
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)*")