Skip to content

Commit 916622b

Browse files
EliahKaganclaude
andcommitted
ci: run tox weekly and on demand
The main CI does not use tox, so the tox configuration can break without anyone noticing. It has: `tox -e html` stopped working when 9e54de4 (gitpython-developers#2243) removed the `doc` extra, `tox -e misc` ran `ruff check` again after b7ce712 (gitpython-developers#2031) changed that hook's id, and the `base_python` fallbacks did not mean what they said from 62c024e (gitpython-developers#1693) on. New releases of tox and virtualenv can also change how the configuration behaves, as when tox 4.56.0 made missing interpreters fail. But running every tox environment is too slow for every push and pull request. Add a `tox` workflow that runs on a weekly schedule and through `workflow_dispatch`. Each job runs the tox environments for one Python version, from 3.8 to 3.15, on Ubuntu. 3.8 and 3.9 run on `ubuntu-24.04`, since `setup-python` has no builds of them for Ubuntu 26.04. The 3.13 job also runs `gix`, `ruff`, `format`, `mypy`, `html`, and `misc`. `gix` goes there because its `base_python` is `python3`, which virtualenv satisfies with the Python that tox itself runs on, which here is 3.13, as described below. The steps that prepare for the tests (Rust for GixPython source builds, current Git from the git-core PPA, `init-tests-after-clone.sh`, and the test Git identity and aliases) are the same as in `pythonpackage.yml`. tox and the plugin used below both need Python 3.11 or later, so `setup-python` also installs Python 3.13, and tox runs on that. tox is installed unpinned, so that the workflow tests the configuration with the tox and virtualenv that a contributor would get. The job has only `contents: read` and uses no secrets. To select each job's environments, use `tox-gh`, from the `tox-dev` organization that maintains tox. It reads a mapping from Python versions to environments, here in `[tool.tox.gh.python]`, puts each environment's output in its own log group, and does nothing outside GitHub Actions. The job sets `TOX_GH_MAJOR_MINOR` to the matrix version, as `tox-gh` documents for when tox runs on a different Python. The alternatives were `tox-gh-actions`, an older plugin maintained outside `tox-dev` whose extra ways of selecting environments this project does not need, and `fedora-python/tox-github-action`, which runs tox as root in a Fedora container that no longer has Python 3.8, pulled by a mutable tag, from a repository with no license. Running as root would also change what GitPython's tests see about file ownership and `safe.directory`. The configuration sets `skip_missing_interpreters = true`, so that local runs skip Python versions that are not installed. A job here must not skip, since it exists to test one Python version, so pass `--skip-missing-interpreters=false`. The option's value is optional, and a bare `--skip-missing-interpreters` means `true`, so the `=` form makes clear that `false` is its value. Give each job `timeout-minutes: 60`, so that a hang, such as a stuck test, Git fetch, or build, stops long before GitHub's default of 6 hours. That should only stop a job that has hung. The `test` jobs on Ubuntu in `pythonpackage.yml` take about 4 to 9 minutes, with a warm Cargo cache. Here there is no Cargo cache, each job for Python 3.11 or later builds GixPython from source, and the 3.13 job runs seven environments. `actionlint`, `zizmor` 1.31.1 (pedantic, with online audits), and `pinact run --check --verify-comment` report nothing for the new workflow, and all pre-commit hooks pass. With `GITHUB_ACTIONS=true` set locally, tox with `tox-gh` ran only `py38` for `TOX_GH_MAJOR_MINOR=3.8`, in its own log group. In a minimal project with `skip_missing_interpreters = true` and `tox-gh` active, a job whose mapped environment had no interpreter failed with `--skip-missing-interpreters=false`. `workflow_dispatch` and `schedule` only work once the workflow is on the default branch, so it was run on a fork through a temporary `push` trigger. Run that way with this branch's other changes, every job passed. In the latest run, the 3.13 job took about 13 minutes, the other jobs for 3.11 and later 8 to 9 minutes, and the 3.8, 3.9, and 3.10 jobs about a minute or less. Earlier runs, before the tests of `tox -e gix` could use the package index, failed only in `gix`. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 9fbf521 commit 916622b

2 files changed

Lines changed: 109 additions & 1 deletion

File tree

‎.github/workflows/tox.yml‎

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
name: tox
2+
3+
# The main CI does not use tox, so this checks that the tox configuration still
4+
# works, including with new releases of tox and virtualenv. That is too slow to
5+
# run on every push and pull request, so it runs weekly and on demand.
6+
on:
7+
schedule:
8+
- cron: "37 5 * * 1" # Mondays at 05:37 UTC.
9+
workflow_dispatch:
10+
11+
permissions:
12+
contents: read
13+
14+
jobs:
15+
tox:
16+
name: tox (${{ matrix.python-version }})
17+
18+
strategy:
19+
matrix:
20+
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "3.15"]
21+
include:
22+
# setup-python has no builds of these versions for Ubuntu 26.04.
23+
- python-version: "3.8"
24+
os: ubuntu-24.04
25+
- python-version: "3.9"
26+
os: ubuntu-24.04
27+
28+
fail-fast: false
29+
30+
runs-on: ${{ matrix.os || 'ubuntu-latest' }}
31+
timeout-minutes: 60
32+
33+
defaults:
34+
run:
35+
shell: bash --noprofile --norc -exo pipefail {0}
36+
37+
steps:
38+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
39+
with:
40+
fetch-depth: 0
41+
persist-credentials: false
42+
43+
- name: Set up Python ${{ matrix.python-version }}, and Python 3.13 for tox
44+
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
45+
with:
46+
# Current tox does not run on some of the versions it tests, so it gets
47+
# its own interpreter. The last version listed becomes the default.
48+
python-version: |
49+
3.13
50+
${{ matrix.python-version }}
51+
allow-prereleases: true
52+
53+
- name: Prepare Rust for GixPython source builds
54+
run: |
55+
# GixPython 0.3.0 publishes macOS wheels only and needs Rust >= 1.89.
56+
rustup toolchain install stable --profile minimal
57+
rustup default stable
58+
rustc --version
59+
60+
- name: Install current Git
61+
run: |
62+
sudo add-apt-repository --yes ppa:git-core/ppa
63+
sudo apt-get update
64+
sudo apt-get install --yes git
65+
66+
- name: Prepare this repo for tests
67+
run: |
68+
./init-tests-after-clone.sh
69+
70+
- name: Set git user identity and command aliases for the tests
71+
run: |
72+
git config --global user.email "travis@ci.com"
73+
git config --global user.name "Travis Runner"
74+
# If we rewrite the user's config by accident, we will mess it up
75+
# and cause subsequent tests to fail
76+
cat test/fixtures/.gitconfig >> ~/.gitconfig
77+
78+
- name: Install tox
79+
# Unpinned on purpose, to find out when a new tox breaks the configuration.
80+
run: |
81+
python3.13 -m pip install tox tox-gh
82+
83+
- name: Show version and platform information
84+
run: |
85+
uname -a
86+
git version
87+
python --version
88+
python3.13 -m tox --version
89+
90+
- name: Run tox
91+
run: |
92+
# Fail, rather than skip, if an environment's Python is missing.
93+
python3.13 -m tox --skip-missing-interpreters=false
94+
env:
95+
# tox-gh selects the environments mapped to this version in `[tool.tox.gh.python]`.
96+
TOX_GH_MAJOR_MINOR: ${{ matrix.python-version }}

