From b0b9ef0c862e9d82df7a0633bbf94d92e018079c Mon Sep 17 00:00:00 2001 From: Teknium Date: Fri, 17 Apr 2026 04:21:02 -0700 Subject: [PATCH] ci: split Tests workflow into 4 parallel shards via pytest-split MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reduces CI wall time by running the test suite as 4 parallel matrix jobs instead of a single job. Each shard runs ~3,000 tests in parallel, so total wall time drops from ~4min to ~60-90s. Changes: - Add pytest-split to dev extras (deterministic test splitting, composes with pytest-xdist's -n auto inside each shard). - Matrix-split tests.yml 'test' job into 4 groups. Each shard runs 'pytest ... --splits 4 --group N' and parallelizes inside with the -n auto already in pyproject.toml's addopts. - fail-fast: false so all shards finish even if one fails (consistent with current behavior when there's no matrix). Expected CI timing: Before: 243s single-job (4m03s) After: ~60-90s per shard in parallel + ~25s install overhead \u2192 total CI ~90-115s No test-file changes. Deterministic hash-based distribution (no .test_durations file yet; can add one later for better balance). The e2e job is unchanged — it's already small (20s) and runs separately. --- .github/workflows/tests.yml | 10 ++++++++-- pyproject.toml | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7d0822690..2dde22745 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,8 +16,13 @@ concurrency: jobs: test: + name: test (${{ matrix.group }}/4) runs-on: ubuntu-latest timeout-minutes: 10 + strategy: + fail-fast: false + matrix: + group: [1, 2, 3, 4] steps: - name: Checkout code uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 @@ -37,10 +42,11 @@ jobs: source .venv/bin/activate uv pip install -e ".[all,dev]" - - name: Run tests + - name: Run tests (shard ${{ matrix.group }}/4) run: | source .venv/bin/activate - python -m pytest tests/ -q --ignore=tests/integration --ignore=tests/e2e --tb=short -n auto + python -m pytest tests/ -q --ignore=tests/integration --ignore=tests/e2e --tb=short \ + --splits 4 --group ${{ matrix.group }} env: # Ensure tests don't accidentally call real APIs OPENROUTER_API_KEY: "" diff --git a/pyproject.toml b/pyproject.toml index a1c46950f..d44b45b0a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ dependencies = [ [project.optional-dependencies] modal = ["modal>=1.0.0,<2"] daytona = ["daytona>=0.148.0,<1"] -dev = ["debugpy>=1.8.0,<2", "pytest>=9.0.2,<10", "pytest-asyncio>=1.3.0,<2", "pytest-xdist>=3.0,<4", "mcp>=1.2.0,<2"] +dev = ["debugpy>=1.8.0,<2", "pytest>=9.0.2,<10", "pytest-asyncio>=1.3.0,<2", "pytest-xdist>=3.0,<4", "pytest-split>=0.9,<1", "mcp>=1.2.0,<2"] messaging = ["python-telegram-bot[webhooks]>=22.6,<23", "discord.py[voice]>=2.7.1,<3", "aiohttp>=3.13.3,<4", "slack-bolt>=1.18.0,<2", "slack-sdk>=3.27.0,<4"] cron = ["croniter>=6.0.0,<7"] slack = ["slack-bolt>=1.18.0,<2", "slack-sdk>=3.27.0,<4"]