# 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 name: Python package on: push: branches: [main] pull_request: workflow_dispatch: permissions: contents: read jobs: test: name: test (${{ matrix.os-type }}, ${{ matrix.python-version }}${{ matrix.backend == 'gix' && ', gix' || '' }}) strategy: matrix: os-type: [ubuntu, macos, windows] python-version: ["3.11", "3.12", "3.13", "3.14", "3.14t", "3.15", "3.15t"] backend: [cli] exclude: - os-type: macos python-version: "3.14t" - os-type: macos python-version: "3.15t" include: - build-docs: true # We ensure documentation builds, except on very old interpreters. - experimental: false - python-version: "3.15" experimental: true - python-version: "3.15t" experimental: true - os-type: ubuntu python-version: "3.12" backend: gix build-docs: false experimental: false - os-type: macos python-version: "3.12" backend: gix build-docs: false experimental: false - os-type: windows python-version: "3.12" backend: gix build-docs: false experimental: false fail-fast: false runs-on: ${{ matrix.os-type }}-latest env: GIT_PYTHON_BACKEND: ${{ matrix.backend }} defaults: run: shell: bash --noprofile --norc -exo pipefail {0} steps: - uses: actions/checkout@v7 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v7 with: python-version: ${{ matrix.python-version }} allow-prereleases: ${{ matrix.experimental }} cache: pip cache-dependency-path: | pyproject.toml requirements.txt test-requirements.txt gix-requirements.txt - name: Prepare Rust for GixPython source builds id: rust run: | # GixPython 0.3.0 publishes macOS wheels only and needs Rust >= 1.89. rustup toolchain install stable --profile minimal rustup default stable rustc --version echo "version=$(rustc --version)" >> "$GITHUB_OUTPUT" - name: Cache GixPython Cargo dependencies and build output uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | ~/.cargo/registry ~/.cargo/git ${{ runner.temp }}/gix-target key: gix-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python-version }}-${{ steps.rust.outputs.version }}-${{ hashFiles('gix-requirements.txt') }} restore-keys: | gix-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python-version }}-${{ steps.rust.outputs.version }}- - name: Set up WSL (Windows) if: matrix.os-type == 'windows' uses: Vampire/setup-wsl@v7.2.0 with: wsl-version: 1 - name: Install current Git (Linux) if: matrix.os-type == 'ubuntu' run: | sudo add-apt-repository --yes ppa:git-core/ppa sudo apt-get update sudo apt-get install --yes git - name: Install current Git (macOS) if: matrix.os-type == 'macos' run: | brew install git echo "$(brew --prefix git)/bin" >> "$GITHUB_PATH" - name: Prepare this repo for tests run: | ./init-tests-after-clone.sh - name: Set git user identity and command aliases for the tests run: | git config --global user.email "travis@ci.com" git config --global user.name "Travis Runner" # If we rewrite the user's config by accident, we will mess it up # and cause subsequent tests to fail cat test/fixtures/.gitconfig >> ~/.gitconfig - name: Update PyPA packages run: | python -m pip install -U pip 'setuptools; python_version<"3.12"' wheel - name: Install project and test dependencies run: | pip install ./smmap ./gitdb ".[${EXTRAS}]" python -c 'import os; from gix import testtools; from git import _backend; print("Backend:", _backend.name); assert _backend.name == os.environ["EXPECTED_BACKEND"]' env: EXTRAS: ${{ matrix.backend == 'gix' && 'test,gix' || 'test' }} EXPECTED_BACKEND: ${{ matrix.backend }} # Keep Cargo output when pip removes its temporary source directory. CARGO_TARGET_DIR: ${{ runner.temp }}/gix-target - name: Show POSIX file ownership # Linux and macOS only. On Windows, Git Bash's `ls -ld` reports a # uniform uid+gid for every path regardless of NTFS Owner (MSYS2's # SID-to-uid mapping doesn't have Cygwin's fidelity), so it would # not be informative here. The NTFS Owner check below covers Windows. if: matrix.os-type != 'windows' run: | ls -ld -- \ "$(pwd)" \ "$(pwd)/.git" \ "${HOME:?HOME is not set}/.gitconfig" \ 2>&1 || true - name: Show NTFS file ownership # Windows only. Reads NTFS Owner directly via Get-Acl, which is the # authoritative view for Windows-side ownership questions; the POSIX # view via Git Bash's MSYS2 layer is not a reliable proxy here. if: matrix.os-type == 'windows' shell: pwsh run: | $paths = @( "$pwd", "$pwd\.git", "$env:USERPROFILE\.gitconfig" ) foreach ($p in $paths) { if (Test-Path -LiteralPath $p) { try { $owner = (Get-Acl -LiteralPath $p).Owner } catch { $owner = "ERROR: $($_.Exception.Message)" } "{0,-44} {1}" -f $owner, $p } else { "(missing: $p)" } } - name: Show safe.directory entries # `actions/checkout`'s safe.directory add is only durable for the # checkout itself (it writes under a throwaway HOME override and # then discards it), so by the time this step runs the runner # user's `~/.gitconfig` has no entries -- and git accepts the # workspace's ownership anyway: Git for Windows via its # Admins-group exemption on the windows matrix; on Linux/macOS # the workspace is owned by the test user. Expected: `(none)`. run: git config --global --get-all safe.directory || echo "(none)" - name: Show version and platform information run: | uname -a command -v git python git version python --version python -c 'import os, sys; print(f"{sys.platform=}, {os.name=}")' # For debugging hook tests on native Windows systems that may have WSL. - name: Show bash.exe candidates (Windows) if: matrix.os-type == 'windows' run: | set +e bash.exe -c 'printenv WSL_DISTRO_NAME; uname -a' python -c 'import subprocess; subprocess.run(["bash.exe", "-c", "printenv WSL_DISTRO_NAME; uname -a"])' continue-on-error: true - name: Check types with mypy if: matrix.python-version != '3.8' run: | mypy --python-version="${PYTHON_VERSION%t}" # Version only, with no "t" for free-threaded. env: MYPY_FORCE_COLOR: "1" TERM: "xterm-256color" # For color: https://github.com/python/mypy/issues/13817 PYTHON_VERSION: ${{ matrix.python-version }} - name: Check types with basedpyright if: matrix.os-type == 'ubuntu' && matrix.python-version == '3.12' run: | basedpyright --warnings - name: Test with pytest run: | if [[ "$RUNNER_OS" == "Windows" && -z "${GIT_PYTHON_GIT_EXECUTABLE+x}" ]]; then # Absolute paths let Windows share minimum-version probes. git_executable="$(python -c 'import os, shutil; print(os.path.abspath(shutil.which("git")))')" export GIT_PYTHON_GIT_EXECUTABLE="$git_executable" fi pytest --color=yes -p no:sugar --instafail -vv --durations=30 \ --junitxml=test-results/pytest.xml --backend-report=test-results/backend.json continue-on-error: false - name: Retain test results and backend operation counts if: always() uses: actions/upload-artifact@v7 with: name: tests-${{ matrix.os-type }}-${{ matrix.python-version }}-${{ matrix.backend }} path: test-results/ - name: Documentation if: matrix.build-docs run: | pip install --group doc make -C doc html import-smoke: name: install/import (${{ matrix.os }}, ${{ matrix.python }}) runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] python: ["3.8", "3.9", "3.10"] env: GIT_PYTHON_BACKEND: cli steps: - uses: actions/checkout@v7 - uses: actions/setup-python@v7 with: python-version: ${{ matrix.python }} - name: Install the supported runtime run: python -m pip install . - name: Import the installed package run: python -I -c "import git; from git import _backend; assert _backend.name == 'cli'; print(git.__version__)"