From 25d0e0335e93fd5b995e1f0022363d5234a55614 Mon Sep 17 00:00:00 2001 From: Seth Michael Larson Date: Wed, 6 May 2026 08:45:36 -0500 Subject: [PATCH 1/4] Use 'uv.lock' for dependency lock in Docker --- Dockerfile | 20 ++++++++++++------- Dockerfile.cabotage | 25 +++++++++++++++-------- Makefile | 14 ++++++------- bootstrap-requirements.in | 3 +++ bootstrap-requirements.txt | 41 ++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 4 ++-- 6 files changed, 83 insertions(+), 24 deletions(-) create mode 100644 bootstrap-requirements.in create mode 100644 bootstrap-requirements.txt diff --git a/Dockerfile b/Dockerfile index 925a7d1e5..9accace4b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,16 +32,22 @@ RUN case $(uname -m) in \ RUN mkdir /code WORKDIR /code -RUN pip --no-cache-dir --disable-pip-version-check install --upgrade pip setuptools wheel +COPY bootstrap-requirements.txt /code/ -COPY pyproject.toml /code/ +RUN pip --no-cache-dir --disable-pip-version-check install \ + -r bootstrap-requirements.txt -RUN --mount=type=cache,target=/root/.cache/pip \ +COPY pyproject.toml uv.lock /code/ + +RUN --mount=type=cache,target=/root/.cache \ set -x \ - && pip --disable-pip-version-check \ - install --group dev \ - . + && uv sync \ + --frozen \ + --no-editable \ + --no-install-project COPY . /code/ -RUN pip --disable-pip-version-check install --no-deps -e '.' +RUN uv sync \ + --frozen \ + --no-editable diff --git a/Dockerfile.cabotage b/Dockerfile.cabotage index 614654d25..bc97f1e61 100644 --- a/Dockerfile.cabotage +++ b/Dockerfile.cabotage @@ -33,17 +33,26 @@ RUN case $(uname -m) in \ RUN mkdir /code WORKDIR /code -RUN pip --no-cache-dir --disable-pip-version-check install --upgrade pip setuptools wheel +COPY bootstrap-requirements.txt /code/ -COPY pyproject.toml /code/ +RUN pip --no-cache-dir --disable-pip-version-check install \ + -r bootstrap-requirements.txt -RUN --mount=type=cache,target=/root/.cache/pip \ +COPY pyproject.toml uv.lock /code/ + +RUN --mount=type=cache,target=/root/.cache \ set -x \ - && pip --disable-pip-version-check \ - install \ - '.[prod]' + && uv sync \ + --frozen \ + --no-editable \ + --no-dev \ + --no-install-project COPY . /code/ -RUN pip --disable-pip-version-check install --no-deps '.' -RUN DJANGO_SETTINGS_MODULE=pydotorg.settings.static python manage.py collectstatic --noinput +RUN uv sync \ + --frozen \ + --no-editable \ + --no-dev + +RUN DJANGO_SETTINGS_MODULE=pydotorg.settings.static uv run python manage.py collectstatic --noinput diff --git a/Makefile b/Makefile index 77c976d48..42af8f689 100644 --- a/Makefile +++ b/Makefile @@ -16,8 +16,8 @@ help: ## Display this help text mkdir -p .state && touch .state/db-migrated .state/db-initialized: .state/docker-build-web .state/db-migrated - docker compose run --rm web ./manage.py createcachetable - docker compose run --rm web ./manage.py loaddata fixtures/*.json + docker compose run --rm web uv run ./manage.py createcachetable + docker compose run --rm web uv run ./manage.py loaddata fixtures/*.json mkdir -p .state && touch .state/db-initialized # ============================================================================= @@ -30,16 +30,16 @@ serve: .state/db-initialized ## Start the application docker compose up --remove-orphans migrations: .state/db-initialized ## Generate migrations from models - docker compose run --rm web ./manage.py makemigrations + docker compose run --rm web uv run ./manage.py makemigrations migrate: .state/docker-build-web ## Run Django migrate - docker compose run --rm web ./manage.py migrate + docker compose run --rm web uv run ./manage.py migrate manage: .state/db-initialized ## Run arbitrary manage.py commands - docker compose run --rm web ./manage.py $(filter-out $@,$(MAKECMDGOALS)) + docker compose run --rm web uv run ./manage.py $(filter-out $@,$(MAKECMDGOALS)) shell: .state/db-initialized ## Open Django interactive shell - docker compose run --rm web ./manage.py shell + docker compose run --rm web uv run ./manage.py shell docker_shell: .state/db-initialized ## Open bash in web container docker compose run --rm web /bin/bash @@ -61,7 +61,7 @@ fmt: ## Run ruff formatter @if command -v ruff >/dev/null 2>&1; then ruff format .; else docker compose run --rm web ruff format .; fi test: .state/db-initialized ## Run test suite - docker compose run --rm web ./manage.py test + docker compose run --rm web uv run python ./manage.py test ci: lint fmt test ## Run lint, fmt, then tests diff --git a/bootstrap-requirements.in b/bootstrap-requirements.in new file mode 100644 index 000000000..97e50b704 --- /dev/null +++ b/bootstrap-requirements.in @@ -0,0 +1,3 @@ +uv +setuptools +wheel diff --git a/bootstrap-requirements.txt b/bootstrap-requirements.txt new file mode 100644 index 000000000..cf6346662 --- /dev/null +++ b/bootstrap-requirements.txt @@ -0,0 +1,41 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# pip-compile --allow-unsafe --generate-hashes --output-file=bootstrap-requirements.txt bootstrap-requirements.in +# +packaging==26.2 \ + --hash=sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e \ + --hash=sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661 + # via wheel +uv==0.11.8 \ + --hash=sha256:0172b5215544844cd3db0fa3c73a2eb74999b3f00cd2527dde578725076d7b65 \ + --hash=sha256:306c624c68d95dd7ea3647675323d72c1abc25f91c3e92ae4cd6f0f11b508726 \ + --hash=sha256:41fbba287efcc9bc9505a60549b3a223220da720eacd03be8c23d9daaafa44f4 \ + --hash=sha256:8278144df8d80a83f770c264a5e79ea50791316d2a0dda869e53b3c1174142a8 \ + --hash=sha256:841ecbb38532698f73b14b49dc5f0c5e756194c7fcf6e5c6b7ed3859200fe91b \ + --hash=sha256:877c9af3b3955a35ef739e5b2ba79c56dae5c4d50420a7ed908c0901e1c8c807 \ + --hash=sha256:91943e77fc962752d4f64ad5739219858395981078051c740b28b52963b366aa \ + --hash=sha256:a4421e27e81f85bce3bdb75986c38b5f9bfab9cdccaf3d977cf124b3f0f0b989 \ + --hash=sha256:a53e704a780a9e78a50f5a880e99a690f84e6fb9e82610903ce26f47c271d74c \ + --hash=sha256:a9853456696d579f206135c9dda7227a6ed8311b8a9a0b9b2008c4ae81950efe \ + --hash=sha256:ad381228b0170ef9646902c7e908d4a10a7ecc3da8139450506cf70c7e7f3e80 \ + --hash=sha256:b3494ad32465f4e02259cfb104d24efe5bb8f7a782351f0354de9385415fb310 \ + --hash=sha256:b3ff2b20c1897105ebe7ed7f9b1b331c7171da029bc1e35970ce31dc086141c1 \ + --hash=sha256:bb2cf302b8503629aab6f0090a05551e6f8cfc2d687ca059cad7ec9e11214335 \ + --hash=sha256:d414fc3795b6f56fb6b1fa359537930924fdfe857750a144d2aedf3077be3f1d \ + --hash=sha256:d97bb2920d6cddc07faa475013461294cc09b77ec8139278416c6e54b938d037 \ + --hash=sha256:e71c1dd23cbb480f3952c3a95b4fd00f96bd618e2a94583fc9388c500af3070d \ + --hash=sha256:f0d402e182ab581e934c159cc9edf25ec6e08d32f29aa797980e949afefc87cd \ + --hash=sha256:fb6a755305eb1e081dfe6a8bc007dbae2d26fe75e551656ca7c9cd08fba21d26 + # via -r bootstrap-requirements.in +wheel==0.47.0 \ + --hash=sha256:212281cab4dff978f6cedd499cd893e1f620791ca6ff7107cf270781e587eced \ + --hash=sha256:cc72bd1009ba0cf63922e28f94d9d83b920aa2bb28f798a31d0691b02fa3c9b3 + # via -r bootstrap-requirements.in + +# The following packages are considered to be unsafe in a requirements file: +setuptools==82.0.1 \ + --hash=sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9 \ + --hash=sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb + # via -r bootstrap-requirements.in diff --git a/docker-compose.yml b/docker-compose.yml index 1f5ea36b4..38c3cebb5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,7 +23,7 @@ services: web: build: . image: pythondotorg:docker-compose - command: python manage.py runserver 0.0.0.0:8000 + command: uv run python manage.py runserver 0.0.0.0:8000 volumes: - .:/code ports: @@ -39,7 +39,7 @@ services: worker: image: pythondotorg:docker-compose - command: celery -A pydotorg worker -B -l INFO --scheduler django_celery_beat.schedulers:DatabaseScheduler + command: uv run celery -A pydotorg worker -B -l INFO --scheduler django_celery_beat.schedulers:DatabaseScheduler volumes: - .:/code environment: From 62b26bb9b102c5cf363befd4906ac785a8c9e940 Mon Sep 17 00:00:00 2001 From: Jacob Coffee Date: Wed, 6 May 2026 10:46:33 -0500 Subject: [PATCH 2/4] single tool, pin hash --- Dockerfile | 5 +---- Dockerfile.cabotage | 9 ++++----- bootstrap-requirements.in | 3 --- bootstrap-requirements.txt | 41 -------------------------------------- 4 files changed, 5 insertions(+), 53 deletions(-) delete mode 100644 bootstrap-requirements.in delete mode 100644 bootstrap-requirements.txt diff --git a/Dockerfile b/Dockerfile index 9accace4b..05a883227 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,10 +32,7 @@ RUN case $(uname -m) in \ RUN mkdir /code WORKDIR /code -COPY bootstrap-requirements.txt /code/ - -RUN pip --no-cache-dir --disable-pip-version-check install \ - -r bootstrap-requirements.txt +COPY --from=ghcr.io/astral-sh/uv@sha256:3b7b60a81d3c57ef471703e5c83fd4aaa33abcd403596fb22ab07db85ae91347 /uv /uvx /usr/local/bin/ COPY pyproject.toml uv.lock /code/ diff --git a/Dockerfile.cabotage b/Dockerfile.cabotage index bc97f1e61..45d86c0d4 100644 --- a/Dockerfile.cabotage +++ b/Dockerfile.cabotage @@ -33,10 +33,7 @@ RUN case $(uname -m) in \ RUN mkdir /code WORKDIR /code -COPY bootstrap-requirements.txt /code/ - -RUN pip --no-cache-dir --disable-pip-version-check install \ - -r bootstrap-requirements.txt +COPY --from=ghcr.io/astral-sh/uv@sha256:3b7b60a81d3c57ef471703e5c83fd4aaa33abcd403596fb22ab07db85ae91347 /uv /uvx /usr/local/bin/ COPY pyproject.toml uv.lock /code/ @@ -46,6 +43,7 @@ RUN --mount=type=cache,target=/root/.cache \ --frozen \ --no-editable \ --no-dev \ + --extra prod \ --no-install-project COPY . /code/ @@ -53,6 +51,7 @@ COPY . /code/ RUN uv sync \ --frozen \ --no-editable \ - --no-dev + --no-dev \ + --extra prod RUN DJANGO_SETTINGS_MODULE=pydotorg.settings.static uv run python manage.py collectstatic --noinput diff --git a/bootstrap-requirements.in b/bootstrap-requirements.in deleted file mode 100644 index 97e50b704..000000000 --- a/bootstrap-requirements.in +++ /dev/null @@ -1,3 +0,0 @@ -uv -setuptools -wheel diff --git a/bootstrap-requirements.txt b/bootstrap-requirements.txt deleted file mode 100644 index cf6346662..000000000 --- a/bootstrap-requirements.txt +++ /dev/null @@ -1,41 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.12 -# by the following command: -# -# pip-compile --allow-unsafe --generate-hashes --output-file=bootstrap-requirements.txt bootstrap-requirements.in -# -packaging==26.2 \ - --hash=sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e \ - --hash=sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661 - # via wheel -uv==0.11.8 \ - --hash=sha256:0172b5215544844cd3db0fa3c73a2eb74999b3f00cd2527dde578725076d7b65 \ - --hash=sha256:306c624c68d95dd7ea3647675323d72c1abc25f91c3e92ae4cd6f0f11b508726 \ - --hash=sha256:41fbba287efcc9bc9505a60549b3a223220da720eacd03be8c23d9daaafa44f4 \ - --hash=sha256:8278144df8d80a83f770c264a5e79ea50791316d2a0dda869e53b3c1174142a8 \ - --hash=sha256:841ecbb38532698f73b14b49dc5f0c5e756194c7fcf6e5c6b7ed3859200fe91b \ - --hash=sha256:877c9af3b3955a35ef739e5b2ba79c56dae5c4d50420a7ed908c0901e1c8c807 \ - --hash=sha256:91943e77fc962752d4f64ad5739219858395981078051c740b28b52963b366aa \ - --hash=sha256:a4421e27e81f85bce3bdb75986c38b5f9bfab9cdccaf3d977cf124b3f0f0b989 \ - --hash=sha256:a53e704a780a9e78a50f5a880e99a690f84e6fb9e82610903ce26f47c271d74c \ - --hash=sha256:a9853456696d579f206135c9dda7227a6ed8311b8a9a0b9b2008c4ae81950efe \ - --hash=sha256:ad381228b0170ef9646902c7e908d4a10a7ecc3da8139450506cf70c7e7f3e80 \ - --hash=sha256:b3494ad32465f4e02259cfb104d24efe5bb8f7a782351f0354de9385415fb310 \ - --hash=sha256:b3ff2b20c1897105ebe7ed7f9b1b331c7171da029bc1e35970ce31dc086141c1 \ - --hash=sha256:bb2cf302b8503629aab6f0090a05551e6f8cfc2d687ca059cad7ec9e11214335 \ - --hash=sha256:d414fc3795b6f56fb6b1fa359537930924fdfe857750a144d2aedf3077be3f1d \ - --hash=sha256:d97bb2920d6cddc07faa475013461294cc09b77ec8139278416c6e54b938d037 \ - --hash=sha256:e71c1dd23cbb480f3952c3a95b4fd00f96bd618e2a94583fc9388c500af3070d \ - --hash=sha256:f0d402e182ab581e934c159cc9edf25ec6e08d32f29aa797980e949afefc87cd \ - --hash=sha256:fb6a755305eb1e081dfe6a8bc007dbae2d26fe75e551656ca7c9cd08fba21d26 - # via -r bootstrap-requirements.in -wheel==0.47.0 \ - --hash=sha256:212281cab4dff978f6cedd499cd893e1f620791ca6ff7107cf270781e587eced \ - --hash=sha256:cc72bd1009ba0cf63922e28f94d9d83b920aa2bb28f798a31d0691b02fa3c9b3 - # via -r bootstrap-requirements.in - -# The following packages are considered to be unsafe in a requirements file: -setuptools==82.0.1 \ - --hash=sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9 \ - --hash=sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb - # via -r bootstrap-requirements.in From 175d12c6661bc6d7ccff0911ad7895decbcaa56d Mon Sep 17 00:00:00 2001 From: Jacob Coffee Date: Wed, 6 May 2026 12:38:41 -0500 Subject: [PATCH 3/4] update docker too --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 59f10472d..164cd1cf0 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -17,3 +17,9 @@ updates: interval: weekly cooldown: default-days: 7 +- package-ecosystem: docker + directory: "/" + schedule: + interval: weekly + cooldown: + default-days: 7 From aff5e1eff8bb9d432c22fd69b9a4445b47d282cc Mon Sep 17 00:00:00 2001 From: Jacob Coffee Date: Wed, 6 May 2026 12:38:59 -0500 Subject: [PATCH 4/4] move to FROM so dependabot can get it --- Dockerfile | 4 +++- Dockerfile.cabotage | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 05a883227..7cd2998b0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,5 @@ +FROM ghcr.io/astral-sh/uv:0.11.8@sha256:3b7b60a81d3c57ef471703e5c83fd4aaa33abcd403596fb22ab07db85ae91347 AS uv + FROM python:3.12.6-bookworm ENV PYTHONUNBUFFERED=1 ENV PYTHONDONTWRITEBYTECODE=1 @@ -32,7 +34,7 @@ RUN case $(uname -m) in \ RUN mkdir /code WORKDIR /code -COPY --from=ghcr.io/astral-sh/uv@sha256:3b7b60a81d3c57ef471703e5c83fd4aaa33abcd403596fb22ab07db85ae91347 /uv /uvx /usr/local/bin/ +COPY --from=uv /uv /uvx /usr/local/bin/ COPY pyproject.toml uv.lock /code/ diff --git a/Dockerfile.cabotage b/Dockerfile.cabotage index 45d86c0d4..d900f4bc7 100644 --- a/Dockerfile.cabotage +++ b/Dockerfile.cabotage @@ -1,3 +1,5 @@ +FROM ghcr.io/astral-sh/uv:0.11.8@sha256:3b7b60a81d3c57ef471703e5c83fd4aaa33abcd403596fb22ab07db85ae91347 AS uv + FROM python:3.12.6-bookworm COPY --from=ewdurbin/nginx-static:1.25.x /usr/bin/nginx /usr/bin/nginx ENV PYTHONUNBUFFERED=1 @@ -33,7 +35,7 @@ RUN case $(uname -m) in \ RUN mkdir /code WORKDIR /code -COPY --from=ghcr.io/astral-sh/uv@sha256:3b7b60a81d3c57ef471703e5c83fd4aaa33abcd403596fb22ab07db85ae91347 /uv /uvx /usr/local/bin/ +COPY --from=uv /uv /uvx /usr/local/bin/ COPY pyproject.toml uv.lock /code/