diff --git a/openstack_releases/cmds/validate.py b/openstack_releases/cmds/validate.py index 418edda3b9..d7a6f6bf18 100644 --- a/openstack_releases/cmds/validate.py +++ b/openstack_releases/cmds/validate.py @@ -20,6 +20,7 @@ from __future__ import print_function import argparse import atexit +import glob import os import os.path import re @@ -76,6 +77,49 @@ def is_a_hash(val): return re.search('^[a-f0-9]{40}$', val, re.I) is not None +def validate_series_open(deliverable_info, + series_name, filename, + mk_warning, mk_error): + "No releases in the new series until the previous one has a branch." + if not deliverable_info.get('releases'): + return + if series_name == '_independent': + # These rules don't apply to independent projects. + return + deliverables_dir = os.path.dirname( + os.path.dirname(filename) + ) + deliverable_base = os.path.basename(filename) + pattern = os.path.join( + deliverables_dir, + '*', + deliverable_base, + ) + all_deliverable_files = list(sorted(glob.glob(pattern))) + idx = all_deliverable_files.index(filename) + if idx == 0: + # This is the first deliverable file. + return + previous_deliverable_file = all_deliverable_files[idx - 1] + previous_series = os.path.basename( + os.path.dirname(previous_deliverable_file) + ) + expected_branch = 'stable/' + previous_series + with open(previous_deliverable_file, 'r') as f: + previous_deliverable = yaml.load(f.read()) + if not previous_deliverable: + # An empty file results in None, so convert to dict to + # make using the value easier. + previous_deliverable = {} + for branch in previous_deliverable.get('branches', []): + if branch['name'] == expected_branch: + # Everything is OK + return + mk_error( + 'There is no {} branch defined in {}. Is the {} series open?'.format( + expected_branch, previous_deliverable_file, series_name)) + + def validate_launchpad(deliverable_info, mk_warning, mk_error): "Look for the launchpad project" try: @@ -634,6 +678,13 @@ def main(): mk_warning, mk_error, ) + validate_series_open( + deliverable_info, + series_name, + filename, + mk_warning, + mk_error, + ) validate_branch_prefixes( deliverable_info, mk_warning, diff --git a/openstack_releases/tests/test_validate.py b/openstack_releases/tests/test_validate.py index 8d5d09bc47..ff55e60ebe 100644 --- a/openstack_releases/tests/test_validate.py +++ b/openstack_releases/tests/test_validate.py @@ -14,6 +14,7 @@ from __future__ import unicode_literals +import os import textwrap import fixtures @@ -1344,3 +1345,136 @@ class TestValidateDriverfixesBranches(base.BaseTestCase): print(warnings, errors) self.assertEqual(0, len(warnings)) self.assertEqual(1, len(errors)) + + +class TestValidateSeriesOpen(base.BaseTestCase): + + def setUp(self): + super(TestValidateSeriesOpen, self).setUp() + self.tmpdir = self.useFixture(fixtures.TempDir()).path + + def test_series_is_open(self): + series_a_dir = self.tmpdir + '/a' + series_a_filename = series_a_dir + '/automaton.yaml' + series_b_dir = self.tmpdir + '/b' + series_b_filename = series_b_dir + '/automaton.yaml' + os.makedirs(series_a_dir) + os.makedirs(series_b_dir) + branch_data = textwrap.dedent(''' + --- + branches: + - name: stable/a + location: 1.4.0 + ''') + deliverable_data = textwrap.dedent(''' + --- + releases: + - version: 1.5.0 + projects: + - repo: openstack/automaton + hash: be2885f544637e6ee6139df7dc7bf937925804dd + ''') + with open(series_a_filename, 'w') as f: + f.write(branch_data) + with open(series_b_filename, 'w') as f: + f.write(deliverable_data) + warnings = [] + errors = [] + deliverable_info = yaml.safe_load(deliverable_data) + validate.validate_series_open( + deliverable_info, + 'a', + series_b_filename, + warnings.append, + errors.append, + ) + print(warnings, errors) + self.assertEqual(0, len(warnings)) + self.assertEqual(0, len(errors)) + + def test_no_earlier_series(self): + series_b_dir = self.tmpdir + '/b' + series_b_filename = series_b_dir + '/automaton.yaml' + os.makedirs(series_b_dir) + deliverable_data = textwrap.dedent(''' + --- + releases: + - version: 1.5.0 + projects: + - repo: openstack/automaton + hash: be2885f544637e6ee6139df7dc7bf937925804dd + ''') + with open(series_b_filename, 'w') as f: + f.write(deliverable_data) + warnings = [] + errors = [] + deliverable_info = yaml.safe_load(deliverable_data) + validate.validate_series_open( + deliverable_info, + 'a', + series_b_filename, + warnings.append, + errors.append, + ) + print(warnings, errors) + self.assertEqual(0, len(warnings)) + self.assertEqual(0, len(errors)) + + def test_independent(self): + deliverable_data = textwrap.dedent(''' + --- + releases: + - version: 1.5.0 + projects: + - repo: openstack/automaton + hash: be2885f544637e6ee6139df7dc7bf937925804dd + ''') + warnings = [] + errors = [] + deliverable_info = yaml.safe_load(deliverable_data) + validate.validate_series_open( + deliverable_info, + '_independent', + 'filename', # not used + warnings.append, + errors.append, + ) + print(warnings, errors) + self.assertEqual(0, len(warnings)) + self.assertEqual(0, len(errors)) + + def test_no_stable_branch(self): + series_a_dir = self.tmpdir + '/a' + series_a_filename = series_a_dir + '/automaton.yaml' + series_b_dir = self.tmpdir + '/b' + series_b_filename = series_b_dir + '/automaton.yaml' + os.makedirs(series_a_dir) + os.makedirs(series_b_dir) + branch_data = textwrap.dedent(''' + --- + ''') + deliverable_data = textwrap.dedent(''' + --- + releases: + - version: 1.5.0 + projects: + - repo: openstack/automaton + hash: be2885f544637e6ee6139df7dc7bf937925804dd + ''') + with open(series_a_filename, 'w') as f: + f.write(branch_data) + with open(series_b_filename, 'w') as f: + f.write(deliverable_data) + warnings = [] + errors = [] + deliverable_info = yaml.safe_load(deliverable_data) + validate.validate_series_open( + deliverable_info, + 'a', + series_b_filename, + warnings.append, + errors.append, + ) + print(warnings, errors) + self.assertEqual(0, len(warnings)) + self.assertEqual(1, len(errors))