Check that all jobs are documented
Copy over the linter from zuul-jobs to check that all jobs are documented. Depends-On: https://review.opendev.org/719042 Change-Id: I8cb7d8e81472bf65f5802358d4c1000fa168547e
This commit is contained in:
parent
d682aeffac
commit
09fa6e4068
145
tools/check_jobs_documented.py
Executable file
145
tools/check_jobs_documented.py
Executable file
@ -0,0 +1,145 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright 2019 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# 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 all jobs and roles appear in the documentation.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
class ZuulSafeLoader(yaml.SafeLoader):
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(ZuulSafeLoader, self).__init__(*args, **kwargs)
|
||||||
|
self.add_multi_constructor('!encrypted/', self.construct_encrypted)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def construct_encrypted(cls, loader, tag_suffix, node):
|
||||||
|
return loader.construct_sequence(node)
|
||||||
|
|
||||||
|
|
||||||
|
class Layout(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.jobs = []
|
||||||
|
|
||||||
|
|
||||||
|
class ZuulConfig(object):
|
||||||
|
def find_zuul_yaml(self):
|
||||||
|
root = os.getcwd()
|
||||||
|
while root:
|
||||||
|
for fn in ['zuul.yaml', '.zuul.yaml', 'zuul.d', '.zuul.d']:
|
||||||
|
path = os.path.join(root, fn)
|
||||||
|
if os.path.exists(path):
|
||||||
|
return path
|
||||||
|
root = os.path.split(root)[0]
|
||||||
|
raise Exception(
|
||||||
|
"Unable to find zuul config in zuul.yaml, .zuul.yaml,"
|
||||||
|
" zuul.d or .zuul.d")
|
||||||
|
|
||||||
|
def parse_zuul_yaml(self, path):
|
||||||
|
with open(path) as f:
|
||||||
|
data = yaml.load(f, Loader=ZuulSafeLoader)
|
||||||
|
layout = Layout()
|
||||||
|
for obj in data:
|
||||||
|
if 'job' in obj:
|
||||||
|
layout.jobs.append(obj['job'])
|
||||||
|
return layout
|
||||||
|
|
||||||
|
def parse_zuul_d(self, path):
|
||||||
|
layout = Layout()
|
||||||
|
for conf in os.listdir(path):
|
||||||
|
with open(os.path.join(path, conf)) as f:
|
||||||
|
data = yaml.load(f, Loader=ZuulSafeLoader)
|
||||||
|
for obj in data:
|
||||||
|
if 'job' in obj:
|
||||||
|
layout.jobs.append(obj['job'])
|
||||||
|
return layout
|
||||||
|
|
||||||
|
def parse_zuul_layout(self):
|
||||||
|
path = self.find_zuul_yaml()
|
||||||
|
if path.endswith('zuul.d'):
|
||||||
|
layout = self.parse_zuul_d(path)
|
||||||
|
else:
|
||||||
|
layout = self.parse_zuul_yaml(path)
|
||||||
|
return layout
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.layout = self.parse_zuul_layout()
|
||||||
|
|
||||||
|
|
||||||
|
class Docs(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.jobs = set()
|
||||||
|
self.roles = set()
|
||||||
|
self.autojobs = False
|
||||||
|
self.autoroles = False
|
||||||
|
self.walk(os.path.join(os.getcwd(), 'doc', 'source'))
|
||||||
|
|
||||||
|
def walk(self, path):
|
||||||
|
for root, dirs, files in os.walk(path):
|
||||||
|
for fn in files:
|
||||||
|
if fn.endswith('.rst'):
|
||||||
|
with open(os.path.join(root, fn)) as f:
|
||||||
|
for line in f:
|
||||||
|
m = re.match(r'.*\.\. zuul:job:: (.*)$', line)
|
||||||
|
if m:
|
||||||
|
self.jobs.add(m.group(1))
|
||||||
|
m = re.match(r'.*\.\. zuul:autojob:: (.*)$', line)
|
||||||
|
if m:
|
||||||
|
self.jobs.add(m.group(1))
|
||||||
|
m = re.match(r'.*\.\. zuul:autojobs::.*$', line)
|
||||||
|
if m:
|
||||||
|
self.autojobs = True
|
||||||
|
m = re.match(r'.*\.\. zuul:role:: (.*)$', line)
|
||||||
|
if m:
|
||||||
|
self.roles.add(m.group(1))
|
||||||
|
m = re.match(r'.*\.\. zuul:autorole:: (.*)$', line)
|
||||||
|
if m:
|
||||||
|
self.roles.add(m.group(1))
|
||||||
|
m = re.match(r'.*\.\. zuul:autoroles::.*$', line)
|
||||||
|
if m:
|
||||||
|
self.autoroles = True
|
||||||
|
|
||||||
|
|
||||||
|
class Roles(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.roles = set()
|
||||||
|
self.walk(os.path.join(os.getcwd(), 'roles'))
|
||||||
|
|
||||||
|
def walk(self, path):
|
||||||
|
for role in os.listdir(path):
|
||||||
|
if os.path.isdir(os.path.join(path, role, 'tasks')):
|
||||||
|
self.roles.add(role)
|
||||||
|
|
||||||
|
|
||||||
|
z = ZuulConfig()
|
||||||
|
r = Roles()
|
||||||
|
d = Docs()
|
||||||
|
|
||||||
|
ret = 0
|
||||||
|
if not d.autoroles:
|
||||||
|
for role in r.roles:
|
||||||
|
if role not in d.roles:
|
||||||
|
print("Role %s not included in document tree" % (role,))
|
||||||
|
ret = 1
|
||||||
|
for job in [x['name'] for x in z.layout.jobs]:
|
||||||
|
if job not in d.jobs:
|
||||||
|
print("Job %s not included in document tree" % (job,))
|
||||||
|
ret = 1
|
||||||
|
|
||||||
|
sys.exit(ret)
|
3
tox.ini
3
tox.ini
@ -35,7 +35,8 @@ setenv =
|
|||||||
whitelist_externals = bash
|
whitelist_externals = bash
|
||||||
commands =
|
commands =
|
||||||
flake8 {posargs}
|
flake8 {posargs}
|
||||||
# Ansible lint
|
{toxinidir}/tools/check_jobs_documented.py
|
||||||
|
# Ansible lint
|
||||||
bash -c "find playbooks -type f -regex '.*.ya?ml' -print0 | \
|
bash -c "find playbooks -type f -regex '.*.ya?ml' -print0 | \
|
||||||
xargs -t -n1 -0 ansible-lint"
|
xargs -t -n1 -0 ansible-lint"
|
||||||
bash -c 'find roles -maxdepth 1 -mindepth 1 -type d -printf "%p/\n" | \
|
bash -c 'find roles -maxdepth 1 -mindepth 1 -type d -printf "%p/\n" | \
|
||||||
|
Loading…
Reference in New Issue
Block a user