‎pyproject.toml‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ env_list = py{38,39,310,311,312,313,314,315}, ruff, format, mypy, html, misc, gi
173173
[testenv:.tox]
174174
base_python = py314, py313, py312, py311, py310, py315
175175
"""
176-
# Skip environments whose Python is not installed.
176+
# Skip environments whose Python is not installed. The `tox` workflow overrides this.
177177
skip_missing_interpreters = true
178178
env_list = [
179179
"py38",
@@ -282,3 +282,15 @@ skip_install = true
282282
deps = ["pre-commit"]
283283
set_env = { SKIP = "ruff-format,ruff-check" }
284284
commands = [["pre-commit", "run", "--all-files"]]
285+
286+
# Environments that the `tox` workflow runs for each Python version, via tox-gh.
287+
# tox-gh does nothing outside GitHub Actions.
288+
[tool.tox.gh.python]
289+
"3.8" = ["py38"]
290+
"3.9" = ["py39"]
291+
"3.10" = ["py310"]
292+
"3.11" = ["py311"]
293+
"3.12" = ["py312"]
294+
"3.13" = ["py313", "gix", "ruff", "format", "mypy", "html", "misc"]
295+
"3.14" = ["py314"]
296+
"3.15" = ["py315"]

0 commit comments

Comments
 (0)