Stop the benchmark CI job hanging on apt (#13489) #3048
This file contains hidden or 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
| name: CI | |
| on: | |
| merge_group: | |
| push: | |
| branches: | |
| - 'master' | |
| - '[0-9].[0-9]+' # matches to backport branches, e.g. 3.6 | |
| tags: [ 'v*' ] | |
| pull_request: | |
| branches: | |
| - 'master' | |
| - '[0-9].[0-9]+' | |
| schedule: | |
| - cron: '0 6 * * *' # Daily 6AM UTC build | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} | |
| cancel-in-progress: true | |
| env: | |
| COLOR: yes | |
| FORCE_COLOR: 1 # Request colored output from CLI tools supporting it | |
| MYPY_FORCE_COLOR: 1 | |
| PY_COLORS: 1 | |
| UPSTREAM_REPOSITORY_ID: >- | |
| 13258039 | |
| permissions: {} | |
| jobs: | |
| pre-setup: | |
| name: Pre-Setup global build settings | |
| runs-on: ubuntu-latest | |
| outputs: | |
| upstream-repository-id: ${{ env.UPSTREAM_REPOSITORY_ID }} | |
| release-requested: >- | |
| ${{ | |
| ( | |
| github.event_name == 'push' | |
| && github.ref_type == 'tag' | |
| ) | |
| && true | |
| || false | |
| }} | |
| steps: | |
| - name: Dummy | |
| if: false | |
| run: | | |
| echo "Pre-setup step" | |
| gen-llhttp: | |
| permissions: | |
| contents: read # to fetch code (actions/checkout) | |
| name: Generate llhttp sources | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| submodules: true | |
| - name: Cache llhttp generated files | |
| uses: actions/cache@v6.1.0 | |
| id: cache | |
| with: | |
| key: llhttp-${{ hashFiles('vendor/llhttp/package*.json', 'vendor/llhttp/src/**/*') }} | |
| path: vendor/llhttp/build | |
| - name: Setup NodeJS | |
| if: steps.cache.outputs.cache-hit != 'true' | |
| uses: actions/setup-node@v7 | |
| with: | |
| node-version: 18 | |
| - name: Generate llhttp sources | |
| if: steps.cache.outputs.cache-hit != 'true' | |
| run: | | |
| make generate-llhttp | |
| - name: Upload llhttp generated files | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: llhttp | |
| path: vendor/llhttp/build | |
| if-no-files-found: error | |
| build-pure-python-dists: | |
| permissions: | |
| contents: read # to fetch code (actions/checkout) | |
| name: 📦 Build distribution packages | |
| runs-on: ubuntu-latest | |
| needs: | |
| - gen-llhttp | |
| outputs: | |
| sdist-filename: >- | |
| ${{ steps.dist-filename-detection.outputs.sdist-filename }} | |
| wheel-filename: >- | |
| ${{ steps.dist-filename-detection.outputs.wheel-filename }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| submodules: true | |
| - name: Setup Python | |
| uses: actions/setup-python@v7.0.0 | |
| - name: Install build tooling and cython | |
| run: >- | |
| python -m | |
| pip install -U build -r requirements/cython.in -c requirements/cython.txt | |
| - name: Restore llhttp generated files | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: llhttp | |
| path: vendor/llhttp/build/ | |
| - name: Cythonize | |
| run: | | |
| make cythonize | |
| - name: Build sdists and pure-python wheel | |
| run: | | |
| python -m build | |
| env: | |
| AIOHTTP_NO_EXTENSIONS: 1 | |
| - name: Determine the sdist and wheel filenames | |
| id: dist-filename-detection | |
| run: | | |
| echo "sdist-filename=$(basename dist/*.tar.gz)" >> "$GITHUB_OUTPUT" | |
| echo "wheel-filename=$(basename dist/*.whl)" >> "$GITHUB_OUTPUT" | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: dist-pure | |
| path: dist | |
| lint-from-git: | |
| permissions: | |
| contents: read # to fetch code (actions/checkout) | |
| name: Lint / Git | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| submodules: true | |
| - name: Setup Python | |
| uses: actions/setup-python@v7.0.0 | |
| with: | |
| python-version: 3.11 | |
| - name: >- | |
| Verify that `requirements/runtime-deps.in` | |
| is in sync with `pyproject.toml` | |
| run: | | |
| set -eEuo pipefail | |
| make sync-direct-runtime-deps | |
| git diff --exit-code -- requirements/runtime-deps.in | |
| - name: Install self | |
| run: | # needed so sphinxcontrib-spelling could allowlist some dep names | |
| python -m pip install . -c requirements/runtime-deps.txt | |
| env: | |
| AIOHTTP_NO_EXTENSIONS: 1 | |
| - name: Install spell checker | |
| run: | | |
| pip install -r requirements/doc-spelling.in -c requirements/doc-spelling.txt | |
| - name: Run docs spelling | |
| run: | | |
| # towncrier --yes # uncomment me after publishing a release | |
| make doc-spelling | |
| lint-from-sdist: | |
| permissions: | |
| pull-requests: read # to read PR metadata (verify change fragments step) | |
| name: Lint / sdist | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| needs: | |
| - build-pure-python-dists | |
| steps: | |
| - name: Retrieve the sdist and unpack it into the workspace | |
| uses: re-actors/checkout-python-sdist@release/v3 | |
| with: | |
| source-tarball-name: >- | |
| ${{ needs.build-pure-python-dists.outputs.sdist-filename }} | |
| workflow-artifact-name: dist-pure | |
| - name: Download the sdist artifact for the twine check | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: dist-pure | |
| path: dist/ | |
| - name: Setup Python | |
| uses: actions/setup-python@v7.0.0 | |
| with: | |
| python-version: 3.11 | |
| - name: Cache PyPI | |
| uses: actions/cache@v6.1.0 | |
| with: | |
| key: pip-lint-${{ hashFiles('requirements/*.txt') }} | |
| path: ~/.cache/pip | |
| restore-keys: | | |
| pip-lint- | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install -U pip twine -r requirements/lint.in -c requirements/lint.txt | |
| - name: Self-install from sdist | |
| run: | | |
| python -m pip install "${SDIST_PATH}" -c requirements/runtime-deps.txt | |
| env: | |
| SDIST_PATH: >- | |
| dist/${{ needs.build-pure-python-dists.outputs.sdist-filename }} | |
| AIOHTTP_NO_EXTENSIONS: 1 | |
| - name: Run mypy | |
| run: | | |
| make mypy | |
| - name: Run slotscheck | |
| run: | | |
| # Some extra requirements are needed to ensure all modules | |
| # can be scanned by slotscheck. | |
| pip install -r requirements/base.in -c requirements/base.txt | |
| slotscheck -v -m aiohttp | |
| - name: Verify CHANGES fragment references PR | |
| # Skipped on backport PRs: their fragments are numbered for the original | |
| # PR/issue, so the check would never pass. The workflow itself stays | |
| # identical across branches. | |
| if: >- | |
| github.event_name == 'pull_request' | |
| && github.event.pull_request.base.ref == 'master' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| run: | | |
| set -euo pipefail | |
| # Fetch the body fresh: github.event.pull_request.body is frozen at | |
| # the webhook payload and stale on re-runs after a body edit. | |
| PR_BODY=$( | |
| gh api "repos/${{ github.repository }}/pulls/${PR_NUMBER}" --jq .body | |
| ) | |
| added=$( | |
| gh api --paginate \ | |
| "repos/${{ github.repository }}/pulls/${PR_NUMBER}/files" \ | |
| --jq '.[] | select(.status=="added") | .filename' \ | |
| | grep '^CHANGES/' || true | |
| ) | |
| failed=0 | |
| for f in $added; do | |
| num=$(basename "$f" | cut -d. -f1) | |
| [[ "$num" =~ ^[0-9]+$ ]] || continue | |
| if [[ "$num" == "$PR_NUMBER" ]]; then continue; fi | |
| if grep -qE "(^|[^0-9])#${num}([^0-9]|$)" <<<"$PR_BODY"; then continue; fi | |
| echo "::error file=$f::Change fragment ($num) must reference PR #$PR_NUMBER or an issue this PR fixes" | |
| failed=1 | |
| done | |
| exit $failed | |
| - name: Run twine checker | |
| run: | | |
| twine check --strict dist/* | |
| - name: Making sure that CONTRIBUTORS.txt remains sorted | |
| run: | | |
| LC_ALL=C sort --check --ignore-case CONTRIBUTORS.txt | |
| test: | |
| name: Test | |
| needs: | |
| - build-pure-python-dists | |
| strategy: | |
| matrix: | |
| pyver: ['3.10', '3.11', '3.12', '3.13', '3.14'] | |
| no-extensions: ['', 'Y'] | |
| os: [ubuntu, macos, windows] | |
| experimental: [false] | |
| exclude: | |
| - os: macos | |
| no-extensions: 'Y' | |
| - os: windows | |
| no-extensions: 'Y' | |
| include: | |
| - pyver: pypy-3.11 | |
| no-extensions: 'Y' | |
| os: ubuntu | |
| experimental: false | |
| - os: ubuntu | |
| pyver: "3.14t" | |
| no-extensions: '' | |
| experimental: false | |
| fail-fast: true | |
| runs-on: ${{ matrix.os }}-latest | |
| continue-on-error: ${{ matrix.experimental }} | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Retrieve the sdist and unpack it into the workspace | |
| uses: re-actors/checkout-python-sdist@release/v3 | |
| with: | |
| source-tarball-name: >- | |
| ${{ needs.build-pure-python-dists.outputs.sdist-filename }} | |
| workflow-artifact-name: dist-pure | |
| - name: Setup Python ${{ matrix.pyver }} | |
| id: python-install | |
| # important: do not use system python | |
| env: | |
| UV_PYTHON_PREFERENCE: only-managed | |
| uses: astral-sh/setup-uv@v10.0.1 | |
| with: | |
| python-version: ${{ matrix.pyver }} | |
| activate-environment: true | |
| enable-cache: true | |
| - name: Install dependencies | |
| env: | |
| DEPENDENCY_GROUP: test${{ endsWith(matrix.pyver, 't') && '-ft' || '' }} | |
| run: | | |
| uv pip install -U pip wheel setuptools build twine -r requirements/${{ env.DEPENDENCY_GROUP }}.in -c requirements/${{ env.DEPENDENCY_GROUP }}.txt | |
| - name: Set PYTHON_GIL=0 for free-threading builds | |
| if: ${{ endsWith(matrix.pyver, 't') }} | |
| run: echo "PYTHON_GIL=0" >> $GITHUB_ENV | |
| - name: Install self | |
| env: | |
| AIOHTTP_NO_EXTENSIONS: ${{ matrix.no-extensions }} | |
| run: uv pip install -e . | |
| - name: Run unittests | |
| env: | |
| COLOR: yes | |
| AIOHTTP_NO_EXTENSIONS: ${{ matrix.no-extensions }} | |
| PIP_USER: 1 | |
| run: >- | |
| pytest --junitxml=junit.xml --numprocesses=auto --cov -m 'not dev_mode and not autobahn' | |
| shell: bash | |
| - name: Re-run the failing tests with maximum verbosity | |
| if: failure() | |
| env: | |
| COLOR: yes | |
| AIOHTTP_NO_EXTENSIONS: ${{ matrix.no-extensions }} | |
| run: >- # `exit 1` makes sure that the job remains red with flaky runs | |
| pytest --no-cov -vvvvv --lf && exit 1 | |
| shell: bash | |
| - name: Run dev_mode tests | |
| env: | |
| COLOR: yes | |
| AIOHTTP_NO_EXTENSIONS: ${{ matrix.no-extensions }} | |
| PIP_USER: 1 | |
| PYTHONDEVMODE: 1 | |
| run: pytest -m dev_mode --cov --cov-append --cov-report=xml | |
| shell: bash | |
| - name: Upload coverage | |
| uses: codecov/codecov-action@v7 | |
| with: | |
| files: ./coverage.xml | |
| flags: >- | |
| CI-GHA,OS-${{ | |
| runner.os | |
| }},VM-${{ | |
| matrix.os | |
| }},Py-${{ | |
| steps.python-install.outputs.python-version | |
| }} | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| - name: Upload test results to Codecov | |
| if: ${{ !cancelled() }} | |
| uses: codecov/codecov-action@v7 | |
| with: | |
| files: ./junit.xml | |
| report_type: test_results | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| test-mobile: | |
| name: Test (${{ matrix.config.platform }}, ${{ matrix.pyver }}, ${{ matrix.config.os }}) | |
| runs-on: ${{ matrix.config.os }} | |
| needs: | |
| - build-pure-python-dists | |
| strategy: | |
| matrix: | |
| pyver: ["cp313", "cp314"] | |
| config: | |
| - os: ubuntu-latest | |
| platform: android | |
| archs: x86_64 | |
| - os: macos-14 | |
| platform: ios | |
| archs: arm64_iphonesimulator | |
| steps: | |
| - name: Download the source distribution | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: dist-pure | |
| path: dist/ | |
| - name: Setup Python ${{ matrix.pyver }} | |
| id: python-install | |
| # important: do not use system python | |
| env: | |
| UV_PYTHON_PREFERENCE: only-managed | |
| uses: astral-sh/setup-uv@v10.0.1 | |
| with: | |
| python-version: ${{ matrix.pyver }} | |
| activate-environment: true | |
| enable-cache: true | |
| - name: Free up disk space for Android emulator | |
| if: ${{ matrix.config.platform == 'android' }} | |
| uses: BRAINSia/free-disk-space@v2.1.3 | |
| with: | |
| android: false | |
| docker-images: false | |
| mandb: false | |
| large-packages: false | |
| - name: Enable KVM group perms for Android emulator | |
| if: ${{ matrix.config.platform == 'android' }} | |
| # This is normally done by cibuildwheel automatically, when it detects Github Actions. But by unsetting GITHUB_ACTIONS | |
| # in the test step, we also disable that automatic setup. So we need to do it manually here. | |
| run: | | |
| echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules | |
| sudo udevadm control --reload-rules | |
| sudo udevadm trigger --name-match=kvm | |
| - name: Install cibuildwheel | |
| run: uv pip install cibuildwheel==3.4.1 | |
| - name: Build wheels and test | |
| # cibuildwheel normally uses grouping in its outputs for its build/test steps. But the loading time when | |
| # expanding large groups in GitHub Actions is very high. So by unsetting GITHUB_ACTIONS, cibuildwheel does | |
| # not know that it is running in a GitHub Action and thus does not use groups. | |
| # Additionally, passing a tarball means that cibuildwheel will use that | |
| # tarball and not the current working directory as the source. | |
| run: env -u GITHUB_ACTIONS cibuildwheel "${SDIST_PATH}" | |
| env: | |
| CIBW_BUILD: ${{ matrix.pyver }}-* | |
| CIBW_PLATFORM: ${{ matrix.config.platform }} | |
| CIBW_ARCHS: ${{ matrix.config.archs }} | |
| CIBW_TEST_REQUIRES: -r requirements/test-mobile.txt | |
| CIBW_TEST_SOURCES: setup.cfg README.rst tests | |
| # Currently only Android supports colored output. See https://github.com/python/cpython/issues/150932 for iOS. | |
| CIBW_TEST_COMMAND: python -m pytest ${{ matrix.config.platform == 'android' && '--color=yes' || '' }} | |
| SDIST_PATH: >- | |
| dist/${{ needs.build-pure-python-dists.outputs.sdist-filename }} | |
| autobahn: | |
| name: Autobahn testsuite | |
| needs: | |
| - build-pure-python-dists | |
| strategy: | |
| matrix: | |
| pyver: ['3.14'] | |
| no-extensions: [''] | |
| os: [ubuntu] | |
| fail-fast: true | |
| runs-on: ${{ matrix.os }}-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Retrieve the sdist and unpack it into the workspace | |
| uses: re-actors/checkout-python-sdist@release/v3 | |
| with: | |
| source-tarball-name: >- | |
| ${{ needs.build-pure-python-dists.outputs.sdist-filename }} | |
| workflow-artifact-name: dist-pure | |
| - name: Setup Python ${{ matrix.pyver }} | |
| id: python-install | |
| # important: do not use system python | |
| env: | |
| UV_PYTHON_PREFERENCE: only-managed | |
| uses: astral-sh/setup-uv@v10.0.1 | |
| with: | |
| python-version: ${{ matrix.pyver }} | |
| activate-environment: true | |
| enable-cache: true | |
| - name: Install dependencies | |
| env: | |
| DEPENDENCY_GROUP: test${{ endsWith(matrix.pyver, 't') && '-ft' || '' }} | |
| run: | | |
| uv pip install -r requirements/${{ env.DEPENDENCY_GROUP }}.in -c requirements/${{ env.DEPENDENCY_GROUP }}.txt | |
| - name: Install self | |
| env: | |
| AIOHTTP_NO_EXTENSIONS: ${{ matrix.no-extensions }} | |
| run: uv pip install -e . | |
| - name: Run unittests | |
| env: | |
| COLOR: yes | |
| AIOHTTP_NO_EXTENSIONS: ${{ matrix.no-extensions }} | |
| PIP_USER: 1 | |
| run: >- | |
| PATH="${HOME}/Library/Python/3.11/bin:${HOME}/.local/bin:${PATH}" | |
| pytest --junitxml=junit.xml --cov --cov-report=xml | |
| --timeout=0 -m autobahn | |
| shell: bash | |
| - name: Upload coverage | |
| uses: codecov/codecov-action@v7 | |
| with: | |
| files: ./coverage.xml | |
| flags: Autobahn | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| - name: Upload test results to Codecov | |
| if: ${{ !cancelled() }} | |
| uses: codecov/codecov-action@v7 | |
| with: | |
| files: ./junit.xml | |
| report_type: test_results | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| benchmark: | |
| name: Benchmark | |
| needs: | |
| - build-pure-python-dists | |
| - pre-setup # transitive, for accessing settings | |
| if: >- | |
| needs.pre-setup.outputs.upstream-repository-id == github.repository_id | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout project | |
| uses: actions/checkout@v7 # despite sdist, codspeed needs Git | |
| - name: Retrieve the sdist and unpack it into the workspace | |
| uses: re-actors/checkout-python-sdist@release/v3 | |
| with: | |
| source-tarball-name: >- | |
| ${{ needs.build-pure-python-dists.outputs.sdist-filename }} | |
| workflow-artifact-name: dist-pure | |
| - name: Download the source distribution | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: dist-pure | |
| path: dist/ | |
| - name: Setup Python 3.13.2 | |
| id: python-install | |
| uses: actions/setup-python@v7.0.0 | |
| with: | |
| python-version: 3.13.2 | |
| cache: pip | |
| cache-dependency-path: requirements/*.txt | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install -r requirements/test.in -c requirements/test.txt | |
| - name: Self-install from sdist | |
| run: | | |
| python -m pip install "${SDIST_PATH}" -c requirements/runtime-deps.txt | |
| env: | |
| SDIST_PATH: >- | |
| dist/${{ needs.build-pure-python-dists.outputs.sdist-filename }} | |
| - name: Load kernel TLS module | |
| if: runner.os == 'Linux' | |
| run: sudo modprobe tls | |
| - name: Show kernel and OpenSSL build information | |
| if: runner.os == 'Linux' | |
| run: | | |
| lsb_release -a | |
| uname -r | |
| openssl version -a | |
| - name: Install libc6-dbg | |
| # The CodSpeed runner installs this itself with a plain apt-get call | |
| # that has no timeout, so a slow apt mirror hangs the job until | |
| # timeout-minutes kills it. Installing it here with a bounded retry | |
| # also lets the runner find it already present after restoring | |
| # valgrind from its cache and skip apt entirely. | |
| run: | | |
| for attempt in 1 2 3; do | |
| if timeout 300 sudo apt-get update \ | |
| && timeout 300 sudo DEBIAN_FRONTEND=noninteractive \ | |
| apt-get install -y libc6-dbg | |
| then | |
| exit 0 | |
| fi | |
| echo "apt-get attempt ${attempt} failed, retrying" | |
| sudo dpkg --configure -a || true | |
| sleep 10 | |
| done | |
| exit 1 | |
| - name: Run benchmarks | |
| uses: CodSpeedHQ/action@v5.0.3 | |
| with: | |
| mode: instrumentation | |
| run: python -Im pytest --no-cov -vvvvv --codspeed --durations=30 --timeout=0 | |
| cython-coverage: | |
| permissions: | |
| contents: read # to fetch code (actions/checkout) | |
| name: Cython coverage | |
| needs: | |
| - gen-llhttp | |
| strategy: | |
| matrix: | |
| os: [ubuntu, windows] | |
| runs-on: ${{ matrix.os }}-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| submodules: true | |
| - name: Setup Python | |
| id: python-install | |
| uses: actions/setup-python@v7.0.0 | |
| with: | |
| python-version: '3.12' | |
| - name: Install dependencies | |
| run: | | |
| python -Im pip install -U pip wheel setuptools build twine -r requirements/test.in -c requirements/test.txt | |
| - name: Uninstall blocbuster | |
| run: python -m pip uninstall blockbuster -y | |
| - name: Restore llhttp generated files | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: llhttp | |
| path: vendor/llhttp/build/ | |
| - name: Cythonize with linetrace | |
| run: | | |
| make cythonize CYTHON_EXTRA="-X linetrace=True" | |
| - name: Install self | |
| env: | |
| AIOHTTP_CYTHON_TRACE: 1 | |
| run: python -m pip install -e . | |
| - name: Run tests with Cython tracing | |
| env: | |
| COLOR: yes | |
| PIP_USER: 1 | |
| run: >- | |
| pytest tests/test_client_functional.py tests/test_http_parser.py tests/test_http_writer.py tests/test_web_functional.py tests/test_web_response.py tests/test_websocket_parser.py | |
| --cov-config=.coveragerc-cython.toml --cov | |
| --cov-report=xml:cython-coverage.xml | |
| --numprocesses=auto | |
| -m 'not dev_mode and not autobahn' | |
| shell: bash | |
| - name: Upload coverage | |
| uses: codecov/codecov-action@v7 | |
| with: | |
| files: ./cython-coverage.xml | |
| disable_search: true | |
| flags: cython-coverage | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| fail_ci_if_error: true | |
| check: # This job does nothing and is only used for the branch protection | |
| if: always() | |
| needs: | |
| - lint-from-sdist | |
| - lint-from-git | |
| - test | |
| - test-mobile | |
| - autobahn | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Decide whether the needed jobs succeeded or failed | |
| uses: re-actors/alls-green@release/v1 | |
| with: | |
| jobs: ${{ toJSON(needs) }} | |
| - name: Trigger codecov notification | |
| uses: codecov/codecov-action@v7 | |
| with: | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| fail_ci_if_error: true | |
| run_command: send-notifications | |
| pre-deploy: | |
| name: Pre-Deploy | |
| runs-on: ubuntu-latest | |
| needs: | |
| - check | |
| - pre-setup # transitive, for accessing settings | |
| if: fromJSON(needs.pre-setup.outputs.release-requested) | |
| steps: | |
| - name: Dummy | |
| run: | | |
| echo "Predeploy step" | |
| build-wheels: | |
| name: >- # ${{ '' } is a hack to nest jobs under the same sidebar category | |
| 📦 Build platform-specific wheels${{ '' }} | |
| needs: | |
| - build-pure-python-dists | |
| - pre-deploy | |
| uses: ./.github/workflows/reusable-cibuildwheel.yml | |
| strategy: | |
| matrix: | |
| runner-vm-os: | |
| - ubuntu-latest | |
| - windows-latest | |
| - windows-11-arm | |
| - macos-latest | |
| - ubuntu-24.04-arm | |
| qemu: | |
| - '' | |
| musl: | |
| - '' | |
| platform: | |
| - '' | |
| include: | |
| # Split ubuntu/musl jobs for the sake of speed-up | |
| - runner-vm-os: ubuntu-latest | |
| qemu: ppc64le | |
| musl: '' | |
| - runner-vm-os: ubuntu-latest | |
| qemu: ppc64le | |
| musl: musllinux | |
| - runner-vm-os: ubuntu-latest | |
| qemu: riscv64 | |
| musl: '' | |
| - runner-vm-os: ubuntu-latest | |
| qemu: riscv64 | |
| musl: musllinux | |
| - runner-vm-os: ubuntu-latest | |
| qemu: s390x | |
| musl: '' | |
| - runner-vm-os: ubuntu-latest | |
| qemu: s390x | |
| musl: musllinux | |
| # armv7l builds on aarch64 hosts. We still register QEMU so | |
| # binfmt picks up the 32-bit ARM userspace handler regardless of | |
| # whether the host kernel has CONFIG_COMPAT enabled. Even with | |
| # emulation, aarch64-on-aarch64 hosting beats x86_64 by a wide | |
| # margin. | |
| - runner-vm-os: ubuntu-24.04-arm | |
| qemu: armv7l | |
| musl: '' | |
| - runner-vm-os: ubuntu-24.04-arm | |
| qemu: armv7l | |
| musl: musllinux | |
| - runner-vm-os: ubuntu-latest | |
| musl: musllinux | |
| - runner-vm-os: ubuntu-24.04-arm | |
| musl: musllinux | |
| - runner-vm-os: ubuntu-latest | |
| platform: android | |
| - runner-vm-os: macos-14 | |
| platform: ios | |
| with: | |
| check-name: >- | |
| ${{ matrix.runner-vm-os }} ${{ matrix.qemu }} | |
| ${{ matrix.musl }} ${{ matrix.platform }} | |
| dists-artifact-name: dist-pure | |
| environment-variables: |- | |
| CIBW_ARCHS_ANDROID=arm64_v8a x86_64 | |
| CIBW_ARCHS_IOS=arm64_iphoneos arm64_iphonesimulator x86_64_iphonesimulator | |
| ${{ matrix.qemu && format('CIBW_ARCHS_LINUX={0}', matrix.qemu) || '' }} | |
| CIBW_ARCHS_MACOS=x86_64 arm64 universal2 | |
| ${{ matrix.qemu && 'CIBW_BUILD_FRONTEND=build' || '' }} | |
| CIBW_PLATFORM=${{ matrix.platform != '' && matrix.platform || 'auto' }} | |
| CIBW_SKIP=pp* *${{ | |
| matrix.musl == 'musllinux' | |
| && 'many' | |
| || 'musl' | |
| }}linux* | |
| qemu: ${{ matrix.qemu != '' }} | |
| runner-vm-os: ${{ matrix.runner-vm-os }} | |
| source-tarball-name: >- | |
| ${{ needs.build-pure-python-dists.outputs.sdist-filename }} | |
| timeout-minutes: ${{ matrix.qemu != '' && 35 || 15 }} | |
| deploy: | |
| name: Deploy | |
| needs: | |
| - build-wheels | |
| - pre-setup # transitive, for accessing settings | |
| runs-on: ubuntu-latest | |
| if: >- | |
| needs.pre-setup.outputs.upstream-repository-id == github.repository_id | |
| permissions: | |
| contents: write # IMPORTANT: mandatory for making GitHub Releases | |
| id-token: write # IMPORTANT: mandatory for trusted publishing & sigstore | |
| environment: | |
| name: pypi | |
| url: https://pypi.org/p/aiohttp | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| submodules: true | |
| - name: Login | |
| run: | | |
| echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token | |
| - name: Download distributions | |
| uses: actions/download-artifact@v8 | |
| with: | |
| path: dist | |
| pattern: dist-* | |
| merge-multiple: true | |
| - name: Collected dists | |
| run: | | |
| tree dist | |
| - name: Check whether the GitHub Release already exists | |
| # Allows re-running the deploy job after a partial failure (e.g. PyPI | |
| # upload error) without the Make Release step failing with HTTP 422 | |
| # because the tag/release was created on a prior attempt. Treat | |
| # only the literal `release not found` reply as "does not exist"; | |
| # other failures (auth, rate-limit, network) re-raise so the job | |
| # fails loudly instead of falling through to Make Release. | |
| id: gh-release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| TAG: ${{ github.ref_name }} | |
| run: | | |
| if gh release view "${TAG}" --repo "${GITHUB_REPOSITORY}" \ | |
| >/dev/null 2>err; then | |
| echo 'exists=true' >> "${GITHUB_OUTPUT}" | |
| elif grep -qx 'release not found' err; then | |
| echo 'exists=false' >> "${GITHUB_OUTPUT}" | |
| else | |
| cat err >&2 | |
| exit 1 | |
| fi | |
| - name: Make Release | |
| if: steps.gh-release.outputs.exists != 'true' | |
| uses: aio-libs/create-release@v1.6.6 | |
| with: | |
| changes_file: CHANGES.rst | |
| name: aiohttp | |
| version_file: aiohttp/__init__.py | |
| github_token: ${{ secrets.GITHUB_TOKEN }} | |
| dist_dir: dist | |
| fix_issue_regex: >- | |
| :issue:`(\d+)` | |
| fix_issue_repl: >- | |
| #\1 | |
| - name: >- | |
| Publish 🐍📦 to PyPI | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| # Allow re-running the deploy job after a partial PyPI upload | |
| # without failing on dists that were already published. | |
| skip-existing: true | |
| - name: Sign the dists with Sigstore | |
| uses: sigstore/gh-action-sigstore-python@v3.5.0 | |
| with: | |
| inputs: >- | |
| ./dist/*.tar.gz | |
| ./dist/*.whl | |
| - name: Upload artifact signatures to GitHub Release | |
| # Confusingly, this action also supports updating releases, not | |
| # just creating them. This is what we want here, since we've manually | |
| # created the release above. | |
| uses: softprops/action-gh-release@v3.0.2 | |
| with: | |
| # dist/ contains the built packages plus the Sigstore signatures | |
| # and certificates emitted alongside them by the signing step above. | |
| files: dist/** |