use deliverable object model to validate the release notes links

Add an extra check that there are no notes links for repos not related
to the deliverable.

Change-Id: I7f0fb614cff8ae38c907670da484c3c75599c7c0
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
This commit is contained in:
Doug Hellmann 2018-02-20 16:24:42 -05:00
parent 1e9eab181a
commit 9583477190
20 changed files with 108 additions and 66 deletions

View File

@ -1,6 +1,7 @@
--- ---
launchpad: python-cliff launchpad: python-cliff
team: OpenStackClient team: OpenStackClient
type: library
releases: releases:
- version: "0.1" - version: "0.1"
projects: projects:

View File

@ -1,6 +1,7 @@
--- ---
launchpad: python-cliff launchpad: python-cliff
team: OpenStackClient team: OpenStackClient
type: library
releases: releases:
- version: "1.3" - version: "1.3"
projects: projects:

View File

@ -1,6 +1,7 @@
--- ---
launchpad: python-cliff launchpad: python-cliff
team: OpenStackClient team: OpenStackClient
type: library
releases: releases:
- version: 1.3.3 - version: 1.3.3
projects: projects:

View File

@ -1,6 +1,7 @@
--- ---
launchpad: python-cliff launchpad: python-cliff
team: OpenStackClient team: OpenStackClient
type: library
releases: releases:
- version: 1.5.0 - version: 1.5.0
projects: projects:

View File

@ -1,6 +1,7 @@
--- ---
launchpad: python-cliff launchpad: python-cliff
team: OpenStackClient team: OpenStackClient
type: library
releases: releases:
- version: 1.7.0 - version: 1.7.0
projects: projects:

View File

@ -1,6 +1,7 @@
--- ---
launchpad: python-stevedore launchpad: python-stevedore
team: oslo team: oslo
type: library
releases: releases:
- version: 1.0.0 - version: 1.0.0
projects: projects:

View File

@ -1,6 +1,7 @@
--- ---
launchpad: django-openstack-auth launchpad: django-openstack-auth
team: horizon team: horizon
type: library
releases: releases:
- version: 1.2.0 - version: 1.2.0
projects: projects:

View File

@ -1,6 +1,7 @@
--- ---
launchpad: python-cliff launchpad: python-cliff
team: OpenStackClient team: OpenStackClient
type: library
releases: releases:
- version: 1.8.0 - version: 1.8.0
projects: projects:

View File

@ -1,6 +1,7 @@
--- ---
launchpad: python-stevedore launchpad: python-stevedore
team: oslo team: oslo
type: library
releases: releases:
- version: 1.1.0 - version: 1.1.0
projects: projects:

View File

@ -1,6 +1,7 @@
--- ---
launchpad: python-tooz launchpad: python-tooz
team: oslo team: oslo
type: library
releases: releases:
- version: "0.10" - version: "0.10"
projects: projects:

View File

@ -1,6 +1,7 @@
--- ---
launchpad: django-openstack-auth launchpad: django-openstack-auth
team: horizon team: horizon
type: library
releases: releases:
- version: 1.3.0 - version: 1.3.0
projects: projects:

View File

@ -1,6 +1,7 @@
--- ---
launchpad: python-cliff launchpad: python-cliff
team: OpenStackClient team: OpenStackClient
type: library
releases: releases:
- version: 1.13.0 - version: 1.13.0
projects: projects:

View File

@ -1,6 +1,7 @@
--- ---
launchpad: python-mox3 launchpad: python-mox3
team: oslo team: oslo
type: library
releases: releases:
- version: 0.8.0 - version: 0.8.0
projects: projects:

View File

@ -1,6 +1,7 @@
--- ---
launchpad: python-stevedore launchpad: python-stevedore
team: oslo team: oslo
type: library
releases: releases:
- version: 1.4.0 - version: 1.4.0
projects: projects:

View File

@ -1,6 +1,7 @@
--- ---
launchpad: python-tooz launchpad: python-tooz
team: oslo team: oslo
type: library
releases: releases:
- version: 0.14.0 - version: 0.14.0
projects: projects:

