From d7c48b06ee3fcc86155c6b49cbafd6b50ba677af Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Sat, 16 May 2026 18:33:41 +0300 Subject: [PATCH] ci: isolate test backend install in venv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The persistent Gitea runner caches the setup-python toolcache between runs. A previous run that produced wheels with broken metadata (no Version field in METADATA) left a notify-bridge-server install with no RECORD file in site-packages. The next run hits: Found existing installation: notify-bridge-server None error: uninstall-no-record-file pip refuses to uninstall (no RECORD) and refuses to overlay (it tries to uninstall first). Switching from a system-pip install into the toolcache to an isolated /tmp/venv per run sidesteps the leak — each CI run starts with empty site-packages. Same change to build.yml and release.yml so the pre-merge gate and the release-gate both run the same setup. --- .gitea/workflows/build.yml | 22 +++++++++++++--------- .gitea/workflows/release.yml | 17 ++++++++++------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 003cec5..592f612 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -50,19 +50,23 @@ jobs: # Editable installs of packages/core + packages/server are extremely slow # on the hosted runner — measured 4-6x slower than building wheels first # because hatchling's editable hook re-resolves on every collection. We - # build wheels once, then install them (and only the test deps) into a - # plain venv. The wheels themselves are NOT cached because their hashes - # depend on every file under packages/ — invalidates on basically every - # PR. Pip's HTTP cache for the test deps is enough. - - name: Build wheels + # build wheels once into an isolated venv, then install them (and only + # the test deps). The venv isolation also prevents broken-wheel installs + # from leaking dist-info across runs on the persistent Gitea runner + # (pip can't uninstall a wheel that landed without a RECORD file). The + # wheels themselves are NOT cached because their hashes depend on every + # file under packages/ — invalidates on basically every PR. Pip's HTTP + # cache for the test deps is enough. + - name: Build wheels in isolated venv run: | - python -m pip install --upgrade pip build + python -m venv /tmp/venv + /tmp/venv/bin/pip install --upgrade pip build mkdir -p /tmp/wheels - pip wheel --no-deps -w /tmp/wheels packages/core packages/server + /tmp/venv/bin/pip wheel --no-deps -w /tmp/wheels packages/core packages/server - name: Install backend + test deps run: | - pip install /tmp/wheels/*.whl pytest pytest-asyncio httpx aioresponses prometheus_client + /tmp/venv/bin/pip install /tmp/wheels/*.whl pytest pytest-asyncio httpx aioresponses prometheus_client - name: Run pytest env: @@ -72,7 +76,7 @@ jobs: NOTIFY_BRIDGE_CORS_ALLOWED_ORIGINS: "http://localhost:8420" run: | cd packages/server - pytest tests --tb=short + /tmp/venv/bin/pytest tests --tb=short build-image: if: ${{ !startsWith(gitea.event.head_commit.message, 'chore: release v') }} diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 527136d..008c2cd 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -20,17 +20,20 @@ jobs: with: python-version: "3.12" - # Same wheel-first strategy as build.yml — editable install is too slow - # on the hosted runner. - - name: Build wheels + # Wheel-first strategy in an isolated venv — editable install is too slow, + # and a plain pip install into the toolcache Python leaks state across + # runs on the persistent Gitea runner (previous broken wheel installs + # leave dist-info dirs that pip can't uninstall: "uninstall-no-record-file"). + - name: Build wheels in isolated venv run: | - python -m pip install --upgrade pip build + python -m venv /tmp/venv + /tmp/venv/bin/pip install --upgrade pip build mkdir -p /tmp/wheels - pip wheel --no-deps -w /tmp/wheels packages/core packages/server + /tmp/venv/bin/pip wheel --no-deps -w /tmp/wheels packages/core packages/server - name: Install backend + test deps run: | - pip install /tmp/wheels/*.whl pytest pytest-asyncio httpx aioresponses prometheus_client + /tmp/venv/bin/pip install /tmp/wheels/*.whl pytest pytest-asyncio httpx aioresponses prometheus_client - name: Run pytest env: @@ -40,7 +43,7 @@ jobs: NOTIFY_BRIDGE_CORS_ALLOWED_ORIGINS: "http://localhost:8420" run: | cd packages/server - pytest tests --tb=short + /tmp/venv/bin/pytest tests --tb=short release: needs: [test-backend]