summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Madden <jamadden@gmail.com>2021-02-26 07:41:55 -0600
committerJason Madden <jamadden@gmail.com>2021-02-26 08:43:43 -0600
commita99dc79884acac5e9e35de2fd222266365bd7c53 (patch)
tree31764afb7ef9b0a9dff096683a8d3bf93a1d75f0
parentbf0de08af2d53261d7eb0ce1e31f574f93524ef6 (diff)
downloadzope-interface-a99dc79884acac5e9e35de2fd222266365bd7c53.tar.gz
First pass at github actions.
Fixes #225. Someone will need to add a `TWINE_PASSWORD` GitHub repository secret that is a token for `zope.eggbuilder` to upload to zope.interface. Builds and uploads manylinux32/64/aarch64 wheels. Builds and uploads Mac wheels. Builds the docs. Runs tests with the C extension and without the C extension. Reports coverage to coveralls. Has the start of an environment to do linting. Removes .travis.yml
-rw-r--r--.coveragerc6
-rw-r--r--.github/workflows/tests.yml422
-rwxr-xr-x.manylinux-install.sh19
-rwxr-xr-x.manylinux.sh11
-rw-r--r--.travis.yml145
-rw-r--r--README.rst4
6 files changed, 459 insertions, 148 deletions
diff --git a/.coveragerc b/.coveragerc
index e8d7d25..b1c092e 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -1,6 +1,8 @@
[run]
branch = True
source = zope.interface
+# New in 5.0; required for the GHA coveralls submission.
+relative_files = True
[report]
show_missing = true
@@ -10,3 +12,7 @@ exclude_lines =
raise NotImplementedError
raise AssertionError
self\.fail
+
+# Local Variables:
+# mode: conf
+# End:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..1d70e3d
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,422 @@
+###
+# Initially copied from
+# https://github.com/actions/starter-workflows/blob/main/ci/python-package.yml
+# And later based on the version I (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
+on: [push, pull_request]
+# Limiting to particular branches might be helpful to conserve minutes.
+#on:
+ # push:
+ # branches: [ $default-branch ]
+ # pull_request:
+ # branches: [ $default-branch ]
+
+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: -Ofast -pipe
+ CXXFLAGS: -Ofast -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 divisin 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-zope_interface:
+ # Sigh. Note that the matrix must be kept in sync
+ # with `test`, and `docs` must use a subset.
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ python-version: [2.7, pypy-2.7, pypy-3.6, 3.5, 3.6, 3.7, 3.8, 3.9]
+ os: [ubuntu-20.04, macos-latest]
+ exclude:
+ - os: macos-latest
+ python-version: pypy-2.7
+ - os: macos-latest
+ python-version: pypy-3.6
+ - 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 "::set-output name=dir::$(pip cache dir)"
+
+ - 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
+ run: |
+ pip install -U pip
+ pip install -U setuptools wheel twine
+ pip install -U coveralls coverage
+
+ - name: Build zope.interface
+ 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 coverage
+ pip install -U 'faulthandler; python_version == "2.7" and platform_python_implementation == "CPython"'
+ pip install .[test]
+
+ - name: Check zope.interface build
+ run: |
+ ls -l dist
+ twine check dist/*
+ - name: Upload zope.interface wheel
+ uses: actions/upload-artifact@v2
+ with:
+ name: zope.interface-${{ 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')
+ env:
+ TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
+ run: |
+ twine upload --skip-existing dist/*
+
+ test:
+ needs: build-zope_interface
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ python-version: [2.7, pypy-2.7, pypy-3.6, 3.5, 3.6, 3.7, 3.8, 3.9]
+ os: [ubuntu-20.04, macos-latest]
+ exclude:
+ - os: macos-latest
+ python-version: pypy-2.7
+ - os: macos-latest
+ python-version: pypy-3.6
+ - 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 }}
+ - name: Get pip cache dir
+ id: pip-cache
+ run: |
+ echo "::set-output name=dir::$(pip cache dir)"
+
+ - 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.interface wheel
+ uses: actions/download-artifact@v2
+ 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 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.interface-*whl -d src
+ pip install -U -e .[test]
+ - name: Run tests and report coverage
+ # Once with C extensions, once without. Yes, this runs them
+ # twice on PyPy.
+ run: |
+ coverage run -p -m unittest discover -s src
+ PURE_PYTHON=1 coverage run -p -m unittest discover -s src
+ 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-zope_interface
+ 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 }}
+ - name: Get pip cache dir
+ id: pip-cache
+ run: |
+ echo "::set-output name=dir::$(pip cache dir)"
+
+ - 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.interface wheel
+ uses: actions/download-artifact@v2
+ 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 'faulthandler; python_version == "2.7" and platform_python_implementation == "CPython"'
+ pip install -U "`ls dist/zope.interface-*.whl`[docs]"
+ - name: Build docs
+ env:
+ ZOPE_INTERFACE_STRICT_IRO: 0
+ 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-zope_interface
+ 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 }}
+
+ - name: Get pip cache dir
+ id: pip-cache
+ run: |
+ echo "::set-output name=dir::$(pip cache dir)"
+
+ - 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.interface wheel
+ uses: actions/download-artifact@v2
+ 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-20.04
+ # 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 }}
+ - name: Get pip cache dir
+ id: pip-cache
+ run: |
+ echo "::set-output name=dir::$(pip cache dir)"
+
+ - 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.interface (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 last one that comes with Python 2.7.
+ env:
+ DOCKER_IMAGE: quay.io/pypa/${{ matrix.image }}
+ run: |
+ bash .manylinux.sh
+ - name: Build zope.interface (i686)
+ if: matrix.image == 'manylinux2010_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@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/
+
+# TODO:
+# * Use YAML syntax to share snippets, like the old .travis.yml did
+# Sadly, as of 2021-02-01, Github Actions does not support anchors at
+# all. Just having an anchor results in an error:
+#
+# The workflow is not valid. .github/workflows/tests.yml: Anchors
+# are not currently supported. Remove the anchor 'an-strategy'
+#
+# The alternative of using composite actions doesn't work either,
+# because composite actions are limited to running shell scripts.
+# Steps in them can't call other actions with `uses:`, and nor can
+# they be conditional with `if:`.
diff --git a/.manylinux-install.sh b/.manylinux-install.sh
index ea41c49..c403ed4 100755
--- a/.manylinux-install.sh
+++ b/.manylinux-install.sh
@@ -2,6 +2,25 @@
set -e -x
+# Running inside docker
+# Set a cache directory for pip. This was
+# mounted to be the same as it is outside docker so it
+# can be persisted.
+export XDG_CACHE_HOME="/cache"
+# XXX: This works for macOS, where everything bind-mounted
+# is seen as owned by root in the container. But when the host is Linux
+# the actual UIDs come through to the container, triggering
+# pip to disable the cache when it detects that the owner doesn't match.
+# The below is an attempt to fix that, taken frob bcrypt. It seems to work on
+# Github Actions.
+if [ -n "$GITHUB_ACTIONS" ]; then
+ echo Adjusting pip cache permissions
+ mkdir -p $XDG_CACHE_HOME/pip
+ chown -R $(whoami) $XDG_CACHE_HOME
+fi
+ls -ld /cache
+ls -ld /cache/pip
+
# Compile wheels
for PYBIN in /opt/python/*/bin; do
if [[ "${PYBIN}" == *"cp27"* ]] || \
diff --git a/.manylinux.sh b/.manylinux.sh
index 2fed778..520d68e 100755
--- a/.manylinux.sh
+++ b/.manylinux.sh
@@ -2,4 +2,13 @@
set -e -x
-docker run --rm -v "$(pwd)":/io $DOCKER_IMAGE $PRE_CMD /io/.manylinux-install.sh
+# Mount the current directory as /io
+# Mount the pip cache directory as /cache
+# `pip cache` requires pip 20.1
+echo Setting up caching
+python --version
+python -mpip --version
+LCACHE="$(dirname `python -mpip cache dir`)"
+echo Sharing pip cache at $LCACHE $(ls -ld $LCACHE)
+
+docker run --rm -e GITHUB_ACTIONS -v "$(pwd)":/io -v "$LCACHE:/cache" $DOCKER_IMAGE $PRE_CMD /io/.manylinux-install.sh
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 6d4701b..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,145 +0,0 @@
-language: python
-dist: focal
-env:
- global:
- ZOPE_INTERFACE_STRICT_IRO: 1
- TWINE_USERNAME: zope.wheelbuilder
- TWINE_PASSWORD:
- secure: "AyR5QxUuZKdmywiepdBG0r8hgFQfaEf2hTxOg/HiXisVNcs1sUPjephBP4MqQBbf1/qxLM95F6Mw3sKneO3gDDQSGCsmvY1MWlDc+6R5TgqVBuOoONji5zGQH7v9RR8IPOyple8BNlFePl1hQ8r0dOT1U6rDVh5FkNJgHYE9OJ4="
-
-python:
- - 2.7
- - 3.5
- - 3.6
- - 3.7
- - 3.8
- - 3.9
- - pypy2
- - pypy3
-
-jobs:
- include:
-
- - name: Documentation
- python: 3.6
- install:
- - pip install -U -e .[docs]
- script:
- - sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html
- - sphinx-build -b doctest -d docs/_build/doctrees docs docs/_build/doctest
- after_success:
- env: ZOPE_INTERFACE_STRICT_IRO=0
-
- - name: CPython No C Extension
- env: PURE_PYTHON=1
- python: 3.8
-
- # manylinux wheel builds
- - name: 64-bit manylinux wheels (all Pythons)
- services: docker
- env: DOCKER_IMAGE=quay.io/pypa/manylinux2010_x86_64
- install: docker pull $DOCKER_IMAGE
- script: bash .manylinux.sh
-
- - name: 32-bit manylinux wheels (all Pythons)
- services: docker
- env: DOCKER_IMAGE=quay.io/pypa/manylinux2010_i686 PRE_CMD=linux32
- install: docker pull $DOCKER_IMAGE
- script: bash .manylinux.sh
-
- - name: aarch64 wheels
- dist: bionic
- group: edge
- arch: arm64
- virt: lxd
- env: DOCKER_IMAGE=quay.io/pypa/manylinux2014_aarch64
- install: docker pull $DOCKER_IMAGE
- script: bash .manylinux.sh
-
- # It's important to use 'macpython' builds to get the least
- # restrictive wheel tag. It's also important to avoid
- # 'homebrew 3' because it floats instead of being a specific version.
- - name: Python 2.7 wheels for MacOS
- os: osx
- language: generic
- # We require at least 2.7.15 to upload wheels.
- # See https://github.com/zopefoundation/BTrees/issues/113
- env: TERRYFY_PYTHON='macpython 2.7.17'
- - name: Python 3.5 wheels for MacOS
- os: osx
- language: generic
- env: TERRYFY_PYTHON='macpython 3.5'
- - name: Python 3.6 wheels for MacOS
- os: osx
- language: generic
- # NB: 3.6.0 causes https://github.com/nedbat/coveragepy/issues/703
- # NB: 3.6.1 had that ABI regression (fixed in 3.6.2) and would be a bad
- # version to use
- env: TERRYFY_PYTHON='macpython 3.6.2'
- - name: Python 3.7 wheels for MacOS
- os: osx
- language: generic
- env: TERRYFY_PYTHON='macpython 3.7.0'
- - name: Python 3.8 wheels for MacOS
- os: osx
- language: generic
- env: TERRYFY_PYTHON='macpython 3.8.0'
- - name: Python 3.9 wheels for MacOS
- os: osx
- language: generic
- env: TERRYFY_PYTHON='macpython 3.9.0'
-
-before_install:
- - |
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
- git clone https://github.com/MacPython/terryfy
- source terryfy/travis_tools.sh
- get_python_environment $TERRYFY_PYTHON venv
- fi
-
-install:
- # virtualenv 20.0 together with terryfy macOS is broken, at least
- # with CPython 2.7.17 (https://github.com/pypa/virtualenv/issues/1555):
- # it doesn't install or activate the virtualenv correctly and PATH
- # isn't setup right. So try to use `python -m` to workaround that.
- - python -m pip install -U pip setuptools
- - python -m pip install -U coveralls coverage
- - python -m pip install -U -e ".[test]"
-
-script:
- - which python
- - python --version
- - python -m coverage run -m unittest discover -s src
- - python setup.py -q bdist_wheel
-
-after_success:
- - python -m coveralls
- - |
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
- # macpython 3.5 doesn't support recent TLS protocols which causes twine
- # upload to fail, so we use the system Python to run twine
- /usr/bin/python -m ensurepip --user
- /usr/bin/python -m pip install --user -U pip
- /usr/bin/python -m pip install --user -U -I twine
- /usr/bin/python -m twine check dist/*
- if [[ $TRAVIS_TAG ]]; then
- printf "Uploading tagged release %s\n" "$TRAVIS_TAG"
- /usr/bin/python -m twine upload --skip-existing dist/*
- fi
- fi
- - |
- if [[ -n "$DOCKER_IMAGE" ]]; then
- pip install twine
- twine check wheelhouse/*
- if [[ $TRAVIS_TAG ]]; then
- printf "Uploading tagged release %s\n" "$TRAVIS_TAG"
- twine upload --skip-existing wheelhouse/*
- fi
- fi
-
-notifications:
- email: false
-
-cache: pip
-before_cache:
- - rm -f $HOME/.cache/pip/log/debug.log
diff --git a/README.rst b/README.rst
index 3238c15..e8a18e9 100644
--- a/README.rst
+++ b/README.rst
@@ -10,8 +10,8 @@
:target: https://pypi.org/project/zope.interface/
:alt: Supported Python versions
-.. image:: https://travis-ci.com/zopefoundation/zope.interface.svg?branch=master
- :target: https://travis-ci.com/zopefoundation/zope.interface
+.. image:: https://github.com/zopefoundation/zope.interface/actions/workflows/tests.yml/badge.svg
+ :target: https://github.com/zopefoundation/zope.interface/actions/workflows/tests.yml
.. image:: https://readthedocs.org/projects/zopeinterface/badge/?version=latest
:target: https://zopeinterface.readthedocs.io/en/latest/