diff --git a/openstack_releases/cmds/validate.py b/openstack_releases/cmds/validate.py index 85d14e4a23..57a58752f4 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 pythonutils from openstack_releases import versionutils urllib3.disable_warnings() @@ -62,6 +63,8 @@ _VALID_BRANCH_PREFIXES = set([ 'feature', 'driverfixes', ]) +_PLEASE = ('It is too expensive to determine this value during ' + 'the site build, please set it explicitly.') def is_a_hash(val): @@ -224,6 +227,31 @@ def validate_releases(deliverable_info, zuul_layout, # No point in running extra checks if the SHA just # doesn't exist. continue + + # Ensure we have a local copy of the repository so we + # can scan for values that are more difficult to get + # remotely. + gitutils.clone_repo(workdir, project['repo']) + + # Check that the sdist name and tarball-base name match. + sdist = pythonutils.get_sdist_name(workdir, project['repo']) + if sdist is not None: + expected = project.get( + 'tarball-base', + os.path.basename(project['repo']), + ) + if sdist != expected: + if 'tarball-base' in deliverable_info: + action = 'is set to' + else: + action = 'defaults to' + mk_error( + ('tarball-base for %s %s %s %r ' + 'but the sdist name is actually %r. ' + + _PLEASE) + % (project['repo'], release['version'], + action, expected, sdist)) + # Report if the version has already been # tagged. We expect it to not exist, but neither # case is an error because sometimes we want to @@ -232,7 +260,6 @@ def validate_releases(deliverable_info, zuul_layout, version_exists = gitutils.tag_exists( project['repo'], release['version'], ) - gitutils.clone_repo(workdir, project['repo']) if version_exists: actual_sha = gitutils.sha_for_tag( workdir, @@ -331,6 +358,7 @@ def validate_releases(deliverable_info, zuul_layout, def validate_new_releases(deliverable_info, filename, team_data, mk_warning, mk_error): + """Apply validation rules that only apply to the current series. """ if not deliverable_info.get('releases'): diff --git a/openstack_releases/pythonutils.py b/openstack_releases/pythonutils.py new file mode 100644 index 0000000000..7634610af7 --- /dev/null +++ b/openstack_releases/pythonutils.py @@ -0,0 +1,32 @@ +# 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 os +import os.path +import subprocess + + +def get_sdist_name(workdir, repo): + "Check out the code." + dest = os.path.join(workdir, repo) + if not os.path.exists(os.path.join(dest, 'setup.py')): + # Not a python project + return None + cmd = ['python', 'setup.py', '--name'] + # Run it once and discard the result to ensure any setup_requires + # dependencies are installed. + subprocess.check_output(cmd, cwd=dest) + # Run it again to get a clean version of the name. + name = subprocess.check_output(cmd, cwd=dest).strip() + return name diff --git a/openstack_releases/tests/test_validate.py b/openstack_releases/tests/test_validate.py index 5aa5820e95..b6ec067403 100644 --- a/openstack_releases/tests/test_validate.py +++ b/openstack_releases/tests/test_validate.py @@ -624,6 +624,120 @@ class TestValidateReleases(base.BaseTestCase): self.assertEqual(0, len(errors)) +class TestValidateTarballBase(base.BaseTestCase): + + def setUp(self): + super(TestValidateTarballBase, self).setUp() + self.tmpdir = self.useFixture(fixtures.TempDir()).path + + @mock.patch('openstack_releases.pythonutils.get_sdist_name') + def test_default_ok(self, gsn): + deliverable_info = { + 'artifact-link-mode': 'none', + 'releases': [ + {'version': '1.5.0', + 'projects': [ + {'repo': 'openstack/automaton', + 'hash': 'be2885f544637e6ee6139df7dc7bf937925804dd'}, + ]} + ], + } + warnings = [] + errors = [] + gsn.return_value = 'automaton' + validate.validate_releases( + deliverable_info, + {'validate-projects-by-name': {}}, + 'ocata', + self.tmpdir, + warnings.append, + errors.append, + ) + self.assertEqual(0, len(warnings)) + self.assertEqual(0, len(errors)) + + @mock.patch('openstack_releases.pythonutils.get_sdist_name') + def test_default_invalid(self, gsn): + deliverable_info = { + 'artifact-link-mode': 'none', + 'releases': [ + {'version': '1.5.0', + 'projects': [ + {'repo': 'openstack/automaton', + 'hash': 'be2885f544637e6ee6139df7dc7bf937925804dd'}, + ]} + ], + } + warnings = [] + errors = [] + gsn.return_value = 'automaton1' + validate.validate_releases( + deliverable_info, + {'validate-projects-by-name': {}}, + 'ocata', + self.tmpdir, + warnings.append, + errors.append, + ) + self.assertEqual(0, len(warnings)) + self.assertEqual(1, len(errors)) + + @mock.patch('openstack_releases.pythonutils.get_sdist_name') + def test_explicit_ok(self, gsn): + deliverable_info = { + 'artifact-link-mode': 'none', + 'releases': [ + {'version': '1.5.0', + 'projects': [ + {'repo': 'openstack/automaton', + 'hash': 'be2885f544637e6ee6139df7dc7bf937925804dd', + 'tarball-base': 'automaton1'}, + ]} + ], + } + warnings = [] + errors = [] + gsn.return_value = 'automaton1' + validate.validate_releases( + deliverable_info, + {'validate-projects-by-name': {}}, + 'ocata', + self.tmpdir, + warnings.append, + errors.append, + ) + self.assertEqual(0, len(warnings)) + self.assertEqual(0, len(errors)) + + @mock.patch('openstack_releases.pythonutils.get_sdist_name') + def test_explicit_invalid(self, gsn): + deliverable_info = { + 'artifact-link-mode': 'none', + 'releases': [ + {'version': '1.5.0', + 'projects': [ + {'repo': 'openstack/automaton', + 'hash': 'be2885f544637e6ee6139df7dc7bf937925804dd', + 'tarball-base': 'does-not-match-sdist'}, + ]} + ], + } + warnings = [] + errors = [] + gsn.return_value = 'automaton' + 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 TestValidateNewReleases(base.BaseTestCase): team_data_yaml = textwrap.dedent("""