diff --git a/openstack_releases/cmds/validate.py b/openstack_releases/cmds/validate.py index c0c7db03a9..2cb0246e1d 100644 --- a/openstack_releases/cmds/validate.py +++ b/openstack_releases/cmds/validate.py @@ -37,6 +37,7 @@ from openstack_releases import defaults from openstack_releases import gitutils from openstack_releases import governance from openstack_releases import project_config +from openstack_releases import puppetutils from openstack_releases import pythonutils from openstack_releases import versionutils @@ -292,6 +293,23 @@ def validate_releases(deliverable_info, zuul_layout, (release['version'], e)) mk_error(msg) + # If this is a puppet module, ensure + # that the tag and metadata file + # match. + if puppetutils.looks_like_a_module(workdir, + project['repo']): + puppet_ver = puppetutils.get_version( + workdir, project['repo']) + if puppet_ver != release['version']: + mk_error( + '%s metadata contains "%s" ' + 'but is being tagged "%s"' % ( + project['repo'], + puppet_ver, + release['version'], + ) + ) + if is_independent: mk_warning('skipping descendant test for ' 'independent project, verify ' diff --git a/openstack_releases/puppetutils.py b/openstack_releases/puppetutils.py new file mode 100644 index 0000000000..a319e83bf0 --- /dev/null +++ b/openstack_releases/puppetutils.py @@ -0,0 +1,38 @@ +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import json +import os.path + + +def looks_like_a_module(workdir, repo): + "Does the directory look like it contains a puppet module?" + if not os.path.exists(os.path.join(workdir, repo, 'metadata.json')): + return False + return any([ + os.path.exists(os.path.join(workdir, repo, 'lib')), + os.path.exists(os.path.join(workdir, repo, 'manifests')), + ]) + + +def get_metadata(workdir, repo): + "Load the metadata.json file from the repo" + with open(os.path.join(workdir, repo, 'metadata.json'), 'r') as f: + body = f.read() + return json.loads(body) + + +def get_version(workdir, repo): + "Get the version string from the project metadata." + return get_metadata(workdir, repo).get('version') diff --git a/openstack_releases/tests/test_puppetutils.py b/openstack_releases/tests/test_puppetutils.py new file mode 100644 index 0000000000..78a9b76ced --- /dev/null +++ b/openstack_releases/tests/test_puppetutils.py @@ -0,0 +1,110 @@ +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from __future__ import unicode_literals + +import os + +import fixtures +import json +import mock +from oslotest import base + +from openstack_releases import puppetutils + + +class TestModuleDetection(base.BaseTestCase): + + def test_no_metadata(self): + + def exists(name): + if name.endswith('metadata.json'): + return False + + with mock.patch('os.path.exists', exists): + is_mod = puppetutils.looks_like_a_module( + '.', 'openstack/puppet-watcher') + self.assertFalse(is_mod) + + def test_no_lib_or_manifests(self): + + def exists(name): + if name.endswith('metadata.json'): + return True + return False + + with mock.patch('os.path.exists', exists): + is_mod = puppetutils.looks_like_a_module( + '.', 'openstack/puppet-watcher') + self.assertFalse(is_mod) + + def test_with_lib(self): + + def exists(name): + if name.endswith('metadata.json'): + return True + if name.endswith('lib'): + return True + return False + + with mock.patch('os.path.exists', exists): + is_mod = puppetutils.looks_like_a_module( + '.', 'openstack/puppet-watcher') + self.assertTrue(is_mod) + + def test_with_manifests(self): + + def exists(name): + if name.endswith('metadata.json'): + return True + if name.endswith('manifests'): + return True + return False + + with mock.patch('os.path.exists', exists): + is_mod = puppetutils.looks_like_a_module( + '.', 'openstack/puppet-watcher') + self.assertTrue(is_mod) + + +class TestGetMetadata(base.BaseTestCase): + + def setUp(self): + super(TestGetMetadata, self).setUp() + self.tmpdir = self.useFixture(fixtures.TempDir()).path + self.repo = 'foo' + self.mdfn = os.path.join(self.tmpdir, self.repo, 'metadata.json') + os.makedirs(os.path.join(self.tmpdir, self.repo)) + self.expected = { + "name": "openstack-zaqar", + "version": "10.1.0", + "author": "OpenStack Contributors", + "summary": "Puppet module for OpenStack Zaqar", + "license": "Apache-2.0", + "source": "git://github.com/openstack/puppet-zaqar.git", + "project_page": "https://launchpad.net/puppet-zaqar", + "issues_url": "https://bugs.launchpad.net/puppet-zaqar", + "description": "Installs and configures OpenStack Zaqar." + } + + with open(self.mdfn, 'w') as f: + f.write(json.dumps(self.expected)) + + def test_get_metadata(self): + md = puppetutils.get_metadata(self.tmpdir, self.repo) + self.assertEqual(self.expected, md) + + def test_get_version(self): + ver = puppetutils.get_version(self.tmpdir, self.repo) + self.assertEqual('10.1.0', ver) diff --git a/openstack_releases/tests/test_validate.py b/openstack_releases/tests/test_validate.py index b94bfb10ed..ffeaa74edb 100644 --- a/openstack_releases/tests/test_validate.py +++ b/openstack_releases/tests/test_validate.py @@ -624,6 +624,71 @@ class TestValidateReleases(base.BaseTestCase): self.assertEqual(0, len(errors)) +class TestPuppetUtils(base.BaseTestCase): + + def setUp(self): + super(TestPuppetUtils, self).setUp() + self.tmpdir = self.useFixture(fixtures.TempDir()).path + + @mock.patch('openstack_releases.puppetutils.get_version') + @mock.patch('openstack_releases.puppetutils.looks_like_a_module') + def test_valid_version(self, llam, get_version): + llam.return_value = True + get_version.return_value = '99.1.0' + deliverable_info = { + 'artifact-link-mode': 'none', + 'releases': [ + {'version': '99.1.0', + 'projects': [ + {'repo': 'openstack/puppet-watcher', + 'hash': '1e7baef27139f69a83e1fe28686bb72ee7e1d6fa'}, + ]} + ], + } + warnings = [] + errors = [] + validate.validate_releases( + deliverable_info, + {'validate-projects-by-name': {}}, + 'ocata', + self.tmpdir, + warnings.append, + errors.append, + ) + print(warnings, errors) + self.assertEqual(0, len(warnings)) + self.assertEqual(0, len(errors)) + + @mock.patch('openstack_releases.puppetutils.get_version') + @mock.patch('openstack_releases.puppetutils.looks_like_a_module') + def test_mismatched_version(self, llam, get_version): + llam.return_value = True + get_version.return_value = '99.1.0' + deliverable_info = { + 'artifact-link-mode': 'none', + 'releases': [ + {'version': '99.2.0', + 'projects': [ + {'repo': 'openstack/puppet-watcher', + 'hash': '1e7baef27139f69a83e1fe28686bb72ee7e1d6fa'}, + ]} + ], + } + warnings = [] + errors = [] + validate.validate_releases( + deliverable_info, + {'validate-projects-by-name': {}}, + 'ocata', + self.tmpdir, + warnings.append, + errors.append, + ) + print(warnings, errors) + self.assertEqual(0, len(warnings)) + self.assertEqual(1, len(errors)) + + class TestValidateTarballBase(base.BaseTestCase): def setUp(self):