View File

@ -1,6 +1,7 @@
--- ---
launchpad: vmware-nsx launchpad: vmware-nsx
team: neutron team: neutron
type: library
releases: releases:
- version: 1.0.0 - version: 1.0.0
projects: projects:

View File

@ -252,14 +252,24 @@ def validate_team(deliv, team_data, messages):
LOG.debug('owned by team {}'.format(deliv.team)) LOG.debug('owned by team {}'.format(deliv.team))
def validate_release_notes(deliverable_info, messages): def validate_release_notes(deliv, messages):
"Make sure the release notes page exists, if it is specified." "Make sure the release notes page exists, if it is specified."
header('Validate Release Notes') header('Validate Release Notes')
if 'release-notes' not in deliverable_info: notes_link = deliv.release_notes
if not notes_link:
print('no release-notes given') print('no release-notes given')
return return
notes_link = deliverable_info['release-notes']
if isinstance(notes_link, dict): if isinstance(notes_link, dict):
# Dictionary mapping repositories to links. We don't want any
# repositories that are not known, so check that as well as
# the actual links.
for repo_name in sorted(notes_link.keys()):
if repo_name not in deliv.known_repo_names:
messages.error(
'linking to release notes for unknown '
'repository {}'.format(
repo_name)
)
links = list(notes_link.values()) links = list(notes_link.values())
else: else:
links = [notes_link] links = [notes_link]
@ -268,22 +278,8 @@ def validate_release_notes(deliverable_info, messages):
if (rn_resp.status_code // 100) != 2: if (rn_resp.status_code // 100) != 2:
messages.error('Could not fetch release notes page %s: %s' % messages.error('Could not fetch release notes page %s: %s' %
(link, rn_resp.status_code)) (link, rn_resp.status_code))
else:
LOG.debug('{} OK'.format(link))
def validate_type(deliverable_info, messages):
"Determine the deliverable type. Require an explicit value."
header('Validate Type')
deliverable_type = deliverable_info.get('type')
if not deliverable_type:
messages.error(
'No deliverable type, must be one of %r' %
sorted(list(_VALID_TYPES))
)
elif deliverable_type not in _VALID_TYPES:
messages.error(
'Invalid deliverable type %r, must be one of %r' %
(deliverable_type, sorted(list(_VALID_TYPES)))
)
def get_model(deliverable_info, series_name): def get_model(deliverable_info, series_name):
@ -1327,11 +1323,11 @@ def main():
name=deliverable_name, name=deliverable_name,
data=deliverable_info, data=deliverable_info,
) )
clone_deliverable(deliv, workdir, messages) clone_deliverable(deliv, workdir, messages)
validate_bugtracker(deliv, messages) validate_bugtracker(deliv, messages)
validate_team(deliv, team_data, messages) validate_team(deliv, team_data, messages)
validate_release_notes(deliverable_info, messages) validate_release_notes(deliv, messages)
validate_type(deliverable_info, messages)
validate_model(deliverable_info, series_name, messages) validate_model(deliverable_info, series_name, messages)
validate_release_type( validate_release_type(
deliverable_info, deliverable_info,

View File

@ -257,6 +257,10 @@ class Deliverable(object):
for name, repo in sorted(self._repos.items()): for name, repo in sorted(self._repos.items()):
yield repo yield repo
@property
def known_repo_names(self):
return set(self._repos.keys())
def get_repo(self, name): def get_repo(self, name):
return self._repos[name] return self._repos[name]

View File

@ -8,6 +8,7 @@ additionalProperties: false
required: required:
- team - team
- type
properties: properties:
team: team:

View File

@ -202,7 +202,12 @@ class TestValidateReleaseNotes(base.BaseTestCase):
def test_no_link(self): def test_no_link(self):
validate.validate_release_notes( validate.validate_release_notes(
{}, deliverable.Deliverable(
team='team',
series='series',
name='name',
data={},
),
self.msg, self.msg,
) )
self.assertEqual(0, len(self.msg.warnings)) self.assertEqual(0, len(self.msg.warnings))
@ -210,7 +215,14 @@ class TestValidateReleaseNotes(base.BaseTestCase):
def test_invalid_link(self): def test_invalid_link(self):
validate.validate_release_notes( validate.validate_release_notes(
{'release-notes': 'https://docs.openstack.org/no-such-page'}, deliverable.Deliverable(
team='team',
series='series',
name='name',
data={
'release-notes': 'https://docs.openstack.org/no-such-page',
},
),
self.msg, self.msg,
) )
self.assertEqual(0, len(self.msg.warnings)) self.assertEqual(0, len(self.msg.warnings))
@ -218,8 +230,13 @@ class TestValidateReleaseNotes(base.BaseTestCase):
def test_valid_link(self): def test_valid_link(self):
validate.validate_release_notes( validate.validate_release_notes(
{'release-notes': deliverable.Deliverable(
'https://docs.openstack.org/releasenotes/oslo.config'}, team='team',
series='series',
name='name',
data={'release-notes':
'https://docs.openstack.org/releasenotes/oslo.config'},
),
self.msg, self.msg,
) )
self.assertEqual(0, len(self.msg.warnings)) self.assertEqual(0, len(self.msg.warnings))
@ -227,11 +244,41 @@ class TestValidateReleaseNotes(base.BaseTestCase):
def test_invalid_link_multi(self): def test_invalid_link_multi(self):
validate.validate_release_notes( validate.validate_release_notes(
{ deliverable.Deliverable(
'release-notes': { team='team',
'openstack/releases': 'https://docs.openstack.org/no-such-page', series='series',
} name='name',
}, data={
'repository-settings': {
'openstack/releases': {},
},
'release-notes': {
'openstack/releases':
'https://docs.openstack.org/no-such-page',
}
},
),
self.msg,
)
self.assertEqual(0, len(self.msg.warnings))
self.assertEqual(1, len(self.msg.errors))
def test_unknown_repo(self):
validate.validate_release_notes(
deliverable.Deliverable(
team='team',
series='series',
name='name',
data={
'repository-settings': {
'openstack/release-test': {},
},
'release-notes': {
'openstack/oslo.config':
'https://docs.openstack.org/releasenotes/oslo.config',
}
},
),
self.msg, self.msg,
) )
self.assertEqual(0, len(self.msg.warnings)) self.assertEqual(0, len(self.msg.warnings))
@ -239,42 +286,20 @@ class TestValidateReleaseNotes(base.BaseTestCase):
def test_valid_link_multi(self): def test_valid_link_multi(self):
validate.validate_release_notes( validate.validate_release_notes(
{ deliverable.Deliverable(
'release-notes': { team='team',
'openstack/releases': 'https://docs.openstack.org/releasenotes/oslo.config', series='series',
} name='name',
}, data={
self.msg, 'repository-settings': {
) 'openstack/releases': {},
self.assertEqual(0, len(self.msg.warnings)) },
self.assertEqual(0, len(self.msg.errors)) 'release-notes': {
'openstack/releases':
'https://docs.openstack.org/releasenotes/oslo.config',
class TestValidateDeliverableType(base.BaseTestCase): },
},
def setUp(self): ),
super().setUp()
self.msg = validate.MessageCollector()
def test_no_type(self):
validate.validate_type(
{},
self.msg,
)
self.assertEqual(0, len(self.msg.warnings))
self.assertEqual(1, len(self.msg.errors))
def test_invalid_type(self):
validate.validate_type(
{'type': 'not-valid'},
self.msg,
)
self.assertEqual(0, len(self.msg.warnings))
self.assertEqual(1, len(self.msg.errors))
def test_valid_type(self):
validate.validate_type(
{'type': 'library'},
self.msg, self.msg,
) )
self.assertEqual(0, len(self.msg.warnings)) self.assertEqual(0, len(self.msg.warnings))