Merge "update to use openstack_governance library"

This commit is contained in:
Zuul 2018-11-23 13:23:01 +00:00 committed by Gerrit Code Review
commit e1e76adca5
8 changed files with 46 additions and 351 deletions

View File

@ -21,17 +21,17 @@ from docutils import nodes
from docutils.parsers import rst
from docutils.parsers.rst import directives
from docutils.statemachine import ViewList
from openstack_governance import governance
from sphinx.util import logging
from sphinx.util.nodes import nested_parse_with_titles
from openstack_releases import deliverable
from openstack_releases import governance
from openstack_releases import links
from openstack_releases import series_status
LOG = logging.getLogger(__name__)
_TEAM_DATA = governance.get_team_data()
_GOV_DATA = governance.Governance.from_remote_repo()
_PHASE_DOC_URL = 'https://docs.openstack.org/project-team-guide/stable-branches.html#maintenance-phases' # noqa
@ -443,14 +443,14 @@ class HighlightsDirective(rst.Directive):
LOG.info('[highlights] rendering %s highlights for %s',
team.title(), series)
tdata = _TEAM_DATA.get(team, {})
tdata = _GOV_DATA.get_team(team)
title = team.title()
if tdata.get('service'):
title = "{} - {}".format(title, tdata['service'])
if tdata.service:
title = "{} - {}".format(title, tdata.service)
result.append(title, source_name)
result.append('-' * len(title), source_name)
if tdata.get('mission'):
result.append(tdata['mission'], source_name)
if tdata.mission:
result.append(tdata.mission, source_name)
result.append('', source_name)
result.append('**Notes:**', source_name)
result.append('', source_name)

View File

@ -23,13 +23,13 @@ import os.path
import urllib
import appdirs
from openstack_governance import governance
import requests
from requests.packages import urllib3
import openstack_releases
from openstack_releases import defaults
from openstack_releases import deliverable
from openstack_releases import governance
# Disable warnings about insecure connections.
urllib3.disable_warnings()
@ -121,7 +121,7 @@ def main():
if not config.has_option('DEFAULT', 'password'):
parser.error('No password set in {}'.format(config_filename))
team_data = governance.get_team_data()
gov_data = governance.Governance.from_remote_repo()
# Some deliverables were independent at one time but might not be
# any more, so compare the independent list with the current
@ -148,7 +148,12 @@ def main():
config['DEFAULT']['password'],
)
for repo in governance.get_repositories(team_data, code_only=True):
for repo in gov_data.get_repositories():
if repo.name.endswith('-specs'):
continue
if 'cookiecutter' in repo.name:
continue
if repo.deliverable.team.name in IGNORED_TEAMS:
if args.verbose:

View File

@ -29,15 +29,16 @@ import subprocess
import sys
import tempfile
from openstack_governance import governance
import pyfiglet
import requests
from openstack_releases import defaults
from openstack_releases import deliverable
from openstack_releases import gitutils
from openstack_releases import governance
from openstack_releases import hound
from openstack_releases import release_notes
from openstack_releases import wiki
from openstack_releases import yamlutils
@ -241,10 +242,10 @@ def main():
print('not cleaning up %s' % workdir)
atexit.register(cleanup_workdir)
team_data = governance.get_team_data()
gov_data = governance.Governance.from_remote_repo()
official_repos = set(
r.name
for r in governance.get_repositories(team_data)
for r in gov_data.get_repositories()
)
all_deliverables = deliverable.Deliverables(
@ -252,6 +253,8 @@ def main():
False,
)
liaison_data = wiki.get_liaison_data()
# Remove any inherited PAGER environment variable to avoid
# blocking the output waiting for input.
os.environ['PAGER'] = ''
@ -273,12 +276,16 @@ def main():
header('Team details')
if deliv.team:
team_name = deliv.team
team_dict = team_data.get(team_name)
if team_dict:
team = governance.Team(team_name, team_dict)
try:
team = gov_data.get_team(team_name)
except ValueError:
team = None
if team:
print('found team %s' % team_name)
print(' PTL : %(name)s (%(irc)s)' % team.ptl)
print(' Liaison: %s (%s)\n' % team.liaison)
team_liaison = liaison_data.get(team.name.lower(), {})
print(' Liaison: %(Liaison)s (%(IRC Handle)s)\n' %
team_liaison)
team_deliv = team.deliverables.get(deliv.name)
if team_deliv:
print('found deliverable %s' % deliv.name)

View File

@ -32,6 +32,7 @@ import shutil
import sys
import tempfile
from openstack_governance import governance
import requests
import six
@ -41,7 +42,6 @@ from requests.packages import urllib3
from openstack_releases import defaults
from openstack_releases import deliverable
from openstack_releases import gitutils
from openstack_releases import governance
from openstack_releases import npmutils
from openstack_releases import project_config
from openstack_releases import puppetutils
@ -470,7 +470,9 @@ def validate_bugtracker(deliv, context):
def validate_team(deliv, context):
"Look for the team name in the governance data."
if deliv.team not in context.team_data:
try:
context.gov_data.get_team(deliv.team)
except ValueError:
context.warning(
'Team {} not in governance data. '
'Only official teams should use this repository '
@ -1309,8 +1311,7 @@ def validate_new_releases(deliv, context):
final_release = deliv.releases[-1]
expected_repos = set(
r.name
for r in governance.get_repositories(
context.team_data,
for r in context.gov_data.get_repositories(
deliverable_name=deliv.name,
)
)
@ -1633,7 +1634,7 @@ def validate_branch_points(deliv, context):
class ValidationContext(object):
_zuul_projects = None
_team_data = None
_gov_data = None
def __init__(self, debug=False, cleanup=True):
self.warnings = []
@ -1693,10 +1694,10 @@ class ValidationContext(object):
return self._zuul_projects
@property
def team_data(self):
if not self._team_data:
self._team_data = governance.get_team_data()
return self._team_data
def gov_data(self):
if not self._gov_data:
self._gov_data = governance.Governance.from_remote_repo()
return self._gov_data
def main():

View File

@ -22,9 +22,9 @@ import os
import os.path
import weakref
from openstack_governance import governance
import pbr.version
from openstack_releases import governance
from openstack_releases import series_status
from openstack_releases import yamlutils
@ -369,7 +369,7 @@ class Branch(object):
@functools.total_ordering
class Deliverable(object):
_governance_data = None
_gov_data = None
_series_status_data = None
def __init__(self, team, series, name, data):
@ -554,10 +554,9 @@ class Deliverable(object):
@property
def tags(self):
if self._governance_data is None:
Deliverable._governance_data = governance.get_team_data()
return governance.get_tags_for_deliverable(
self._governance_data, self.team, self.name)
if self._gov_data is None:
Deliverable._gov_data = governance.Governance.from_remote_repo()
return self._gov_data.get_team(self.team).deliverables[self.name].tags
@property
def filename(self):

View File

@ -1,178 +0,0 @@
# 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.
"""Work with the governance repository.
"""
import weakref
from openstack_releases import wiki
from openstack_releases import yamlutils
import requests
PROJECTS_LIST = "http://git.openstack.org/cgit/openstack/governance/plain/reference/projects.yaml" # noqa
def get_team_data(url=PROJECTS_LIST):
"""Return the parsed team data from the governance repository.
:param url: Optional URL to the location of the projects.yaml
file. Defaults to the most current version in the public git
repository.
"""
r = requests.get(url)
return yamlutils.loads(r.text)
def get_tags_for_deliverable(team_data, team, name):
"Return the tags for the deliverable owned by the team."
if team not in team_data:
return set()
team_info = team_data[team]
dinfo = team_info['deliverables'].get(name)
if not dinfo:
return set()
return set(dinfo.get('tags', [])).union(set(team_info.get('tags', [])))
def get_repo_owner(team_data, repo_name):
"""Return the name of the team that owns the repository.
:param team_data: The result of calling :func:`get_team_data`
:param repo_name: Long name of the repository, such as 'openstack/nova'.
"""
for team, info in team_data.items():
for dname, dinfo in info.get('deliverables', {}).items():
if repo_name in dinfo.get('repos', []):
return team
raise ValueError('Repository %s not found in governance list' % repo_name)
class Team(object):
_liaison_data = None
def __init__(self, name, data):
self.name = name
self.data = data
# Protectively initialize the ptl data structure in case part
# of it is missing from the project list, then replace any
# values we do have from that data.
self.ptl = {
'name': 'MISSING',
'irc': 'MISSING',
}
self.ptl.update(data.get('ptl', {}))
self.deliverables = {
dn: Deliverable(dn, di, self)
for dn, di in self.data.get('deliverables', {}).items()
}
@property
def tags(self):
return set(self.data.get('tags', []))
@property
def liaison(self):
if self._liaison_data is None:
# Only hit the wiki page one time.
Team._liaison_data = wiki.get_liaison_data()
team_liaison = self._liaison_data.get(self.name.lower(), {})
return (team_liaison.get('Liaison'),
team_liaison.get('IRC Handle'))
class Deliverable(object):
def __init__(self, name, data, team):
self.name = name
self.data = data
self.team = weakref.proxy(team)
self.repositories = {
rn: Repository(rn, self)
for rn in self.data.get('repos', [])
}
@property
def type(self):
for t in self.tags:
if t.startswith('type:'):
return t.partition(':')[-1]
return 'other'
@property
def model(self):
for t in self.tags:
if t.startswith('release:'):
return t.partition(':')[-1]
return 'none'
@property
def tags(self):
return set(self.data.get('tags', [])).union(self.team.tags)
class Repository(object):
def __init__(self, name, deliverable):
self.name = name
self.deliverable = weakref.proxy(deliverable)
@property
def tags(self):
return self.deliverable.tags
@property
def code_related(self):
return not (self.name.endswith('-specs') or
'cookiecutter' in self.name)
def get_repositories(team_data, team_name=None, deliverable_name=None,
tags=[], code_only=False):
"""Return a sequence of repositories, possibly filtered.
:param team_data: The result of calling :func:`get_team_data`
:param team_name: The name of the team owning the repositories. Can be
None.
:para deliverable_name: The name of the deliverable to which all
repos should belong.
:param tags: The names of any tags the repositories should
have. Can be empty.
:param code_only: Boolean indicating whether to return only code
repositories (ignoring specs and cookiecutter templates).
"""
if tags:
tags = set(tags)
if team_name:
try:
teams = [Team(team_name, team_data[team_name])]
except KeyError:
raise RuntimeError('No team %r found in %r' %
(team_name, list(team_data.keys())))
else:
teams = [Team(n, i) for n, i in team_data.items()]
for team in teams:
if deliverable_name and deliverable_name not in team.deliverables:
continue
if deliverable_name:
deliverables = [team.deliverables[deliverable_name]]
else:
deliverables = team.deliverables.values()
for deliverable in deliverables:
for repository in deliverable.repositories.values():
if tags and not tags.issubset(repository.tags):
continue
if code_only and not repository.code_related:
continue
yield repository

View File

@ -1,141 +0,0 @@
# 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.
from oslotest import base
from openstack_releases import governance
from openstack_releases import yamlutils
_team_data_yaml = """
Release Management:
ptl:
name: Doug Hellmann
irc: dhellmann
email: doug@doughellmann.com
irc-channel: openstack-release
mission: >
Coordinating the release of OpenStack deliverables, by defining the
overall development cycle, release models, publication processes,
versioning rules and tools, then enabling project teams to produce
their own releases.
url: https://wiki.openstack.org/wiki/Release_Management
tags:
- team:diverse-affiliation
deliverables:
release-schedule-generator:
repos:
- openstack/release-schedule-generator
release-test:
repos:
- openstack/release-test
release-tools:
repos:
- openstack-infra/release-tools
releases:
repos:
- openstack/releases
reno:
repos:
- openstack/reno
docs:
contributor: https://docs.openstack.org/developer/reno/
specs-cookiecutter:
repos:
- openstack-dev/specs-cookiecutter
"""
TEAM_DATA = yamlutils.loads(_team_data_yaml)
class TestGetRepoOwner(base.BaseTestCase):
def test_repo_exists(self):
owner = governance.get_repo_owner(
TEAM_DATA,
'openstack/releases',
)
self.assertEqual('Release Management', owner)
def test_no_such_repo(self):
self.assertRaises(
ValueError,
governance.get_repo_owner,
TEAM_DATA,
'openstack/no-such-repo',
)
class TestGetRepositories(base.BaseTestCase):
def test_by_team(self):
repos = governance.get_repositories(
TEAM_DATA,
team_name='Release Management',
)
self.assertEqual(
sorted(['openstack/release-schedule-generator',
'openstack/release-test',
'openstack-infra/release-tools',
'openstack/releases',
'openstack/reno',
'openstack-dev/specs-cookiecutter']),
sorted(r.name for r in repos),
)
def test_by_deliverable(self):
repos = governance.get_repositories(
TEAM_DATA,
deliverable_name='release-tools',
)
self.assertEqual(
['openstack-infra/release-tools'],
[r.name for r in repos],
)
def test_code_only(self):
repos = governance.get_repositories(
TEAM_DATA,
code_only=True,
)
self.assertEqual(
sorted(['openstack/release-schedule-generator',
'openstack/release-test',
'openstack-infra/release-tools',
'openstack/releases',
'openstack/reno']),
sorted(r.name for r in repos),
)
def test_tag_negative(self):
repos = governance.get_repositories(
TEAM_DATA,
tags=['team:single-vendor'],
)
self.assertEqual([], list(repos))
def test_tags_positive(self):
repos = governance.get_repositories(
TEAM_DATA,
tags=['team:diverse-affiliation'],
)
self.assertEqual(
sorted(['openstack/release-schedule-generator',
'openstack/release-test',
'openstack-infra/release-tools',
'openstack/releases',
'openstack/reno',
'openstack-dev/specs-cookiecutter']),
sorted(r.name for r in repos),
)

View File

@ -32,3 +32,5 @@ pyfiglet>=0.7.5
appdirs
packaging>=16.5
openstack-governance>=0.1.0 # Apache 2.0