diff --git a/.coveragerc b/.coveragerc index 36046472..4087bc44 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,8 +1,23 @@ [run] -source = smartcard +branch = True +parallel = True relative_files = True +source = + smartcard + test + +[paths] +source = + src + */site-packages [report] +skip_covered = True +fail_under = 33 exclude_lines = pragma: no cover if __name__ == '__main__': + +[html] +directory = htmlcov/ +skip_covered = False diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 08737607..99006725 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,8 +10,8 @@ on: jobs: test: - name: "${{ matrix.os.name }} (${{ matrix.cpython }})" - runs-on: "${{ matrix.os.runner }}" + name: "${{ matrix.name }} / ${{ matrix.cpython }}" + runs-on: "${{ matrix.runner }}" defaults: run: shell: "bash" @@ -19,60 +19,92 @@ jobs: strategy: fail-fast: false matrix: - os: - - name: "Linux" - runner: "ubuntu-latest" - - name: "macOS" - runner: "macos-latest" + name: + - "Linux" + - "macOS" + - "Windows (x64)" + - "Windows (x86)" cpython: - "3.9" - "3.10" - "3.11" - "3.12" + include: + # Augment the matrix with additional values. + # The values match on "name". + - name: "Linux" + runner: "ubuntu-latest" + architecture: "x64" + + - name: "macOS" + runner: "macos-latest" + architecture: "arm64" + + - name: "Windows (x64)" + runner: "windows-latest" + architecture: "x64" + + - name: "Windows (x86)" + runner: "windows-latest" + architecture: "x86" + steps: - - uses: actions/checkout@v4 + - name: "Checkout the repository" + uses: actions/checkout@v4 - - name: Set up Python ${{ matrix.cpython }} + - name: "Set up Python ${{ matrix.cpython }}" uses: actions/setup-python@v5 with: - python-version: ${{ matrix.cpython }} + python-version: "${{ matrix.cpython }}" + architecture: "${{ matrix.architecture }}" - - name: setup prerequisites (Linux) - if: matrix.os.name == 'Linux' + - name: "Install build prerequisites (Linux)" + if: matrix.name == 'Linux' run: | sudo apt install libpcsclite-dev python3-all-dev python3-setuptools swig - - name: setup prerequisites (macOS) - if: matrix.os.name == 'macOS' + - name: "Install build prerequisites (macOS)" + if: matrix.name == 'macOS' run: | brew install swig pylint - - name: build + - name: "Install build prerequisites (Windows)" + if: startsWith(matrix.name, 'Windows') + run: | + choco upgrade swig --allow-empty-checksums --yes --limit-output + swig -version + + - name: "Determine virtual environment bin path" + shell: "bash" run: | - python3 -m venv temp - source temp/bin/activate - pip install -r dev-requirements.txt - make + echo 'venv-path=temp/${{ runner.os == 'Windows' && 'Scripts' || 'bin' }}' >> "$GITHUB_ENV" - - name: test run + - name: "Create a virtual environment" run: | - source temp/bin/activate - make test + python -m venv temp + ${{ env.venv-path }}/python -m pip install --upgrade pip setuptools wheel + ${{ env.venv-path }}/pip install tox - - name: coverage + - name: "Test" run: | - source temp/bin/activate - python3 -m coverage erase - python3 -m coverage run -m pytest - python3 -m coverage report - python3 -m coverage xml + ${{ env.venv-path }}/tox -e py${{ matrix.cpython }},coverage_report-ci - - name: Coveralls + - name: "Coveralls" uses: coverallsapp/github-action@v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} - - name: pylint + - name: "Build" + run: | + ${{ env.venv-path }}/tox -e build + + - name: "Upload wheel" + uses: actions/upload-artifact@v4 + with: + name: wheel-${{ matrix.name }}-${{ matrix.cpython }}-${{ matrix.architecture }} + path: dist/*.whl + + - name: "Lint" run: | - pylint --errors-only smartcard || true + ${{ env.venv-path }}/tox -e pylint diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml deleted file mode 100644 index 6e3aaa0c..00000000 --- a/.github/workflows/windows.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Windows Build - -on: [push, pull_request] - -jobs: - build: - - runs-on: windows-latest - - strategy: - matrix: - python-version: ['3.9', '3.10', '3.11', '3.12'] - windows-arch: ['x86', 'x64'] - - steps: - - uses: actions/checkout@v4 - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - architecture: ${{ matrix.windows-arch }} - - - name: Install build tools - run: | - python --version - python -c "import struct; print(struct.calcsize('P') * 8)" - python -m pip install --upgrade pip - pip install -r dev-requirements.txt - - choco install swig --version 2.0.12 --allow-empty-checksums --yes --limit-output - swig -version - - - name: Build - run: | - python -m build - python -m pip install . - - - name: Tests - run: | - cd test - python -m unittest - - - uses: actions/upload-artifact@v4 - with: - name: wheel-${{ matrix.python-version }}-${{ matrix.windows-arch }} - path: dist/*.whl diff --git a/ChangeLog b/ChangeLog index 8d7ec582..695595de 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,8 @@ Unreleased changes * Migrate a `src/` layout. * Support only Python 3.9 and higher * Migrate CI to use the official Coveralls action + * Standardize local and CI testing to use tox + * Build wheels in CI for all supported Python versions 2.1.1 (September 2024) ====================== diff --git a/Makefile b/Makefile index df0db41f..540ed19d 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ PYTHON ?= python3 -COVERAGE ?= coverage +TOX ?= tox build: - $(PYTHON) -m build + $(TOX) run -m build install: clean $(PYTHON) -m pip install --editable . @@ -21,17 +21,15 @@ pypi: clean # files generated by pydoctor rm -rf src/smartcard/doc/html rm -rf dist - $(PYTHON) -m build + # Use the tox 'build' label to generate wheels for all Python versions. + $(TOX) run -m build python3 -m twine upload dist/* -test: install - pytest +test: + $(TOX) run -e py coverage: - $(COVERAGE) erase - $(COVERAGE) run -m unittest discover - $(COVERAGE) report - $(COVERAGE) html + $(TOX) run ChangeLog.git: git log --stat --decorate=short > $@ diff --git a/dev-requirements.txt b/dev-requirements.txt index e7d897f1..6fc75ea6 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -4,3 +4,4 @@ wheel build setuptools pytest +tox diff --git a/tox.ini b/tox.ini index eafa61ea..0b11e408 100644 --- a/tox.ini +++ b/tox.ini @@ -1,24 +1,62 @@ +# The following list of Python versions appears in several places in this file. +# +# {3.9, 3.10, 3.11, 3.12} +# +# This affects parallel test suite execution and wheels that get built, +# so use search-and-replace to update this list in all locations. +# Manual editing may lead to mistakes. + [tox] envlist = pylint - py3.9 - py3.10 - py3.11 - py3.12 + coverage_erase + py{3.9, 3.10, 3.11, 3.12} + coverage_report skip_missing_interpreters = True +labels = + build=build-py{3.9, 3.10, 3.11, 3.12} + +[testenv:coverage_erase] +description = Erase existing coverage reports +skip_install = True +deps = + coverage +commands = + - coverage erase [testenv] +depends = + py{3.9, 3.10, 3.11, 3.12}: coverage_erase deps = -r{toxinidir}/dev-requirements.txt commands = - coverage erase - coverage run -m unittest discover - coverage report - coverage html + coverage run -m pytest -[testenv:pylint] -base_python = py3.12 +[testenv:coverage_report{,-ci}] +depends = py{3.9, 3.10, 3.11, 3.12} +description = + !ci: Generate HTML and console reports + ci: Generate an XML report +deps = + coverage +commands_pre = + - coverage combine +commands = + # Locally, generate an HTML and a console report + !ci: - coverage html + !ci: coverage report + # In CI, simply generate an XML report + ci: - coverage xml + +[testenv:build,build-py{3.9, 3.10, 3.11, 3.12}] +description = Build sdist and wheel files skip_install = True +deps = + build +commands = + python -m build + +[testenv:pylint] deps = pylint commands =