From 58e3d8ca6b13c119fb6271c3cc396c01dec87e4e Mon Sep 17 00:00:00 2001 From: Gabor Szabo Date: Tue, 12 May 2026 02:47:26 +0200 Subject: [PATCH] fix(ci): pin uv run with --frozen to stop transient resolution failures (#95) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit every uv run invocation in ci.yml, schema-validation.yml, and phase-snapshot.yml now uses --frozen. without it, uv re-resolves the dependency graph at command time and crashes when a freshly published pydantic-ai-slim version's [mistral] extra requires a mistralai version that does not yet exist on PyPI — observed on PR #93's most recent push where all five blocking CI jobs went red 75 minutes after a green run on the same branch with the same lockfile. dependency-check.yml's pip-audit calls deliberately retain the re-resolve behavior; that workflow's purpose is to pick up newly published vulnerabilities. uv sync --frozen --all-extras --dev was already in place to install the lock; this patch propagates the same intent to every subsequent uv run. --- .github/workflows/ci.yml | 16 ++++++++-------- .github/workflows/phase-snapshot.yml | 12 ++++++------ .github/workflows/schema-validation.yml | 18 +++++++++--------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 68d9cc69..4d4321c2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,10 +48,10 @@ jobs: run: uv sync --frozen --all-extras --dev - name: Run Ruff linter - run: uv run ruff check . + run: uv run --frozen ruff check . - name: Run Ruff formatter check - run: uv run ruff format --check . + run: uv run --frozen ruff format --check . typecheck: name: Type Check @@ -74,10 +74,10 @@ jobs: run: uv sync --frozen --all-extras --dev - name: Run MyPy - run: uv run mypy app/ + run: uv run --frozen mypy app/ - name: Run Pyright - run: uv run pyright app/ + run: uv run --frozen pyright app/ test: name: Test @@ -118,13 +118,13 @@ jobs: - name: Run migrations env: DATABASE_URL: postgresql+asyncpg://forecastlab:forecastlab@localhost:5432/forecastlab_test - run: uv run alembic upgrade head + run: uv run --frozen alembic upgrade head - name: Run tests env: DATABASE_URL: postgresql+asyncpg://forecastlab:forecastlab@localhost:5432/forecastlab_test APP_ENV: testing - run: uv run pytest -v --tb=short + run: uv run --frozen pytest -v --tb=short migration-check: name: Migration Check @@ -165,12 +165,12 @@ jobs: - name: Apply migrations to fresh DB env: DATABASE_URL: postgresql+asyncpg://forecastlab:forecastlab@localhost:5432/forecastlab_migration_test - run: uv run alembic upgrade head + run: uv run --frozen alembic upgrade head - name: Verify no pending migrations env: DATABASE_URL: postgresql+asyncpg://forecastlab:forecastlab@localhost:5432/forecastlab_migration_test run: | # Check that current head matches database - uv run alembic current + uv run --frozen alembic current # This would fail if there are unapplied migrations diff --git a/.github/workflows/phase-snapshot.yml b/.github/workflows/phase-snapshot.yml index 78babdbc..792e766f 100644 --- a/.github/workflows/phase-snapshot.yml +++ b/.github/workflows/phase-snapshot.yml @@ -58,24 +58,24 @@ jobs: - name: Lint check id: lint run: | - uv run ruff check . - uv run ruff format --check . + uv run --frozen ruff check . + uv run --frozen ruff format --check . - name: Type check id: typecheck run: | - uv run mypy app/ - uv run pyright app/ + uv run --frozen mypy app/ + uv run --frozen pyright app/ - name: Run migrations id: migration - run: uv run alembic upgrade head + run: uv run --frozen alembic upgrade head - name: Run tests id: test env: APP_ENV: testing - run: uv run pytest -v --tb=short + run: uv run --frozen pytest -v --tb=short create-snapshot: name: Create Audit Snapshot diff --git a/.github/workflows/schema-validation.yml b/.github/workflows/schema-validation.yml index 4ae38ef3..a2f772bc 100644 --- a/.github/workflows/schema-validation.yml +++ b/.github/workflows/schema-validation.yml @@ -59,14 +59,14 @@ jobs: - name: Fresh DB migration test run: | echo "::group::Applying all migrations to fresh database" - uv run alembic upgrade head + uv run --frozen alembic upgrade head echo "::endgroup::" - name: Check migration chain integrity run: | echo "::group::Verifying migration chain" # Get all revision heads - should be exactly one - HEADS=$(uv run alembic heads 2>&1) + HEADS=$(uv run --frozen alembic heads 2>&1) HEAD_COUNT=$(echo "$HEADS" | grep -c "^[a-f0-9]" || true) if [ "$HEAD_COUNT" -gt 1 ]; then @@ -84,7 +84,7 @@ jobs: echo "::group::Checking for schema drift" # alembic check compares models to current DB state # Returns non-zero if autogenerate would create new migrations - if uv run alembic check 2>&1; then + if uv run --frozen alembic check 2>&1; then echo "Schema is in sync with models" else echo "::error::Schema drift detected - models don't match migrations" @@ -97,7 +97,7 @@ jobs: run: | echo "::group::Testing migration reversibility" # Get current revision - CURRENT=$(uv run alembic current 2>&1 | grep -oE "^[a-f0-9]+" | head -1) + CURRENT=$(uv run --frozen alembic current 2>&1 | grep -oE "^[a-f0-9]+" | head -1) if [ -z "$CURRENT" ]; then echo "No migrations applied, skipping cycle test" @@ -108,14 +108,14 @@ jobs: # Downgrade one step echo "Downgrading one migration..." - uv run alembic downgrade -1 + uv run --frozen alembic downgrade -1 # Upgrade back echo "Upgrading back to head..." - uv run alembic upgrade head + uv run --frozen alembic upgrade head # Verify we're back at head - FINAL=$(uv run alembic current 2>&1 | grep -oE "^[a-f0-9]+" | head -1) + FINAL=$(uv run --frozen alembic current 2>&1 | grep -oE "^[a-f0-9]+" | head -1) if [ "$CURRENT" != "$FINAL" ]; then echo "::error::Migration cycle failed - revision mismatch after downgrade/upgrade" @@ -133,10 +133,10 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY echo "### Migration History" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY - uv run alembic history --verbose 2>&1 | head -50 >> $GITHUB_STEP_SUMMARY + uv run --frozen alembic history --verbose 2>&1 | head -50 >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### Current State" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY - uv run alembic current --verbose 2>&1 >> $GITHUB_STEP_SUMMARY + uv run --frozen alembic current --verbose 2>&1 >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY