This change enacts the first steps of the TC's decision to remove the tags framework. [1] This change does not remove all the parts to avoid breaking the releases tooling as well as to preserve useful information as discussed under this change and during one of the TC meetings. [2] [1] http://lists.openstack.org/pipermail/openstack-discuss/2021-October/025554.html [2] https://meetings.opendev.org/meetings/tc/2022/tc.2022-01-20-15.00.log.html Change-Id: Iab4a136905a9c7a61530ff7576a216d229f717a0
181 lines
6.1 KiB
Python
181 lines
6.1 KiB
Python
# 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 logging
|
|
import os.path
|
|
import weakref
|
|
|
|
from openstack_governance import _yamlutils
|
|
|
|
import requests
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
REPO_URL_BASE = "https://opendev.org/openstack/governance/raw/branch/master"
|
|
|
|
|
|
class Team(object):
|
|
|
|
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()
|
|
}
|
|
self.liaisons = data.get('liaisons', [])
|
|
|
|
@property
|
|
def service(self):
|
|
return self.data.get('service')
|
|
|
|
@property
|
|
def mission(self):
|
|
return self.data.get('mission')
|
|
|
|
|
|
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 tags(self):
|
|
return set(self.data.get('tags', []))
|
|
|
|
|
|
class Repository(object):
|
|
def __init__(self, name, deliverable):
|
|
self.name = name
|
|
self.deliverable = weakref.proxy(deliverable)
|
|
|
|
|
|
class Governance(object):
|
|
|
|
_projects_filename = 'reference/projects.yaml'
|
|
_tc_repos_filename = 'reference/technical-committee-repos.yaml'
|
|
_sigs_repos_filename = 'reference/sigs-repos.yaml'
|
|
|
|
def __init__(self, team_data, tc_data, sigs_data):
|
|
self._team_data = team_data
|
|
self._tc_data = tc_data
|
|
self._sigs_data = sigs_data
|
|
|
|
team_data['Technical Committee'] = {
|
|
'deliverables': {
|
|
repo['repo'].partition('/')[-1]: {'repos': [repo['repo']]}
|
|
for repo in tc_data['Technical Committee']
|
|
}
|
|
}
|
|
for sig_name, sig_info in sigs_data.items():
|
|
team_data['{} SIG'.format(sig_name)] = {
|
|
'deliverables': {
|
|
repo['repo'].partition('/')[-1]: {'repos': [repo['repo']]}
|
|
for repo in sig_info
|
|
}
|
|
}
|
|
|
|
self._teams = [Team(n, i) for n, i in self._team_data.items()]
|
|
|
|
@classmethod
|
|
def from_local_repo(cls, repo_dir='.'):
|
|
team_filename = os.path.join(repo_dir, cls._projects_filename)
|
|
team_data = _yamlutils.load_from_file(team_filename)
|
|
|
|
tc_filename = os.path.join(repo_dir, cls._tc_repos_filename)
|
|
tc_data = _yamlutils.load_from_file(tc_filename)
|
|
|
|
sigs_filename = os.path.join(repo_dir, cls._sigs_repos_filename)
|
|
sigs_data = _yamlutils.load_from_file(sigs_filename)
|
|
|
|
return cls(team_data, tc_data, sigs_data)
|
|
|
|
@classmethod
|
|
def from_remote_repo(cls, repo_url_base=REPO_URL_BASE, gittag=None):
|
|
query_options = {}
|
|
if gittag:
|
|
query_options.update({'h': gittag})
|
|
team_url = REPO_URL_BASE + '/reference/projects.yaml'
|
|
LOG.debug('fetching team data from %s', team_url)
|
|
r = requests.get(team_url, params=query_options)
|
|
team_data = _yamlutils.loads(r.text)
|
|
|
|
tc_url = REPO_URL_BASE + '/reference/technical-committee-repos.yaml'
|
|
LOG.debug('fetching TC data from %s', tc_url)
|
|
r = requests.get(tc_url, params=query_options)
|
|
tc_data = _yamlutils.loads(r.text)
|
|
|
|
sigs_url = REPO_URL_BASE + '/reference/sigs-repos.yaml'
|
|
LOG.debug('fetching SIGs data from %s', sigs_url)
|
|
r = requests.get(sigs_url, params=query_options)
|
|
sigs_data = _yamlutils.loads(r.text)
|
|
|
|
return cls(team_data, tc_data, sigs_data)
|
|
|
|
def get_team(self, name):
|
|
for team in self._teams:
|
|
if team.name == name:
|
|
return team
|
|
raise ValueError('No team {!r} found'.format(name))
|
|
|
|
def get_repo_owner(self, repo_name):
|
|
"""Return the name of the team that owns the repository.
|
|
|
|
:param repo_name: Long name of the repository, such as 'openstack/nova'.
|
|
|
|
"""
|
|
for team, info in self._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)
|
|
|
|
def get_repositories(self, team_name=None, deliverable_name=None):
|
|
"""Return a sequence of repositories, possibly filtered.
|
|
|
|
:param team_name: The name of the team owning the repositories. Can be
|
|
None. For Example: team_name='adjutant' or team_name='security SIG'
|
|
or team_name='Technical Committee'
|
|
:para deliverable_name: The name of the deliverable to which all
|
|
repos should belong.
|
|
|
|
"""
|
|
if team_name:
|
|
teams = [self.get_team(team_name)]
|
|
else:
|
|
teams = self._teams
|
|
|
|
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():
|
|
yield repository
|