Repository: pypa/cibuildwheel

Issue:
Avoid recommending deprecated practice of calling setup.py directly
The [Delivering to PyPI](https://cibuildwheel.readthedocs.io/en/stable/deliver-to-pypi/#manual-method) docs and the [GitHub Actions](https://github.com/pypa/cibuildwheel/blob/main/examples/github-deploy.ym) and [Travis](https://github.com/pypa/cibuildwheel/blob/main/examples/travis-ci-test-and-deploy.yml) examples use direct invocations of setup.py, `python setup.py sdist`, and the latter even uses the truly archaic `python setup.py install`.

This will only work for legacy `setuptools`-based projects with a `setup.py`, and direct invocation of `setup.py` has long been discouraged, has been deprecated for some time, as of `setuptools` 58.3.0 formal `DeprecationWarnings` are now issued, and will eventually be removed completely. The canonical replacement for `python setup.py sdist` is `python -m build --sdist` (preceded by `python -m pip install --upgrade build`, in case it is not already installed). and for `python setup.py install`, it is of course `pip install .`.

See [here](https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html) for more info.

Discussion:

Patch:
diff --git a/cibuildwheel/resources/build-platforms.toml b/cibuildwheel/resources/build-platforms.toml
index 10ac3c7f..78efd3f8 100644
--- a/cibuildwheel/resources/build-platforms.toml
+++ b/cibuildwheel/resources/build-platforms.toml
@@ -11,6 +11,7 @@ python_configurations = [
   { identifier = "cp39-manylinux_i686", version = "3.9", path_str = "/opt/python/cp39-cp39" },
   { identifier = "cp310-manylinux_i686", version = "3.10", path_str = "/opt/python/cp310-cp310" },
   { identifier = "pp37-manylinux_x86_64", version = "3.7", path_str = "/opt/python/pp37-pypy37_pp73" },
+  { identifier = "pp38-manylinux_x86_64", version = "3.8", path_str = "/opt/python/pp38-pypy38_pp73" },
   { identifier = "cp36-manylinux_aarch64", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
   { identifier = "cp37-manylinux_aarch64", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
   { identifier = "cp38-manylinux_aarch64", version = "3.8", path_str = "/opt/python/cp38-cp38" },
@@ -27,7 +28,9 @@ python_configurations = [
   { identifier = "cp39-manylinux_s390x", version = "3.9", path_str = "/opt/python/cp39-cp39" },
   { identifier = "cp310-manylinux_s390x", version = "3.10", path_str = "/opt/python/cp310-cp310" },
   { identifier = "pp37-manylinux_aarch64", version = "3.7", path_str = "/opt/python/pp37-pypy37_pp73" },
+  { identifier = "pp38-manylinux_aarch64", version = "3.8", path_str = "/opt/python/pp38-pypy38_pp73" },
   { identifier = "pp37-manylinux_i686", version = "3.7", path_str = "/opt/python/pp37-pypy37_pp73" },
+  { identifier = "pp38-manylinux_i686", version = "3.8", path_str = "/opt/python/pp38-pypy38_pp73" },
   { identifier = "cp36-musllinux_x86_64", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
   { identifier = "cp37-musllinux_x86_64", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
   { identifier = "cp38-musllinux_x86_64", version = "3.8", path_str = "/opt/python/cp38-cp38" },
@@ -62,13 +65,14 @@ python_configurations = [
   { identifier = "cp38-macosx_x86_64", version = "3.8", url = "https://www.python.org/ftp/python/3.8.10/python-3.8.10-macosx10.9.pkg" },
   { identifier = "cp38-macosx_arm64", version = "3.8", url = "https://www.python.org/ftp/python/3.8.10/python-3.8.10-macosx10.9.pkg" },
   { identifier = "cp38-macosx_universal2", version = "3.8", url = "https://www.python.org/ftp/python/3.8.10/python-3.8.10-macosx10.9.pkg" },
-  { identifier = "cp39-macosx_x86_64", version = "3.9", url = "https://www.python.org/ftp/python/3.9.7/python-3.9.7-macos11.pkg" },
-  { identifier = "cp39-macosx_arm64", version = "3.9", url = "https://www.python.org/ftp/python/3.9.7/python-3.9.7-macos11.pkg" },
-  { identifier = "cp39-macosx_universal2", version = "3.9", url = "https://www.python.org/ftp/python/3.9.7/python-3.9.7-macos11.pkg" },
-  { identifier = "cp310-macosx_x86_64", version = "3.10", url = "https://www.python.org/ftp/python/3.10.0/python-3.10.0-macos11.pkg" },
-  { identifier = "cp310-macosx_arm64", version = "3.10", url = "https://www.python.org/ftp/python/3.10.0/python-3.10.0-macos11.pkg" },
-  { identifier = "cp310-macosx_universal2", version = "3.10", url = "https://www.python.org/ftp/python/3.10.0/python-3.10.0-macos11.pkg" },
-  { identifier = "pp37-macosx_x86_64", version = "3.7", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.5-osx64.tar.bz2" },
+  { identifier = "cp39-macosx_x86_64", version = "3.9", url = "https://www.python.org/ftp/python/3.9.8/python-3.9.8-macos11.pkg" },
+  { identifier = "cp39-macosx_arm64", version = "3.9", url = "https://www.python.org/ftp/python/3.9.8/python-3.9.8-macos11.pkg" },
+  { identifier = "cp39-macosx_universal2", version = "3.9", url = "https://www.python.org/ftp/python/3.9.8/python-3.9.8-macos11.pkg" },
+  { identifier = "cp310-macosx_x86_64", version = "3.10", url = "https://www.python.org/ftp/python/3.10.0/python-3.10.0post2-macos11.pkg" },
+  { identifier = "cp310-macosx_arm64", version = "3.10", url = "https://www.python.org/ftp/python/3.10.0/python-3.10.0post2-macos11.pkg" },
+  { identifier = "cp310-macosx_universal2", version = "3.10", url = "https://www.python.org/ftp/python/3.10.0/python-3.10.0post2-macos11.pkg" },
+  { identifier = "pp37-macosx_x86_64", version = "3.7", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.7-osx64.tar.bz2" },
+  { identifier = "pp38-macosx_x86_64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.7-osx64.tar.bz2" },
 ]
 
 [windows]
@@ -79,9 +83,10 @@ python_configurations = [
   { identifier = "cp37-win_amd64", version = "3.7.9", arch = "64" },
   { identifier = "cp38-win32", version = "3.8.10", arch = "32" },
   { identifier = "cp38-win_amd64", version = "3.8.10", arch = "64" },
-  { identifier = "cp39-win32", version = "3.9.7", arch = "32" },
-  { identifier = "cp39-win_amd64", version = "3.9.7", arch = "64" },
+  { identifier = "cp39-win32", version = "3.9.8", arch = "32" },
+  { identifier = "cp39-win_amd64", version = "3.9.8", arch = "64" },
   { identifier = "cp310-win32", version = "3.10.0", arch = "32" },
   { identifier = "cp310-win_amd64", version = "3.10.0", arch = "64" },
-  { identifier = "pp37-win_amd64", version = "3.7", arch = "64", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.5-win64.zip" },
+  { identifier = "pp37-win_amd64", version = "3.7", arch = "64", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.7-win64.zip" },
+  { identifier = "pp38-win_amd64", version = "3.8", arch = "64", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.7-win64.zip" },
 ]
diff --git a/cibuildwheel/resources/constraints-python36.txt b/cibuildwheel/resources/constraints-python36.txt
index 36380a9d..997c0348 100644
--- a/cibuildwheel/resources/constraints-python36.txt
+++ b/cibuildwheel/resources/constraints-python36.txt
@@ -4,19 +4,19 @@
 #
 #    bin/update_dependencies.py
 #
-backports.entry-points-selectable==1.1.0
+backports.entry-points-selectable==1.1.1
     # via virtualenv
 delocate==0.10.0
     # via -r cibuildwheel/resources/constraints.in
 distlib==0.3.3
     # via virtualenv
-filelock==3.3.0
+filelock==3.3.2
     # via virtualenv
-importlib-metadata==4.8.1
+importlib-metadata==4.8.2
     # via
     #   backports.entry-points-selectable
     #   virtualenv
-importlib-resources==5.2.2
+importlib-resources==5.4.0
     # via virtualenv
 platformdirs==2.4.0
     # via virtualenv
@@ -26,7 +26,7 @@ typing-extensions==3.10.0.2
     # via
     #   delocate
     #   importlib-metadata
-virtualenv==20.8.1
+virtualenv==20.10.0
     # via -r cibuildwheel/resources/constraints.in
 wheel==0.37.0
     # via
@@ -38,7 +38,7 @@ zipp==3.6.0
     #   importlib-resources
 
 # The following packages are considered to be unsafe in a requirements file:
-pip==21.2.4
+pip==21.3.1
     # via -r cibuildwheel/resources/constraints.in
-setuptools==58.2.0
+setuptools==58.5.3
     # via -r cibuildwheel/resources/constraints.in
diff --git a/cibuildwheel/resources/constraints-python37.txt b/cibuildwheel/resources/constraints-python37.txt
index 9dfe3a88..ef7f2d11 100644
--- a/cibuildwheel/resources/constraints-python37.txt
+++ b/cibuildwheel/resources/constraints-python37.txt
@@ -4,15 +4,15 @@
 #
 #    bin/update_dependencies.py
 #
-backports.entry-points-selectable==1.1.0
+backports.entry-points-selectable==1.1.1
     # via virtualenv
 delocate==0.10.0
     # via -r cibuildwheel/resources/constraints.in
 distlib==0.3.3
     # via virtualenv
-filelock==3.3.0
+filelock==3.3.2
     # via virtualenv
-importlib-metadata==4.8.1
+importlib-metadata==4.8.2
     # via
     #   backports.entry-points-selectable
     #   virtualenv
@@ -24,7 +24,7 @@ typing-extensions==3.10.0.2
     # via
     #   delocate
     #   importlib-metadata
-virtualenv==20.8.1
+virtualenv==20.10.0
     # via -r cibuildwheel/resources/constraints.in
 wheel==0.37.0
     # via
@@ -34,7 +34,7 @@ zipp==3.6.0
     # via importlib-metadata
 
 # The following packages are considered to be unsafe in a requirements file:
-pip==21.2.4
+pip==21.3.1
     # via -r cibuildwheel/resources/constraints.in
-setuptools==58.2.0
+setuptools==58.5.3
     # via -r cibuildwheel/resources/constraints.in
diff --git a/cibuildwheel/resources/constraints-python38.txt b/cibuildwheel/resources/constraints-python38.txt
index c3bd567c..1e964eb2 100644
--- a/cibuildwheel/resources/constraints-python38.txt
+++ b/cibuildwheel/resources/constraints-python38.txt
@@ -4,13 +4,13 @@
 #
 #    bin/update_dependencies.py
 #
-backports.entry-points-selectable==1.1.0
+backports.entry-points-selectable==1.1.1
     # via virtualenv
 delocate==0.10.0
     # via -r cibuildwheel/resources/constraints.in
 distlib==0.3.3
     # via virtualenv
-filelock==3.3.0
+filelock==3.3.2
     # via virtualenv
 platformdirs==2.4.0
     # via virtualenv
@@ -18,7 +18,7 @@ six==1.16.0
     # via virtualenv
 typing-extensions==3.10.0.2
     # via delocate
-virtualenv==20.8.1
+virtualenv==20.10.0
     # via -r cibuildwheel/resources/constraints.in
 wheel==0.37.0
     # via
@@ -26,7 +26,7 @@ wheel==0.37.0
     #   delocate
 
 # The following packages are considered to be unsafe in a requirements file:
-pip==21.2.4
+pip==21.3.1
     # via -r cibuildwheel/resources/constraints.in
-setuptools==58.2.0
+setuptools==58.5.3
     # via -r cibuildwheel/resources/constraints.in
diff --git a/cibuildwheel/resources/constraints-python39.txt b/cibuildwheel/resources/constraints-python39.txt
index d2824450..ae417444 100644
--- a/cibuildwheel/resources/constraints-python39.txt
+++ b/cibuildwheel/resources/constraints-python39.txt
@@ -4,13 +4,13 @@
 #
 #    bin/update_dependencies.py
 #
-backports.entry-points-selectable==1.1.0
+backports.entry-points-selectable==1.1.1
     # via virtualenv
 delocate==0.10.0
     # via -r cibuildwheel/resources/constraints.in
 distlib==0.3.3
     # via virtualenv
-filelock==3.3.0
+filelock==3.3.2
     # via virtualenv
 platformdirs==2.4.0
     # via virtualenv
@@ -18,7 +18,7 @@ six==1.16.0
     # via virtualenv
 typing-extensions==3.10.0.2
     # via delocate
-virtualenv==20.8.1
+virtualenv==20.10.0
     # via -r cibuildwheel/resources/constraints.in
 wheel==0.37.0
     # via
@@ -26,7 +26,7 @@ wheel==0.37.0
     #   delocate
 
 # The following packages are considered to be unsafe in a requirements file:
-pip==21.2.4
+pip==21.3.1
     # via -r cibuildwheel/resources/constraints.in
-setuptools==58.2.0
+setuptools==58.5.3
     # via -r cibuildwheel/resources/constraints.in
diff --git a/cibuildwheel/resources/constraints.txt b/cibuildwheel/resources/constraints.txt
index d2824450..ae417444 100644
--- a/cibuildwheel/resources/constraints.txt
+++ b/cibuildwheel/resources/constraints.txt
@@ -4,13 +4,13 @@
 #
 #    bin/update_dependencies.py
 #
-backports.entry-points-selectable==1.1.0
+backports.entry-points-selectable==1.1.1
     # via virtualenv
 delocate==0.10.0
     # via -r cibuildwheel/resources/constraints.in
 distlib==0.3.3
     # via virtualenv
-filelock==3.3.0
+filelock==3.3.2
     # via virtualenv
 platformdirs==2.4.0
     # via virtualenv
@@ -18,7 +18,7 @@ six==1.16.0
     # via virtualenv
 typing-extensions==3.10.0.2
     # via delocate
-virtualenv==20.8.1
+virtualenv==20.10.0
     # via -r cibuildwheel/resources/constraints.in
 wheel==0.37.0
     # via
@@ -26,7 +26,7 @@ wheel==0.37.0
     #   delocate
 
 # The following packages are considered to be unsafe in a requirements file:
-pip==21.2.4
+pip==21.3.1
     # via -r cibuildwheel/resources/constraints.in
-setuptools==58.2.0
+setuptools==58.5.3
     # via -r cibuildwheel/resources/constraints.in
diff --git a/cibuildwheel/resources/pinned_docker_images.cfg b/cibuildwheel/resources/pinned_docker_images.cfg
index b889af8d..e8cf043f 100644
--- a/cibuildwheel/resources/pinned_docker_images.cfg
+++ b/cibuildwheel/resources/pinned_docker_images.cfg
@@ -1,43 +1,43 @@
 [x86_64]
-manylinux1 = quay.io/pypa/manylinux1_x86_64:2021-10-10-fee0ae1
-manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2021-10-10-790306f
-manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2021-10-10-790306f
-manylinux_2_24 = quay.io/pypa/manylinux_2_24_x86_64:2021-10-10-790306f
-musllinux_1_1 = quay.io/pypa/musllinux_1_1_x86_64:2021-10-10-790306f
+manylinux1 = quay.io/pypa/manylinux1_x86_64:2021-11-07-f38ff36
+manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2021-11-07-28723f3
+manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2021-11-07-28723f3
+manylinux_2_24 = quay.io/pypa/manylinux_2_24_x86_64:2021-11-07-28723f3
+musllinux_1_1 = quay.io/pypa/musllinux_1_1_x86_64:2021-11-07-28723f3
 
 [i686]
-manylinux1 = quay.io/pypa/manylinux1_i686:2021-10-10-fee0ae1
-manylinux2010 = quay.io/pypa/manylinux2010_i686:2021-10-10-790306f
-manylinux2014 = quay.io/pypa/manylinux2014_i686:2021-10-10-790306f
-manylinux_2_24 = quay.io/pypa/manylinux_2_24_i686:2021-10-10-790306f
-musllinux_1_1 = quay.io/pypa/musllinux_1_1_i686:2021-10-10-790306f
+manylinux1 = quay.io/pypa/manylinux1_i686:2021-11-07-f38ff36
+manylinux2010 = quay.io/pypa/manylinux2010_i686:2021-11-07-28723f3
+manylinux2014 = quay.io/pypa/manylinux2014_i686:2021-11-07-28723f3
+manylinux_2_24 = quay.io/pypa/manylinux_2_24_i686:2021-11-07-28723f3
+musllinux_1_1 = quay.io/pypa/musllinux_1_1_i686:2021-11-07-28723f3
 
 [pypy_x86_64]
-manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2021-10-10-790306f
-manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2021-10-10-790306f
-manylinux_2_24 = quay.io/pypa/manylinux_2_24_x86_64:2021-10-10-790306f
+manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2021-11-07-28723f3
+manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2021-11-07-28723f3
+manylinux_2_24 = quay.io/pypa/manylinux_2_24_x86_64:2021-11-07-28723f3
 
 [pypy_i686]
-manylinux2010 = quay.io/pypa/manylinux2010_i686:2021-10-10-790306f
-manylinux2014 = quay.io/pypa/manylinux2014_i686:2021-10-10-790306f
-manylinux_2_24 = quay.io/pypa/manylinux_2_24_i686:2021-10-10-790306f
+manylinux2010 = quay.io/pypa/manylinux2010_i686:2021-11-07-28723f3
+manylinux2014 = quay.io/pypa/manylinux2014_i686:2021-11-07-28723f3
+manylinux_2_24 = quay.io/pypa/manylinux_2_24_i686:2021-11-07-28723f3
 
 [aarch64]
-manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2021-10-10-790306f
-manylinux_2_24 = quay.io/pypa/manylinux_2_24_aarch64:2021-10-10-790306f
-musllinux_1_1 = quay.io/pypa/musllinux_1_1_aarch64:2021-10-10-790306f
+manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2021-11-07-28723f3
+manylinux_2_24 = quay.io/pypa/manylinux_2_24_aarch64:2021-11-07-28723f3
+musllinux_1_1 = quay.io/pypa/musllinux_1_1_aarch64:2021-11-07-28723f3
 
 [ppc64le]
-manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2021-10-10-790306f
-manylinux_2_24 = quay.io/pypa/manylinux_2_24_ppc64le:2021-10-10-790306f
-musllinux_1_1 = quay.io/pypa/musllinux_1_1_ppc64le:2021-10-10-790306f
+manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2021-11-07-28723f3
+manylinux_2_24 = quay.io/pypa/manylinux_2_24_ppc64le:2021-11-07-28723f3
+musllinux_1_1 = quay.io/pypa/musllinux_1_1_ppc64le:2021-11-07-28723f3
 
 [s390x]
-manylinux2014 = quay.io/pypa/manylinux2014_s390x:2021-10-10-790306f
-manylinux_2_24 = quay.io/pypa/manylinux_2_24_s390x:2021-10-10-790306f
-musllinux_1_1 = quay.io/pypa/musllinux_1_1_s390x:2021-10-10-790306f
+manylinux2014 = quay.io/pypa/manylinux2014_s390x:2021-11-07-28723f3
+manylinux_2_24 = quay.io/pypa/manylinux_2_24_s390x:2021-11-07-28723f3
+musllinux_1_1 = quay.io/pypa/musllinux_1_1_s390x:2021-11-07-28723f3
 
 [pypy_aarch64]
-manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2021-10-10-790306f
-manylinux_2_24 = quay.io/pypa/manylinux_2_24_aarch64:2021-10-10-790306f
+manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2021-11-07-28723f3
+manylinux_2_24 = quay.io/pypa/manylinux_2_24_aarch64:2021-11-07-28723f3
 
diff --git a/cibuildwheel/windows.py b/cibuildwheel/windows.py
index bd5ad085..0a429c6d 100644
--- a/cibuildwheel/windows.py
+++ b/cibuildwheel/windows.py
@@ -112,7 +112,6 @@ def install_pypy(version: str, arch: str, url: str) -> Path:
         download(url, pypy_zip)
         # Extract to the parent directory because the zip file still contains a directory
         extract_zip(pypy_zip, installation_path.parent)
-        (installation_path / "python.exe").symlink_to(installation_path / "pypy3.exe")
     return installation_path
 
 
diff --git a/docs/deliver-to-pypi.md b/docs/deliver-to-pypi.md
index 3d794f23..610fe6e5 100644
--- a/docs/deliver-to-pypi.md
+++ b/docs/deliver-to-pypi.md
@@ -4,15 +4,16 @@
 
 After you've built your wheels, you'll probably want to deliver them to PyPI.
 
-### Manual method
+## Manual method
 
-On your development machine, do the following...
+On your development machine, install [pipx](https://pypa.github.io/pipx/) and do the following:
 
 ```bash
+# Either download the SDist from your CI, or make it:
 # Clear out your 'dist' folder.
 rm -rf dist
 # Make a source distribution
-python setup.py sdist
+pipx run build --sdist
 
 # 🏃🏻
 # Go and download your wheel files from wherever you put them. e.g. your CI
@@ -20,17 +21,77 @@ # provider can be configured to store them for you. Put them all into the
 # 'dist' folder.
 
 # Upload using 'twine' (you may need to 'pip install twine')
-twine upload dist/*
+pipx run twine upload dist/*
 ```
 
-### Semi-automatic method using wheelhouse-uploader
+## Automatic method
 
-Obviously, manual steps are for chumps, so we can automate this a little by using [wheelhouse-uploader](https://github.com/ogrisel/wheelhouse-uploader).
+If you don't need much control over the release of a package, you can set up
+cibuildwheel to deliver the wheels straight to PyPI. You just need to bump the
+version and tag it.
 
-> Quick note from me - using S3 as a storage didn't work due to a [bug](https://issues.apache.org/jira/browse/LIBCLOUD-792) in libcloud. Feel free to use my fork of that package that fixes the bug `pip install https://github.com/joerick/libcloud/archive/v1.5.0-s3fix.zip`
+### Generic instructions
 
-### Automatic method
+Make your SDist with the [build](https://github.com/pypa/build) tool, and your wheels with cibuildwheel. If you can make the files available as
+downloadable artifacts, this make testing before releases easier (depending on your CI provider's options). The "publish" job/step should collect the
+files, and then run `twine upload <paths>` (possibly via [pipx](https://github.com/pypa/pipx)); this should only happen on tags or "releases".
 
-If you don't need much control over the release of a package, you can set up cibuildwheel to deliver the wheels straight to PyPI. This doesn't require anycloud storage to work - you just need to bump the version and tag it.
+### GitHub Actions
 
-See [`examples/travis-ci-deploy.yml`](https://github.com/pypa/cibuildwheel/blob/main/examples/travis-ci-deploy.yml) and [`examples/github-deploy.yml`](https://github.com/pypa/cibuildwheel/blob/main/examples/github-deploy.yml) for example configurations that automatically upload wheels to PyPI.
+GitHub actions has pipx in all the runners as a supported package manager, as
+well as several useful actions. Alongside your existing job(s) that runs cibuildwheel to make wheels, you will probably want to build an SDist:
+
+```yaml
+  make_sdist:
+    name: Make SDist
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v2
+      with:
+        fetch-depth: 0  # Optional, use if you use setuptools_scm
+        submodules: true  # Optional, use if you have submodules
+
+    - name: Build SDist
+      run: pipx run build --sdist
+
+    - uses: actions/upload-artifact@v2
+      with:
+        path: dist/*.tar.gz
+```
+
+Then, you need to publish the artifacts that the previous jobs have built. This final job should run only on release or tag, depending on your preference. It gathers the artifacts from the sdist and wheel jobs and uploads them to PyPI.
+
+This requires a [PyPI upload token](https://pypi.org/manage/account/token/), stored in your [GitHub repo's secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository) as `pypi_password`.
+
+```yaml
+  upload_all:
+    needs: [build_wheels, make_sdist]
+    runs-on: ubuntu-latest
+    if: github.event_name == 'release' && github.event.action == 'published'
+    steps:
+    - uses: actions/download-artifact@v2
+      with:
+        name: artifact
+        path: dist
+
+    - uses: pypa/gh-action-pypi-publish@v1.4.2
+      with:
+        user: __token__
+        password: ${{ secrets.pypi_password }}
+```
+
+You should use dependabot to keep the publish action up to date. In the above
+example, the same name (the default, "artifact" is used for all upload-artifact
+runs, so we can just download all of the in one step into a common directory.
+
+See
+[`examples/github-deploy.yml`](https://github.com/pypa/cibuildwheel/blob/main/examples/github-deploy.yml)
+for an example configuration that automatically upload wheels to PyPI. Also see
+[scikit-hep.org/developer/gha_wheels](https://scikit-hep.org/developer/gha_wheels)
+for a complete guide.
+
+### TravisCI
+
+See
+[`examples/travis-ci-deploy.yml`](https://github.com/pypa/cibuildwheel/blob/main/examples/travis-ci-deploy.yml)
+for an example configuration.
diff --git a/docs/options.md b/docs/options.md
index aa625133..3b9aaeb3 100644
--- a/docs/options.md
+++ b/docs/options.md
@@ -208,7 +208,8 @@ ### `CIBW_BUILD`, `CIBW_SKIP` {: #build-skip}
 | Python 3.8   | cp38-macosx_x86_64<br/>cp38-macosx_universal2<br/>cp38-macosx_arm64    | cp38-win_amd64<br/>cp38-win32    | cp38-manylinux_x86_64<br/>cp38-manylinux_i686<br/>cp38-musllinux_x86_64<br/>cp38-musllinux_i686     | cp38-manylinux_aarch64<br/>cp38-manylinux_ppc64le<br/>cp38-manylinux_s390x<br/>cp38-musllinux_aarch64<br/>cp38-musllinux_ppc64le<br/>cp38-musllinux_s390x       |
 | Python 3.9   | cp39-macosx_x86_64<br/>cp39-macosx_universal2<br/>cp39-macosx_arm64    | cp39-win_amd64<br/>cp39-win32    | cp39-manylinux_x86_64<br/>cp39-manylinux_i686<br/>cp39-musllinux_x86_64<br/>cp39-musllinux_i686     | cp39-manylinux_aarch64<br/>cp39-manylinux_ppc64le<br/>cp39-manylinux_s390x<br/>cp39-musllinux_aarch64<br/>cp39-musllinux_ppc64le<br/>cp39-musllinux_s390x       |
 | Python 3.10  | cp310-macosx_x86_64<br/>cp310-macosx_universal2<br/>cp310-macosx_arm64 | cp310-win_amd64<br/>cp310-win32  | cp310-manylinux_x86_64<br/>cp310-manylinux_i686<br/>cp310-musllinux_x86_64<br/>cp310-musllinux_i686 | cp310-manylinux_aarch64<br/>cp310-manylinux_ppc64le<br/>cp310-manylinux_s390x<br/>cp310-musllinux_aarch64<br/>cp310-musllinux_ppc64le<br/>cp310-musllinux_s390x |
-| PyPy3.7 v7.3 | pp37-macosx_x86_64                                                     | pp37-win_amd64                   | pp37-manylinux_x86_64                                                                               |                                                                                                                                                                 |
+| PyPy3.7 v7.3 | pp37-macosx_x86_64                                                     | pp37-win_amd64                   | pp37-manylinux_x86_64<br/>pp37-manylinux_i686                                                       | pp37-manylinux_aarch64                                                                                                                                          |
+| PyPy3.8 v7.3 | pp38-macosx_x86_64                                                     | pp38-win_amd64                   | pp38-manylinux_x86_64<br/>pp38-manylinux_i686                                                       | pp38-manylinux_aarch64                                                                                                                                          |
 
 The list of supported and currently selected build identifiers can also be retrieved by passing the `--print-build-identifiers` flag to cibuildwheel.
 The format is `python_tag-platform_tag`, with tags similar to those in [PEP 425](https://www.python.org/dev/peps/pep-0425/#details).
diff --git a/docs/working-examples.md b/docs/working-examples.md
index 5301bb80..5a355bac 100644
--- a/docs/working-examples.md
+++ b/docs/working-examples.md
@@ -30,8 +30,8 @@
 | [PyOxidizer][]                    | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A modern Python application packaging and distribution tool |
 | [pyzmq][]                         | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python bindings for zeromq, the networking library. Uses Cython and CFFI.  |
 | [OpenSpiel][]                     | ![github icon][] | ![apple icon][] ![linux icon][] | OpenSpiel is a collection of environments and algorithms for research in general reinforcement learning and search/planning in games. |
-| [vispy][]                         | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Main repository for Vispy |
 | [River][]                         | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | 🌊 Online machine learning in Python |
+| [vispy][]                         | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Main repository for Vispy |
 | [aiortc][]                        | ![github icon][] | ![apple icon][] ![linux icon][] | WebRTC and ORTC implementation for Python using asyncio. |
 | [Confluent client for Kafka][]    | ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | setup in `tools/wheels/build-wheels.bat` |
 | [tinyobjloader][]                 | ![azurepipelines icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Tiny but powerful single file wavefront obj loader |
@@ -51,8 +51,8 @@
 | [aioquic][]                       | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | QUIC and HTTP/3 implementation in Python |
 | [google neuroglancer][]           | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | WebGL-based viewer for volumetric data |
 | [DeepForest][]                    | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | An Efficient, Scalable and Optimized Python Framework for Deep Forest (2021.2.1) |
-| [Parselmouth][]                   | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python interface to the Praat software package, using pybind11, C++17 and CMake, with the core Praat static library built only once and shared between wheels. |
 | [AutoPy][]                        | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. |
+| [Parselmouth][]                   | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python interface to the Praat software package, using pybind11, C++17 and CMake, with the core Praat static library built only once and shared between wheels. |
 | [H3-py][]                         | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Python bindings for H3, a hierarchical hexagonal geospatial indexing system |
 | [python-rapidjson][]              | ![travisci icon][] ![gitlab icon][] ![appveyor icon][] | ![windows icon][] ![linux icon][] | Python wrapper around rapidjson |
 | [markupsafe][]                    | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Safely add untrusted strings to HTML/XML markup. |
@@ -70,7 +70,7 @@
 | [CTranslate2][]                   | ![github icon][] | ![apple icon][] ![linux icon][] | Includes libraries from the [Intel oneAPI toolkit](https://software.intel.com/content/www/us/en/develop/tools/oneapi/base-toolkit.html). The Linux wheels also include CUDA libraries for GPU execution. |
 | [iminuit][]                       | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Jupyter-friendly Python interface for C++ MINUIT2 |
 | [jq.py][]                         | ![travisci icon][] | ![apple icon][] ![linux icon][] | Python bindings for jq |
-| [Tokenizer][]                     | ![github icon][] ![travisci icon][] | ![apple icon][] ![linux icon][] | Fast and customizable text tokenization library with BPE and SentencePiece support |
+| [Tokenizer][]                     | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast and customizable text tokenization library with BPE and SentencePiece support |
 | [PyGLM][]                         | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Fast OpenGL Mathematics (GLM) for Python |
 | [bx-python][]                     | ![travisci icon][] | ![apple icon][] ![linux icon][] | A library that includes Cython extensions. |
 | [boost-histogram][]               | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Supports full range of wheels, including PyPy and alternate archs. |
@@ -115,8 +115,8 @@
 [PyOxidizer]: https://github.com/indygreg/PyOxidizer
 [pyzmq]: https://github.com/zeromq/pyzmq
 [OpenSpiel]: https://github.com/deepmind/open_spiel
-[vispy]: https://github.com/vispy/vispy
 [River]: https://github.com/online-ml/river
+[vispy]: https://github.com/vispy/vispy
 [aiortc]: https://github.com/aiortc/aiortc
 [Confluent client for Kafka]: https://github.com/confluentinc/confluent-kafka-python
 [tinyobjloader]: https://github.com/tinyobjloader/tinyobjloader
@@ -136,8 +136,8 @@
 [aioquic]: https://github.com/aiortc/aioquic
 [google neuroglancer]: https://github.com/google/neuroglancer
 [DeepForest]: https://github.com/LAMDA-NJU/Deep-Forest
-[Parselmouth]: https://github.com/YannickJadoul/Parselmouth
 [AutoPy]: https://github.com/autopilot-rs/autopy
+[Parselmouth]: https://github.com/YannickJadoul/Parselmouth
 [H3-py]: https://github.com/uber/h3-py
 [python-rapidjson]: https://github.com/python-rapidjson/python-rapidjson
 [markupsafe]: https://github.com/pallets/markupsafe
@@ -188,90 +188,90 @@
 [apple icon]: data/readme_icons/apple.svg
 [linux icon]: data/readme_icons/linux.svg
 
-<!-- scikit-learn: 47839, last pushed 0 days ago -->
-<!-- Tornado: 20257, last pushed 2 days ago -->
-<!-- Matplotlib: 14472, last pushed 0 days ago -->
-<!-- pytorch-fairseq: 14335, last pushed 1 days ago -->
-<!-- MyPy: 11712, last pushed 0 days ago -->
-<!-- uvloop: 8150, last pushed 2 days ago -->
-<!-- pydantic: 7969, last pushed 0 days ago -->
-<!-- psutil: 7796, last pushed 1 days ago -->
-<!-- vaex: 6682, last pushed 0 days ago -->
-<!-- Google Benchmark: 5856, last pushed 0 days ago -->
-<!-- asyncpg: 5164, last pushed 45 days ago -->
-<!-- Apache Beam: 5059, last pushed 0 days ago -->
-<!-- scikit-image: 4599, last pushed 0 days ago -->
-<!-- twisted-iocpsupport: 4415, last pushed 4 days ago -->
-<!-- cmake: 4254, last pushed 0 days ago -->
-<!-- duckdb: 3800, last pushed 0 days ago -->
-<!-- websockets: 3657, last pushed 8 days ago -->
-<!-- cvxpy: 3577, last pushed 0 days ago -->
-<!-- Triton: 3335, last pushed 0 days ago -->
-<!-- PyOxidizer: 3250, last pushed 0 days ago -->
-<!-- pyzmq: 2945, last pushed 0 days ago -->
-<!-- OpenSpiel: 2926, last pushed 1 days ago -->
-<!-- vispy: 2755, last pushed 2 days ago -->
-<!-- River: 2737, last pushed 6 days ago -->
-<!-- aiortc: 2637, last pushed 30 days ago -->
-<!-- Confluent client for Kafka: 2527, last pushed 1 days ago -->
-<!-- tinyobjloader: 2319, last pushed 27 days ago -->
-<!-- coverage.py: 1809, last pushed 0 days ago -->
-<!-- PyCryptodome: 1765, last pushed 5 days ago -->
-<!-- Dependency Injector: 1676, last pushed 4 days ago -->
-<!-- numexpr: 1670, last pushed 8 days ago -->
-<!-- PyYAML: 1649, last pushed 7 days ago -->
-<!-- h5py: 1607, last pushed 0 days ago -->
-<!-- PyAV: 1381, last pushed 40 days ago -->
-<!-- OpenColorIO: 1177, last pushed 0 days ago -->
-<!-- PyTables: 1068, last pushed 40 days ago -->
-<!-- Line Profiler: 940, last pushed 7 days ago -->
+<!-- scikit-learn: 47885, last pushed 0 days ago -->
+<!-- Tornado: 20263, last pushed 6 days ago -->
+<!-- Matplotlib: 14498, last pushed 0 days ago -->
+<!-- pytorch-fairseq: 14377, last pushed 0 days ago -->
+<!-- MyPy: 11768, last pushed 0 days ago -->
+<!-- uvloop: 8165, last pushed 6 days ago -->
+<!-- pydantic: 7995, last pushed 0 days ago -->
+<!-- psutil: 7806, last pushed 5 days ago -->
+<!-- vaex: 6691, last pushed 0 days ago -->
+<!-- Google Benchmark: 5867, last pushed 1 days ago -->
+<!-- asyncpg: 5169, last pushed 1 days ago -->
+<!-- Apache Beam: 5065, last pushed 0 days ago -->
+<!-- scikit-image: 4612, last pushed 0 days ago -->
+<!-- twisted-iocpsupport: 4417, last pushed 1 days ago -->
+<!-- cmake: 4256, last pushed 0 days ago -->
+<!-- duckdb: 3820, last pushed 0 days ago -->
+<!-- websockets: 3664, last pushed 3 days ago -->
+<!-- cvxpy: 3586, last pushed 0 days ago -->
+<!-- Triton: 3342, last pushed 0 days ago -->
+<!-- PyOxidizer: 3254, last pushed 4 days ago -->
+<!-- pyzmq: 2947, last pushed 1 days ago -->
+<!-- OpenSpiel: 2938, last pushed 1 days ago -->
+<!-- River: 2794, last pushed 0 days ago -->
+<!-- vispy: 2755, last pushed 0 days ago -->
+<!-- aiortc: 2644, last pushed 3 days ago -->
+<!-- Confluent client for Kafka: 2532, last pushed 5 days ago -->
+<!-- tinyobjloader: 2323, last pushed 31 days ago -->
+<!-- coverage.py: 1815, last pushed 0 days ago -->
+<!-- PyCryptodome: 1770, last pushed 1 days ago -->
+<!-- Dependency Injector: 1686, last pushed 1 days ago -->
+<!-- numexpr: 1673, last pushed 0 days ago -->
+<!-- PyYAML: 1653, last pushed 11 days ago -->
+<!-- h5py: 1608, last pushed 1 days ago -->
+<!-- PyAV: 1383, last pushed 44 days ago -->
+<!-- OpenColorIO: 1178, last pushed 0 days ago -->
+<!-- PyTables: 1075, last pushed 44 days ago -->
+<!-- Line Profiler: 946, last pushed 11 days ago -->
 <!-- OpenTimelineIO: 927, last pushed 0 days ago -->
-<!-- ruptures: 838, last pushed 14 days ago -->
-<!-- pikepdf: 782, last pushed 4 days ago -->
-<!-- aioquic: 761, last pushed 3 days ago -->
-<!-- google neuroglancer: 696, last pushed 0 days ago -->
-<!-- DeepForest: 669, last pushed 105 days ago -->
-<!-- Parselmouth: 584, last pushed 32 days ago -->
-<!-- AutoPy: 582, last pushed 141 days ago -->
-<!-- H3-py: 441, last pushed 3 days ago -->
-<!-- python-rapidjson: 432, last pushed 20 days ago -->
-<!-- markupsafe: 430, last pushed 0 days ago -->
-<!-- Rtree: 425, last pushed 30 days ago -->
-<!-- python-snappy: 411, last pushed 2 days ago -->
-<!-- pybind11 cmake_example: 323, last pushed 10 days ago -->
-<!-- KDEpy: 305, last pushed 155 days ago -->
-<!-- tgcalls: 285, last pushed 46 days ago -->
+<!-- ruptures: 842, last pushed 18 days ago -->
+<!-- pikepdf: 787, last pushed 0 days ago -->
+<!-- aioquic: 764, last pushed 7 days ago -->
+<!-- google neuroglancer: 697, last pushed 0 days ago -->
+<!-- DeepForest: 673, last pushed 109 days ago -->
+<!-- AutoPy: 585, last pushed 145 days ago -->
+<!-- Parselmouth: 584, last pushed 36 days ago -->
+<!-- H3-py: 442, last pushed 7 days ago -->
+<!-- python-rapidjson: 434, last pushed 24 days ago -->
+<!-- markupsafe: 433, last pushed 4 days ago -->
+<!-- Rtree: 428, last pushed 34 days ago -->
+<!-- python-snappy: 411, last pushed 6 days ago -->
+<!-- pybind11 cmake_example: 324, last pushed 14 days ago -->
+<!-- KDEpy: 307, last pushed 159 days ago -->
+<!-- tgcalls: 287, last pushed 50 days ago -->
 <!-- dd-trace-py: 281, last pushed 0 days ago -->
-<!-- pybind11 python_example: 277, last pushed 9 days ago -->
-<!-- cyvcf2: 275, last pushed 10 days ago -->
-<!-- sourmash: 262, last pushed 4 days ago -->
-<!-- time-machine: 217, last pushed 4 days ago -->
-<!-- matrixprofile: 205, last pushed 132 days ago -->
-<!-- CTranslate2: 197, last pushed 0 days ago -->
-<!-- iminuit: 187, last pushed 21 days ago -->
-<!-- jq.py: 181, last pushed 95 days ago -->
-<!-- Tokenizer: 158, last pushed 28 days ago -->
-<!-- PyGLM: 120, last pushed 0 days ago -->
-<!-- bx-python: 107, last pushed 7 days ago -->
-<!-- boost-histogram: 99, last pushed 4 days ago -->
-<!-- iDynTree: 90, last pushed 3 days ago -->
-<!-- TgCrypto: 76, last pushed 25 days ago -->
-<!-- pybase64: 74, last pushed 0 days ago -->
-<!-- etebase-py: 52, last pushed 305 days ago -->
-<!-- fathon: 40, last pushed 11 days ago -->
-<!-- pyjet: 31, last pushed 9 days ago -->
-<!-- numpythia: 31, last pushed 9 days ago -->
-<!-- Imagecodecs (fork): 25, last pushed 24 days ago -->
-<!-- polaroid: 25, last pushed 34 days ago -->
-<!-- ninja: 20, last pushed 25 days ago -->
-<!-- clang-format: 19, last pushed 22 days ago -->
-<!-- pybind11 scikit_build_example: 18, last pushed 9 days ago -->
-<!-- GSD: 18, last pushed 1 days ago -->
-<!-- pyinstrument_cext: 10, last pushed 28 days ago -->
-<!-- xmlstarlet: 7, last pushed 18 days ago -->
-<!-- CorrectionLib: 7, last pushed 0 days ago -->
-<!-- SiPM: 4, last pushed 6 days ago -->
-<!-- pillow-heif: 4, last pushed 0 days ago -->
+<!-- pybind11 python_example: 279, last pushed 13 days ago -->
+<!-- cyvcf2: 275, last pushed 14 days ago -->
+<!-- sourmash: 262, last pushed 8 days ago -->
+<!-- time-machine: 218, last pushed 1 days ago -->
+<!-- matrixprofile: 208, last pushed 136 days ago -->
+<!-- CTranslate2: 200, last pushed 0 days ago -->
+<!-- iminuit: 187, last pushed 25 days ago -->
+<!-- jq.py: 181, last pushed 99 days ago -->
+<!-- Tokenizer: 159, last pushed 32 days ago -->
+<!-- PyGLM: 120, last pushed 4 days ago -->
+<!-- bx-python: 107, last pushed 11 days ago -->
+<!-- boost-histogram: 99, last pushed 1 days ago -->
+<!-- iDynTree: 90, last pushed 0 days ago -->
+<!-- TgCrypto: 78, last pushed 29 days ago -->
+<!-- pybase64: 75, last pushed 1 days ago -->
+<!-- etebase-py: 52, last pushed 309 days ago -->
+<!-- fathon: 41, last pushed 1 days ago -->
+<!-- pyjet: 31, last pushed 13 days ago -->
+<!-- numpythia: 31, last pushed 13 days ago -->
+<!-- Imagecodecs (fork): 26, last pushed 28 days ago -->
+<!-- polaroid: 25, last pushed 38 days ago -->
+<!-- ninja: 20, last pushed 1 days ago -->
+<!-- clang-format: 19, last pushed 26 days ago -->
+<!-- pybind11 scikit_build_example: 18, last pushed 13 days ago -->
+<!-- GSD: 18, last pushed 5 days ago -->
+<!-- pyinstrument_cext: 10, last pushed 32 days ago -->
+<!-- xmlstarlet: 7, last pushed 1 days ago -->
+<!-- CorrectionLib: 7, last pushed 4 days ago -->
+<!-- SiPM: 4, last pushed 2 days ago -->
+<!-- pillow-heif: 4, last pushed 4 days ago -->
 
 <!-- END bin/projects.py -->
 
diff --git a/examples/github-deploy.yml b/examples/github-deploy.yml
index 8f16439a..ef4ec299 100644
--- a/examples/github-deploy.yml
+++ b/examples/github-deploy.yml
@@ -21,11 +21,6 @@ jobs:
     steps:
       - uses: actions/checkout@v2
 
-      - uses: actions/setup-python@v2
-        name: Install Python
-        with:
-          python-version: '3.8'
-
       - name: Build wheels
         uses: pypa/cibuildwheel@v2.2.2
 
@@ -39,13 +34,8 @@ jobs:
     steps:
       - uses: actions/checkout@v2
 
-      - uses: actions/setup-python@v2
-        name: Install Python
-        with:
-          python-version: '3.8'
-
       - name: Build sdist
-        run: python setup.py sdist
+        run: pipx run build --sdist
 
       - uses: actions/upload-artifact@v2
         with:


Test patch:
diff --git a/examples/travis-ci-test-and-deploy.yml b/examples/travis-ci-test-and-deploy.yml
index a538071f..cb556385 100644
--- a/examples/travis-ci-test-and-deploy.yml
+++ b/examples/travis-ci-test-and-deploy.yml
@@ -26,7 +26,7 @@ install:
   - python3 -m pip install pytest
 
 script:
-  - python3 setup.py install
+  - python3 -m pip install .
   - pytest
 
 stages:
@@ -48,30 +48,24 @@ jobs:
     # Deploy source distribution
     - stage: deploy
       name: Deploy source distribution
-      install: skip
-      script: python3 setup.py sdist --formats=gztar
-      after_success: |
-        python3 -m pip install twine
-        python3 -m twine upload --skip-existing dist/*.tar.gz
+      install: python3 -m pip install build twine
+      script: python3 -m build --sdist --formats=gztar
+      after_success: python3 -m twine upload --skip-existing dist/*.tar.gz
     # Deploy on linux
     - stage: deploy
       name: Build and deploy Linux wheels
       services: docker
-      install: python3 -m pip install cibuildwheel==2.2.2
+      install: python3 -m pip install cibuildwheel==2.2.2 twine
       script: python3 -m cibuildwheel --output-dir wheelhouse
-      after_success: |
-        python3 -m pip install twine
-        python3 -m twine upload --skip-existing wheelhouse/*.whl
+      after_success: python3 -m twine upload --skip-existing wheelhouse/*.whl
     # Deploy on windows
     - stage: deploy
       name: Build and deploy Windows wheels
       os: windows
       language: shell
-      install: python3 -m pip install cibuildwheel==2.2.2
+      install: python3 -m pip install cibuildwheel==2.2.2 twine
       script: python3 -m cibuildwheel --output-dir wheelhouse
-      after_success: |
-        python3 -m pip install twine
-        python3 -m twine upload --skip-existing wheelhouse/*.whl
+      after_success: python3 -m twine upload --skip-existing wheelhouse/*.whl
 
 env:
   global:
diff --git a/test/utils.py b/test/utils.py
index 34632c20..97675c7d 100644
--- a/test/utils.py
+++ b/test/utils.py
@@ -130,7 +130,7 @@ def expected_wheels(
     python_abi_tags = ["cp36-cp36m", "cp37-cp37m", "cp38-cp38", "cp39-cp39", "cp310-cp310"]
 
     if machine_arch in ["x86_64", "AMD64", "x86", "aarch64"]:
-        python_abi_tags += ["pp37-pypy37_pp73"]
+        python_abi_tags += ["pp37-pypy37_pp73", "pp38-pypy38_pp73"]
 
     if platform == "macos" and machine_arch == "arm64":
         # currently, arm64 macs are only supported by cp39 & cp310
diff --git a/unit_test/build_selector_test.py b/unit_test/build_selector_test.py
index c99b28f1..7555ab33 100644
--- a/unit_test/build_selector_test.py
+++ b/unit_test/build_selector_test.py
@@ -53,6 +53,9 @@ def test_skip():
 
     assert not build_selector("pp36-manylinux_x86_64")
     assert build_selector("pp37-manylinux_x86_64")
+    assert build_selector("pp38-manylinux_x86_64")
+    assert build_selector("pp37-manylinux_i686")
+    assert build_selector("pp38-manylinux_i686")
     assert build_selector("cp36-manylinux_x86_64")
     assert build_selector("cp37-manylinux_x86_64")
     assert not build_selector("cp36-manylinux_i686")
diff --git a/unit_test/option_prepare_test.py b/unit_test/option_prepare_test.py
index cadab279..55d7edb2 100644
--- a/unit_test/option_prepare_test.py
+++ b/unit_test/option_prepare_test.py
@@ -11,7 +11,7 @@
 from cibuildwheel import linux, util
 from cibuildwheel.__main__ import main
 
-ALL_IDS = {"cp36", "cp37", "cp38", "cp39", "cp310", "pp37"}
+ALL_IDS = {"cp36", "cp37", "cp38", "cp39", "cp310", "pp37", "pp38"}
 
 
 @pytest.fixture
@@ -132,7 +132,9 @@ def test_build_with_override_launches(mock_build_docker, monkeypatch, tmp_path):
     assert not kwargs["docker"]["simulate_32_bit"]
 
     identifiers = {x.identifier for x in kwargs["platform_configs"]}
-    assert identifiers == {f"{x}-manylinux_x86_64" for x in ALL_IDS - {"cp36", "cp310", "pp37"}}
+    assert identifiers == {
+        f"{x}-manylinux_x86_64" for x in ALL_IDS - {"cp36", "cp310", "pp37", "pp38"}
+    }
     assert kwargs["options"].build_options("cp37-manylinux_x86_64").before_all == ""
 
     kwargs = build_on_docker.call_args_list[2][1]
@@ -140,7 +142,11 @@ def test_build_with_override_launches(mock_build_docker, monkeypatch, tmp_path):
     assert kwargs["docker"]["cwd"] == Path("/project")
     assert not kwargs["docker"]["simulate_32_bit"]
     identifiers = {x.identifier for x in kwargs["platform_configs"]}
-    assert identifiers == {"cp310-manylinux_x86_64", "pp37-manylinux_x86_64"}
+    assert identifiers == {
+        "cp310-manylinux_x86_64",
+        "pp37-manylinux_x86_64",
+        "pp38-manylinux_x86_64",
+    }
 
     kwargs = build_on_docker.call_args_list[3][1]
     assert "quay.io/pypa/manylinux2010_i686" in kwargs["docker"]["docker_image"]