name: Tests # gh-84728: "paths-ignore" is not used to skip documentation-only PRs, because # it prevents to mark a job as mandatory. A PR cannot be merged if a job is # mandatory but not scheduled because of "paths-ignore". on: workflow_dispatch: push: branches: - 'main' - '3.11' - '3.10' - '3.9' - '3.8' - '3.7' pull_request: branches: - 'main' - '3.11' - '3.10' - '3.9' - '3.8' - '3.7' permissions: contents: read concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}-reusable cancel-in-progress: true jobs: check_source: name: 'Check for source changes' runs-on: ubuntu-latest timeout-minutes: 10 outputs: run-docs: ${{ steps.docs-changes.outputs.run-docs || false }} run_tests: ${{ steps.check.outputs.run_tests }} run_ssl_tests: ${{ steps.check.outputs.run_ssl_tests }} config_hash: ${{ steps.config_hash.outputs.hash }} steps: - uses: actions/checkout@v4 - name: Check for source changes id: check run: | if [ -z "$GITHUB_BASE_REF" ]; then echo "run_tests=true" >> $GITHUB_OUTPUT echo "run_ssl_tests=true" >> $GITHUB_OUTPUT else git fetch origin $GITHUB_BASE_REF --depth=1 # git diff "origin/$GITHUB_BASE_REF..." (3 dots) may be more # reliable than git diff "origin/$GITHUB_BASE_REF.." (2 dots), # but it requires to download more commits (this job uses # "git fetch --depth=1"). # # git diff "origin/$GITHUB_BASE_REF..." (3 dots) works with Git # 2.26, but Git 2.28 is stricter and fails with "no merge base". # # git diff "origin/$GITHUB_BASE_REF.." (2 dots) should be enough on # GitHub, since GitHub starts by merging origin/$GITHUB_BASE_REF # into the PR branch anyway. # # https://github.com/python/core-workflow/issues/373 git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qvE '(\.rst$|^Doc|^Misc|^\.pre-commit-config\.yaml$|\.ruff\.toml$)' && echo "run_tests=true" >> $GITHUB_OUTPUT || true git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qE '(ssl|hashlib|hmac|^.github)' && echo "run_ssl_tests=true" >> $GITHUB_OUTPUT || true fi - name: Compute hash for config cache key id: config_hash run: | echo "hash=${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }}" >> $GITHUB_OUTPUT - name: Get a list of the changed documentation-related files if: github.event_name == 'pull_request' id: changed-docs-files uses: Ana06/get-changed-files@v2.2.0 with: filter: | Doc/** Misc/** .github/workflows/reusable-docs.yml format: csv # works for paths with spaces - name: Check for docs changes if: >- github.event_name == 'pull_request' && steps.changed-docs-files.outputs.added_modified_renamed != '' id: docs-changes run: | echo "run-docs=true" >> "${GITHUB_OUTPUT}" check-docs: name: Docs needs: check_source if: fromJSON(needs.check_source.outputs.run-docs) uses: ./.github/workflows/reusable-docs.yml check_abi: name: 'Check if the ABI has changed' runs-on: ubuntu-20.04 needs: check_source if: needs.check_source.outputs.run_tests == 'true' steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v4 - name: Install Dependencies run: | sudo ./.github/workflows/posix-deps-apt.sh sudo apt-get install -yq abigail-tools - name: Build CPython env: CFLAGS: -g3 -O0 run: | # Build Python with the libpython dynamic library ./configure --enable-shared make -j4 - name: Check for changes in the ABI id: check run: | if ! make check-abidump; then echo "Generated ABI file is not up to date." echo "Please, add the release manager of this branch as a reviewer of this PR." echo "" echo "The up to date ABI file should be attached to this build as an artifact." echo "" echo "To learn more about this check: https://devguide.python.org/setup/#regenerate-the-abi-dump" echo "" exit 1 fi - name: Generate updated ABI files if: ${{ failure() && steps.check.conclusion == 'failure' }} run: | make regen-abidump - uses: actions/upload-artifact@v3 name: Publish updated ABI files if: ${{ failure() && steps.check.conclusion == 'failure' }} with: name: abi-data path: ./Doc/data/*.abi check_generated_files: name: 'Check if generated files are up to date' runs-on: ubuntu-latest timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' steps: - uses: actions/checkout@v4 - name: Restore config.cache uses: actions/cache@v3 with: path: config.cache key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }} - uses: actions/setup-python@v4 with: python-version: '3.x' - name: Install Dependencies run: sudo ./.github/workflows/posix-deps-apt.sh - name: Add ccache to PATH run: echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV - name: Configure ccache action uses: hendrikmuhs/ccache-action@v1.2 - name: Check Autoconf version 2.69 and aclocal 1.16.3 run: | grep "Generated by GNU Autoconf 2.69" configure grep "aclocal 1.16.3" aclocal.m4 grep -q "runstatedir" configure grep -q "PKG_PROG_PKG_CONFIG" aclocal.m4 - name: Configure CPython run: | # Build Python with the libpython dynamic library ./configure --config-cache --with-pydebug --enable-shared - name: Regenerate autoconf files with container image run: make regen-configure - name: Build CPython run: | # Deepfreeze will usually cause global objects to be added or removed, # so we run it before regen-global-objects gets rum (in regen-all). make regen-deepfreeze make -j4 regen-all make regen-stdlib-module-names - name: Check for changes run: | git add -u changes=$(git status --porcelain) # Check for changes in regenerated files if test -n "$changes"; then echo "Generated files not up to date." echo "Perhaps you forgot to run make regen-all or build.bat --regen. ;)" echo "configure files must be regenerated with a specific version of autoconf." echo "$changes" echo "" git diff --staged || true exit 1 fi - name: Check exported libpython symbols run: make smelly - name: Check limited ABI symbols run: make check-limited-abi build_win32: name: 'Windows (x86)' runs-on: windows-latest timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: IncludeUwp: 'true' steps: - uses: actions/checkout@v4 - name: Build CPython run: .\PCbuild\build.bat -e -d -p Win32 - name: Display build info run: .\python.bat -m test.pythoninfo - name: Tests run: .\PCbuild\rt.bat -p Win32 -d -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0 build_win_amd64: name: 'Windows (x64)' runs-on: windows-latest timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: IncludeUwp: 'true' steps: - uses: actions/checkout@v4 - name: Register MSVC problem matcher run: echo "::add-matcher::.github/problem-matchers/msvc.json" - name: Build CPython run: .\PCbuild\build.bat -e -d -p x64 - name: Display build info run: .\python.bat -m test.pythoninfo - name: Tests run: .\PCbuild\rt.bat -p x64 -d -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0 build_win_arm64: name: 'Windows (arm64)' runs-on: windows-latest timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: IncludeUwp: 'true' steps: - uses: actions/checkout@v4 - name: Register MSVC problem matcher run: echo "::add-matcher::.github/problem-matchers/msvc.json" - name: Build CPython run: .\PCbuild\build.bat -e -d -p arm64 build_macos: name: 'macOS' runs-on: macos-latest timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: HOMEBREW_NO_ANALYTICS: 1 HOMEBREW_NO_AUTO_UPDATE: 1 HOMEBREW_NO_INSTALL_CLEANUP: 1 PYTHONSTRICTEXTENSIONBUILD: 1 steps: - uses: actions/checkout@v4 - name: Restore config.cache uses: actions/cache@v3 with: path: config.cache key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }} - name: Install Homebrew dependencies run: brew install pkg-config openssl@3.0 xz gdbm tcl-tk - name: Configure CPython run: | GDBM_CFLAGS="-I$(brew --prefix gdbm)/include" \ GDBM_LIBS="-L$(brew --prefix gdbm)/lib -lgdbm" \ ./configure \ --config-cache \ --with-pydebug \ --prefix=/opt/python-dev \ --with-openssl="$(brew --prefix openssl@3.0)" - name: Build CPython run: make -j4 - name: Display build info run: make pythoninfo - name: Tests run: make buildbottest TESTOPTS="-j4 -uall,-cpu" build_ubuntu: name: 'Ubuntu' runs-on: ubuntu-20.04 timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: OPENSSL_VER: 3.0.11 PYTHONSTRICTEXTENSIONBUILD: 1 steps: - uses: actions/checkout@v4 - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Install Dependencies run: sudo ./.github/workflows/posix-deps-apt.sh - name: Configure OpenSSL env vars run: | echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> $GITHUB_ENV echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> $GITHUB_ENV echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> $GITHUB_ENV - name: 'Restore OpenSSL build' id: cache-openssl uses: actions/cache@v3 with: path: ./multissl/openssl/${{ env.OPENSSL_VER }} key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }} - name: Install OpenSSL if: steps.cache-openssl.outputs.cache-hit != 'true' run: python3 Tools/ssl/multissltests.py --steps=library --base-directory $MULTISSL_DIR --openssl $OPENSSL_VER --system Linux - name: Add ccache to PATH run: | echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV - name: Configure ccache action uses: hendrikmuhs/ccache-action@v1.2 - name: Setup directory envs for out-of-tree builds run: | echo "CPYTHON_RO_SRCDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-ro-srcdir)" >> $GITHUB_ENV echo "CPYTHON_BUILDDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-builddir)" >> $GITHUB_ENV - name: Create directories for read-only out-of-tree builds run: mkdir -p $CPYTHON_RO_SRCDIR $CPYTHON_BUILDDIR - name: Bind mount sources read-only run: sudo mount --bind -o ro $GITHUB_WORKSPACE $CPYTHON_RO_SRCDIR - name: Restore config.cache uses: actions/cache@v3 with: path: ${{ env.CPYTHON_BUILDDIR }}/config.cache key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }} - name: Configure CPython out-of-tree working-directory: ${{ env.CPYTHON_BUILDDIR }} run: | ../cpython-ro-srcdir/configure \ --config-cache \ --with-pydebug \ --with-openssl=$OPENSSL_DIR - name: Build CPython out-of-tree working-directory: ${{ env.CPYTHON_BUILDDIR }} run: make -j4 - name: Display build info working-directory: ${{ env.CPYTHON_BUILDDIR }} run: make pythoninfo - name: Remount sources writable for tests # some tests write to srcdir, lack of pyc files slows down testing run: sudo mount $CPYTHON_RO_SRCDIR -oremount,rw - name: Tests working-directory: ${{ env.CPYTHON_BUILDDIR }} run: xvfb-run make buildbottest TESTOPTS="-j4 -uall,-cpu" build_ubuntu_ssltests: name: 'Ubuntu SSL tests with OpenSSL' runs-on: ubuntu-20.04 timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' && needs.check_source.outputs.run_ssl_tests == 'true' strategy: fail-fast: false matrix: openssl_ver: [1.1.1w, 3.0.11, 3.1.3] env: OPENSSL_VER: ${{ matrix.openssl_ver }} MULTISSL_DIR: ${{ github.workspace }}/multissl OPENSSL_DIR: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }} LD_LIBRARY_PATH: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}/lib steps: - uses: actions/checkout@v4 - name: Restore config.cache uses: actions/cache@v3 with: path: config.cache key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }} - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Install Dependencies run: sudo ./.github/workflows/posix-deps-apt.sh - name: Configure OpenSSL env vars run: | echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> $GITHUB_ENV echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> $GITHUB_ENV echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> $GITHUB_ENV - name: 'Restore OpenSSL build' id: cache-openssl uses: actions/cache@v3 with: path: ./multissl/openssl/${{ env.OPENSSL_VER }} key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }} - name: Install OpenSSL if: steps.cache-openssl.outputs.cache-hit != 'true' run: python3 Tools/ssl/multissltests.py --steps=library --base-directory $MULTISSL_DIR --openssl $OPENSSL_VER --system Linux - name: Add ccache to PATH run: | echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV - name: Configure ccache action uses: hendrikmuhs/ccache-action@v1.2 - name: Configure CPython run: ./configure --config-cache --with-pydebug --with-openssl=$OPENSSL_DIR - name: Build CPython run: make -j4 - name: Display build info run: make pythoninfo - name: SSL tests run: ./python Lib/test/ssltests.py build_asan: name: 'Address sanitizer' runs-on: ubuntu-20.04 timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: OPENSSL_VER: 3.0.11 PYTHONSTRICTEXTENSIONBUILD: 1 ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0 steps: - uses: actions/checkout@v4 - name: Restore config.cache uses: actions/cache@v3 with: path: config.cache key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }} - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Install Dependencies run: sudo ./.github/workflows/posix-deps-apt.sh - name: Set up GCC-10 for ASAN uses: egor-tensin/setup-gcc@v1 with: version: 10 - name: Configure OpenSSL env vars run: | echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> $GITHUB_ENV echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> $GITHUB_ENV echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> $GITHUB_ENV - name: 'Restore OpenSSL build' id: cache-openssl uses: actions/cache@v3 with: path: ./multissl/openssl/${{ env.OPENSSL_VER }} key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }} - name: Install OpenSSL if: steps.cache-openssl.outputs.cache-hit != 'true' run: python3 Tools/ssl/multissltests.py --steps=library --base-directory $MULTISSL_DIR --openssl $OPENSSL_VER --system Linux - name: Add ccache to PATH run: | echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV - name: Configure ccache action uses: hendrikmuhs/ccache-action@v1.2 - name: Configure CPython run: ./configure --config-cache --with-address-sanitizer --without-pymalloc - name: Build CPython run: make -j4 - name: Display build info run: make pythoninfo - name: Tests run: xvfb-run make buildbottest TESTOPTS="-j4 -uall,-cpu" all-required-green: # This job does nothing and is only used for the branch protection name: All required checks pass if: always() needs: - check_source # Transitive dependency, needed to access `run_tests` value - check-docs - check_generated_files - build_win32 - build_win_amd64 - build_win_arm64 - build_macos - build_ubuntu - build_ubuntu_ssltests - build_asan runs-on: ubuntu-latest steps: - name: Check whether the needed jobs succeeded or failed uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe with: allowed-failures: >- build_macos, build_ubuntu_ssltests, build_win32, build_win_arm64, allowed-skips: >- ${{ !fromJSON(needs.check_source.outputs.run-docs) && ' check-docs, ' || '' }} ${{ needs.check_source.outputs.run_tests != 'true' && ' check_generated_files, build_win32, build_win_amd64, build_win_arm64, build_macos, build_ubuntu, build_ubuntu_ssltests, build_asan, ' || '' }} jobs: ${{ toJSON(needs) }}