From 617315ade81b18b767ba3162c58cf9920a1f9d86 Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 23 Sep 2022 10:22:16 +0200 Subject: [PATCH] Switch from tox to nox This greatly simplifies (and makes more idiomatic) both our local tests and CI. --- setup.cfg => .flake8 | 3 + .github/workflows/ci.yml | 57 +++++++--------- .gitignore | 2 +- CONTRIBUTING.rst | 22 +++---- MANIFEST.in | 5 +- noxfile.py | 97 ++++++++++++++++++++++++++++ pyproject.toml | 9 ++- setup.py | 1 - src/towncrier/_project.py | 5 +- src/towncrier/newsfragments/430.misc | 2 + src/towncrier/test/test_project.py | 17 +++++ tox.ini | 68 ------------------- tox_build.sh | 16 ----- 13 files changed, 165 insertions(+), 139 deletions(-) rename setup.cfg => .flake8 (53%) create mode 100644 noxfile.py create mode 100644 src/towncrier/newsfragments/430.misc delete mode 100644 tox.ini delete mode 100644 tox_build.sh diff --git a/setup.cfg b/.flake8 similarity index 53% rename from setup.cfg rename to .flake8 index 9b086e81..3907f28c 100644 --- a/setup.cfg +++ b/.flake8 @@ -1,3 +1,6 @@ [flake8] # Allow for longer test strings. Code is formatted to 88 columns by Black. max-line-length = 99 +extend-ignore = + # Conflict between flake8 & black about whitespace in slices. + E203 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 741df488..cf0f9245 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,27 +22,25 @@ jobs: runs-on: ubuntu-latest python: - name: CPython 3.9 - tox: py39 action: 3.9 task: - name: Build - tox: build + nox: build steps: - uses: actions/checkout@v3 - name: Set up ${{ matrix.python.name }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python.action }} - name: Install dependencies - run: python -m pip install --upgrade pip tox + run: python -m pip install --upgrade pip nox - uses: twisted/python-info-action@v1 - - name: Tox - run: tox -c tox.ini -e ${{ matrix.task.tox }} + - run: nox -e ${{ matrix.task.nox }} - name: Publish uses: actions/upload-artifact@v3 @@ -60,29 +58,22 @@ jobs: matrix: python: - name: CPython 3.7 - tox: py37 action: 3.7 - name: CPython 3.8 - tox: py38 action: 3.8 - name: CPython 3.9 - tox: py39 action: 3.9 - name: CPython 3.10 - tox: py310 action: '3.10' - name: CPython 3.11 - tox: py311 action: '3.11.0-beta - 3.11' - name: PyPy 3.7 - tox: pypy37 - action: pypy-3.7 + action: pypy3.7 - name: PyPy 3.8 - tox: pypy38 - action: pypy-3.8 + action: pypy3.8 task: - name: Test - tox: tests + nox: tests steps: - uses: actions/checkout@v3 @@ -94,17 +85,16 @@ jobs: path: dist/ - name: Set up ${{ matrix.python.name }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python.action }} - name: Install dependencies - run: python -m pip install --upgrade pip tox codecov coverage[toml] + run: python -m pip install --upgrade pip nox codecov coverage[toml] - uses: twisted/python-info-action@v1 - - name: Tox - run: tox -c tox.ini --installpkg dist/*.whl -e ${{ matrix.python.tox }}-tests + - run: nox --python ${{ matrix.python.action }} -e ${{ matrix.task.nox }} -- --use-wheel dist/*.whl - name: Codecov run: | @@ -121,11 +111,10 @@ jobs: matrix: python: - name: CPython 3.9 - tox: py39 action: '3.9' task: - name: Test - tox: tests + nox: tests steps: - uses: actions/checkout@v3 @@ -137,17 +126,16 @@ jobs: path: dist/ - name: Set up ${{ matrix.python.name }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python.action }} - name: Install dependencies - run: python -m pip install --upgrade pip tox codecov coverage[toml] + run: python -m pip install --upgrade pip nox codecov coverage[toml] - uses: twisted/python-info-action@v1 - - name: Tox - run: tox -c tox.ini --installpkg dist/*.whl -e ${{ matrix.python.tox }}-tests + - run: nox --python ${{ matrix.python.action }} -e ${{ matrix.task.nox }} -- --use-wheel dist/*.whl - name: Codecov run: | @@ -165,17 +153,16 @@ jobs: # Using second most recent minor release for whatever little # increase in stability over using the latest minor. - name: CPython 3.9 - tox: py39 python-version: '3.9' task: - name: Check Newsfragment - tox: check-newsfragment + nox: check_newsfragment run-if: ${{ github.head_ref != 'pre-commit-ci-update-config' }} - name: Check package manifest - tox: check-manifest + nox: check_manifest run-if: true - name: Check mypy - tox: typecheck + nox: typecheck run-if: true steps: @@ -190,18 +177,18 @@ jobs: path: dist/ - name: Set up ${{ matrix.python.name }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python.python-version }} - name: Install dependencies - run: python -m pip install --upgrade pip tox + run: python -m pip install --upgrade pip nox - uses: twisted/python-info-action@v1 - - name: Tox + - run: nox -e ${{ matrix.task.nox }} if: ${{ matrix.task.run-if }} - run: tox -c tox.ini -e ${{ matrix.task.tox }} + pypi-publish: # https://github.community/t/is-it-possible-to-require-all-github-actions-tasks-to-pass-without-enumerating-them/117957/4?u=graingert @@ -222,7 +209,7 @@ jobs: path: dist/ - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: 3.9 diff --git a/.gitignore b/.gitignore index 75e82d46..c44127a6 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,7 @@ apidocs/ *.pyproj .DS_Store .eggs -.tox/ +.nox/ .coverage.* .vscode .idea diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 6dd5b340..e69f970b 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -88,7 +88,7 @@ We recommend the following workflow: Running the test suite ---------------------- -We use the `twisted.trial`_ module and `tox`_ to run tests against all supported +We use the `twisted.trial`_ module and `nox`_ to run tests against all supported Python versions and operating systems. The following list contains some ways how to run the test suite: @@ -109,26 +109,26 @@ The following list contains some ways how to run the test suite: This will invoke a PDB session. If you press ``c`` it will continue running the test suite until it runs into an error. -* To run all tests against all supported versions, install tox and use:: +* To run all tests against all supported versions, install nox and use:: - $ tox + $ nox - You may want to add the ``--skip-missing-interpreters`` option to avoid errors + You may want to add the ``--no-error-on-missing-interpreters`` option to avoid errors when a specific Python interpreter version couldn't be found. * To get a complete list of the available targets, run:: - $ tox -av + $ nox -l * To run only a specific test only, use the ``towncrier.test.FILE.CLASS.METHOD`` syntax, for example:: - $ tox -- towncrier.test.test_project.InvocationTests.test_version + $ nox -e tests -- towncrier.test.test_project.InvocationTests.test_version * To run some quality checks before you create the pull request, we recommend using this call:: - $ tox -e pre-commit,check-manifest,check-newsfragment + $ nox -e pre_commit check_manifest check_newsfragment * Or enable `pre-commit` as a git hook:: @@ -136,15 +136,15 @@ The following list contains some ways how to run the test suite: $ pre-commit install -**Please note**: If the test suite works in tox, but doesn't by calling +**Please note**: If the test suite works in nox, but doesn't by calling ``trial``, it could be that you've got GPG-signing active for git commits which fails with our dummy test commits. .. ### Links -.. _flake8: https://flake8.rtfd.io +.. _flake8: https://flake8.pycqa.org/ .. _GitHub Discussions: https://github.com/twisted/towncrier/discussions .. _issues: https://github.com/twisted/towncrier/issues .. _pull request: https://github.com/twisted/towncrier/pulls -.. _tox: https://tox.rtfd.org/ -.. _twisted.trial: https://twistedmatrix.com/trac/wiki/TwistedTrial +.. _nox: https://nox.thea.codes/ +.. _twisted.trial: https://github.com/twisted/trac-wiki-archive/blob/trunk/TwistedTrial.mediawiki diff --git a/MANIFEST.in b/MANIFEST.in index a2261b30..9494555b 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,11 +3,10 @@ include .coveragerc include LICENSE include CODE_OF_CONDUCT.md include pyproject.toml -include tox.ini -include tox_build.sh -include tox_check-release.sh +include noxfile.py include *.yaml include .git-blame-ignore-revs +include .flake8 recursive-include src *.rst exclude bin diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 00000000..38b65b98 --- /dev/null +++ b/noxfile.py @@ -0,0 +1,97 @@ +from __future__ import annotations + +import os + +import nox + + +nox.options.sessions = ["pre_commit", "docs", "typecheck", "tests"] +nox.options.reuse_existing_virtualenvs = True +nox.options.error_on_external_run = True + + +@nox.session +def pre_commit(session: nox.Session) -> None: + session.install("pre-commit") + + session.run("pre-commit", "run", "--all-files", "--show-diff-on-failure") + + +@nox.session(python=["pypy3.7", "pypy3.8", "3.7", "3.8", "3.9", "3.10", "3.11"]) +def tests(session: nox.Session) -> None: + session.install("Twisted", "coverage[toml]") + posargs = list(session.posargs) + + try: + # Allow `--use-wheel path/to/wheel.whl` to be passed. + i = session.posargs.index("--use-wheel") + session.install(session.posargs[i + 1]) + del posargs[i : i + 2] + except ValueError: + session.install(".") + + if not posargs: + posargs = ["towncrier"] + + session.run("coverage", "run", "--module", "twisted.trial", *posargs) + + if os.environ.get("CI") != "true": + session.notify("coverage_report") + else: + session.run("coverage", "combine") + + +@nox.session +def coverage_report(session: nox.Session) -> None: + session.install("coverage[toml]") + + session.run("coverage", "combine") + session.run("coverage", "report") + + +@nox.session +def check_newsfragment(session: nox.Session) -> None: + session.install(".") + session.run("python", "-m", "towncrier.check", "--compare-with", "origin/trunk") + + +@nox.session +def check_manifest(session: nox.Session) -> None: + session.install("check-manifest") + session.run("check-manifest") + + +@nox.session +def typecheck(session: nox.Session) -> None: + session.install(".", "mypy", "types-setuptools") + session.run("mypy", "src") + + +@nox.session +def docs(session: nox.Session) -> None: + session.install(".[dev]") + + session.run( + # fmt: off + "python", "-m", "sphinx", + "-T", "-E", + "-W", "--keep-going", + "-b", "html", + "-d", "docs/_build/doctrees", + "-D", "language=en", + "docs", + "docs/_build/html", + # fmt: on + ) + + +@nox.session +def build(session: nox.Session) -> None: + session.install("build", "check-manifest>=0.44", "twine") + + session.run("check-manifest", "--verbose") + # If no argument is passed, build builds an sdist and then a wheel from + # that sdist. + session.run("python", "-m", "build") + + session.run("twine", "check", "dist/*") diff --git a/pyproject.toml b/pyproject.toml index 8cd04260..bff18919 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,7 @@ exclude = ''' /( \.eggs # exclude a few common directories in the | \.git # root of the project - | \.tox + | \.nox | \.venv | \.env | env @@ -71,6 +71,11 @@ module = 'click_default_group' # 2022-09-04: This library has no type annotations. ignore_missing_imports = true +[[tool.mypy.overrides]] +module = 'incremental' +# No released version with type hints. +ignore_missing_imports = true + [build-system] requires = [ @@ -86,7 +91,7 @@ branch = true source = ["towncrier"] [tool.coverage.paths] -source = ["src", ".tox/*/site-packages"] +source = ["src", ".nox/*/site-packages"] [tool.coverage.report] show_missing = true diff --git a/setup.py b/setup.py index 81a686aa..a55a7598 100644 --- a/setup.py +++ b/setup.py @@ -61,5 +61,4 @@ description="Building newsfiles for your project.", long_description=open("README.rst").read(), entry_points={"console_scripts": ["towncrier = towncrier._shell:cli"]}, - options={"bdist_wheel": {"universal": "1"}}, ) diff --git a/src/towncrier/_project.py b/src/towncrier/_project.py index 9c887ff0..ac40ddfd 100644 --- a/src/towncrier/_project.py +++ b/src/towncrier/_project.py @@ -12,6 +12,7 @@ from importlib import import_module from types import ModuleType +from typing import cast from incremental import Version @@ -51,7 +52,7 @@ def get_version(package_dir: str, package: str) -> str: return version.strip() if isinstance(version, Version): - return version.base().strip() + return cast(str, version.base().strip()) if isinstance(version, tuple): return ".".join(map(str, version)).strip() @@ -78,6 +79,6 @@ def get_project_name(package_dir: str, package: str) -> str: if isinstance(version, Version): # Incremental has support for package names - return version.package + return cast(str, version.package) raise TypeError(f"Unsupported type for __version__: {type(version)}") diff --git a/src/towncrier/newsfragments/430.misc b/src/towncrier/newsfragments/430.misc new file mode 100644 index 00000000..a88a7a85 --- /dev/null +++ b/src/towncrier/newsfragments/430.misc @@ -0,0 +1,2 @@ +We now use `Nox `_ instead of Tox. +You may have to adjust a few command lines, but overall contributing should now be more comfortable. diff --git a/src/towncrier/test/test_project.py b/src/towncrier/test/test_project.py index 4d3531ce..0e55e068 100644 --- a/src/towncrier/test/test_project.py +++ b/src/towncrier/test/test_project.py @@ -5,12 +5,19 @@ import sys from subprocess import check_output +from unittest import skipIf from twisted.trial.unittest import TestCase from .._project import get_project_name, get_version +try: + from importlib.metadata import version +except ImportError: + version = None + + class VersionFetchingTests(TestCase): def test_str(self): """ @@ -40,6 +47,16 @@ def test_tuple(self): version = get_version(temp, "mytestproja") self.assertEqual(version, "1.3.12") + @skipIf(version is None, "Needs importlib.metadata.") + def test_incremental(self): + """ + An incremental Version __version__ is picked up. + """ + init = "../src/towncrier/__init__.py" + + self.assertEqual(version("towncrier"), get_version(init, "towncrier")) + self.assertEqual("towncrier", get_project_name(init, "towncrier")) + def test_unknown_type(self): """ A __version__ of unknown type will lead to an exception. diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 8f686157..00000000 --- a/tox.ini +++ /dev/null @@ -1,68 +0,0 @@ -[tox] -envlist = pre-commit, {pypy37,pypy38,py37,py38,py39,py310,py311}-tests, check-manifest, check-newsfragment, typecheck -isolated_build=true -skip_missing_envs = true - -[testenv:pre-commit] -skip_install = True -deps = pre-commit -commands = - pre-commit run --all-files --verbose - -[testenv:check-newsfragment] -commands = - python -m towncrier.check --compare-with origin/trunk - -[testenv:check-manifest] -deps = check-manifest -skip_install = true -commands = check-manifest - -[testenv] -deps = - Twisted - coverage[toml] - incremental - -commands = - python -V - coverage --version - {envbindir}/trial --version - coverage erase - # `coverage run` tries to act like Python so we use `--module` instead of - # specifying the entry point script in `{envbindir}`. - coverage run -p --module twisted.trial {posargs:towncrier} - coverage combine -a - coverage report - -[testenv:typecheck] -deps = - mypy - # 2022-09-04: There is no release yet which includes type annotations. - incremental @ git+https://github.com/twisted/incremental.git@5845557ab9 - types-setuptools -commands = - mypy src/ - -[testenv:build] -allowlist_externals = - bash -changedir = {envtmpdir} -deps = - build - check-manifest>=0.44 - twine -setenv = - toxinidir={toxinidir} -skip_install = true -commands = - # could be brought inside tox.ini after https://github.com/tox-dev/tox/issues/1571 - bash {toxinidir}/tox_build.sh - -[testenv:docs] -extras = dev -# I have no idea why the previous `extra = dev` doesn't install sphinx via tox. -deps = sphinx >= 5 -commands = - # This tries to be as close as possible to the command used by Read The Docs. - python -m sphinx -T -E -W --keep-going -b html -d docs/_build/doctrees -D language=en docs docs/_build/html diff --git a/tox_build.sh b/tox_build.sh deleted file mode 100644 index c43685f3..00000000 --- a/tox_build.sh +++ /dev/null @@ -1,16 +0,0 @@ -# build the sdist - -set -evx - -check-manifest --verbose ${toxinidir} - -python -m build --sdist --outdir ${toxinidir}/dist/ ${toxinidir} - -tar -xvf ${toxinidir}/dist/* -cd * - -# build the wheel from the sdist -python -m build --wheel --outdir ${toxinidir}/dist/ . -cd - - -twine check ${toxinidir}/dist/*