fix(ci+docker): install from uv.lock — stop resolving dependencies at build time #81
+11
-11
@@ -40,6 +40,9 @@ on:
|
||||
- "frontend/**"
|
||||
- "tests/**"
|
||||
- "pyproject.toml"
|
||||
# The lock now determines what gets installed, so a lock-only change has
|
||||
# to trigger a run — otherwise a dependency bump lands untested.
|
||||
- "uv.lock"
|
||||
- "alembic/**"
|
||||
- "alembic.ini"
|
||||
- "Dockerfile"
|
||||
@@ -140,19 +143,16 @@ jobs:
|
||||
# red with no repo change (issue #2194). Green CI has to mean "these exact
|
||||
# versions passed", or it isn't evidence of anything.
|
||||
#
|
||||
# `--frozen`, not `--locked`, and that difference is a known gap: --locked
|
||||
# additionally fails when the lock is STALE against pyproject, which is the
|
||||
# guard that would catch someone editing a dependency without re-locking.
|
||||
# It can't be turned on until uv.lock is regenerated with `uv lock` — the
|
||||
# mcp cap edited pyproject, so the lock no longer matches, and this
|
||||
# workstation has no uv (or pip) to regenerate it with. --frozen still
|
||||
# delivers the reproducibility this fix is for; a forgotten re-lock shows
|
||||
# up as a loud ImportError rather than a silent version drift. Flip to
|
||||
# --locked in the same change that regenerates the lock.
|
||||
# `--locked` also FAILS when uv.lock is stale against pyproject, so a
|
||||
# dependency edit has to go through a deliberate `uv lock` — it can't
|
||||
# arrive on its own. That check earned its place immediately: it caught
|
||||
# that the lock had been missing `pgvector` entirely (added to pyproject,
|
||||
# never re-locked), which the old install path had been silently papering
|
||||
# over by resolving from pyproject instead.
|
||||
- name: Install locked dependencies
|
||||
env:
|
||||
UV_PROJECT_ENVIRONMENT: /opt/venv
|
||||
run: uv sync --frozen --extra dev
|
||||
run: uv sync --locked --extra dev
|
||||
|
||||
- name: Run tests
|
||||
# Integration tests (real Postgres) run in the `integration` job below.
|
||||
@@ -197,7 +197,7 @@ jobs:
|
||||
- name: Install locked dependencies
|
||||
env:
|
||||
UV_PROJECT_ENVIRONMENT: /opt/venv
|
||||
run: uv sync --frozen --extra dev
|
||||
run: uv sync --locked --extra dev
|
||||
- name: Integration suite (resolve service IP, migrate, test)
|
||||
run: |
|
||||
set -eux
|
||||
|
||||
@@ -354,54 +354,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scribe"
|
||||
version = "0.1.0"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "aiosmtplib" },
|
||||
{ name = "alembic" },
|
||||
{ name = "apscheduler" },
|
||||
{ name = "asyncpg" },
|
||||
{ name = "bcrypt" },
|
||||
{ name = "caldav" },
|
||||
{ name = "fastembed" },
|
||||
{ name = "httpx" },
|
||||
{ name = "hypercorn" },
|
||||
{ name = "icalendar" },
|
||||
{ name = "mcp", extra = ["cli"] },
|
||||
{ name = "quart" },
|
||||
{ name = "sqlalchemy", extra = ["asyncio"] },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
dev = [
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-asyncio" },
|
||||
{ name = "ruff" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "aiosmtplib", specifier = ">=3.0" },
|
||||
{ name = "alembic", specifier = ">=1.13" },
|
||||
{ name = "apscheduler", specifier = ">=3.10,<4.0" },
|
||||
{ name = "asyncpg", specifier = ">=0.29" },
|
||||
{ name = "bcrypt", specifier = ">=4.0" },
|
||||
{ name = "caldav", specifier = ">=1.3" },
|
||||
{ name = "fastembed", specifier = ">=0.4" },
|
||||
{ name = "httpx", specifier = ">=0.27" },
|
||||
{ name = "hypercorn", specifier = ">=0.17" },
|
||||
{ name = "icalendar", specifier = ">=5.0" },
|
||||
{ name = "mcp", extras = ["cli"], specifier = ">=1.0,<2" },
|
||||
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0" },
|
||||
{ name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.23" },
|
||||
{ name = "quart", specifier = ">=0.19" },
|
||||
{ name = "ruff", marker = "extra == 'dev'", specifier = ">=0.6" },
|
||||
{ name = "sqlalchemy", extras = ["asyncio"], specifier = ">=2.0" },
|
||||
]
|
||||
provides-extras = ["dev"]
|
||||
|
||||
[[package]]
|
||||
name = "fastembed"
|
||||
version = "0.8.0"
|
||||
@@ -1038,6 +990,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pgvector"
|
||||
version = "0.5.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a7/ec/6eb80aebc728200f95229219882994c1b0585b956ca47da5edb9d062627a/pgvector-0.5.0.tar.gz", hash = "sha256:07a9dcf735696879406983afc6eba9a787cef7c0cf6c367ca1a5779f036dee74", size = 35170, upload-time = "2026-07-06T18:27:27.767Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/e4/a5573f2c579ca9ad133293bfb624148ba0893674ca4a6eeec85ced9a6a09/pgvector-0.5.0-py3-none-any.whl", hash = "sha256:fedc9800894e6da2be51358d7b7c574bf34f247ca741a5a09513622135f5964f", size = 30958, upload-time = "2026-07-06T18:27:26.797Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pillow"
|
||||
version = "12.2.0"
|
||||
@@ -1496,6 +1457,56 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/58/ed/dea90a65b7d9e69888890fb14c90d7f51bf0c1e82ad800aeb0160e4bacfd/ruff-0.15.10-py3-none-win_arm64.whl", hash = "sha256:601d1610a9e1f1c2165a4f561eeaa2e2ea1e97f3287c5aa258d3dab8b57c6188", size = 11035607, upload-time = "2026-04-09T14:05:47.593Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scribe"
|
||||
version = "0.1.0"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "aiosmtplib" },
|
||||
{ name = "alembic" },
|
||||
{ name = "apscheduler" },
|
||||
{ name = "asyncpg" },
|
||||
{ name = "bcrypt" },
|
||||
{ name = "caldav" },
|
||||
{ name = "fastembed" },
|
||||
{ name = "httpx" },
|
||||
{ name = "hypercorn" },
|
||||
{ name = "icalendar" },
|
||||
{ name = "mcp", extra = ["cli"] },
|
||||
{ name = "pgvector" },
|
||||
{ name = "quart" },
|
||||
{ name = "sqlalchemy", extra = ["asyncio"] },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
dev = [
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-asyncio" },
|
||||
{ name = "ruff" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "aiosmtplib", specifier = ">=3.0" },
|
||||
{ name = "alembic", specifier = ">=1.13" },
|
||||
{ name = "apscheduler", specifier = ">=3.10,<4.0" },
|
||||
{ name = "asyncpg", specifier = ">=0.29" },
|
||||
{ name = "bcrypt", specifier = ">=4.0" },
|
||||
{ name = "caldav", specifier = ">=1.3" },
|
||||
{ name = "fastembed", specifier = ">=0.4" },
|
||||
{ name = "httpx", specifier = ">=0.27" },
|
||||
{ name = "hypercorn", specifier = ">=0.17" },
|
||||
{ name = "icalendar", specifier = ">=5.0" },
|
||||
{ name = "mcp", extras = ["cli"], specifier = ">=1.0,<2" },
|
||||
{ name = "pgvector", specifier = ">=0.3" },
|
||||
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0" },
|
||||
{ name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.23" },
|
||||
{ name = "quart", specifier = ">=0.19" },
|
||||
{ name = "ruff", marker = "extra == 'dev'", specifier = ">=0.6" },
|
||||
{ name = "sqlalchemy", extras = ["asyncio"], specifier = ">=2.0" },
|
||||
]
|
||||
provides-extras = ["dev"]
|
||||
|
||||
[[package]]
|
||||
name = "shellingham"
|
||||
version = "1.5.4"
|
||||
|
||||
Reference in New Issue
Block a user