Build list of teams from YAML file

Render the YAML file contents as the list of official teams and create a
directive to render the list of projects with a given tag to avoid
having to update that data in two places.

Change-Id: I7c6effe6e440f2147f8c68df090152e716c38fba
This commit is contained in:
Doug Hellmann 2014-10-02 16:04:14 -04:00
parent 53c0ee30e7
commit 72b8b9a74d
12 changed files with 260 additions and 17 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
doc/build
*.egg-info
pbr*.egg
reference/projects/*.rst

View File

@ -1,3 +1,15 @@
# 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.
"""Build a table of the current members of the TC.
"""

View File

@ -0,0 +1,41 @@
# 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.
"""Load the projects.yaml file.
"""
import copy
import os.path
import yaml
_projects_yaml = {}
def get_project_data():
"""Return a copy of the project data."""
return copy.deepcopy(_projects_yaml)
def slugify(name):
"""Convert name to slug form for references."""
return name.lower().replace(' ', '-')
def setup(app):
global _projects_yaml
filename = os.path.abspath('reference/projects.yaml')
app.info('reading %s' % filename)
with open(filename, 'r') as f:
_projects_yaml = yaml.load(f.read())

82
doc/source/_exts/tags.py Normal file
View File

@ -0,0 +1,82 @@
# 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.
"""Show information about tagged projects.
"""
from docutils import nodes
from docutils.parsers import rst
from docutils.statemachine import ViewList
from sphinx.util.nodes import nested_parse_with_titles
import projects
_projects_by_tag = {}
class TaggedProjectsDirective(rst.Directive):
"""List the projects tagged with the given tag.
"""
has_content = True
def run(self):
env = self.state.document.settings.env
app = env.app
tagname = ' '.join(self.content)
app.info('building list of projects tagged %r' % tagname)
if not tagname:
error = self.state_machine.reporter.error(
'No tagname in tagged-projects directive',
nodes.literal_block(self.block_text, self.block_text),
line=self.lineno)
return [error]
# Build the view of the data to be parsed for rendering.
result = ViewList()
project_data = _projects_by_tag.get(tagname)
source_name = '<' + __name__ + '>'
if not project_data:
result.append(
'.. note:: No projects are using %s, yet.' % tagname,
source_name,
)
else:
for team_name, repo in sorted(project_data):
line = '- :ref:`project-%s` -- :repo:`%s`' % (
projects.slugify(team_name),
repo,
)
result.append(line, source_name)
# Parse what we have into a new section.
node = nodes.section()
node.document = self.state.document
nested_parse_with_titles(self.state, result, node)
return node.children
def _build_projects_by_tag():
for proj_name, info in projects.get_project_data().items():
for repo in info.get('projects', []):
for tag in repo.get('tags', []):
tn = tag['name']
l = _projects_by_tag.setdefault(tn, [])
l.append((proj_name, repo['repo']))
def setup(app):
app.info('loading tags extension')
_build_projects_by_tag()
app.add_directive('tagged-projects', TaggedProjectsDirective)

98
doc/source/_exts/teams.py Normal file
View File

@ -0,0 +1,98 @@
# 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.
"""Report on the current list of projects.
"""
import yaml
from docutils import nodes
from docutils.parsers import rst
from docutils.statemachine import ViewList
from sphinx.util.nodes import nested_parse_with_titles
import projects
def _team_to_rst(name, info):
yield '.. _project-%s:' % projects.slugify(name)
yield ''
yield '=' * len(name)
yield name.title()
yield '=' * len(name)
yield ''
yield ':Home Page: ' + info.get('url', '')
yield ':PTL: ' + info.get('ptl', '')
service = info.get('service')
if service:
yield ':Service: ' + service
yield ''
mission = info.get('mission', '').rstrip()
if mission:
yield mission
yield ''
for project in info.get('projects', []):
tags = [
':ref:`tag-%s`' % t['name']
for t in project.get('tags', [])
]
if tags:
tag_references = '(%s)' % ', '.join(tags)
else:
tag_references = ''
yield '- :repo:`%s` %s' % (project['repo'], tag_references)
yield ''
yield ''
def _write_team_pages(app):
all_teams = projects.get_project_data()
files = []
for team, info in all_teams.items():
slug = projects.slugify(team)
filename = 'reference/projects/%s.rst' % slug
app.info('generating team page for %s' % team)
with open(filename, 'w') as f:
f.write('\n'.join(_team_to_rst(team, info)))
files.append(filename)
return files
class TeamsListDirective(rst.Directive):
has_content = False
def run(self):
env = self.state.document.settings.env
app = env.app
all_teams = projects.get_project_data()
# Build the view of the data to be parsed for rendering.
result = ViewList()
for team_name in sorted(all_teams.keys()):
team_info = all_teams[team_name]
for line in _team_to_rst(team_name, team_info):
result.append(line, '<' + __name__ + '>')
# Parse what we have into a new section.
node = nodes.section()
node.document = self.state.document
nested_parse_with_titles(self.state, result, node)
return node.children
def setup(app):
app.info('loading teams extension')
app.add_directive('teamslist', TeamsListDirective)
_write_team_pages(app)

View File

@ -27,12 +27,21 @@ sys.path.insert(0, os.path.join(os.path.abspath('.'), '_exts'))
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
'sphinx.ext.extlinks',
'oslosphinx',
'members',
'projects',
'teams',
'tags',
]
todo_include_todos = True
# Define shorthand roles for making links to common destinations.
extlinks = {
'repo': ('http://git.openstack.org/cgit/%s', ''),
}
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

View File

@ -23,7 +23,7 @@ Reference documents and Resolutions
===================================
.. toctree::
:maxdepth: 3
:maxdepth: 2
:glob:
:titlesonly:

View File

@ -5,9 +5,10 @@
Reference documents which need to be revised over time.
.. toctree::
:maxdepth: 2
:maxdepth: 1
charter
projects/index
new-projects-requirements
project-testing-interface
tags/index

View File

@ -0,0 +1,8 @@
=========================
OpenStack Project Teams
=========================
.. toctree::
:glob:
*

View File

@ -91,3 +91,5 @@ the proposed tag to at least some subset of the current project list. This
will serve as an example of how the tag should be applied in the real world.
You may also submit (as a subsequent change) the corresponding governance
change to immediately apply the proposed tag to projects.
.. tagged-projects:: <tag name>

View File

@ -4,6 +4,8 @@
Unported License.
http://creativecommons.org/licenses/by/3.0/legalcode
.. _tag-integrated-release:
==================
integrated-release
==================
@ -67,18 +69,4 @@ The following code repositories would get the proposed tag. Those match the
contents of the Kilo release as decided at the end of the Juno cycle, and
take into account the recent Neutron advanced services code split:
* openstack/nova
* openstack/swift
* openstack/glance
* openstack/keystone
* openstack/horizon
* openstack/neutron
* openstack/neutron-fwaas
* openstack/neutron-lbaas
* openstack/neutron-vpnaas
* openstack/cinder
* openstack/ceilometer
* openstack/heat
* openstack/trove
* openstack/ironic
* openstack/sahara
.. tagged-projects:: integrated-release

View File

@ -1,3 +1,4 @@
# needed for doc build
sphinx>=1.1.2,!=1.2.0,<1.3
oslosphinx>=2.2.0 # Apache-2.0
PyYAML>=3.1.0