Add nox role and some simple jobs

This is an alternative to tox.

Change-Id: Ib4920acec09c2c980af909e8f9d1eabd1c6d253a
This commit is contained in:
Clark Boylan 2022-12-16 12:32:16 -08:00
parent 77b1b24911
commit 50fd134646
18 changed files with 860 additions and 1 deletions

View File

@ -17,6 +17,17 @@ Python Jobs
.. zuul:autojob:: tox-cover
.. zuul:autojob:: tox-bashate
.. zuul:autojob:: tox-nodejs-npm
.. zuul:autojob:: nox
.. zuul:autojob:: nox-py27
.. zuul:autojob:: nox-py36
.. zuul:autojob:: nox-py37
.. zuul:autojob:: nox-py38
.. zuul:autojob:: nox-py39
.. zuul:autojob:: nox-py310
.. zuul:autojob:: nox-py311
.. zuul:autojob:: nox-docs
.. zuul:autojob:: nox-linters
.. zuul:autojob:: nox-cover
.. zuul:autojob:: build-python-release
.. zuul:autojob:: python-upload-pypi
.. zuul:autojob:: build-sphinx-docs

View File

@ -21,4 +21,5 @@ Python Roles
.. zuul:autorole:: find-constraints
.. zuul:autorole:: sphinx
.. zuul:autorole:: tox
.. zuul:autorole:: nox
.. zuul:autorole:: upload-pypi

View File

@ -0,0 +1,3 @@
- hosts: all
roles:
- role: fetch-coverage-output

View File

@ -0,0 +1,3 @@
- hosts: all
roles:
- fetch-sphinx-tarball

View File

@ -0,0 +1,4 @@
- hosts: all
roles:
- role: bindep
bindep_dir: "{{ zuul_work_dir }}"

4
playbooks/nox/pre.yaml Normal file
View File

@ -0,0 +1,4 @@
- hosts: all
roles:
- ensure-python
- ensure-nox

4
playbooks/nox/run.yaml Normal file
View File

@ -0,0 +1,4 @@
- hosts: all
roles:
- revoke-sudo
- nox

View File

@ -5,7 +5,8 @@
name: bindep
vars:
bindep_dir: "{{ zuul_work_dir }}"
when: tox_install_bindep | default(true)
# TODO don't make this runtime specific
when: (tox_install_bindep | default(true)) and (nox_install_bindep | default(true))
- name: Run test-setup role
include_role:
name: test-setup

84
roles/nox/README.rst Normal file
View File

@ -0,0 +1,84 @@
Runs nox for a project
This role overrides Python packages installed into nox environments with
corresponding Zuul sibling projects and runs nox tests as follows:
#. Create nox environments. Note this role currently relies on using
the default .nox/session name environment paths.
#. Get Python sibling package names for sibling projects created by
Zuul (using ``required-projects`` job variable). Package names are
searched in following sources:
* ``setup.cfg`` of *pbr* projects,
* ``setup.py``,
* ``nox_package_name`` role variable.
#. Remove sibling packages from nox environments.
#. Create temporary constraints file, lines for sibling packages are
removed.
#. Install sibling packages from Zuul projects into nox environments
with temporary constraints file.
#. Run nox tests.
**Role Variables**
.. zuul:rolevar:: nox_environment
:type: dict
:default: { "CI": "1" }
Environment variables to pass in to the nox run. Nox behaves differently
when the CI env var is set. We set that by default but allow you to
override it if the CI behaviors are not desireable.
.. zuul:rolevar:: nox_session
Space separated string listing nox sessions to run.
.. zuul:rolevar:: nox_keyword
String to select nox sessions via keyword rather than session name.
.. zuul:rolevar:: nox_tag
String to select nox sessions via tag rather than session name.
.. zuul:rolevar:: nox_force_python
String to force a specific python version to be used in the session.
This allows you to request session `tests` be run against python `3.11`.
.. zuul:rolevar:: nox_executable
:default: nox
Location of the nox executable.
.. zuul:rolevar:: nox_config_file
Path to a nox configuration file. If not specified the nox will look
for noxfile.py by default.
.. zuul:rolevar:: nox_extra_args
:default: -v
String of extra command line options to pass to nox.
.. zuul:rolevar:: nox_constraints_file
Path to a pip constraints file. Will be provided to nox via
``NOX_CONSTRAINTS_FILE``.
.. zuul:rolevar:: nox_install_siblings
:default: true
Flag controlling whether to attempt to install python packages from any
other source code repos zuul has checked out. Defaults to True.
.. zuul:rolevar:: nox_package_name
Allows a user to setup the package name to be used by nox, over reading
a setup.cfg file in the project.
.. zuul:rolevar:: zuul_work_dir
:default: {{ zuul.project.src_dir }}
Directory to run nox in.

