Add an extension for validating blueprint names
This new extension requires spec filenames to match blueprint names in the relevant project. This is based on work originally done in oslo-specs under https://review.openstack.org/#/c/138392/ Change-Id: Ifd58f4f71f661229f09ecf01047bc7a7b1dc0b08
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
===========================================================
|
||||
Using oslosphinx.check_blueprints with Specs Repositories
|
||||
===========================================================
|
||||
|
||||
The ``oslosphinx.check_blueprints`` extension verifies that the
|
||||
filenames in spec repositories match a blueprint under a given
|
||||
launchpad project.
|
||||
|
||||
Enabling
|
||||
========
|
||||
|
||||
Add ``'oslosphinx.check_blueprints'`` to the ``extensions`` list in
|
||||
the ``conf.py`` file in your Sphinx project.
|
||||
|
||||
Specifying the Launchpad Project
|
||||
================================
|
||||
|
||||
Most projects should set ``check_blueprints_project`` to the name of
|
||||
their launchpad project. This limits the search to the single project
|
||||
named.
|
||||
|
||||
::
|
||||
|
||||
check_blueprints_project = 'nova'
|
||||
|
||||
Projects with multiple launchpad projects under their own project
|
||||
group (such as Oslo), should instead set
|
||||
``check_blueprints_project_group``. All projects in the group will be
|
||||
scanned for each spec/blueprint name.
|
||||
|
||||
::
|
||||
|
||||
check_blueprints_project_group = 'oslo'
|
||||
|
||||
Checking Only the Current Release
|
||||
=================================
|
||||
|
||||
By default, all files under ``specs/`` are checked. For large specs
|
||||
repositories, this can take a long time. To limit the checks to a
|
||||
subdirectory for the current release, set
|
||||
``check_blueprints_release``.
|
||||
|
||||
For example::
|
||||
|
||||
check_blueprints_release = 'kilo'
|
||||
|
||||
will cause files under ``specs/kilo`` to be checked, and other files
|
||||
to be ignored.
|
||||
@@ -6,6 +6,7 @@
|
||||
:maxdepth: 2
|
||||
|
||||
usage
|
||||
check_blueprints
|
||||
contributing
|
||||
|
||||
Indices and tables
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
==================
|
||||
Using oslosphinx
|
||||
==================
|
||||
============================
|
||||
Using the oslosphinx Theme
|
||||
============================
|
||||
|
||||
To use the theme, add ``'oslosphinx'`` to the ``extensions`` list in
|
||||
the ``conf.py`` file in your Sphinx project.
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
# 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.
|
||||
"""Ensure that the name of the spec file matches the name of a blueprint.
|
||||
"""
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
class BlueprintChecker(object):
|
||||
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
self.project_names = []
|
||||
self._good_bps = set()
|
||||
self._prefix = None
|
||||
self._warn_search = 'unset'
|
||||
|
||||
BP_URL_TEMPLATE = 'https://api.launchpad.net/devel/%s/+spec/%s'
|
||||
PROJ_LIST_URL_TEMPLATE = 'https://api.launchpad.net/1.0/%s/projects'
|
||||
|
||||
def _load_project_settings(self):
|
||||
if self.project_names:
|
||||
return
|
||||
# If a project_name is set in the configuration, use
|
||||
# that. Otherwise, allow any project in the project group.
|
||||
project_name = self.app.config.check_blueprints_project
|
||||
pg_name = self.app.config.check_blueprints_project_group
|
||||
if project_name:
|
||||
self.project_names = [project_name]
|
||||
self._warn_search = 'the %s project' % project_name
|
||||
else:
|
||||
proj_list_response = requests.get(self.PROJ_LIST_URL_TEMPLATE
|
||||
% pg_name)
|
||||
projects = proj_list_response.json()['entries']
|
||||
self.project_names = [p['name'] for p in projects]
|
||||
self._warn_search = ('any projects in the %s project group'
|
||||
% pg_name)
|
||||
|
||||
@property
|
||||
def desired_prefix(self):
|
||||
"""Determine the prefix for files we care to check.
|
||||
|
||||
We only care about blueprints in the current release, if the
|
||||
check_blueprints_release option is set.
|
||||
|
||||
"""
|
||||
if self._prefix is None:
|
||||
release = self.app.config.check_blueprints_release
|
||||
if release:
|
||||
self._prefix = 'specs/%s/' % release
|
||||
else:
|
||||
self._prefix = 'specs/'
|
||||
return self._prefix
|
||||
|
||||
def doctree_resolved(self, app, doctree, docname):
|
||||
"""Hook registered as event handler."""
|
||||
if not docname.startswith(self.desired_prefix):
|
||||
return
|
||||
bp_name = docname.split('/')[-1]
|
||||
if bp_name == 'index':
|
||||
return
|
||||
self.check(bp_name)
|
||||
|
||||
def blueprint_exists(self, project_name, bp_name):
|
||||
"""Return boolean indicating whether the blueprint exists."""
|
||||
url = self.BP_URL_TEMPLATE % (project_name, bp_name)
|
||||
response = requests.get(url)
|
||||
return response.status_code == 200
|
||||
|
||||
def check(self, bp_name):
|
||||
"""Given one blueprint name, check to see if it is valid."""
|
||||
if bp_name in self._good_bps:
|
||||
return True
|
||||
self._load_project_settings()
|
||||
self.app.info('') # emit newline
|
||||
for project_name in self.project_names:
|
||||
self.app.info('Checking for %s in %s' % (bp_name, project_name))
|
||||
if self.blueprint_exists(project_name, bp_name):
|
||||
self.app.info('Found %s in %s' % (bp_name, project_name))
|
||||
self._good_bps.add(bp_name)
|
||||
break
|
||||
else:
|
||||
self.app.warn(
|
||||
'Could not find a blueprint called %r in %s'
|
||||
% (bp_name, self._warn_search),
|
||||
location=(bp_name, 0),
|
||||
)
|
||||
raise ValueError(
|
||||
'Document %s does not match any blueprint name in %s'
|
||||
% (bp_name, self._warn_search))
|
||||
|
||||
|
||||
def setup(app):
|
||||
app.info('Initializing %s' % __name__)
|
||||
checker = BlueprintChecker(app)
|
||||
app.connect('doctree-resolved', checker.doctree_resolved)
|
||||
app.add_config_value('check_blueprints_project_group', 'openstack', 'env')
|
||||
app.add_config_value('check_blueprints_project', '', 'env')
|
||||
app.add_config_value('check_blueprints_release', '', 'env')
|
||||
@@ -3,3 +3,4 @@
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
pbr>=0.6,!=0.7,<1.0
|
||||
requests>=2.2.0,!=2.4.0
|
||||
|
||||
Reference in New Issue
Block a user