From f8a436c382c23fbb82359b59b97732eaf83b5b8a Mon Sep 17 00:00:00 2001 From: Brian Helba Date: Sat, 27 Feb 2021 16:14:12 -0500 Subject: [PATCH] Add CI, linting, and automatic versioning --- .github/workflows/ci.yml | 45 +++++++++++++++++++++ .github/workflows/release.yml | 70 +++++++++++++++++++++++++++++++++ MANIFEST.in | 11 +++++- hashstate/__init__.py | 2 +- mypy.ini | 3 ++ pyproject.toml | 19 +++++++++ setup.py | 13 ++---- test/test_hashstate.py | 3 +- tox.ini | 74 +++++++++++++++++++++++++++++++++-- 9 files changed, 225 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml create mode 100644 mypy.ini create mode 100644 pyproject.toml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..fa34051 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,45 @@ +name: ci +on: + pull_request: + push: + branches: + - master + schedule: + - cron: "0 0 * * *" +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ + ubuntu-16.04 +# ubuntu-latest, +# macos-latest, +# windows-latest + ] + python-version: [ + "3.6", +# "3.7", +# "3.8", +# "3.9" + ] + steps: + - uses: actions/checkout@v2 + with: + lfs: true + submodules: true + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install tox + run: | + pip install --upgrade pip + pip install tox + - name: Run linting tests + if: ${{ matrix.os == 'ubuntu-latest' }} + run: | + tox -e lint,type + - name: Run pytest tests + run: | + tox -e test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..0ebe512 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,70 @@ +name: release +on: + release: + types: [published] +jobs: + publish: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: ["3.6", "3.7", "3.8", "3.9"] + # Linux builds don't need to run across different Python versions, + # they will all be installed under the manylinux action + exclude: + - os: ubuntu-latest + python-version: "3.6" + - os: ubuntu-latest + python-version: "3.7" + - os: ubuntu-latest + python-version: "3.8" + - os: ubuntu-latest + python-version: "3.9" + # Use the latest Python version as a base for Linux builds + include: + - os: ubuntu-latest + python-version: "3.x" + steps: + - uses: actions/checkout@v2 + with: + lfs: true + submodules: true + # Tags are needed to compute the current version number + fetch-depth: 0 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install tox and pypa-build + run: | + pip install --upgrade pip + pip install tox build + - name: Build sdist + # Do this before the manylinux build, so the output directory doesn't get created by Docker + if: ${{ matrix.os == 'ubuntu-latest' }} + run: | + pyproject-build --sdist + - name: Build manylinux wheels + if: ${{ matrix.os == 'ubuntu-latest' }} + uses: RalfG/python-wheels-manylinux-build@v0.3.3-manylinux2014_x86_64 + with: + python-versions: 'cp36-cp36m cp37-cp37m cp38-cp38 cp39-cp39' + # Necessary for setuptools_scm to read the version from Git + system-packages: 'git-lfs' + - name: Remove non-manylinux wheels + if: ${{ matrix.os == 'ubuntu-latest' }} + # Those are built as intermediate artifacts, but should not be published + # Since these are built by Docker, they must be removed with sudo + run: | + sudo rm -f dist/*-linux*.whl + - name: Build non-Linux wheels + if: ${{ matrix.os != 'ubuntu-latest' }} + run: | + pyproject-build --wheel + - name: Publish to PyPI + env: + TWINE_USERNAME: "__token__" + TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} + TWINE_NON_INTERACTIVE: "true" + run: | + tox -e release diff --git a/MANIFEST.in b/MANIFEST.in index 060ee72..cee822e 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1,10 @@ -prune test/ +# Reset the auto-include from setuptools_scm +exclude * +prune * + +# Re-include files which setuptools auto-includes +include MANIFEST.in pyproject.toml README.md setup.py +graft *.egg-info + +# Include the module +graft hashstate diff --git a/hashstate/__init__.py b/hashstate/__init__.py index 1dd2c71..9294bfa 100644 --- a/hashstate/__init__.py +++ b/hashstate/__init__.py @@ -1 +1 @@ -from ._hashstate import * +from ._hashstate import * # noqa: F401, F403 diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000..e765405 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,3 @@ +[mypy] +ignore_missing_imports = True +show_error_codes = True diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..862e4bb --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,19 @@ +[build-system] +requires = ["setuptools >= 42", "wheel", "setuptools-scm[toml]>=3.4"] +build-backend = "setuptools.build_meta" + +[tool.setuptools_scm] + +[tool.black] +line-length = 100 +skip-string-normalization = true +target-version = ["py38"] +exclude='\.eggs|\.git|\.mypy_cache|\.tox|\.venv|_build|buck-out|build|dist' + +[tool.isort] +profile = "black" +line_length = 100 +# Sort by name, don't cluster "from" vs "import" +force_sort_within_sections = true +# Combines "as" imports on the same line +combine_as_imports = true diff --git a/setup.py b/setup.py index b90d027..d80191e 100644 --- a/setup.py +++ b/setup.py @@ -1,17 +1,12 @@ -from setuptools import setup, Extension +from setuptools import Extension, setup with open('README.md') as f: readme = f.read() -c_ext = Extension( - 'hashstate._hashstate', - sources=['hashstate/_hashstate.c'], - libraries=['ssl'] -) +c_ext = Extension('hashstate._hashstate', sources=['hashstate/_hashstate.c'], libraries=['ssl']) setup( name='hashstate', - version='0.2.1', description='Serializable hash objects', url='https://github.com/zachmullen/hashstate', license='MIT', @@ -25,6 +20,6 @@ 'Intended Audience :: Developers', 'Operating System :: OS Independent', 'Programming Language :: Python', - 'Programming Language :: Python :: 3' - ] + 'Programming Language :: Python :: 3', + ], ) diff --git a/test/test_hashstate.py b/test/test_hashstate.py index 124673b..b5c762f 100644 --- a/test/test_hashstate.py +++ b/test/test_hashstate.py @@ -1,6 +1,7 @@ -import hashstate import pytest +import hashstate + ALGS = {'md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512'} diff --git a/tox.ini b/tox.ini index 528347c..c58ddaa 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,75 @@ [tox] -envlist = py +# Build in an environment which respects PEP 518 +isolated_build = true +envlist = + lint, + type, + test, -[testenv] -deps = pytest +[testenv:lint] +skipsdist = true +skip_install = true +deps = + flake8 + flake8-black + flake8-bugbear + flake8-docstrings + flake8-isort + flake8-quotes + pep8-naming commands = + flake8 {posargs:.} + +[testenv:type] +skipsdist = true +skip_install = true +deps = + mypy +commands = + mypy {posargs:.} + +[testenv:format] +skipsdist = true +skip_install = true +deps = + black + isort +commands = + isort {posargs:.} + black {posargs:.} + +[testenv:test] +deps = pytest +commands = + pytest {posargs} + +[testenv:release] +skipsdist = true +skip_install = true +passenv = + TWINE_USERNAME + TWINE_PASSWORD + TWINE_NON_INTERACTIVE +deps = + twine +commands = + # Don't build any packages, that's done in a more particular way by CI + twine check dist/* + twine upload --skip-existing dist/* + +[flake8] +max-line-length = 100 +show-source = True +ignore = + # closing bracket does not match indentation of opening bracket’s line + E123 + # whitespace before ':' + E203, + # line break before binary operator + W503, + # Missing docstring in * + D10, + +[pytest] +addopts = --strict-markers --showlocals --verbose