0
roles/nox/__init__.py Normal file
View File

View File

@ -0,0 +1,10 @@
---
nox_environment:
# nox will fail with missing session with this flag set.
CI: "1"
nox_executable: nox
nox_extra_args: '-v'
nox_install_siblings: true
nox_inline_comments: true
zuul_work_dir: "{{ zuul.project.src_dir }}"

View File

View File

@ -0,0 +1,347 @@
# Copyright (c) 2017 Red Hat
#
# This module is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this software. If not, see <http://www.gnu.org/licenses/>.
# This was adapted from the tox siblings role.
DOCUMENTATION = '''
---
module: nox_install_sibling_packages
short_description: Install packages needed by nox that have local git versions
author: Monty Taylor (@mordred) and Clark Boylan
description:
- Looks for git repositories that zuul has placed on the system that provide
python packages needed by package nox is testing. If if finds any, it will
install them into the nox virtualenv so that subsequent runs of nox will
use the provided git versions.
requirements:
- "python >= 3.6"
options:
nox_sessions:
description:
- output of `nox --list` showing which sessions are selected
required: true
type: path
project_dir:
description:
- The directory in which the project we care about is in.
required: true
type: str
projects:
description:
- A list of project dicts that zuul knows about
required: true
type: list
'''
try:
import configparser
except ImportError:
import ConfigParser as configparser
import os
import os.path
import subprocess
import tempfile
import traceback
from ansible.module_utils.basic import AnsibleModule
log = list()
def to_filename(name):
"""Convert a project or version name to its filename-escaped form
Any '-' characters are currently replaced with '_'.
Implementation vendored from pkg_resources.to_filename in order to avoid
adding an extra runtime dependency.
"""
return name.replace('-', '_')
def get_sibling_python_packages(projects, nox_python):
'''Finds all python packages that zuul has cloned.
If someone does a require_project: and then runs a nox job, it can be
assumed that what they want to do is to test the two together.
'''
packages = {}
for project in projects:
root = project['src_dir']
package_name = None
setup_cfg = os.path.join(root, 'setup.cfg')
found_python = False
if os.path.exists(setup_cfg):
found_python = True
c = configparser.ConfigParser()
c.read(setup_cfg)
try:
package_name = c.get('metadata', 'name')
packages[package_name] = root
except Exception:
# Some things have a setup.cfg, but don't keep
# metadata in it; fall back to setup.py below
log.append(
"[metadata] name not found in %s, skipping" % setup_cfg)
if not package_name and os.path.exists(os.path.join(root, 'setup.py')):
found_python = True
# It's a python package but doesn't use pbr, so we need to run
# python setup.py --name to get setup.py to tell us what the
# package name is.
package_name = subprocess.check_output(
[os.path.abspath(nox_python), 'setup.py', '--name'],
cwd=os.path.abspath(root),
stderr=subprocess.STDOUT).decode('utf-8')
if package_name:
package_name = package_name.strip()
packages[package_name] = root
if found_python and not package_name:
log.append(
"Could not find package name for {root}".format(
root=root))
return packages
def get_installed_packages(nox_python):
# We use the output of pip freeze here as that is pip's stable public
# interface.
frozen_pkgs = subprocess.check_output(
[nox_python, '-m', 'pip', '-qqq', 'freeze'],
stderr=subprocess.STDOUT
).decode('utf-8')
# Matches strings of the form:
# 1. '<package_name>==<version>'
# 2. '# Editable Git install with no remote (<package_name>==<version>)'
# 3. '<package_name> @ <URI_reference>' # PEP440, PEP508, PEP610
# results <package_name>
installed_packages = []
for x in frozen_pkgs.split('\n'):
if '==' in x:
installed_packages.append(x[x.find('(') + 1:].split('==')[0])
elif '@' in x:
installed_packages.append(x.split('@')[0].rstrip(' \t'))
return installed_packages
def write_new_constraints_file(constraints, packages):
with tempfile.NamedTemporaryFile(mode='w', delete=False) \
as constraints_file:
constraints_lines = open(constraints, 'r').read().split('\n')
for line in constraints_lines:
package_name = line.split('===')[0]
if package_name in packages:
continue
constraints_file.write(line)
constraints_file.write('\n')
return constraints_file.name
def _get_package_root(name, sibling_packages):
'''
Returns a package root from the sibling packages dict.
If name is not found in sibling_packages, tries again using the 'filename'
form of the name returned by the setuptools package resource API.
:param name: package name
:param sibling_packages: dict of python packages that zuul has cloned
:returns: the package root (str)
:raises: KeyError
'''
try:
pkg_root = sibling_packages[name]
except KeyError:
pkg_root = sibling_packages[to_filename(name)]
return pkg_root
def find_installed_siblings(nox_python, package_name, sibling_python_packages):
installed_sibling_packages = []
for dep_name in get_installed_packages(nox_python):
log.append(
"Found {name} python package installed".format(
name=dep_name))
if (dep_name == package_name or
to_filename(dep_name) == package_name):
# We don't need to re-process ourself.
# We've filtered ourselves from the source dir list,
# but let's be sure nothing is weird.
log.append(
"Skipping {name} because it's us".format(
name=dep_name))
continue
if dep_name in sibling_python_packages:
log.append(
"Package {name} on system in {root}".format(
name=dep_name,
root=sibling_python_packages[dep_name]))
installed_sibling_packages.append(dep_name)
elif to_filename(dep_name) in sibling_python_packages:
real_name = to_filename(dep_name)
log.append(
"Package {name} ({pkg_name}) on system in {root}".format(
name=dep_name,
pkg_name=real_name,
root=sibling_python_packages[real_name]))
# need to use dep_name here for later constraint file rewrite
installed_sibling_packages.append(dep_name)
return installed_sibling_packages
def install_siblings(envdir, projects, package_name, constraints):
changed = False
nox_python = '{envdir}/bin/python'.format(envdir=envdir)
sibling_python_packages = get_sibling_python_packages(
projects, nox_python)
for name, root in sibling_python_packages.items():
log.append("Sibling {name} at {root}".format(name=name,
root=root))
installed_sibling_packages = find_installed_siblings(
nox_python,
package_name,
sibling_python_packages)
if constraints:
constraints_file = write_new_constraints_file(
constraints, installed_sibling_packages)
for sibling_package in installed_sibling_packages:
changed = True
log.append("Uninstalling {name}".format(name=sibling_package))
uninstall_output = subprocess.check_output(
[nox_python, '-m',
'pip', 'uninstall', '-y', sibling_package],
stderr=subprocess.STDOUT)
log.extend(uninstall_output.decode('utf-8').split('\n'))
args = [nox_python, '-m', 'pip', 'install']
if constraints:
args.extend(['-c', constraints_file])
pkg_root = _get_package_root(sibling_package,
sibling_python_packages)
log.append(
"Installing {name} from {root} for deps".format(
name=sibling_package,
root=pkg_root))
args.append(pkg_root)
install_output = subprocess.check_output(args)
log.extend(install_output.decode('utf-8').split('\n'))
for sibling_package in installed_sibling_packages:
changed = True
pkg_root = _get_package_root(sibling_package,
sibling_python_packages)
log.append(
"Installing {name} from {root}".format(
name=sibling_package,
root=pkg_root))
install_output = subprocess.check_output(
[nox_python, '-m', 'pip', 'install', '--no-deps',
pkg_root])
log.extend(install_output.decode('utf-8').split('\n'))
return changed
def main():
module = AnsibleModule(
argument_spec=dict(
nox_sessions=dict(required=True, type='str'),
nox_constraints_file=dict(type='str'),
nox_package_name=dict(type='str'),
project_dir=dict(required=True, type='str'),
projects=dict(required=True, type='list'),
)
)
constraints = module.params.get('nox_constraints_file')
nox_package_name = module.params.get('nox_package_name')
project_dir = module.params['project_dir']
projects = module.params['projects']
nox_sessions = module.params.get('nox_sessions')
sessions = []
for line in nox_sessions.split('\n'):
if line.startswith('*'):
sessions.append(line[1:].strip())
if not sessions:
module.exit_json(
changed=False,
msg='No sessions to run, no action needed.')
log.append('Using sessions: {}'.format(sessions))
if (not nox_package_name
and not os.path.exists(os.path.join(project_dir, 'setup.cfg'))
):
module.exit_json(changed=False, msg="No setup.cfg, no action needed")
if constraints and not os.path.exists(constraints):
module.fail_json(msg="Constraints file {constraints} was not found")
# Who are we?
package_name = nox_package_name
if not package_name:
try:
c = configparser.ConfigParser()
c.read(os.path.join(project_dir, 'setup.cfg'))
package_name = c.get('metadata', 'name')
except Exception:
module.exit_json(
changed=False, msg="No name in setup.cfg, skipping siblings")
log.append(
"Processing siblings for {name} from {project_dir}".format(
name=package_name,
project_dir=project_dir))
changed = False
for session in sessions:
# Nox replaces dots in the session name with dashes when creating
# venvs.
envdir = os.path.join(project_dir, '.nox', session.replace('.', '-'))
if not os.path.exists(envdir):
# Nox doesn't appear to allow us to lookup the env dir that was
# created in a previous step. We look for it where we expect it
# to be and fail otherwise.
module.fail_json(msg="Nox session env not found: {envdir}")
try:
siblings_changed = install_siblings(envdir,
projects,
package_name,
constraints)
changed = changed or siblings_changed
except subprocess.CalledProcessError as e:
tb = traceback.format_exc()
log.append(str(e))
log.append(tb)
log.append("Output:")
log.extend(e.output.decode('utf-8').split('\n'))
module.fail_json(msg=str(e), log="\n".join(log))
except Exception as e:
tb = traceback.format_exc()
log.append(str(e))
log.append(tb)
module.fail_json(msg=str(e), log="\n".join(log))
module.exit_json(changed=changed, msg="\n".join(log))
if __name__ == '__main__':
main()

View File

@ -0,0 +1,2 @@
requests===2.18.4
doesnotexistonpypi===0.0.1

View File

@ -0,0 +1,61 @@
# Copyright (C) 2019 VEXXHOST, 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.
# This was adapted from the tox siblings role.
import os
import sys
import testtools
from .nox_install_sibling_packages import get_installed_packages
from .nox_install_sibling_packages import write_new_constraints_file
class TestNoxInstallSiblingPackages(testtools.TestCase):
def test_get_installed_packages(self):
# NOTE(mnaser): Given that we run our tests inside a venv, we can
# leverage the virtual environment we use in
# unit tests instead of mocking up everything.
pkgs = get_installed_packages(sys.executable)
# NOTE(mnaser): requests should be installed in this virtualenv
# but this might fail later if we stop adding requests
# in the unit tests.
self.assertIn("requests", pkgs)
def test_write_new_constraints_file(self):
# NOTE(mnaser): Given that we run our tests inside a venv, we can
# leverage the virtual environment we use in
# unit tests instead of mocking up everything.
pkgs = get_installed_packages(sys.executable)
# NOTE(mnaser): requests should be installed in this virtualenv
# but this might fail later if we stop adding requests
# in the unit tests.
test_constraints = os.path.join(os.path.dirname(__file__),
'test-constraints.txt')
constraints = write_new_constraints_file(test_constraints, pkgs)
def cleanup_constraints_file():
if os.path.exists(constraints):
os.unlink(constraints)
self.addCleanup(cleanup_constraints_file)
self.assertTrue(os.path.exists(constraints))
with open(constraints) as f:
s = f.read()
self.assertNotIn("requests", s)
self.assertIn("doesnotexistonpypi", s)

83
roles/nox/tasks/main.yaml Normal file
View File

@ -0,0 +1,83 @@
- name: Check to see if the constraints file exists
stat:
path: "{{ nox_constraints_file }}"
get_checksum: false
get_mime: false
get_md5: false
register: stat_results
when: nox_constraints_file is defined
- name: Fail if constraints file is missing
when: nox_constraints_file is defined and not stat_results.stat.exists
fail:
msg: nox_constraints_file is defined but was not found
- name: Record constraints file location
set_fact:
nox_constraints_env:
NOX_CONSTRAINTS_FILE: "{{ nox_constraints_file }}"
when: nox_constraints_file is defined
- name: Install nox siblings
include_tasks: siblings.yaml
when: nox_install_siblings
- name: Emit nox command
debug:
msg: >-
{{ nox_executable }}
{% if nox_config_file is defined and nox_config_file %}
-f {{ nox_config_file }}
{% endif %}
{% if nox_session is defined and nox_session %}
-s {{ nox_session }}
{% endif %}
{% if nox_keyword is defined and nox_keyword %}
-k {{ nox_keyword }}
{% endif %}
{% if nox_tag is defined and nox_tag %}
-t {{ nox_tag }}
{% endif %}
{% if nox_force_python is defined and nox_force_python %}
--force-python {{ nox_force_python }}
{% endif %}
{% if nox_install_siblings %}
--reuse-existing-virtualenvs --no-install
{% endif %}
{{ nox_extra_args }}
- name: Run nox
block:
- name: Run nox
args:
chdir: "{{ zuul_work_dir }}"
environment: "{{ nox_environment | combine(nox_constraints_env | default({})) }}"
command: >-
{{ nox_executable }}
{% if nox_config_file is defined and nox_config_file %}
-f {{ nox_config_file }}
{% endif %}
{% if nox_session is defined and nox_session %}
-s {{ nox_session }}
{% endif %}
{% if nox_keyword is defined and nox_keyword %}
-k {{ nox_keyword }}
{% endif %}
{% if nox_tag is defined and nox_tag %}
-t {{ nox_tag }}
{% endif %}
{% if nox_force_python is defined and nox_force_python %}
--force-python {{ nox_force_python }}
{% endif %}
{% if nox_install_siblings %}
--reuse-existing-virtualenvs --no-install
{% endif %}
{{ nox_extra_args }}
register: nox_output
# Even though any test environment in nox failed we want to
# return file comments produced so always run this.
always:
- name: TODO
debug:
msg: TODO

