diff --git a/.gitignore b/.gitignore index 0282b7e95..739c1b8d4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ doc/build *.egg-info pbr*.egg +reference/projects/*.rst diff --git a/doc/source/_exts/members.py b/doc/source/_exts/members.py index 2209fff82..6f43327bb 100644 --- a/doc/source/_exts/members.py +++ b/doc/source/_exts/members.py @@ -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. """ diff --git a/doc/source/_exts/projects.py b/doc/source/_exts/projects.py new file mode 100644 index 000000000..2ecc062fa --- /dev/null +++ b/doc/source/_exts/projects.py @@ -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()) diff --git a/doc/source/_exts/tags.py b/doc/source/_exts/tags.py new file mode 100644 index 000000000..da84945b2 --- /dev/null +++ b/doc/source/_exts/tags.py @@ -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) diff --git a/doc/source/_exts/teams.py b/doc/source/_exts/teams.py new file mode 100644 index 000000000..44688f095 --- /dev/null +++ b/doc/source/_exts/teams.py @@ -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) diff --git a/doc/source/conf.py b/doc/source/conf.py index 6c069f31d..3722c001b 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -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'] diff --git a/doc/source/index.rst b/doc/source/index.rst index 51f7c7c2b..8426ce0ae 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -23,7 +23,7 @@ Reference documents and Resolutions =================================== .. toctree:: - :maxdepth: 3 + :maxdepth: 2 :glob: :titlesonly: diff --git a/reference/index.rst b/reference/index.rst index 7bd03adc8..a4c6809e2 100644 --- a/reference/index.rst +++ b/reference/index.rst @@ -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 diff --git a/reference/projects/index.rst b/reference/projects/index.rst new file mode 100644 index 000000000..86df53ed7 --- /dev/null +++ b/reference/projects/index.rst @@ -0,0 +1,8 @@ +========================= + OpenStack Project Teams +========================= + +.. toctree:: + :glob: + + * diff --git a/reference/tag-template.rst b/reference/tag-template.rst index 1c97c2656..50252da6b 100644 --- a/reference/tag-template.rst +++ b/reference/tag-template.rst @@ -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:: diff --git a/reference/tags/integrated-release.rst b/reference/tags/integrated-release.rst index a1c23d38c..df9769880 100644 --- a/reference/tags/integrated-release.rst +++ b/reference/tags/integrated-release.rst @@ -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 diff --git a/test-requirements.txt b/test-requirements.txt index 8e7314b1c..f51dd0995 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -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