[tox]
envlist = py3, lowest-supported-dev, black, flake8, isort, mypy, pylint
recreate = True

[testenv]
basepython = python3
setenv =
    LC_ALL = en_US.utf-8
passenv=
    PYTEST_ADDOPTS

[format_deps]
black==21.12b0
flake8==3.9.2
isort==5.10.1
mypy==0.931
pylint==2.11.1
pytest==7.0.0
types-PyYAML==6.0.4
types-requests==2.27.8
types-setuptools==57.4.9

[testenv:flake8]
deps =
    flake8=={[format_deps]flake8}
commands = {envpython} -m flake8 {posargs:cloudinit/ tests/ tools/ setup.py}

[testenv:pylint]
deps =
    pylint=={[format_deps]pylint}
    -r{toxinidir}/test-requirements.txt
    -r{toxinidir}/integration-requirements.txt
commands = {envpython} -m pylint {posargs:cloudinit tests tools}

[testenv:black]
deps =
    black=={[format_deps]black}
commands = {envpython} -m black . --check

[testenv:isort]
deps =
    isort=={[format_deps]isort}
commands = {envpython} -m isort . --check-only

[testenv:mypy]
deps =
    mypy=={[format_deps]mypy}
    types-pyyaml=={[format_deps]types-PyYAML}
    types-requests=={[format_deps]types-requests}
    types-setuptools=={[format_deps]types-setuptools}
    pytest=={[format_deps]pytest}
commands = {envpython} -m mypy .

[testenv:check_format]
deps =
    black=={[format_deps]black}
    flake8=={[format_deps]flake8}
    isort=={[format_deps]isort}
    mypy=={[format_deps]mypy}
    pylint=={[format_deps]pylint}
    pytest=={[format_deps]pytest}
    -r{toxinidir}/test-requirements.txt
    -r{toxinidir}/integration-requirements.txt
commands =
    {[testenv:black]commands}
    {[testenv:flake8]commands}
    {[testenv:isort]commands}
    {[testenv:mypy]commands}
    {[testenv:pylint]commands}

[testenv:do_format]
deps =
    black=={[format_deps]black}
    isort=={[format_deps]isort}
commands =
    {envpython} -m isort .
    {envpython} -m black .

[testenv:py3]
deps =
    -r{toxinidir}/test-requirements.txt
commands = {envpython} -m pytest \
            --durations 10 \
            {posargs:--cov=cloudinit --cov-branch \
            tests/unittests}

[lowest-supported-deps]
# Tox is going to install requirements from pip. This is fine for
# testing python version compatibility, but when we build cloud-init, we are
# building against the dependencies in the OS repo, not pip. The OS
# dependencies will generally be older than what is found in pip.

# To obtain these versions, check the versions of these libraries
# in the oldest support Ubuntu distro.

# httpretty isn't included here because python2.7 requires a higher version
# than whats run on bionic, so we need two different definitions.
deps =
    jinja2==2.10
    oauthlib==2.0.6
    pyserial==3.4
    configobj==5.0.6
    pyyaml==3.12
    requests==2.18.4
    jsonpatch==1.16
    jsonschema==2.6.0
    netifaces==0.10.4
    # test-requirements
    pytest==3.3.2
    pytest-cov==2.5.1
    # Needed by pytest and default causes failures
    attrs==17.4.0

[testenv:lowest-supported]
# This definition will run on bionic with the version of httpretty
# that runs there
deps =
    {[lowest-supported-deps]deps}
    httpretty==0.8.14
commands = {[testenv:py3]commands}

[testenv:lowest-supported-dev]
# The oldest httpretty version to work with Python 3.7+ is 0.9.5,
# because it is the first to include this commit:
# https://github.com/gabrielfalcao/HTTPretty/commit/5776d97da3992b9071db5e21faf175f6e8729060
deps =
    {[lowest-supported-deps]deps}
    httpretty==0.9.5
commands = {[testenv:py3]commands}

[testenv:doc]
deps =
    -r{toxinidir}/doc-requirements.txt
commands =
    {envpython} -m sphinx {posargs:doc/rtd doc/rtd_html}
    doc8 doc/rtd

[testenv:tip-flake8]
commands = {envpython} -m flake8 {posargs:cloudinit/ tests/ tools/ setup.py}
deps = flake8

[testenv:tip-mypy]
commands = {envpython} -m mypy --install-types --non-interactive .
deps =
    mypy
    pytest
    types-PyYAML
    types-requests
    types-setuptools

[testenv:tip-pylint]
commands = {envpython} -m pylint {posargs:cloudinit tests tools}
deps =
    # requirements
    pylint
    # test-requirements
    -r{toxinidir}/test-requirements.txt
    -r{toxinidir}/integration-requirements.txt

[testenv:integration-tests]
commands = {envpython} -m pytest --log-cli-level=INFO {posargs:tests/integration_tests}
deps =
    -r{toxinidir}/integration-requirements.txt
passenv = CLOUD_INIT_* PYCLOUDLIB_* SSH_AUTH_SOCK OS_*

[testenv:integration-tests-ci]
commands = {[testenv:integration-tests]commands}
deps = {[testenv:integration-tests]deps}
passenv = CLOUD_INIT_* SSH_AUTH_SOCK OS_* TRAVIS
setenv =
    PYTEST_ADDOPTS="-m ci and not adhoc"

[testenv:integration-tests-jenkins]
commands = {[testenv:integration-tests]commands}
deps = {[testenv:integration-tests]deps}
passenv = *_proxy CLOUD_INIT_* PYCLOUDLIB_* SSH_AUTH_SOCK OS_* GOOGLE_* GCP_*
setenv =
    PYTEST_ADDOPTS="-m not adhoc"

[flake8]
# E203: whitespace before ':', doesn't adhere to pep8 or black formatting
# W503: line break before binary operator
ignore=E203,W503
exclude = .venv,.tox,dist,doc,*egg,.git,build,tools
per-file-ignores =
    cloudinit/cmd/main.py:E402

[pytest]
# TODO: s/--strict/--strict-markers/ once pytest version is high enough
testpaths = tests/unittests
addopts = --strict
log_format = %(asctime)s %(levelname)-9s %(name)s:%(filename)s:%(lineno)d %(message)s
log_date_format = %Y-%m-%d %H:%M:%S
markers =
    allow_subp_for: allow subp usage for the given commands (disable_subp_usage)
    allow_all_subp: allow all subp usage (disable_subp_usage)
    ci: run this integration test as part of CI test runs
    ds_sys_cfg: a sys_cfg dict to be used by datasource fixtures
    ec2: test will only run on EC2 platform
    gce: test will only run on GCE platform
    azure: test will only run on Azure platform
    oci: test will only run on OCI platform
    openstack: test will only run on openstack platform
    lxd_config_dict: set the config_dict passed on LXD instance creation
    lxd_container: test will only run in LXD container
    lxd_setup: specify callable to be called between init and start
    lxd_use_exec: `execute` will use `lxc exec` instead of SSH
    lxd_vm: test will only run in LXD VM
    not_bionic: test cannot run on the bionic release
    no_container: test cannot run in a container
    user_data: the user data to be passed to the test instance
    instance_name: the name to be used for the test instance
    ubuntu: this test should run on Ubuntu
    unstable: skip this test because it is flakey
    adhoc: only run on adhoc basis, not in any CI environment (travis or jenkins)