View File

@ -0,0 +1,56 @@
# Install sibling with nox so we can replace them later
- name: Run nox without tests
command: >-
{{ nox_executable }}
{% if nox_config_file is defined and nox_config_file %}
-f {{ nox_config_file }}
{% endif %}
{% if nox_session is defined and nox_session %}
-s {{ nox_session }}
{% endif %}
{% if nox_keyword is defined and nox_keyword %}
-k {{ nox_keyword }}
{% endif %}
{% if nox_tag is defined and nox_tag %}
-t {{ nox_tag }}
{% endif %}
{% if nox_force_python is defined and nox_force_python %}
--force-python {{ nox_force_python }}
{% endif %}
--install-only
{{ nox_extra_args }}
args:
chdir: "{{ zuul_work_dir }}"
environment: "{{ nox_environment | combine(nox_constraints_env | default({})) }}"
- name: Get nox session list
command: >-
{{ nox_executable }}
{% if nox_config_file is defined and nox_config_file %}
-f {{ nox_config_file }}
{% endif %}
{% if nox_session is defined and nox_session %}
-s {{ nox_session }}
{% endif %}
{% if nox_keyword is defined and nox_keyword %}
-k {{ nox_keyword }}
{% endif %}
{% if nox_tag is defined and nox_tag %}
-t {{ nox_tag }}
{% endif %}
{% if nox_force_python is defined and nox_force_python %}
--force-python {{ nox_force_python }}
{% endif %}
--list
args:
chdir: "{{ zuul_work_dir }}"
environment: "{{ nox_environment | combine(nox_constraints_env | default({})) }}"
register: _nox_session_listing
- name: Install any sibling python packages
nox_install_sibling_packages:
nox_sessions: "{{ _nox_session_listing.stdout }}"
nox_constraints_file: "{{ nox_constraints_file | default(omit) }}"
nox_package_name: "{{ nox_package_name | default(omit) }}"
project_dir: "{{ zuul_work_dir }}"
projects: "{{ zuul.projects.values() | selectattr('required') | list }}"

View File

