From 083ba20f5008083510d46943bc2e22bada937bf0 Mon Sep 17 00:00:00 2001 From: Mark Burnett Date: Fri, 13 Oct 2017 23:28:03 -0500 Subject: [PATCH] fix(git): allow specifying git refs for sources This allows, e.g., pointing at a particular Gerrit Patch Set using natural configuration, e.g.: --- schema: armada/Chart/v1 metadata: schema: metadata/Document/v1 name: ceph-config data: chart_name: ceph-config release: ceph-config namespace: ucp timeout: 3600 install: no_hooks: true upgrade: no_hooks: true values: {} source: type: git location: https://github.com/openstack/openstack-helm subpath: ceph reference: refs/changes/54/457754/73 dependencies: [] Change-Id: Ib6af0fec2bbfa1fa4e523d839df44af047697522 --- armada/handlers/armada.py | 2 +- armada/tests/unit/utils/test_source.py | 54 +++++++++++++------ armada/utils/source.py | 11 ++-- .../operations/guide-build-armada-yaml.rst | 22 ++++---- tox.ini | 2 +- 5 files changed, 56 insertions(+), 35 deletions(-) diff --git a/armada/handlers/armada.py b/armada/handlers/armada.py index 2e2c891d..6143cf53 100644 --- a/armada/handlers/armada.py +++ b/armada/handlers/armada.py @@ -152,7 +152,7 @@ class Armada(object): repo_dir = source.git_clone(*repo_branch) except Exception: raise source_exceptions.GitLocationException( - '{} branch: {}'.format(*repo_branch)) + '{} reference: {}'.format(*repo_branch)) repos[repo_branch] = repo_dir ch.get('chart')['source_dir'] = (repo_dir, subpath) else: diff --git a/armada/tests/unit/utils/test_source.py b/armada/tests/unit/utils/test_source.py index 104ac969..43775372 100644 --- a/armada/tests/unit/utils/test_source.py +++ b/armada/tests/unit/utils/test_source.py @@ -12,40 +12,61 @@ # See the License for the specific language governing permissions and # limitations under the License. +import os +import shutil + import mock import unittest from armada.exceptions import source_exceptions - from armada.utils import source class GitTestCase(unittest.TestCase): - SOURCE_UTILS_LOCATION = 'armada.utils.source' + def _validate_git_clone(self, repo_dir, expected_ref=None): + self.assertTrue(os.path.isdir(repo_dir)) + self.addCleanup(shutil.rmtree, repo_dir) + self.assertIn('armada', repo_dir) + # Assert that the directory is a Git repo. + self.assertTrue(os.path.isdir(os.path.join(repo_dir, '.git'))) + if expected_ref: + # Assert the FETCH_HEAD is at the expected ref. + with open(os.path.join(repo_dir, '.git', 'FETCH_HEAD'), 'r') \ + as git_file: + self.assertIn(expected_ref, git_file.read()) - @mock.patch('armada.utils.source.Git') - @mock.patch('armada.utils.source.tempfile') - @mock.patch('armada.utils.source.Repo') - def test_git_clone_good_url(self, mock_git_repo, mock_temp, mock_git_lib): - mock_temp.mkdtemp.return_value = '/tmp/armada' - mock_git_lib.checkout.return_value = "Repository" + def test_git_clone_good_url(self): url = 'http://github.com/att-comdev/armada' + git_dir = source.git_clone(url) + self._validate_git_clone(git_dir) - dir = source.git_clone(url) + def test_git_clone_commit(self): + url = 'http://github.com/att-comdev/armada' + commit = 'cba78d1d03e4910f6ab1691bae633c5bddce893d' + git_dir = source.git_clone(url, commit) + self._validate_git_clone(git_dir) - self.assertIsNotNone(dir) + def test_git_clone_ref(self): + ref = 'refs/changes/54/457754/73' + git_dir = source.git_clone( + 'https://github.com/openstack/openstack-helm', ref) + self._validate_git_clone(git_dir, ref) def test_git_clone_empty_url(self): url = '' + error_re = '%s is not a valid git repository.' % url - with self.assertRaises(Exception): - self.assertFalse(source.git_clone(url)) + with self.assertRaisesRegexp( + source_exceptions.GitLocationException, error_re): + source.git_clone(url) def test_git_clone_bad_url(self): url = 'http://github.com/dummy/armada' + error_re = '%s is not a valid git repository.' % url - with self.assertRaises(Exception): + with self.assertRaisesRegexp( + source_exceptions.GitLocationException, error_re): source.git_clone(url) @mock.patch('armada.utils.source.tempfile') @@ -58,8 +79,7 @@ class GitTestCase(unittest.TestCase): mock_requests.get.return_value = mock_response mock_open = mock.mock_open() - with mock.patch('{}.open'.format(self.SOURCE_UTILS_LOCATION), - mock_open, create=True): + with mock.patch.object(source, 'open', mock_open, create=True): source.download_tarball(url) mock_temp.mkstemp.assert_called_once() @@ -90,7 +110,7 @@ class GitTestCase(unittest.TestCase): def test_tarball_extract_bad_path(self, mock_tarfile, mock_path): mock_path.exists.return_value = False path = '/tmp/armada' - with self.assertRaises(Exception): + with self.assertRaises(source_exceptions.InvalidPathException): source.extract_tarball(path) mock_tarfile.open.assert_not_called() @@ -115,6 +135,6 @@ class GitTestCase(unittest.TestCase): def test_source_cleanup_bad_path(self, mock_path, mock_shutil): mock_path.exists.return_value = False path = 'armada' - with self.assertRaises(Exception): + with self.assertRaises(source_exceptions.InvalidPathException): source.source_cleanup(path) mock_shutil.rmtree.assert_not_called() diff --git a/armada/utils/source.py b/armada/utils/source.py index f918993a..8e60c36b 100644 --- a/armada/utils/source.py +++ b/armada/utils/source.py @@ -22,13 +22,13 @@ import tempfile from git import Repo from git import Git -from ..exceptions import source_exceptions +from armada.exceptions import source_exceptions -def git_clone(repo_url, branch='master'): +def git_clone(repo_url, ref='master'): ''' :params repo_url - URL of git repo to clone - :params branch - branch of the repo to clone + :params ref - branch, commit or reference in the repo to clone Returns a path to the cloned repo ''' @@ -40,9 +40,10 @@ def git_clone(repo_url, branch='master'): _tmp_dir = tempfile.mkdtemp(prefix='armada') try: - repo = Repo.clone_from(repo_url, _tmp_dir, **{'branch': 'master'}) + repo = Repo.clone_from(repo_url, _tmp_dir) + repo.remotes.origin.fetch(ref) g = Git(repo.working_dir) - g.checkout(branch) + g.checkout('FETCH_HEAD') except Exception: raise source_exceptions.GitLocationException(repo_url) diff --git a/docs/source/operations/guide-build-armada-yaml.rst b/docs/source/operations/guide-build-armada-yaml.rst index 634cd6c2..9948df50 100644 --- a/docs/source/operations/guide-build-armada-yaml.rst +++ b/docs/source/operations/guide-build-armada-yaml.rst @@ -230,17 +230,17 @@ Example Source ^^^^^^ -+-------------+----------+-------------------------------------------------------------------------------+ -| keyword | type | action | -+=============+==========+===============================================================================+ -| type | string | source to build the chart: ``git``, ``local``, or ``tar`` | -+-------------+----------+-------------------------------------------------------------------------------+ -| location | string | ``url`` or ``path`` to the chart's parent directory | -+-------------+----------+-------------------------------------------------------------------------------+ -| subpath | string | (optional) relative path to target chart from parent (``.`` if not specified) | -+-------------+----------+-------------------------------------------------------------------------------+ -| reference | string | (optional) branch of the repo (``master`` if not specified) | -+-------------+----------+-------------------------------------------------------------------------------+ ++-------------+----------+-----------------------------------------------------------------------------------+ +| keyword | type | action | ++=============+==========+===================================================================================+ +| type | string | source to build the chart: ``git``, ``local``, or ``tar`` | ++-------------+----------+-----------------------------------------------------------------------------------+ +| location | string | ``url`` or ``path`` to the chart's parent directory | ++-------------+----------+-----------------------------------------------------------------------------------+ +| subpath | string | (optional) relative path to target chart from parent (``.`` if not specified) | ++-------------+----------+-----------------------------------------------------------------------------------+ +| reference | string | (optional) branch, commit, or reference in the repo (``master`` if not specified) | ++-------------+----------+-----------------------------------------------------------------------------------+ Example diff --git a/tox.ini b/tox.ini index e6c6a193..91f82436 100644 --- a/tox.ini +++ b/tox.ini @@ -42,4 +42,4 @@ commands = [flake8] filename= *.py ignore = -exclude= .git, .idea, .tox, *.egg-info, *.eggs, bin, dist, hapi +exclude= .git, .idea, .tox, *.egg-info, *.eggs, bin, dist, hapi, docs/*