group service and library projects separately

Split the deliverables based on whether they are a service or
library. Default to service, since we do have some untagged projects and
they tend toward service rather than library.

Change-Id: Icaa2bacf5aadf7c53543c6c4a1abc5ef62eb77e7
This commit is contained in:
Doug Hellmann
2015-09-01 20:20:59 +00:00
parent 500685887b
commit 15b0758543
2 changed files with 157 additions and 14 deletions

View File

@@ -0,0 +1,77 @@
# 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
import requests
import yaml
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 yaml.load(r.text)
class Team(object):
def __init__(self, name, data):
self.name = name
self.data = data
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', []))
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', [])).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)

View File

@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import collections
import glob
import os.path
@@ -23,6 +24,8 @@ from sphinx.util.nodes import nested_parse_with_titles
import yaml
from openstack_releases import governance
def _list_table(add, headers, data, title='', columns=None):
"""Build a list-table directive.
@@ -46,16 +49,35 @@ def _list_table(add, headers, data, title='', columns=None):
add('')
def _get_deliverable_type(deliverable_types, name):
if (name.startswith('python-') and not name.endswith('client')):
name = name[7:]
if (name.startswith('python-') and name.endswith('client')):
return 'type:library'
if name in deliverable_types:
return deliverable_types[name]
no_dashes = name.replace('-', '_')
if no_dashes in deliverable_types:
return deliverable_types[no_dashes]
return 'type:service'
class DeliverableDirective(rst.Directive):
option_spec = {
'series': directives.unchanged,
}
_TYPE_ORDER = [
'type:service',
'type:library',
]
def run(self):
env = self.state.document.settings.env
app = env.app
source_name = '<' + __name__ + '>'
team_data = governance.get_team_data()
series = self.options.get('series')
if not series:
@@ -65,25 +87,74 @@ class DeliverableDirective(rst.Directive):
line=self.lineno)
return [error]
deliverable_types = {}
for team in (governance.Team(n, i) for n, i in team_data.items()):
for dn, di in team.deliverables.items():
for tag in di.tags:
if tag.startswith('type:'):
deliverable_types[dn] = tag
result = ViewList()
# Read all of the deliverable data for the series.
deliverables = []
deliverables = collections.defaultdict(list)
for filename in sorted(glob.glob('deliverables/%s/*.yaml' % series)):
app.info('[deliverables] reading %s' % filename)
deliverable_name = os.path.basename(filename)[:-5] # strip .yaml ext
deliverable_name = os.path.basename(filename)[:-5] # strip .yaml
deliverable_type = _get_deliverable_type(
deliverable_types,
deliverable_name,
)
with open(filename, 'r') as f:
deliverables.append((deliverable_name,
filename,
yaml.load(f.read())))
deliverables[deliverable_type].append(
(deliverable_name,
filename,
yaml.load(f.read())))
for type_tag in self._TYPE_ORDER:
self._add_deliverables(
type_tag,
deliverables[type_tag],
series,
app,
result,
)
# NOTE(dhellmann): Useful for debugging.
# print('\n'.join(result))
node = nodes.section()
node.document = self.state.document
nested_parse_with_titles(self.state, result, node)
return node.children
_TYPE_TITLE = {
'type:service': 'Service Projects',
'type:library': 'Library Projects',
}
def _add_deliverables(self, type_tag, deliverables, series, app, result):
source_name = '<' + __name__ + '>'
if not deliverables:
# There are no deliverables of this type, and that's OK.
return
result.append('', source_name)
title = self._TYPE_TITLE.get(type_tag, 'Unknown Projects')
result.append('-' * len(title), source_name)
result.append(title, source_name)
result.append('-' * len(title), source_name)
result.append('', source_name)
# Build a table of the most recent version of each deliverable.
most_recent = []
for deliverable_name, filename, deliverable_info in deliverables:
version = deliverable_info.get('releases', {})[-1].get('version', 'unreleased')
version = deliverable_info.get('releases', {})[-1].get(
'version', 'unreleased')
ref = ':ref:`%s-%s`' % (series, deliverable_name)
most_recent.append((ref, version))
_list_table(
@@ -103,7 +174,7 @@ class DeliverableDirective(rst.Directive):
result.append(text, filename)
def _title(text, underline):
text = str(text) # version numbers might be converted to floats
text = str(text) # version numbers might be seen as floats
_add('.. _%s-%s:' % (series, text))
_add('')
_add(text)
@@ -111,7 +182,7 @@ class DeliverableDirective(rst.Directive):
_add('')
def _rubric(text):
text = str(text) # version numbers might be converted to floats
text = str(text) # version numbers might be seen as floats
_add('.. rubric:: %s' % text)
_add('')
@@ -128,11 +199,6 @@ class DeliverableDirective(rst.Directive):
columns=[10, 40, 50],
)
node = nodes.section()
node.document = self.state.document
nested_parse_with_titles(self.state, result, node)
return node.children
def setup(app):
app.add_directive('deliverable', DeliverableDirective)