Switch Windows builds to GHA #387
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Generated from: | |
# https://github.com/zopefoundation/meta/tree/master/config/c-code | |
### | |
# Initially copied from | |
# https://github.com/actions/starter-workflows/blob/main/ci/python-package.yml | |
# And later based on the version jamadden updated at | |
# gevent/gevent, and then at zodb/relstorage and zodb/perfmetrics | |
# | |
# Original comment follows. | |
### | |
### | |
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions | |
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions | |
### | |
### | |
# Important notes on GitHub actions: | |
# | |
# - We only get 2,000 free minutes a month (private repos) | |
# - We only get 500MB of artifact storage | |
# - Cache storage is limited to 7 days and 5GB. | |
# - macOS minutes are 10x as expensive as Linux minutes | |
# - windows minutes are twice as expensive. | |
# | |
# So keep those workflows light. Note: Currently, they seem to be free | |
# and unlimited for open source projects. But for how long... | |
# | |
# In December 2020, github only supports x86/64. If we wanted to test | |
# on other architectures, we can use docker emulation, but there's no | |
# native support. It works, but is slow. | |
# | |
# Another major downside: You can't just re-run the job for one part | |
# of the matrix. So if there's a transient test failure that hit, say, 3.8, | |
# to get a clean run every version of Python runs again. That's bad. | |
# https://github.community/t/ability-to-rerun-just-a-single-job-in-a-workflow/17234/65 | |
name: tests | |
# Triggers the workflow on push or pull request events and periodically | |
on: | |
push: | |
pull_request: | |
schedule: | |
- cron: '0 12 * * 0' # run once a week on Sunday | |
# Allow to run this workflow manually from the Actions tab | |
workflow_dispatch: | |
env: | |
# Weirdly, this has to be a top-level key, not ``defaults.env`` | |
PYTHONHASHSEED: 8675309 | |
PYTHONUNBUFFERED: 1 | |
PYTHONDONTWRITEBYTECODE: 1 | |
PYTHONDEVMODE: 1 | |
PYTHONFAULTHANDLER: 1 | |
ZOPE_INTERFACE_STRICT_IRO: 1 | |
PIP_UPGRADE_STRATEGY: eager | |
# Don't get warnings about Python 2 support being deprecated. We | |
# know. The env var works for pip 20. | |
PIP_NO_PYTHON_VERSION_WARNING: 1 | |
PIP_NO_WARN_SCRIPT_LOCATION: 1 | |
CFLAGS: -O3 -pipe | |
CXXFLAGS: -O3 -pipe | |
# Uploading built wheels for releases. | |
# TWINE_PASSWORD is encrypted and stored directly in the | |
# github repo settings. | |
TWINE_USERNAME: __token__ | |
### | |
# caching | |
# This is where we'd set up ccache, but this compiles so fast its not worth it. | |
### | |
jobs: | |
# Because sharing code/steps is so hard, and because it can be | |
# extremely valuable to be able to get binary wheels without | |
# uploading to PyPI and even if there is some failure, (e.g., for | |
# other people to test/debug), the strategy is to divide the process | |
# into several different jobs. The first builds and saves the binary | |
# wheels. It has dependent jobs that download and install the wheel | |
# to run tests, build docs, and perform linting. Building the | |
# manylinux wheels is an independent set of jobs. | |
# | |
# This division is time-saving for projects that take awhile to | |
# build, but somewhat less of a clear-cut win given how quick this | |
# is to compile (at least at this writing). | |
build-package: | |
# Sigh. Note that the matrix must be kept in sync | |
# with `test`, and `docs` must use a subset. | |
runs-on: ${{ matrix.os }} | |
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name | |
strategy: | |
fail-fast: false | |
matrix: | |
python-version: | |
- "pypy-3.10" | |
- "3.7" | |
- "3.8" | |
- "3.9" | |
- "3.10" | |
- "3.11" | |
- "3.12" | |
- "3.13.0-alpha - 3.13.0" | |
os: [ubuntu-latest, macos-latest, windows-latest] | |
exclude: | |
- os: macos-latest | |
python-version: "pypy-3.10" | |
steps: | |
- name: checkout | |
uses: actions/checkout@v4 | |
- name: Set up Python ${{ matrix.python-version }} | |
uses: actions/setup-python@v5 | |
with: | |
python-version: ${{ matrix.python-version }} | |
### | |
# Caching. | |
# This actually *restores* a cache and schedules a cleanup action | |
# to save the cache. So it must come before the thing we want to use | |
# the cache. | |
### | |
- name: Get pip cache dir (default) | |
id: pip-cache-default | |
if: ${{ !startsWith(runner.os, 'Windows') }} | |
run: | | |
echo "dir=$(pip cache dir)" >>$GITHUB_OUTPUT | |
- name: Get pip cache dir (Windows) | |
id: pip-cache-windows | |
if: ${{ startsWith(runner.os, 'Windows') }} | |
run: | | |
echo "dir=$(pip cache dir)" >> $Env:GITHUB_OUTPUT | |
- name: pip cache (default) | |
uses: actions/cache@v4 | |
if: ${{ !startsWith(runner.os, 'Windows') }} | |
with: | |
path: ${{ steps.pip-cache-default.outputs.dir }} | |
key: ${{ runner.os }}-pip-${{ matrix.python-version }} | |
restore-keys: | | |
${{ runner.os }}-pip- | |
- name: pip cache (Windows) | |
uses: actions/cache@v4 | |
if: ${{ startsWith(runner.os, 'Windows') }} | |
with: | |
path: ${{ steps.pip-cache-windows.outputs.dir }} | |
key: ${{ runner.os }}-pip-${{ matrix.python-version }} | |
restore-keys: | | |
${{ runner.os }}-pip- | |
- name: Install Build Dependencies (3.13.0-alpha - 3.13.0) | |
if: matrix.python-version == '3.13.0-alpha - 3.13.0' | |
run: | | |
pip install -U pip | |
pip install -U setuptools wheel twine | |
- name: Install Build Dependencies | |
if: matrix.python-version != '3.13.0-alpha - 3.13.0' | |
run: | | |
pip install -U pip | |
pip install -U setuptools wheel twine | |
- name: Build zope.interface (macOS x86_64, Python 3.8+) | |
if: > | |
startsWith(runner.os, 'Mac') | |
&& !(startsWith(matrix.python-version, 'pypy') | |
|| matrix.python-version == '3.7') | |
env: | |
MACOSX_DEPLOYMENT_TARGET: 10.9 | |
_PYTHON_HOST_PLATFORM: macosx-10.9-x86_64 | |
ARCHFLAGS: -arch x86_64 | |
run: | | |
# Next, build the wheel *in place*. This helps ccache, and also lets us cache the configure | |
# output (pip install uses a random temporary directory, making this difficult). | |
python setup.py build_ext -i | |
python setup.py bdist_wheel | |
- name: Build zope.interface (macOS arm64, Python 3.8+) | |
if: > | |
startsWith(runner.os, 'Mac') | |
&& !(startsWith(matrix.python-version, 'pypy') | |
|| matrix.python-version == '3.7') | |
env: | |
MACOSX_DEPLOYMENT_TARGET: 11.0 | |
_PYTHON_HOST_PLATFORM: macosx-11.0-arm64 | |
ARCHFLAGS: -arch arm64 | |
run: | | |
# Next, build the wheel *in place*. This helps ccache, and also lets us cache the configure | |
# output (pip install uses a random temporary directory, making this difficult). | |
python setup.py build_ext -i | |
python setup.py bdist_wheel | |
- name: Build zope.interface (all other versions) | |
if: > | |
!startsWith(runner.os, 'Mac') | |
|| startsWith(matrix.python-version, 'pypy') | |
|| matrix.python-version == '3.7' | |
run: | | |
# Next, build the wheel *in place*. This helps ccache, and also lets us cache the configure | |
# output (pip install uses a random temporary directory, making this difficult). | |
python setup.py build_ext -i | |
python setup.py bdist_wheel | |
- name: Install zope.interface and dependencies (3.13.0-alpha - 3.13.0) | |
if: matrix.python-version == '3.13.0-alpha - 3.13.0' | |
run: | | |
# Install to collect dependencies into the (pip) cache. | |
# Use "--pre" here because dependencies with support for this future | |
# Python release may only be available as pre-releases | |
pip install --pre .[test] | |
- name: Install zope.interface and dependencies | |
if: matrix.python-version != '3.13.0-alpha - 3.13.0' | |
run: | | |
# Install to collect dependencies into the (pip) cache. | |
pip install .[test] | |
- name: Check zope.interface build | |
run: | | |
ls -l dist | |
twine check dist/* | |
- name: Upload zope.interface wheel (macOS x86_64) | |
if: > | |
startsWith(runner.os, 'Mac') | |
uses: actions/upload-artifact@v4 | |
with: | |
name: zope.interface-${{ runner.os }}-${{ matrix.python-version }}.whl | |
path: dist/*x86_64.whl | |
- name: Upload zope.interface wheel (macOS arm64) | |
if: > | |
startsWith(runner.os, 'Mac') | |
&& !(startsWith(matrix.python-version, 'pypy') | |
|| matrix.python-version == '3.7') | |
uses: actions/upload-artifact@v4 | |
with: | |
# The arm64 wheel is uploaded with a different name just so it can be | |
# manually downloaded when desired. The wheel itself *cannot* be tested | |
# on the GHA runner, which uses x86_64 architecture. | |
name: zope.interface-${{ runner.os }}-${{ matrix.python-version }}-arm64.whl | |
path: dist/*arm64.whl | |
- name: Upload zope.interface wheel (all other platforms) | |
if: > | |
!startsWith(runner.os, 'Mac') | |
uses: actions/upload-artifact@v4 | |
with: | |
name: zope.interface-${{ runner.os }}-${{ matrix.python-version }}.whl | |
path: dist/*whl | |
- name: Publish package to PyPI (mac) | |
# We cannot 'uses: pypa/[email protected]' because | |
# that's apparently a container action, and those don't run on | |
# the Mac. | |
if: > | |
github.event_name == 'push' | |
&& startsWith(github.ref, 'refs/tags') | |
&& startsWith(runner.os, 'Mac') | |
&& !startsWith(matrix.python-version, 'pypy') | |
&& !startsWith(matrix.python-version, '3.13.0-alpha - 3.13.0') | |
env: | |
TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} | |
run: | | |
twine upload --skip-existing dist/* | |
test: | |
needs: build-package | |
runs-on: ${{ matrix.os }} | |
strategy: | |
fail-fast: false | |
matrix: | |
python-version: | |
- "pypy-3.10" | |
- "3.7" | |
- "3.8" | |
- "3.9" | |
- "3.10" | |
- "3.11" | |
- "3.12" | |
- "3.13.0-alpha - 3.13.0" | |
os: [ubuntu-latest, macos-latest, windows-latest] | |
exclude: | |
- os: macos-latest | |
python-version: "pypy-3.10" | |
steps: | |
- name: checkout | |
uses: actions/checkout@v4 | |
- name: Set up Python ${{ matrix.python-version }} | |
uses: actions/setup-python@v5 | |
with: | |
python-version: ${{ matrix.python-version }} | |
### | |
# Caching. | |
# This actually *restores* a cache and schedules a cleanup action | |
# to save the cache. So it must come before the thing we want to use | |
# the cache. | |
### | |
- name: Get pip cache dir (default) | |
id: pip-cache-default | |
if: ${{ !startsWith(runner.os, 'Windows') }} | |
run: | | |
echo "dir=$(pip cache dir)" >>$GITHUB_OUTPUT | |
- name: Get pip cache dir (Windows) | |
id: pip-cache-windows | |
if: ${{ startsWith(runner.os, 'Windows') }} | |
run: | | |
echo "dir=$(pip cache dir)" >> $Env:GITHUB_OUTPUT | |
- name: pip cache (default) | |
uses: actions/cache@v4 | |
if: ${{ !startsWith(runner.os, 'Windows') }} | |
with: | |
path: ${{ steps.pip-cache-default.outputs.dir }} | |
key: ${{ runner.os }}-pip-${{ matrix.python-version }} | |
restore-keys: | | |
${{ runner.os }}-pip- | |
- name: pip cache (Windows) | |
uses: actions/cache@v4 | |
if: ${{ startsWith(runner.os, 'Windows') }} | |
with: | |
path: ${{ steps.pip-cache-windows.outputs.dir }} | |
key: ${{ runner.os }}-pip-${{ matrix.python-version }} | |
restore-keys: | | |
${{ runner.os }}-pip- | |
- name: Download zope.interface wheel | |
uses: actions/download-artifact@v4 | |
with: | |
name: zope.interface-${{ runner.os }}-${{ matrix.python-version }}.whl | |
path: dist/ | |
- name: Install zope.interface | |
# ``python -m unittest discover`` only works with editable | |
# installs, so we have to duplicate some work and can't | |
# install the built wheel. (zope.testrunner | |
# works fine with non-editable installs.) | |
run: | | |
pip install -U wheel | |
pip install -U --no-binary :all: coverage | |
# Unzip into src/ so that testrunner can find the .so files | |
# when we ask it to load tests from that directory. This | |
# might also save some build time? | |
unzip -n dist/zope.interface-*whl -d src | |
pip install -U -e .[test] | |
- name: Run tests with C extensions | |
if: ${{ !startsWith(matrix.python-version, 'pypy') }} | |
run: | | |
coverage run -p -m unittest discover -s src | |
- name: Run tests without C extensions | |
run: | | |
coverage run -p -m unittest discover -s src | |
env: | |
PURE_PYTHON: 1 | |
- name: Report Coverage | |
run: | | |
coverage combine | |
coverage report --ignore-errors --show-missing | |
- name: Submit to Coveralls | |
# This is a container action, which only runs on Linux. | |
if: ${{ startsWith(runner.os, 'Linux') }} | |
uses: AndreMiras/coveralls-python-action@develop | |
with: | |
parallel: true | |
coveralls_finish: | |
needs: test | |
runs-on: ubuntu-latest | |
steps: | |
- name: Coveralls Finished | |
uses: AndreMiras/coveralls-python-action@develop | |
with: | |
parallel-finished: true | |
docs: | |
needs: build-package | |
runs-on: ${{ matrix.os }} | |
strategy: | |
matrix: | |
python-version: ["3.9"] | |
os: [ubuntu-latest] | |
steps: | |
- name: checkout | |
uses: actions/checkout@v4 | |
- name: Set up Python ${{ matrix.python-version }} | |
uses: actions/setup-python@v5 | |
with: | |
python-version: ${{ matrix.python-version }} | |
### | |
# Caching. | |
# This actually *restores* a cache and schedules a cleanup action | |
# to save the cache. So it must come before the thing we want to use | |
# the cache. | |
### | |
- name: Get pip cache dir (default) | |
id: pip-cache-default | |
if: ${{ !startsWith(runner.os, 'Windows') }} | |
run: | | |
echo "dir=$(pip cache dir)" >>$GITHUB_OUTPUT | |
- name: Get pip cache dir (Windows) | |
id: pip-cache-windows | |
if: ${{ startsWith(runner.os, 'Windows') }} | |
run: | | |
echo "dir=$(pip cache dir)" >> $Env:GITHUB_OUTPUT | |
- name: pip cache (default) | |
uses: actions/cache@v4 | |
if: ${{ !startsWith(runner.os, 'Windows') }} | |
with: | |
path: ${{ steps.pip-cache-default.outputs.dir }} | |
key: ${{ runner.os }}-pip-${{ matrix.python-version }} | |
restore-keys: | | |
${{ runner.os }}-pip- | |
- name: pip cache (Windows) | |
uses: actions/cache@v4 | |
if: ${{ startsWith(runner.os, 'Windows') }} | |
with: | |
path: ${{ steps.pip-cache-windows.outputs.dir }} | |
key: ${{ runner.os }}-pip-${{ matrix.python-version }} | |
restore-keys: | | |
${{ runner.os }}-pip- | |
- name: Download zope.interface wheel | |
uses: actions/download-artifact@v4 | |
with: | |
name: zope.interface-${{ runner.os }}-${{ matrix.python-version }}.whl | |
path: dist/ | |
- name: Install zope.interface | |
run: | | |
pip install -U wheel | |
pip install -U coverage | |
pip install -U "`ls dist/zope.interface-*.whl`[docs]" | |
- name: Build docs | |
env: | |
ZOPE_INTERFACE_STRICT_IRO: 1 | |
run: | | |
sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html | |
sphinx-build -b doctest -d docs/_build/doctrees docs docs/_build/doctest | |
lint: | |
needs: build-package | |
runs-on: ${{ matrix.os }} | |
strategy: | |
matrix: | |
python-version: ["3.9"] | |
os: [ubuntu-latest] | |
steps: | |
- name: checkout | |
uses: actions/checkout@v4 | |
- name: Set up Python ${{ matrix.python-version }} | |
uses: actions/setup-python@v5 | |
with: | |
python-version: ${{ matrix.python-version }} | |
### | |
# Caching. | |
# This actually *restores* a cache and schedules a cleanup action | |
# to save the cache. So it must come before the thing we want to use | |
# the cache. | |
### | |
- name: Get pip cache dir (default) | |
id: pip-cache-default | |
if: ${{ !startsWith(runner.os, 'Windows') }} | |
run: | | |
echo "dir=$(pip cache dir)" >>$GITHUB_OUTPUT | |
- name: Get pip cache dir (Windows) | |
id: pip-cache-windows | |
if: ${{ startsWith(runner.os, 'Windows') }} | |
run: | | |
echo "dir=$(pip cache dir)" >> $Env:GITHUB_OUTPUT | |
- name: pip cache (default) | |
uses: actions/cache@v4 | |
if: ${{ !startsWith(runner.os, 'Windows') }} | |
with: | |
path: ${{ steps.pip-cache-default.outputs.dir }} | |
key: ${{ runner.os }}-pip-${{ matrix.python-version }} | |
restore-keys: | | |
${{ runner.os }}-pip- | |
- name: pip cache (Windows) | |
uses: actions/cache@v4 | |
if: ${{ startsWith(runner.os, 'Windows') }} | |
with: | |
path: ${{ steps.pip-cache-windows.outputs.dir }} | |
key: ${{ runner.os }}-pip-${{ matrix.python-version }} | |
restore-keys: | | |
${{ runner.os }}-pip- | |
- name: Download zope.interface wheel | |
uses: actions/download-artifact@v4 | |
with: | |
name: zope.interface-${{ runner.os }}-${{ matrix.python-version }}.whl | |
path: dist/ | |
- name: Install zope.interface | |
run: | | |
pip install -U pip | |
pip install -U wheel | |
pip install -U `ls dist/zope.interface-*`[test] | |
- name: Lint | |
# We only need to do this on one version, and it should be Python 3, because | |
# pylint has stopped updating for Python 2. | |
# TODO: Pick a linter and configuration and make this step right. | |
run: | | |
pip install -U pylint | |
# python -m pylint --limit-inference-results=1 --rcfile=.pylintrc zope.interface -f parseable -r n | |
manylinux: | |
runs-on: ubuntu-latest | |
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name | |
# We use a regular Python matrix entry to share as much code as possible. | |
strategy: | |
matrix: | |
python-version: ["3.9"] | |
image: [manylinux2014_x86_64, manylinux2014_i686, manylinux2014_aarch64] | |
steps: | |
- name: checkout | |
uses: actions/checkout@v4 | |
- name: Set up Python ${{ matrix.python-version }} | |
uses: actions/setup-python@v5 | |
with: | |
python-version: ${{ matrix.python-version }} | |
### | |
# Caching. | |
# This actually *restores* a cache and schedules a cleanup action | |
# to save the cache. So it must come before the thing we want to use | |
# the cache. | |
### | |
- name: Get pip cache dir (default) | |
id: pip-cache-default | |
if: ${{ !startsWith(runner.os, 'Windows') }} | |
run: | | |
echo "dir=$(pip cache dir)" >>$GITHUB_OUTPUT | |
- name: Get pip cache dir (Windows) | |
id: pip-cache-windows | |
if: ${{ startsWith(runner.os, 'Windows') }} | |
run: | | |
echo "dir=$(pip cache dir)" >> $Env:GITHUB_OUTPUT | |
- name: pip cache (default) | |
uses: actions/cache@v4 | |
if: ${{ !startsWith(runner.os, 'Windows') }} | |
with: | |
path: ${{ steps.pip-cache-default.outputs.dir }} | |
key: ${{ runner.os }}-pip_manylinux-${{ matrix.image }}-${{ matrix.python-version }} | |
restore-keys: | | |
${{ runner.os }}-pip- | |
- name: pip cache (Windows) | |
uses: actions/cache@v4 | |
if: ${{ startsWith(runner.os, 'Windows') }} | |
with: | |
path: ${{ steps.pip-cache-windows.outputs.dir }} | |
key: ${{ runner.os }}-pip_manylinux-${{ matrix.image }}-${{ matrix.python-version }} | |
restore-keys: | | |
${{ runner.os }}-pip- | |
- name: Update pip | |
run: pip install -U pip | |
- name: Build zope.interface (x86_64) | |
if: matrix.image == 'manylinux2014_x86_64' | |
# An alternate way to do this is to run the container directly with a uses: | |
# and then the script runs inside it. That may work better with caching. | |
# See https://github.com/pyca/bcrypt/blob/f6b5ee2eda76d077c531362ac65e16f045cf1f29/.github/workflows/wheel-builder.yml | |
env: | |
DOCKER_IMAGE: quay.io/pypa/${{ matrix.image }} | |
run: | | |
bash .manylinux.sh | |
- name: Build zope.interface (i686) | |
if: matrix.image == 'manylinux2014_i686' | |
env: | |
DOCKER_IMAGE: quay.io/pypa/${{ matrix.image }} | |
PRE_CMD: linux32 | |
run: | | |
bash .manylinux.sh | |
- name: Build zope.interface (aarch64) | |
if: matrix.image == 'manylinux2014_aarch64' | |
env: | |
DOCKER_IMAGE: quay.io/pypa/${{ matrix.image }} | |
run: | | |
# First we must enable emulation | |
docker run --rm --privileged hypriot/qemu-register | |
bash .manylinux.sh | |
- name: Upload zope.interface wheels | |
uses: actions/upload-artifact@v4 | |
with: | |
path: wheelhouse/*whl | |
name: manylinux_${{ matrix.image }}_wheels.zip | |
- name: Restore pip cache permissions | |
run: sudo chown -R $(whoami) ${{ steps.pip-cache-default.outputs.dir }} | |
- name: Publish package to PyPI | |
uses: pypa/gh-action-pypi-publish@release/v1 | |
if: > | |
github.event_name == 'push' | |
&& startsWith(github.ref, 'refs/tags') | |
with: | |
user: __token__ | |
password: ${{ secrets.TWINE_PASSWORD }} | |
skip_existing: true | |
packages_dir: wheelhouse/ |