Update zuul-jobs to handle tox3 and tox4

Tox 4 released today and is a complete rewrite with many backward
incompatible changes. We need to update a number of things to support
that in the zuul-jobs tox role and elsewhere. A possibly incomplete
list of what was changed in this commit to make this work:

  * Don't run tox --showconfig with {{ tox_extra_args }} as -vv is
    in tox_extra_args by default and results in interleaved debug
    output in the ini output making it invalid ini content.
  * Update the tox siblings tox config parser to look for renamed
    environment dir locations.
  * Stop using whitelist_externals and use allowlist_exteranls
    because whitelist_externals is removed and external commands that
    are not explicitly allowed produce errors.
  * Make the tox version configurable in ensure-tox as some users
    may not be able to easily upgrade to tox v4.
  * Escape literal # chars in tox.ini as they are treated as comments
    when in the command strings now.
    https://github.com/tox-dev/tox/issues/2617

Change-Id: I38e13b4f13bb1b2d6fb7e5c70b708e9bb016a455
This commit is contained in:
Clark Boylan 2022-12-07 12:05:07 -08:00
parent e5dc872f09
commit 41153f0653
7 changed files with 37 additions and 8 deletions

View File

@ -5,6 +5,15 @@ virtual environment for the current user.
**Role Variables** **Role Variables**
.. zuul:rolevar:: ensure_tox_version
:default: '<4'
Version specifier to select the version of tox. For example if your
project is not compatible with tox v4 you can set this value to
`<4` to install the latest v3 release. We have started this value
at `<4` for maximum compatibility, but expect it to change to ''
in the future when tox v4 is better understood.
.. zuul:rolevar:: tox_prefer_python2 .. zuul:rolevar:: tox_prefer_python2
:default: False :default: False

View File

@ -1,4 +1,5 @@
tox_executable: tox tox_executable: tox
ensure_tox_version: '<4'
tox_venv_path: '{{ ansible_user_dir }}/.local/tox' tox_venv_path: '{{ ansible_user_dir }}/.local/tox'
tox_prefer_python2: false tox_prefer_python2: false
ensure_global_symlinks: false ensure_global_symlinks: false

View File

@ -27,7 +27,7 @@
- name: Install tox to local venv - name: Install tox to local venv
# We pin tox to version <4 as v4 is not currently compatible with # We pin tox to version <4 as v4 is not currently compatible with
# zuul's tox siblings processing. # zuul's tox siblings processing.
command: '{{ tox_venv_path }}/bin/pip install tox<4' command: '{{ tox_venv_path }}/bin/pip install tox{{ ensure_tox_version }}'
- name: Export installed tox_executable path - name: Export installed tox_executable path
set_fact: set_fact:

View File

@ -272,6 +272,11 @@ def get_envlist(tox_config):
# This is overly LBYL to deal with differences in older Python 2.7 # This is overly LBYL to deal with differences in older Python 2.7
# ConfigParser which would necessitate a fairly large number of exceptions # ConfigParser which would necessitate a fairly large number of exceptions
# if we wanted to do a simple try/except with the get() instead # if we wanted to do a simple try/except with the get() instead
# Note this is tox<4 specific. tox>=4 is handled by the else block
# as tox>=4 does not provide tox.env (it is tox.env_list) and more
# importantly it does not provide args to check how we were called.
# But it does emit the appropriate testenv blocks depending on what -e
# value is used.
if ( if (
'tox' in tox_config.sections() and 'env' in 'tox' in tox_config.sections() and 'env' in
tox_config.options('tox') and "'-e" not in tox_config.options('tox') and "'-e" not in
@ -363,8 +368,19 @@ def main():
changed = False changed = False
for testenv in envlist: for testenv in envlist:
envdir = tox_config.get("testenv:{}".format(testenv), 'envdir') # Under tox<4 these names are envdir and envlogdir. Under tox>=4
envlogdir = tox_config.get("testenv:{}".format(testenv), 'envlogdir') # they are env_dir and env_log_dir.
envname = "testenv:{}".format(testenv)
if tox_config.has_option(envname, 'envdir') and \
tox_config.has_option(envname, 'envlogdir'):
envdir = tox_config.get(envname, 'envdir')
envlogdir = tox_config.get(envname, 'envlogdir')
elif tox_config.has_option(envname, 'env_dir') and \
tox_config.has_option(envname, 'env_log_dir'):
envdir = tox_config.get(envname, 'env_dir')
envlogdir = tox_config.get(envname, 'env_log_dir')
else:
raise Exception("Unknown tox env directories")
try: try:
# Write a log file into the .tox dir so that it'll get picked up # Write a log file into the .tox dir so that it'll get picked up
# Name it with testenv as a prefix so that fetch-tox-output # Name it with testenv as a prefix so that fetch-tox-output

View File

@ -29,7 +29,6 @@
{% if tox_envlist is defined and tox_envlist %} {% if tox_envlist is defined and tox_envlist %}
-e{{ tox_envlist }} -e{{ tox_envlist }}
{% endif %} {% endif %}
{{ tox_extra_args }}
> {{ _tox_show_config_tempfile.path }} > {{ _tox_show_config_tempfile.path }}
args: args:
chdir: "{{ zuul_work_dir }}" chdir: "{{ zuul_work_dir }}"

View File

@ -3,7 +3,9 @@ minversion = 3.2
envlist = linters envlist = linters
skipsdist = true skipsdist = true
# Test that we don't break when the requires feature is used # Test that we don't break when the requires feature is used
requires = tox-bindep requires =
tox-bindep
tox<4
[testenv] [testenv]
whitelist_externals = sh whitelist_externals = sh

View File

@ -41,12 +41,14 @@ passenv =
TERM TERM
setenv = setenv =
GIT_PAGER: cat GIT_PAGER: cat
whitelist_externals = bash allowlist_externals =
bash
{toxinidir}/tools/check_jobs_documented.py
{toxinidir}/tools/update-test-platforms.py
deps = deps =
-r{toxinidir}/linters-requirements.txt -r{toxinidir}/linters-requirements.txt
commands = commands =
bash -c "for f in $(find . -path './roles/*/library/*.py' | xargs); do echo Checking shebang on $f; if head -1 $f | grep -q '^#!'; then echo $f 'starts with #!, it should not as Ansible will choose the interpreter'; exit 1; fi; done" bash -c "for f in $(find . -path './roles/*/library/*.py' | xargs); do echo Checking shebang on $f; if head -1 $f | grep -q '^\#!'; then echo $f 'starts with \#!, it should not as Ansible will choose the interpreter'; exit 1; fi; done"
flake8 {posargs} flake8 {posargs}
yamllint -s -f parsable . yamllint -s -f parsable .
python -m ansiblelint --version python -m ansiblelint --version