update validation to support eol tags

Update the version string validation to allow a series-eol
tag. Require that the EOL tag for a deliverable match the series and
be applied to all repositories that are part of the deliverable.

Extend the Release data object to understand whether its tag is an EOL
tag and if so to return the series component from it as eol_series.

Story: #2001879
Task: #14344
Change-Id: I40b6822c942b559dc6f18a4b6be6abb5407c4d7c
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
This commit is contained in:
Doug Hellmann 2018-06-14 10:23:12 -04:00
parent c43e9e483f
commit be69bc3581
4 changed files with 368 additions and 4 deletions

View File

@ -251,6 +251,39 @@ def validate_series_final(deliv, context):
print('OK')
@applies_to_released
def validate_series_eol(deliv, context):
"The EOL tag should be applied to the previous release."
current_release = deliv.releases[-1]
if not current_release.is_eol:
print('this rule only applies when tagging a series as end-of-life')
return
# The tag should be applied to all of the repositories for the
# deliverable.
actual_repos = set(p.repo.name for p in current_release.projects)
expected_repos = set(r.name for r in deliv.repos)
error = False
for extra in actual_repos.difference(expected_repos):
error = True
context.error(
'EOL release %s includes repository %s '
'that is not in deliverable' %
(current_release.version, extra)
)
for missing in expected_repos.difference(actual_repos):
error = True
context.error(
'release %s is missing %s, '
'which appears in the deliverable' %
(current_release.version, missing)
)
if not error:
print('OK')
@applies_to_current
@applies_to_released
@applies_to_cycle
@ -786,6 +819,15 @@ def validate_version_numbers(deliv, context):
LOG.debug('checking {}'.format(release.version))
if release.is_eol:
LOG.debug('Found new EOL tag {} for {}'.format(
release.version, deliv.name))
if release.eol_series != deliv.series:
context.error(
'EOL tag {} does not refer to the {} series.'.format(
release.version, deliv.series))
continue
for project in release.projects:
if not gitutils.safe_clone_repo(context.workdir, project.repo.name,
@ -958,13 +1000,17 @@ def validate_new_releases_in_open_series(deliv, context):
print('tag exists, skipping further validation')
continue
if release.is_eol:
LOG.debug('Found new EOL tag {} for {}'.format(
release.version, project.repo))
else:
LOG.debug('Found new version {} for {}'.format(
release.version, project.repo))
new_releases[release.version] = release
if new_releases:
# The series is closed but there is a new release.
msg = ('deliverable {} has status {!r} for {}'
msg = ('deliverable {} has status {!r} for {} '
'and cannot have new releases tagged').format(
deliv.name, deliv.stable_status, deliv.series)
context.error(msg)
@ -1589,6 +1635,7 @@ def main():
validate_series_first,
validate_series_final,
validate_series_post_final,
validate_series_eol,
validate_branch_prefixes,
validate_stable_branches,
validate_feature_branches,

View File

@ -300,6 +300,16 @@ class Release(object):
or 'b' in self.version
)
@property
def is_eol(self):
return self.version.endswith('-eol')
@property
def eol_series(self):
if self.is_eol:
return self.version.rpartition('-')[0]
return ''
def __eq__(self, other):
return self.version == other.version

View File

@ -79,3 +79,95 @@ class TestReleaseWasForced(base.BaseTestCase):
def test_true(self):
r = deliverable.Release('version', [], {'flags': ['forced']}, None)
self.assertTrue(r.was_forced)
class TestEOLTags(base.BaseTestCase):
def setUp(self):
super().setUp()
def test_is_eol_tag_true(self):
deliverable_data = textwrap.dedent('''
releases:
- version: newton-eol
projects:
- repo: openstack/release-test
hash: a26e6a2e8a5e321b2e3517dbb01a7b9a56a8bfd5
''')
deliv = deliverable.Deliverable(
team='team',
series='newton',
name='name',
data=yamlutils.loads(deliverable_data),
)
self.assertTrue(deliv.releases[-1].is_eol)
def test_is_eol_tag_false(self):
deliverable_data = textwrap.dedent('''
releases:
- version: 0.3.0
projects:
- repo: openstack/release-test
hash: a26e6a2e8a5e321b2e3517dbb01a7b9a56a8bfd5
''')
deliv = deliverable.Deliverable(
team='team',
series='newton',
name='name',
data=yamlutils.loads(deliverable_data),
)
self.assertFalse(deliv.releases[-1].is_eol)
def test_is_eol_tag_false_typo(self):
deliverable_data = textwrap.dedent('''
releases:
- version: newton-dol
projects:
- repo: openstack/release-test
hash: a26e6a2e8a5e321b2e3517dbb01a7b9a56a8bfd5
''')
deliv = deliverable.Deliverable(
team='team',
series='newton',
name='name',
data=yamlutils.loads(deliverable_data),
)
self.assertFalse(deliv.releases[-1].is_eol)
def test_eol_series_for_eol_tag(self):
deliverable_data = textwrap.dedent('''
releases:
- version: newton-eol
projects:
- repo: openstack/release-test
hash: a26e6a2e8a5e321b2e3517dbb01a7b9a56a8bfd5
''')
deliv = deliverable.Deliverable(
team='team',
series='newton',
name='name',
data=yamlutils.loads(deliverable_data),
)
self.assertEqual(
'newton',
deliv.releases[-1].eol_series,
)
def test_eol_series_for_version_tag(self):
deliverable_data = textwrap.dedent('''
releases:
- version: 0.3.0
projects:
- repo: openstack/release-test
hash: a26e6a2e8a5e321b2e3517dbb01a7b9a56a8bfd5
''')
deliv = deliverable.Deliverable(
team='team',
series='newton',
name='name',
data=yamlutils.loads(deliverable_data),
)
self.assertEqual(
'',
deliv.releases[-1].eol_series,
)

View File

@ -1157,6 +1157,28 @@ class TestValidateNewReleasesInOpenSeries(base.BaseTestCase):
self.assertEqual(0, len(self.ctx.warnings))
self.assertEqual(1, len(self.ctx.errors))
def test_eol_in_end_of_life(self):
deliv = deliverable.Deliverable(
team='team',
series='newton',
name='name',
data={
'artifact-link-mode': 'none',
'releases': [
{'version': 'newton-eol',
'projects': [
{'repo': 'openstack/release-test',
'hash': 'a26e6a2e8a5e321b2e3517dbb01a7b9a56a8bfd5',
'tarball-base': 'openstack-release-test'},
]},
],
}
)
validate.validate_new_releases_in_open_series(deliv, self.ctx)
self.ctx.show_summary()
self.assertEqual(0, len(self.ctx.warnings))
self.assertEqual(0, len(self.ctx.errors))
class TestValidateVersionNumbers(base.BaseTestCase):
@ -1193,6 +1215,69 @@ class TestValidateVersionNumbers(base.BaseTestCase):
self.assertEqual(0, len(self.ctx.warnings))
self.assertEqual(1, len(self.ctx.errors))
def test_valid_version(self):
deliv = deliverable.Deliverable(
team='team',
series='ocata',
name='name',
data={
'artifact-link-mode': 'none',
'releases': [
{'version': '99.5.0',
'projects': [
{'repo': 'openstack/release-test',
'hash': 'a26e6a2e8a5e321b2e3517dbb01a7b9a56a8bfd5'},
]}
],
}
)
validate.validate_version_numbers(deliv, self.ctx)
self.ctx.show_summary()
self.assertEqual(0, len(self.ctx.warnings))
self.assertEqual(0, len(self.ctx.errors))
def test_eol_valid_version(self):
deliv = deliverable.Deliverable(
team='team',
series='ocata',
name='name',
data={
'artifact-link-mode': 'none',
'releases': [
{'version': 'ocata-eol',
'projects': [
{'repo': 'openstack/release-test',
'hash': 'a26e6a2e8a5e321b2e3517dbb01a7b9a56a8bfd5'},
]}
],
}
)
validate.validate_version_numbers(deliv, self.ctx)
self.ctx.show_summary()
self.assertEqual(0, len(self.ctx.warnings))
self.assertEqual(0, len(self.ctx.errors))
def test_eol_wrong_branch(self):
deliv = deliverable.Deliverable(
team='team',
series='ocata',
name='name',
data={
'artifact-link-mode': 'none',
'releases': [
{'version': 'newton-eol',
'projects': [
{'repo': 'openstack/release-test',
'hash': 'a26e6a2e8a5e321b2e3517dbb01a7b9a56a8bfd5'},
]}
],
}
)
validate.validate_version_numbers(deliv, self.ctx)
self.ctx.show_summary()
self.assertEqual(0, len(self.ctx.warnings))
self.assertEqual(1, len(self.ctx.errors))
def test_no_releases(self):
# When we initialize a new series, we won't have any release
# data. That's OK.
@ -2926,6 +3011,136 @@ class TestValidateSeriesFinal(base.BaseTestCase):
self.assertEqual(1, len(self.ctx.errors))
class TestValidateSeriesEOL(base.BaseTestCase):
def setUp(self):
super().setUp()
self.tmpdir = self.useFixture(fixtures.TempDir()).path
self.ctx = validate.ValidationContext()
def test_no_releases(self):
deliverable_data = yamlutils.loads(textwrap.dedent('''
---
team: Release Management
'''))
deliv = deliverable.Deliverable(
None,
defaults.RELEASE,
'test',
deliverable_data,
)
validate.validate_series_eol(
deliv,
self.ctx,
)
self.ctx.show_summary()
self.assertEqual(0, len(self.ctx.warnings))
self.assertEqual(0, len(self.ctx.errors))
def test_only_normal(self):
deliverable_data = yamlutils.loads(textwrap.dedent('''
---
team: Release Management
releases:
- version: 1.5.1
projects:
- repo: openstack/automaton
hash: be2885f544637e6ee6139df7dc7bf937925804dd
'''))
deliv = deliverable.Deliverable(
None,
defaults.RELEASE,
'test',
deliverable_data,
)
validate.validate_series_eol(
deliv,
self.ctx,
)
self.ctx.show_summary()
self.assertEqual(0, len(self.ctx.warnings))
self.assertEqual(0, len(self.ctx.errors))
def test_no_eol(self):
deliverable_data = yamlutils.loads(textwrap.dedent('''
---
team: Release Management
releases:
- version: 1.5.1
projects:
- repo: openstack/automaton
hash: be2885f544637e6ee6139df7dc7bf937925804dd
- version: 1.5.2
projects:
- repo: openstack/automaton
hash: ce2885f544637e6ee6139df7dc7bf937925804dd
'''))
deliv = deliverable.Deliverable(
None,
defaults.RELEASE,
'test',
deliverable_data,
)
validate.validate_series_eol(
deliv,
self.ctx,
)
self.ctx.show_summary()
self.assertEqual(0, len(self.ctx.warnings))
self.assertEqual(0, len(self.ctx.errors))
def test_eol_ok(self):
deliverable_data = yamlutils.loads(textwrap.dedent('''
---
team: Release Management
releases:
- version: newton-eol
projects:
- repo: openstack/automaton
hash: be2885f544637e6ee6139df7dc7bf937925804dd
'''))
deliv = deliverable.Deliverable(
None,
'newton',
'test',
deliverable_data,
)
validate.validate_series_eol(
deliv,
self.ctx,
)
self.ctx.show_summary()
self.assertEqual(0, len(self.ctx.warnings))
self.assertEqual(0, len(self.ctx.errors))
def test_eol_missing_repo(self):
deliverable_data = yamlutils.loads(textwrap.dedent('''
---
team: Release Management
releases:
- version: newton-eol
projects:
- repo: openstack/automaton
hash: ce2885f544637e6ee6139df7dc7bf937925804dd
repository-settings:
openstack/automaton: {}
openstack/release-test: {}
'''))
deliv = deliverable.Deliverable(
None,
'newton',
'test',
deliverable_data,
)
validate.validate_series_eol(
deliv,
self.ctx,
)
self.ctx.show_summary()
self.assertEqual(0, len(self.ctx.warnings))
self.assertEqual(1, len(self.ctx.errors))
class TestValidatePostSeriesFinal(base.BaseTestCase):
def setUp(self):