Merge "Introduce 'abandoned' release model"
This commit is contained in:
commit
7f4cc0edf5
@ -148,6 +148,22 @@ projects.
|
|||||||
* Release tags for deliverables using this tag are managed without
|
* Release tags for deliverables using this tag are managed without
|
||||||
oversight from the Release Management team.
|
oversight from the Release Management team.
|
||||||
|
|
||||||
|
.. _abandoned:
|
||||||
|
|
||||||
|
abandoned
|
||||||
|
=========
|
||||||
|
|
||||||
|
As time passes, some deliverables are abandoned, as they are
|
||||||
|
no longer useful, or their functionality is absorbed by another deliverable.
|
||||||
|
For cycle-tied release models they just disappear in the next cycle. However
|
||||||
|
deliverables with a cycle-independent model just stay around.
|
||||||
|
|
||||||
|
The 'abandoned' release model describes a formally-independent deliverable
|
||||||
|
that will no longer be released, because it changed release models or
|
||||||
|
because it was abandoned.
|
||||||
|
|
||||||
|
* "abandoned" deliverables never produce new releases.
|
||||||
|
|
||||||
.. _untagged:
|
.. _untagged:
|
||||||
|
|
||||||
untagged
|
untagged
|
||||||
|
@ -552,11 +552,12 @@ def validate_model(deliv, context):
|
|||||||
'no release-model specified',
|
'no release-model specified',
|
||||||
)
|
)
|
||||||
|
|
||||||
if deliv.model == 'independent' and deliv.series != 'independent':
|
if (deliv.model in ['independent', 'abandoned']
|
||||||
# If the project is release:independent, make sure
|
and deliv.series != 'independent'):
|
||||||
# that's where the deliverable file is.
|
# If the project is release:independent or abandoned, make sure
|
||||||
|
# the deliverable file is in _independent.
|
||||||
context.error(
|
context.error(
|
||||||
'uses the independent release model '
|
'uses the independent or abandoned release model '
|
||||||
'and should be in the _independent '
|
'and should be in the _independent '
|
||||||
'directory'
|
'directory'
|
||||||
)
|
)
|
||||||
@ -566,10 +567,11 @@ def validate_model(deliv, context):
|
|||||||
# bypass the model property because that always returns
|
# bypass the model property because that always returns
|
||||||
# 'independent' for deliverables in that series.
|
# 'independent' for deliverables in that series.
|
||||||
model_value = deliv.data.get('release-model', 'independent')
|
model_value = deliv.data.get('release-model', 'independent')
|
||||||
if deliv.series == 'independent' and model_value != 'independent':
|
if (deliv.series == 'independent'
|
||||||
|
and model_value not in ['independent', 'abandoned']):
|
||||||
context.error(
|
context.error(
|
||||||
'deliverables in the _independent directory '
|
'deliverables in the _independent directory '
|
||||||
'should all use the independent release model'
|
'should use either the independent or abandoned release models'
|
||||||
)
|
)
|
||||||
|
|
||||||
if deliv.model == 'untagged' and deliv.is_released:
|
if deliv.model == 'untagged' and deliv.is_released:
|
||||||
@ -921,6 +923,15 @@ def validate_pypi_permissions(deliv, context):
|
|||||||
sorted(uploaders), pypi_name))
|
sorted(uploaders), pypi_name))
|
||||||
|
|
||||||
|
|
||||||
|
@skip_existing_tags
|
||||||
|
@applies_to_released
|
||||||
|
def validate_deliverable_is_not_abandoned(deliv, context):
|
||||||
|
"Ensure the deliverable is not an independent abandoned deliverable."
|
||||||
|
|
||||||
|
if deliv.model == 'abandoned':
|
||||||
|
context.error('Abandoned deliverables should not see new releases')
|
||||||
|
|
||||||
|
|
||||||
@skip_existing_tags
|
@skip_existing_tags
|
||||||
@applies_to_released
|
@applies_to_released
|
||||||
def validate_release_sha_exists(deliv, context):
|
def validate_release_sha_exists(deliv, context):
|
||||||
@ -1848,6 +1859,7 @@ def main():
|
|||||||
# Check readme after sdist build to slightly optimize things
|
# Check readme after sdist build to slightly optimize things
|
||||||
validate_pypi_readme,
|
validate_pypi_readme,
|
||||||
validate_gitreview,
|
validate_gitreview,
|
||||||
|
validate_deliverable_is_not_abandoned,
|
||||||
validate_release_sha_exists,
|
validate_release_sha_exists,
|
||||||
validate_existing_tags,
|
validate_existing_tags,
|
||||||
validate_version_numbers,
|
validate_version_numbers,
|
||||||
|
@ -453,9 +453,10 @@ class Deliverable(object):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def model(self):
|
def model(self):
|
||||||
if self.is_independent:
|
model = self._data.get('release-model', '')
|
||||||
|
if self.is_independent and model != 'abandoned':
|
||||||
return 'independent'
|
return 'independent'
|
||||||
return self._data.get('release-model', '')
|
return model
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_independent(self):
|
def is_independent(self):
|
||||||
|
@ -30,7 +30,7 @@ properties:
|
|||||||
type: "boolean"
|
type: "boolean"
|
||||||
release-model:
|
release-model:
|
||||||
type: "string"
|
type: "string"
|
||||||
enum: ["cycle-with-intermediary", "cycle-with-milestones", "cycle-trailing", "untagged", "cycle-with-rc", "cycle-automatic"]
|
enum: ["cycle-with-intermediary", "cycle-with-milestones", "cycle-trailing", "untagged", "cycle-with-rc", "cycle-automatic", "abandoned"]
|
||||||
type:
|
type:
|
||||||
type: "string"
|
type: "string"
|
||||||
enum: ["horizon-plugin", "library", "client-library", "service", "tempest-plugin", "other"]
|
enum: ["horizon-plugin", "library", "client-library", "service", "tempest-plugin", "other"]
|
||||||
|
@ -486,6 +486,32 @@ class TestValidateModel(base.BaseTestCase):
|
|||||||
self.assertEqual(0, len(self.ctx.warnings))
|
self.assertEqual(0, len(self.ctx.warnings))
|
||||||
self.assertEqual(1, len(self.ctx.errors))
|
self.assertEqual(1, len(self.ctx.errors))
|
||||||
|
|
||||||
|
def test_with_model_abandoned_match(self):
|
||||||
|
validate.validate_model(
|
||||||
|
deliverable.Deliverable(
|
||||||
|
team='team',
|
||||||
|
series='independent',
|
||||||
|
name='name',
|
||||||
|
data={'release-model': 'abandoned'},
|
||||||
|
),
|
||||||
|
self.ctx,
|
||||||
|
)
|
||||||
|
self.assertEqual(0, len(self.ctx.warnings))
|
||||||
|
self.assertEqual(0, len(self.ctx.errors))
|
||||||
|
|
||||||
|
def test_with_model_abandoned_nomatch(self):
|
||||||
|
validate.validate_model(
|
||||||
|
deliverable.Deliverable(
|
||||||
|
team='team',
|
||||||
|
series='ocata',
|
||||||
|
name='name',
|
||||||
|
data={'release-model': 'abandoned'},
|
||||||
|
),
|
||||||
|
self.ctx,
|
||||||
|
)
|
||||||
|
self.assertEqual(0, len(self.ctx.warnings))
|
||||||
|
self.assertEqual(1, len(self.ctx.errors))
|
||||||
|
|
||||||
def test_with_independent_and_model(self):
|
def test_with_independent_and_model(self):
|
||||||
validate.validate_model(
|
validate.validate_model(
|
||||||
deliverable.Deliverable(
|
deliverable.Deliverable(
|
||||||
@ -535,6 +561,38 @@ class TestValidateModel(base.BaseTestCase):
|
|||||||
self.assertEqual(1, len(self.ctx.errors))
|
self.assertEqual(1, len(self.ctx.errors))
|
||||||
|
|
||||||
|
|
||||||
|
class TestValidateNotAbandoned(base.BaseTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.ctx = validate.ValidationContext()
|
||||||
|
gitutils.clone_repo(self.ctx.workdir, 'openstack/release-test')
|
||||||
|
|
||||||
|
def test_new_release_on_abandoned_deliverable(self):
|
||||||
|
deliv = deliverable.Deliverable(
|
||||||
|
team='team',
|
||||||
|
series='independent',
|
||||||
|
name='name',
|
||||||
|
data={
|
||||||
|
'release-model': 'abandoned',
|
||||||
|
'artifact-link-mode': 'none',
|
||||||
|
'releases': [
|
||||||
|
{'version': '0.8.1',
|
||||||
|
'projects': [
|
||||||
|
{'repo': 'openstack/release-test',
|
||||||
|
# hash from master
|
||||||
|
'hash': '218c9c82f168f1db681b27842b5a829428c6b5e1',
|
||||||
|
'tarball-base': 'openstack-release-test'},
|
||||||
|
]}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
validate.validate_deliverable_is_not_abandoned(deliv, self.ctx)
|
||||||
|
self.ctx.show_summary()
|
||||||
|
self.assertEqual(0, len(self.ctx.warnings))
|
||||||
|
self.assertEqual(1, len(self.ctx.errors))
|
||||||
|
|
||||||
|
|
||||||
class TestValidateReleaseSHAExists(base.BaseTestCase):
|
class TestValidateReleaseSHAExists(base.BaseTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user