@ -335,6 +335,191 @@
vars:
npm_command: build
- job:
name: nox
parent: unittests
description: |
Base job containing setup and teardown for nox-based test jobs.
This performs basic host and general project setup tasks common
to all nox unit test jobs.
Responds to these variables:
.. zuul:jobvar:: nox_session
Use the specified nox sessions
.. zuul:jobvar:: nox_keyword
Use the specified nox keyword
.. zuul:jobvar:: nox_tag
Use the specified nox tag
.. zuul:jobvar:: nox_force_python
Force nox to run the selected sessions under this version of python.
.. zuul:jobvar:: nox_config_file
Override the default noxfile.py configuration path.
.. zuul:jobvar:: nox_environment
:type: dict
Environment variables to pass in to the nox run.
Nox behaves differently when CI=1 is set. Consider setting this
if you override the role defaults.
.. zuul:jobvar:: nox_extra_args
String containing extra arguments to append to the nox command line.
.. zuul:jobvar:: nox_constraints_file
Path to a pip constraints file. Will be provided to nox in the
NOX_CONSTRAINTS_FILE environment variable if it exists.
.. zuul:jobvar:: nox_install_siblings
:default: true
Override nox requirements that have corresponding zuul git repos
on the node by installing the git versions into the nox virtualenv.
.. zuul:jobvar:: nox_install_bindep
:default: true
Whether or not to run the binary dependencies detection and
installation with bindep.
run: playbooks/nox/run.yaml
pre-run: playbooks/nox/pre.yaml
- job:
name: nox-py27
parent: nox
description: |
Run unit tests for a Python project under cPython version 2.7.
Uses nox with the ``test`` keyword forcing python 2.7.
vars:
nox_keyword: tests
nox_force_python: "2.7"
python_version: "2.7"
- job:
name: nox-py36
parent: nox
description: |
Run unit tests for a Python project under cPython version 3.6.
Uses nox with the ``test`` keyword forcing python 3.6.
vars:
nox_keyword: tests
nox_force_python: "3.6"
python_version: "3.6"
- job:
name: nox-py37
parent: nox
description: |
Run unit tests for a Python project under cPython version 3.7.
Uses nox with the ``test`` keyword forcing python 3.7.
vars:
nox_keyword: tests
nox_force_python: "3.7"
python_version: "3.7"
- job:
name: nox-py38
parent: nox
description: |
Run unit tests for a Python project under cPython version 3.8.
Uses nox with the ``test`` keyword forcing python 3.8.
vars:
nox_keyword: tests
nox_force_python: "3.8"
python_version: "3.8"
- job:
name: nox-py39
parent: nox
description: |
Run unit tests for a Python project under cPython version 3.9.
Uses nox with the ``test`` keyword forcing python 3.9.
vars:
nox_keyword: tests
nox_force_python: "3.9"
python_version: "3.9"
- job:
name: nox-py310
parent: nox
description: |
Run unit tests for a Python project under cPython version 3.10.
Uses nox with the ``test`` keyword forcing python 3.10.
vars:
nox_keyword: tests
nox_force_python: "3.10"
python_version: "3.10"
- job:
name: nox-py311
parent: nox
description: |
Run unit tests for a Python project under cPython version 3.11.
Uses nox with the ``test`` keyword forcing python 3.11.
vars:
nox_keyword: tests
nox_force_python: "3.11"
python_version: "3.11"
- job:
name: nox-cover
parent: nox
description: |
Run code coverage tests.
Uses nox with the ``cover`` keyword.
post-run: playbooks/nox/cover-post.yaml
vars:
nox_keyword: cover
- job:
name: nox-linters
parent: nox
description: |
Runs code linting tests.
Uses nox with the ``linters`` keyword.
vars:
nox_keyword: linters
test_setup_skip: true
- job:
name: nox-docs
# This is not parented to nox since we do not need
# the roles from its parent unittests.
description: |
Run documentation unit tests.
Uses nox with the ``docs`` keyword.
vars:
nox_keyword: docs
bindep_profile: compile doc
run: playbooks/nox/run.yaml
pre-run:
- playbooks/nox/docs-pre.yaml
- playbooks/nox/pre.yaml
post-run:
- playbooks/nox/docs-post.yaml
- job:
name: build-python-release
description: |