diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index c5a15a7..a444deb 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -1,15 +1,24 @@ +# Format and labels used aim to match those used by Ansible project categories: - - title: 'Features' + - title: 'Major Changes' labels: - - 'feature' - - 'enhancement' - - title: 'Bug Fixes' + - 'major' # c6476b + - title: 'Minor Changes' + labels: + - 'feature' # 006b75 + - 'enhancement' # ededed + - 'performance' # 555555 + - title: 'Bugfixes' labels: - 'fix' - 'bugfix' - - 'bug' - - title: 'Maintenance' - label: 'chore' + - 'bug' # fbca04 + - 'docs' # 4071a5 + - 'packaging' # 4071a5 + - 'test' # #0e8a16 + - title: 'Deprecations' + labels: + - 'deprecated' # fef2c0 exclude-labels: - 'skip-changelog' template: | diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml new file mode 100644 index 0000000..7d3004a --- /dev/null +++ b/.github/workflows/release-drafter.yml @@ -0,0 +1,18 @@ +name: Release Drafter + +on: + push: + # branches to consider in the event; optional, defaults to all + branches: + - master + - 'releases/**' + - 'stable/**' + +jobs: + update_release_draft: + runs-on: ubuntu-latest + steps: + # Drafts your next Release notes as Pull Requests are merged into "master" + - uses: release-drafter/release-drafter@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml new file mode 100644 index 0000000..7cff2d4 --- /dev/null +++ b/.github/workflows/tox.yml @@ -0,0 +1,146 @@ +name: tox + +on: + create: # is used for publishing to TestPyPI + tags: # any tag regardless of its name, no branches + - "**" + push: # only publishes pushes to the main branch to TestPyPI + branches: # any integration branch but not tag + - "master" + pull_request: + release: + types: + - published # It seems that you can publish directly without creating + schedule: + - cron: 1 0 * * * # Run daily at 0:01 UTC + +jobs: + build: + name: ${{ matrix.tox_env }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - tox_env: lint + # - tox_env: docs + - tox_env: py36 + PREFIX: PYTEST_REQPASS=3 + - tox_env: py36-devel + PREFIX: PYTEST_REQPASS=3 + - tox_env: py37 + PREFIX: PYTEST_REQPASS=3 + - tox_env: py38 + PREFIX: PYTEST_REQPASS=3 + - tox_env: py39 + PREFIX: PYTEST_REQPASS=3 + - tox_env: py39-devel + PREFIX: PYTEST_REQPASS=3 + - tox_env: packaging + + steps: + - uses: actions/checkout@v1 + - name: Install system dependencies + run: | + sudo apt-get update \ + && sudo apt-get install -y ansible \ + && ansible-doc -l | grep docker_container + - name: Find python version + id: py_ver + shell: python + if: ${{ contains(matrix.tox_env, 'py') }} + run: | + v = '${{ matrix.tox_env }}'.split('-')[0].lstrip('py') + print('::set-output name=version::{0}.{1}'.format(v[0],v[1:])) + # Even our lint and other envs need access to tox + - name: Install a default Python + uses: actions/setup-python@v2 + if: ${{ ! contains(matrix.tox_env, 'py') }} + # Be sure to install the version of python needed by a specific test, if necessary + - name: Set up Python version + uses: actions/setup-python@v2 + if: ${{ contains(matrix.tox_env, 'py') }} + with: + python-version: ${{ steps.py_ver.outputs.version }} + - name: Install dependencies + run: | + docker version + docker info + python -m pip install -U pip + pip install tox + - name: Run tox -e ${{ matrix.tox_env }} + run: | + echo "${{ matrix.PREFIX }} tox -e ${{ matrix.tox_env }}" + ${{ matrix.PREFIX }} tox -e ${{ matrix.tox_env }} + + publish: + name: Publish to PyPI registry + needs: + - build + runs-on: ubuntu-latest + + env: + PY_COLORS: 1 + TOXENV: packaging + + steps: + - name: Switch to using Python 3.6 by default + uses: actions/setup-python@v2 + with: + python-version: 3.6 + - name: Install tox + run: python -m pip install --user tox + - name: Check out src from Git + uses: actions/checkout@v2 + with: + # Get shallow Git history (default) for release events + # but have a complete clone for any other workflows. + # Both options fetch tags but since we're going to remove + # one from HEAD in non-create-tag workflows, we need full + # history for them. + fetch-depth: >- + ${{ + ( + ( + github.event_name == 'create' && + github.event.ref_type == 'tag' + ) || + github.event_name == 'release' + ) && + 1 || 0 + }} + - name: Drop Git tags from HEAD for non-tag-create and non-release events + if: >- + ( + github.event_name != 'create' || + github.event.ref_type != 'tag' + ) && + github.event_name != 'release' + run: >- + git tag --points-at HEAD + | + xargs git tag --delete + - name: Build dists + run: python -m tox + - name: Publish to test.pypi.org + if: >- + ( + github.event_name == 'push' && + github.ref == format( + 'refs/heads/{0}', github.event.repository.default_branch + ) + ) || + ( + github.event_name == 'create' && + github.event.ref_type == 'tag' + ) + uses: pypa/gh-action-pypi-publish@master + with: + password: ${{ secrets.testpypi_password }} + repository_url: https://test.pypi.org/legacy/ + - name: Publish to pypi.org + if: >- # "create" workflows run separately from "push" & "pull_request" + github.event_name == 'release' + uses: pypa/gh-action-pypi-publish@master + with: + password: ${{ secrets.pypi_password }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 05d16f3..9384a96 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,16 +1,16 @@ --- repos: - repo: https://github.com/PyCQA/doc8.git - rev: 0.8.1rc1 + rev: 0.9.0a1 hooks: - id: doc8 - repo: https://github.com/python/black.git - rev: 19.3b0 + rev: 20.8b1 hooks: - id: black language_version: python3 - repo: https://github.com/pre-commit/pre-commit-hooks.git - rev: v2.2.3 + rev: v3.3.0 hooks: - id: end-of-file-fixer - id: trailing-whitespace @@ -20,20 +20,20 @@ repos: - id: check-merge-conflict - id: debug-statements - repo: https://gitlab.com/pycqa/flake8.git - rev: 3.7.8 + rev: 3.8.4 hooks: - id: flake8 additional_dependencies: - flake8-black - repo: https://github.com/adrienverge/yamllint.git - rev: v1.16.0 + rev: v1.25.0 hooks: - id: yamllint files: \.(yaml|yml)$ types: [file, yaml] entry: yamllint --strict - repo: https://github.com/codespell-project/codespell.git - rev: v1.15.0 + rev: v1.17.1 hooks: - id: codespell name: codespell diff --git a/molecule_libvirt/driver.py b/molecule_libvirt/driver.py index 663a4df..d983ae3 100644 --- a/molecule_libvirt/driver.py +++ b/molecule_libvirt/driver.py @@ -136,7 +136,7 @@ def sanity_checks(self): pass def template_dir(self): - """ Return path to its own cookiecutterm templates. It is used by init + """Return path to its own cookiecutterm templates. It is used by init command in order to figure out where to load the templates from. """ return os.path.join( diff --git a/molecule_libvirt/test/functional/test_libvirt.py b/molecule_libvirt/test/functional/test_libvirt.py index dee1448..a5d4c5d 100644 --- a/molecule_libvirt/test/functional/test_libvirt.py +++ b/molecule_libvirt/test/functional/test_libvirt.py @@ -21,10 +21,10 @@ import pytest import os -import sh from molecule import logger -from molecule.test.conftest import run_command, change_dir_to +from molecule.util import run_command +from molecule.test.conftest import change_dir_to from molecule.test.functional.conftest import metadata_lint_update # import change_dir_to, temp_dir @@ -35,23 +35,27 @@ @pytest.mark.xfail(reason="need to fix template path") def test_command_init_scenario(temp_dir): role_directory = os.path.join(temp_dir.strpath, "test-init") - options = {"role_name": "test-init"} - cmd = sh.molecule.bake("init", "role", **options) - run_command(cmd) + cmd = ["molecule", "init", "role", "--role-name", "test-init"] + assert run_command(cmd).returncode == 0 metadata_lint_update(role_directory) with change_dir_to(role_directory): molecule_directory = pytest.helpers.molecule_directory() scenario_directory = os.path.join(molecule_directory, "test-scenario") - options = { - "scenario_name": "test-scenario", - "role_name": "test-init", - "driver-name": "libvirt", - } - cmd = sh.molecule.bake("init", "scenario", **options) - run_command(cmd) + cmd = [ + "molecule", + "init", + "scenario", + "--scenario-name", + "test-scenario", + "--role-name", + "test-init", + "--driver-name", + "libvirt", + ] + assert run_command(cmd).returncode == 0 assert os.path.isdir(scenario_directory) - cmd = sh.molecule.bake("test", "-s", "test-scenario") - run_command(cmd) + cmd = ["molecule", "test", "-s", "test-scenario"] + assert run_command(cmd).returncode == 0 diff --git a/pyproject.toml b/pyproject.toml index 0b7dd6c..5fc57a3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,8 +1,22 @@ [build-system] requires = [ + "pip >= 19.3.1", "setuptools >= 42.0.2", - "setuptools_scm >= 1.15.0", - "setuptools_scm_git_archive >= 1.0", - "wheel", + "setuptools_scm[toml] >= 3.5.0", + "setuptools_scm_git_archive >= 1.1", + "wheel >= 0.33.6", ] build-backend = "setuptools.build_meta" + +[tool.black] +skip-string-normalization = false + +[tool.isort] +profile = "black" +float_to_top = true +known_third_party = [ + "molecule" +] + +[tool.setuptools_scm] +local_scheme = "no-local-version" diff --git a/setup.cfg b/setup.cfg index 784eae1..6808856 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,9 +1,6 @@ [aliases] dists = clean --all sdist bdist_wheel -[bdist_wheel] -universal = 1 - [metadata] name = molecule-libvirt url = https://github.com/ansible-community/molecule-libvirt @@ -11,7 +8,7 @@ project_urls = Bug Tracker = https://github.com/ansible-community/molecule-libvirt/issues Release Management = https://github.com/ansible-community/molecule-libvirt/projects CI: Zuul = https://dashboard.zuul.ansible.com/t/ansible/builds?project=ansible-community/molecule-libvirt - Mailing lists = https://docs.ansible.com/ansible/latest/community/communication.html#mailing-list-information + Discussions = https://github.com/ansible-community/molecule/discussions Source Code = https://github.com/ansible-community/molecule-libvirt description = libvirt Molecule Plugin :: run molecule tests on libvirt long_description = file: README.rst @@ -25,17 +22,22 @@ license_file = LICENSE classifiers = Development Status :: 2 - Pre-Alpha Environment :: Console - Framework :: Pytest + Intended Audience :: Developers Intended Audience :: Information Technology Intended Audience :: System Administrators + License :: OSI Approved :: MIT License + Natural Language :: English + Operating System :: OS Independent + Programming Language :: Python :: 3 - Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 Topic :: System :: Systems Administration Topic :: Utilities @@ -50,7 +52,7 @@ keywords = [options] use_scm_version = True -python_requires = >=3.5 +python_requires = >=3.6 packages = find: include_package_data = True zip_safe = False @@ -62,26 +64,13 @@ setup_requires = # These are required in actual runtime: install_requires = - # https://github.com/ansible/ansible/blob/devel/packaging/requirements/requirements-libvirt.txt - ansible - libvirt-python>=5.9.0 - molecule >= 3.0a4 + molecule >= 3.2.0a0 pyyaml >= 5.1, < 6 [options.extras_require] test = - flake8>=3.6.0, < 4 - - mock>=3.0.5, < 4 - pytest-cov>=2.7.1, < 3 - pytest-dependency - pytest-helpers-namespace>=2019.1.8, < 2020 - pytest-html - pytest-mock>=1.10.4, < 2 - pytest-plus - pytest-verbose-parametrize>=1.7.0, < 2 - pytest-xdist>=1.29.0, < 2 - pytest>=4.6.3 + molecule[test] + pytest-helpers-namespace [options.entry_points] molecule.driver = diff --git a/setup.py b/setup.py index 140dc8d..3f01b73 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,16 @@ # !/usr/bin/env python + +import site +import sys + import setuptools +# See https://github.com/pypa/pip/issues/7953 +site.ENABLE_USER_SITE = "--user" in sys.argv[1:] + if __name__ == "__main__": - setuptools.setup(use_scm_version=True) + setuptools.setup( + use_scm_version={"local_scheme": "no-local-version"}, + setup_requires=["setuptools_scm[toml]>=3.5.0"], + ) diff --git a/tox.ini b/tox.ini index 44ec986..cbeda59 100644 --- a/tox.ini +++ b/tox.ini @@ -1,100 +1,126 @@ -# For more information about tox, see https://tox.readthedocs.io/en/latest/ [tox] minversion = 3.9.0 envlist = - linters + lint + docs packaging - py{35,36,37,38} - devel -skipsdist = True + py{36,37,38,39} + py{36,37,38,39}-{devel} + +# do not enable skip missing to avoid CI false positives +skip_missing_interpreters = False isolated_build = True [testenv] -description = - Unit testing usedevelop = True -# download assures tox gets newest pip, see https://github.com/tox-dev/tox/issues/791 -download = true -# to reach libvirt-python which could prove problematic to install -# sitepackages = True -extras = test -commands = - pytest --collect-only - pytest --color=yes {tty:-s} -setenv = - ANSIBLE_FORCE_COLOR={env:ANSIBLE_FORCE_COLOR:1} - ANSIBLE_INVENTORY={toxinidir}/tests/hosts.ini - ANSIBLE_CONFIG={toxinidir}/ansible.cfg - ANSIBLE_NOCOWS=1 - ANSIBLE_RETRY_FILES_ENABLED=0 - ANSIBLE_STDOUT_CALLBACK={env:ANSIBLE_STDOUT_CALLBACK:debug} - ANSIBLE_VERBOSITY={env:ANSIBLE_VERBOSITY:0} - PIP_DISABLE_PIP_VERSION_CHECK=1 - PY_COLORS={env:PY_COLORS:1} - # pip: Avoid 2020-01-01 warnings: https://github.com/pypa/pip/issues/6207 - PYTHONWARNINGS=ignore:DEPRECATION::pip._internal.cli.base_command - PYTHONDONTWRITEBYTECODE=1 - # This should pass these args to molecule, no effect here as this is the default - # but it validates that it accepts extra params. - MOLECULE_OPTS=--destroy always +# do not put * in passenv as it may break builds do to reduced isolation passenv = CI - CURL_CA_BUNDLE + CONTAINER_* DOCKER_* + GITHUB_* + HOME + PODMAN_* PYTEST_* - REQUESTS_CA_BUNDLE SSH_AUTH_SOCK - SSL_CERT_FILE - TOXENV - TRAVIS - TRAVIS_* - TWINE_* - ZUUL* + TERM +setenv = + ANSIBLE_CONFIG={toxinidir}/dev/null + ANSIBLE_CALLABLE_WHITELIST={env:ANSIBLE_CALLABLE_WHITELIST:timer,profile_roles} + ANSIBLE_DISPLAY_FAILED_STDERR=1 + ANSIBLE_VERBOSITY=1 + PYTHONDONTWRITEBYTECODE=1 + PYTHONUNBUFFERED=1 + # Disabled new resolved due to https://github.com/pypa/pip/issues/8713 + # new resolve a must or test extras will not install right + # PIP_USE_FEATURE=2020-resolver + MOLECULE_NO_LOG=0 +deps = + devel: ansible>=2.10.0a2,<2.11 + py{36,37,38,39}: molecule[test] + py{36,37,38,39}-{devel}: git+https://github.com/ansible-community/molecule.git@master#egg=molecule[test] + dockerfile: ansible>=2.9.12 + selinux +extras = + lint + test +commands = + ansibledevel: ansible-galaxy install git+https://github.com/ansible-collections/community.general.git + # failsafe as pip may install incompatible dependencies + pip check + # failsafe for preventing changes that may break pytest collection + python -m pytest -p no:cov --collect-only + python -m pytest {posargs:-l} + whitelist_externals = - bash - twine - pytest - pre-commit + find + rm + sh + +[testenv:lint] +description = Runs all linting tasks +commands = + # to run a single linter you can do "pre-commit run flake8" + python -m pre_commit run {posargs:--all} +deps = pre-commit>=1.18.1 +extras = +skip_install = true +usedevelop = false + +[testenv:docs] +description = Invoke sphinx-build to build the HTML docs +# doc requires py3 due to use of f'' strings and using only python3 as +# basepython risks using python3.4 which is not supported. +basepython = python3 +passenv = * +usedevelop = False +commands = + python -m sphinx \ + -a -n -W \ + -b html --color \ + -d "{toxinidir}/docs/docstree" \ + docs/ "{toxinidir}/docs/docstree/html" + + # Print out the output docs dir and a way to serve html: + python -c \ + 'import pathlib; '\ + 'docs_dir = pathlib.Path(r"{toxinidir}") / "docs/docstree/html"; index_file = docs_dir / "index.html"; print(f"\nDocumentation available under `file://\{index_file\}`\n\nTo serve docs, use `python3 -m http.server --directory \{docs_dir\} 0`\n")' +extras = + docs + +[testenv:docs-livereload] +description = Invoke sphinx-autobuild to build and reload the HTML docs +basepython = {[testenv:docs]basepython} +passenv = {[testenv:docs]passenv} +usedevelop = {[testenv:docs]usedevelop} +commands = + python -m sphinx_autobuild docs/ "{toxworkdir}/docs/html" +deps = + sphinx-autobuild>=0.7.1,<1.0 +extras = + docs [testenv:packaging] +description = + Do packaging/distribution. If tag is not present or PEP440 compliant upload to + PYPI could fail +# `usedevelop = true` overrides `skip_install` instruction, it's unwanted usedevelop = false +# don't install molecule itself in this env skip_install = true deps = collective.checkdocs >= 0.2 - pep517 >= 0.5.0 - twine >= 2.0.0 + pep517 >= 0.8.2 + pip >= 20.2.2 + toml >= 0.10.1 + twine >= 3.2.0 # pyup: ignore +setenv = commands = - bash -c "rm -rf {toxinidir}/dist/ && mkdir -p {toxinidir}/dist/" + rm -rfv {toxinidir}/dist/ python -m pep517.build \ --source \ --binary \ --out-dir {toxinidir}/dist/ \ {toxinidir} - twine check dist/* - -[testenv:devel] -description= Unit testing using master branches of molecule and ansible -extras = test -commands = - {[testenv]commands} -deps = - git+https://github.com/ansible/ansible.git#egg=ansible - git+https://github.com/ansible/molecule#egg=molecule - -[testenv:linters] -description = Performs linting, style checks -skip_install = true -sitepackages = false -deps = - pre-commit -commands = - pre-commit run -a - -[testenv:upload] -description = Builds the packages and uploads them to https://pypi.org -envdir={toxworkdir}/dist -deps= - {[testenv:packaging]deps} -commands = - {[testenv:packaging]commands} - twine upload --verbose dist/* + # metadata validation + sh -c "python -m twine check {toxinidir}/dist/*"