diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 34bc5b6..e0b020d 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -7,8 +7,28 @@ on: branches: [main] jobs: + # mypy and pylint check the whole repo and are the two slowest hooks, so + # each gets its own runner and the other hooks share a third; the workflow + # takes as long as the slowest group rather than the sum. pre-commit: runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - group: mypy + hooks: mypy + skip: "" + - group: pylint + hooks: pylint + skip: "" + # free-days-interop needs Flutter and the freedays venv; it runs as + # its own job in python-tests.yml, so skipping it here is not + # fail-open. + - group: rest + hooks: "" + skip: mypy,pylint,free-days-interop + name: pre-commit (${{ matrix.group }}) steps: - uses: actions/checkout@v4 @@ -27,10 +47,25 @@ jobs: - uses: actions/setup-python@v5 with: python-version: "3.x" - - name: Install dependencies - run: pip install -r requirements.txt - # free-days-interop needs Flutter and the freedays venv; it runs as its - # own job in python-tests.yml, so skipping it here is not fail-open. - - uses: pre-commit/action@v3.0.1 + - uses: astral-sh/setup-uv@v10.2.0 + + # Every hook brings its own environment except the language: system + # ones; of those only dependency-freshness imports third-party code + # (pyyaml, packaging). The whole requirements.txt used to be installed + # here for nothing -- 28 s of a 60 s run. + - name: Install pre-commit and the system hooks' imports + run: uv pip install --system pre-commit pyyaml packaging + + # One cache per group: a shared key would hold whichever group saved + # first, and the others would rebuild their hook envs on every run. The + # restore key lets a config change reuse every env whose rev it kept. + - uses: actions/cache@v4 + with: + path: ~/.cache/pre-commit + key: pre-commit-${{ matrix.group }}-${{ env.pythonLocation }}-${{ hashFiles('.pre-commit-config.yaml') }} + restore-keys: pre-commit-${{ matrix.group }}-${{ env.pythonLocation }}- + + - name: pre-commit run (${{ matrix.group }}) env: - SKIP: free-days-interop + SKIP: ${{ matrix.skip }} + run: pre-commit run ${{ matrix.hooks }} --all-files --show-diff-on-failure --color=always diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index bb46833..57d9cb5 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -17,11 +17,22 @@ jobs: with: python-version: "3.x" - - name: Install dependencies - run: pip install -r requirements.txt + # uv with a cached wheel store (and cached builds of the three + # git+ kuhyx/utils packages) installs requirements.txt in seconds; + # plain pip took 22 s of a 32 s job. + - uses: astral-sh/setup-uv@v10.2.0 + with: + enable-cache: true + cache-dependency-glob: requirements.txt + - name: Install dependencies + run: uv pip install --system -r requirements.txt + + # No -n auto: the whole suite runs in ~0.5 s, and under pytest-xdist it + # measured ~1.2 s locally (worker start-up outweighs the parallelism). + # Coverage and its 100% bar come from pyproject.toml's addopts. - name: Run tests with coverage - run: python -m pytest -v + run: python -m pytest -q -p no:sugar # The Dart free-day rules are a port of ~/src/utils/freedays. This is the # cross-language gate (scripts/free_days_interop/check.sh): it needs both @@ -42,11 +53,21 @@ jobs: with: python-version: "3.x" + # This job is the workflow's critical path (the Flutter SDK restore and + # the Dart test are its floor); uv builds the venv in a couple of + # seconds where venv + pip took 12 s. + - uses: astral-sh/setup-uv@v10.2.0 + with: + enable-cache: true + cache-dependency-glob: | + .utils/crdt-sync/pyproject.toml + .utils/freedays/pyproject.toml + - name: Install freedays into its own venv run: | - python -m venv .freedays-venv - .freedays-venv/bin/pip install --quiet .utils/crdt-sync - .freedays-venv/bin/pip install --quiet --no-deps .utils/freedays + uv venv --python "$pythonLocation/bin/python" .freedays-venv + uv pip install --quiet --python .freedays-venv/bin/python .utils/crdt-sync + uv pip install --quiet --python .freedays-venv/bin/python --no-deps .utils/freedays - uses: subosito/flutter-action@v2 with: