From cb6def05fdea2b2c40bcc154a159cfae0ed46b92 Mon Sep 17 00:00:00 2001 From: Jens Vagelpohl Date: Thu, 3 Nov 2022 16:23:33 +0100 Subject: - update with meta/config and add support for Python 3.9, 3.10 and 3.11 --- .github/workflows/tests.yml | 485 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 485 insertions(+) create mode 100644 .github/workflows/tests.yml (limited to '.github/workflows/tests.yml') diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..a62f6fb --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,485 @@ +# 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: + - "2.7" + - "3.5" + - "pypy-2.7" + - "pypy-3.7" + - "3.6" + - "3.7" + - "3.8" + - "3.9" + - "3.10" + - "3.11" + os: [ubuntu-20.04, macos-latest] + exclude: + - os: macos-latest + python-version: "pypy-2.7" + - os: macos-latest + python-version: "pypy-3.7" + - os: macos-latest + python-version: "3.5" + + steps: + - name: checkout + uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + 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 + id: pip-cache + run: | + echo "dir=$(pip cache dir)" >>$GITHUB_OUTPUT + + - name: pip cache + uses: actions/cache@v2 + with: + path: ${{ steps.pip-cache.outputs.dir }} + key: ${{ runner.os }}-pip-${{ matrix.python-version }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Install Build Dependencies (PyPy2) + if: > + startsWith(matrix.python-version, 'pypy-2.7') + run: | + pip install -U pip + pip install -U setuptools wheel twine "cffi != 1.15.1" + - name: Install Build Dependencies (other Python versions) + if: > + !startsWith(matrix.python-version, 'pypy-2.7') + run: | + pip install -U pip + pip install -U setuptools wheel twine cffi + + - name: Build zope.i18nmessageid (Python 3.10 on MacOS) + if: > + startsWith(runner.os, 'Mac') + && startsWith(matrix.python-version, '3.10') + env: + _PYTHON_HOST_PLATFORM: macosx-11-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 + # Also install it, so that we get dependencies in the (pip) cache. + pip install -U 'faulthandler; python_version == "2.7" and platform_python_implementation == "CPython"' + pip install .[test] + + - name: Build zope.i18nmessageid (all other versions) + if: > + !startsWith(runner.os, 'Mac') + || !startsWith(matrix.python-version, '3.10') + 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 + # Also install it, so that we get dependencies in the (pip) cache. + pip install -U 'faulthandler; python_version == "2.7" and platform_python_implementation == "CPython"' + pip install .[test] + + - name: Check zope.i18nmessageid build + run: | + ls -l dist + twine check dist/* + - name: Upload zope.i18nmessageid wheel + uses: actions/upload-artifact@v2 + with: + name: zope.i18nmessageid-${{ runner.os }}-${{ matrix.python-version }}.whl + path: dist/*whl + - name: Publish package to PyPI (mac) + # We cannot 'uses: pypa/gh-action-pypi-publish@v1.4.1' 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') + 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: + - "2.7" + - "3.5" + - "pypy-2.7" + - "pypy-3.7" + - "3.6" + - "3.7" + - "3.8" + - "3.9" + - "3.10" + - "3.11" + os: [ubuntu-20.04, macos-latest] + exclude: + - os: macos-latest + python-version: "pypy-2.7" + - os: macos-latest + python-version: "pypy-3.7" + - os: macos-latest + python-version: "3.5" + + steps: + - name: checkout + uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + 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 + id: pip-cache + run: | + echo "dir=$(pip cache dir)" >>$GITHUB_OUTPUT + + - name: pip cache + uses: actions/cache@v2 + with: + path: ${{ steps.pip-cache.outputs.dir }} + key: ${{ runner.os }}-pip-${{ matrix.python-version }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Download zope.i18nmessageid wheel + uses: actions/download-artifact@v2 + with: + name: zope.i18nmessageid-${{ runner.os }}-${{ matrix.python-version }}.whl + path: dist/ + - name: Install zope.i18nmessageid + run: | + pip install -U wheel setuptools + pip install -U coverage + pip install -U 'faulthandler; python_version == "2.7" and platform_python_implementation == "CPython"' + # 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.i18nmessageid-*whl -d src + pip install -U -e .[test] + - name: Run tests with C extensions + if: ${{ !startsWith(matrix.python-version, 'pypy') }} + run: | + python -m coverage run -p -m zope.testrunner --test-path=src --auto-color --auto-progress + - name: Run tests without C extensions + run: + # coverage makes PyPy run about 3x slower! + PURE_PYTHON=1 python -m coverage run -p -m zope.testrunner --test-path=src --auto-color --auto-progress + - name: Report Coverage + run: | + coverage combine + coverage report -i + - 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-20.04 + 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-20.04] + + steps: + - name: checkout + uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + 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 + id: pip-cache + run: | + echo "dir=$(pip cache dir)" >>$GITHUB_OUTPUT + + - name: pip cache + uses: actions/cache@v2 + with: + path: ${{ steps.pip-cache.outputs.dir }} + key: ${{ runner.os }}-pip-${{ matrix.python-version }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Download zope.i18nmessageid wheel + uses: actions/download-artifact@v2 + with: + name: zope.i18nmessageid-${{ runner.os }}-${{ matrix.python-version }}.whl + path: dist/ + - name: Install zope.i18nmessageid + run: | + pip install -U wheel + pip install -U coverage + pip install -U "`ls dist/zope.i18nmessageid-*.whl`[docs]" + - name: Build docs + env: + ZOPE_INTERFACE_STRICT_IRO: 1 + run: | + sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html + + lint: + needs: build-package + runs-on: ${{ matrix.os }} + strategy: + matrix: + python-version: ["3.9"] + os: [ubuntu-20.04] + + steps: + - name: checkout + uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + 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 + id: pip-cache + run: | + echo "dir=$(pip cache dir)" >>$GITHUB_OUTPUT + + - name: pip cache + uses: actions/cache@v2 + with: + path: ${{ steps.pip-cache.outputs.dir }} + key: ${{ runner.os }}-pip-${{ matrix.python-version }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Download zope.i18nmessageid wheel + uses: actions/download-artifact@v2 + with: + name: zope.i18nmessageid-${{ runner.os }}-${{ matrix.python-version }}.whl + path: dist/ + - name: Install zope.i18nmessageid + run: | + pip install -U pip + pip install -U wheel + pip install -U `ls dist/zope.i18nmessageid-*`[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.i18nmessageid -f parseable -r n + + manylinux: + runs-on: ubuntu-20.04 + 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: [manylinux2010_x86_64, manylinux2010_i686, manylinux2014_aarch64] + + steps: + - name: checkout + uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + 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 + id: pip-cache + run: | + echo "dir=$(pip cache dir)" >>$GITHUB_OUTPUT + + - name: pip cache + uses: actions/cache@v2 + with: + path: ${{ steps.pip-cache.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.i18nmessageid (x86_64) + if: matrix.image == 'manylinux2010_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 + # The 2010 image is the most recent spec that comes with Python 2.7, + # and only up through the tag 2021-02-06-3d322a5 + env: + DOCKER_IMAGE: quay.io/pypa/${{ matrix.image }} + run: | + bash .manylinux.sh + - name: Build zope.i18nmessageid (i686) + if: matrix.image == 'manylinux2010_i686' + env: + DOCKER_IMAGE: quay.io/pypa/${{ matrix.image }} + PRE_CMD: linux32 + run: | + bash .manylinux.sh + - name: Build zope.i18nmessageid (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.i18nmessageid wheels + uses: actions/upload-artifact@v2 + with: + path: wheelhouse/*whl + name: manylinux_${{ matrix.image }}_wheels.zip + - name: Restore pip cache permissions + run: sudo chown -R $(whoami) ${{ steps.pip-cache.outputs.dir }} + - name: Publish package to PyPI + uses: pypa/gh-action-pypi-publish@v1.4.1 + if: > + github.event_name == 'push' + && startsWith(github.ref, 'refs/tags') + with: + user: __token__ + password: ${{ secrets.TWINE_PASSWORD }} + skip_existing: true + packages_dir: wheelhouse/ -- cgit v1.2.1