From c55172fc9d20aba866f3759391caa397db4130d9 Mon Sep 17 00:00:00 2001 From: Krzysztof kuhy Rudnicki Date: Sat, 26 Sep 2026 17:58:53 +0200 Subject: [PATCH] Split pre-commit into mypy/pylint/rest runners and install with uv pre-commit took ~119 s as one job (24 s of pip, then every hook env and every hook in series); Tests took ~56 s (26 s of pip, 7 s of apt-get for an xvfb the image already ships, 17 s of -v pytest). Same hooks, same flags, same 100% bar -- just parallel runners, cached uv wheels, xdist workers. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0188kZdx3bb56QM8JFUnbHuM --- .github/workflows/pre-commit.yml | 76 +++++++++++++++++++++++++----- .github/workflows/python-tests.yml | 27 +++++++++-- app/pubspec.yaml | 2 +- 3 files changed, 88 insertions(+), 17 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index a752d4d..0ca9d65 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -7,27 +7,77 @@ on: branches: [main] jobs: + # mypy (~17 s) and pylint (~10 s, plus ~20 s to build its hook env) checked + # the whole repo inside one ~2 min job, 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: "" + - group: rest + hooks: "" + skip: mypy,pylint + name: pre-commit (${{ matrix.group }}) steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: "3.x" - - name: Install dependencies - run: pip install -r requirements.txt - # The file-length hook delegates to the shared gate in kuhyx/utils, which - # a runner does not have at $HOME/utils. Check it out and point the shim - # at it via UTILS_ROOT, or `pre-commit run --all-files` fails on a - # missing checker rather than on anything in this repo. `.utils` is in - # the gate's own EXCLUDED_DIRS, so it does not lint itself. - - name: Check out the shared gate + # The file-length, md-naming and dependency-freshness hooks delegate to + # the shared gates in kuhyx/utils, which a runner does not have at + # $HOME/src/utils. Only the rest group runs them. + - name: Check out the shared gates + if: matrix.group == 'rest' uses: actions/checkout@v4 with: repository: kuhyx/utils path: .utils + - name: Point the delegates at that checkout + if: matrix.group == 'rest' + run: echo "UTILS_ROOT=$GITHUB_WORKSPACE/.utils" >> "$GITHUB_ENV" - - uses: pre-commit/action@v3.0.1 + - uses: actions/setup-python@v5 + with: + python-version: "3.x" + + # Only rest caches its wheels: its install is the big one, and a shared + # key would hold whichever group saved first (the suffix keeps it apart + # from the Tests workflow's cache of the same requirements.txt). + - uses: astral-sh/setup-uv@v10.2.0 + with: + enable-cache: ${{ matrix.group == 'rest' }} + cache-dependency-glob: requirements.txt + cache-suffix: pre-commit-${{ matrix.group }} + + # mypy and pylint bring their own hook environments, so they need only + # pre-commit. The rest group's language: system patch-targets hook + # imports diet_guard and every patched module (requests, gatelock, + # crdt_sync, freedays, mcp, pydantic), and dependency-freshness needs + # pyyaml and packaging -- so it keeps the full requirements.txt. That + # install used to run in the one job, with plain pip, for ~24 s. + - name: Install pre-commit and the system hooks' imports + run: | + if [[ "${{ matrix.group }}" == rest ]]; then + uv pip install --system -r requirements.txt + else + uv pip install --system pre-commit + fi + + # One cache per group: a shared key would hold whichever group saved + # first, and the others would rebuild their hook envs on every run. + - uses: actions/cache@v4 + with: + path: ~/.cache/pre-commit + key: pre-commit-${{ matrix.group }}-${{ env.pythonLocation }}-${{ hashFiles('.pre-commit-config.yaml') }} + + - name: pre-commit run (${{ matrix.group }}) env: - UTILS_ROOT: ${{ github.workspace }}/.utils + 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 51f8901..1f19d15 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -17,15 +17,36 @@ jobs: with: python-version: "3.x" + # uv with a cached wheel store installs requirements.txt (git deps + # included) in seconds; plain pip took ~26 s of a ~56 s run. + - uses: astral-sh/setup-uv@v10.2.0 + with: + enable-cache: true + cache-dependency-glob: requirements.txt + cache-suffix: tests + - name: Install dependencies - run: pip install -r requirements.txt + run: uv pip install --system -r requirements.txt # The gate's keyboard and layout tests drive real Tk: widget heights and # the focus ring come from the font engine, and no mock can answer what # they ask. Without a display they do not skip -- they fail, which is how # this job stayed red while the tests themselves were fine. + # ubuntu-latest already ships xvfb, so the unconditional + # `apt-get update && install` spent ~7 s to report "already the newest + # version"; it now installs only on an image that lacks it. - name: Install a virtual X display - run: sudo apt-get update && sudo apt-get install -y xvfb + run: | + command -v xvfb-run >/dev/null \ + || { sudo apt-get update && sudo apt-get install -y xvfb; } + # -n auto spreads the suite over every runner core (pytest-xdist is in + # requirements.txt); pytest-cov merges the workers' coverage and the + # 100% bar still comes from pyproject's fail_under. -q because -v + # printed all ~1050 test ids. - name: Run tests with coverage - run: xvfb-run -a -s "-screen 0 1600x1200x24" python -m pytest -v + run: | + xvfb-run -a -s "-screen 0 1600x1200x24" python -m pytest \ + -n auto \ + -p no:sugar \ + -q diff --git a/app/pubspec.yaml b/app/pubspec.yaml index d392d8d..e29762e 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -2,7 +2,7 @@ name: diet_guard_app description: "Companion phone app for diet_guard: log meals on the go." publish_to: 'none' -version: 1.0.90+1 +version: 1.0.91+1 environment: sdk: ^3.12.2