Skip to content

Commit

Permalink
Migrate to uv for building container
Browse files Browse the repository at this point in the history
This migrates the dependencies from requirements.in/txt to pyproject.toml and uv.lock.
  • Loading branch information
michelletran-codecov committed Feb 25, 2025
1 parent 74b3287 commit e402935
Show file tree
Hide file tree
Showing 8 changed files with 2,304 additions and 564 deletions.
22 changes: 2 additions & 20 deletions .envrc
Original file line number Diff line number Diff line change
@@ -1,20 +1,2 @@
#!/bin/bash
# shellcheck disable=SC1091

if [ ! -d .venv ]; then
echo "warning: creating virtualenv for the first time"
if which pyenv > /dev/null; then
eval "$(pyenv init -)"
pyenv install -s
else
echo "warning: pyenv not installed, using python3 and hoping for the best"
fi

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install ruff
else
source .venv/bin/activate
unset PS1
fi
uv sync
source .venv/bin/activate
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ epoch := $(shell date +"%s")

AR_REPO ?= codecov/worker
DOCKERHUB_REPO ?= codecov/self-hosted-worker
REQUIREMENTS_TAG := requirements-v1-$(shell sha1sum requirements.txt | cut -d ' ' -f 1)-$(shell sha1sum docker/Dockerfile.requirements | cut -d ' ' -f 1)
REQUIREMENTS_TAG := requirements-v1-$(shell sha1sum uv.lock | cut -d ' ' -f 1)-$(shell sha1sum docker/Dockerfile.requirements | cut -d ' ' -f 1)
VERSION := release-${sha}
CODECOV_UPLOAD_TOKEN ?= "notset"
CODECOV_STATIC_TOKEN ?= "notset"
Expand Down Expand Up @@ -48,13 +48,13 @@ lint:
make lint.run

test:
COVERAGE_CORE=sysmon python -m pytest --cov=./ --junitxml=junit.xml -o junit_family=legacy
COVERAGE_CORE=sysmon pytest --cov=./ --junitxml=junit.xml -o junit_family=legacy

test.unit:
COVERAGE_CORE=sysmon python -m pytest --cov=./ -m "not integration" --cov-report=xml:unit.coverage.xml --junitxml=unit.junit.xml -o junit_family=legacy
COVERAGE_CORE=sysmon pytest --cov=./ -m "not integration" --cov-report=xml:unit.coverage.xml --junitxml=unit.junit.xml -o junit_family=legacy

test.integration:
COVERAGE_CORE=sysmon python -m pytest --cov=./ -m "integration" --cov-report=xml:integration.coverage.xml --junitxml=integration.junit.xml -o junit_family=legacy
COVERAGE_CORE=sysmon pytest --cov=./ -m "integration" --cov-report=xml:integration.coverage.xml --junitxml=integration.junit.xml -o junit_family=legacy


update-requirements:
Expand Down
4 changes: 1 addition & 3 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ ARG BERGLAS_VERSION=2.0.6
FROM us-docker.pkg.dev/berglas/berglas/berglas:$BERGLAS_VERSION as berglas

FROM $REQUIREMENTS_IMAGE as app
COPY . /worker
WORKDIR /worker
RUN pip install setuptools==72.1.0
ADD . /worker
RUN chmod +x worker.sh
ARG RELEASE_VERSION
ENV RELEASE_VERSION=$RELEASE_VERSION
Expand All @@ -20,7 +19,6 @@ FROM app as cloud
COPY --chmod=755 --from=berglas /bin/berglas /usr/local/bin/berglas

FROM app as self-hosted
RUN pip uninstall -y typing
ENV RUN_ENV="ENTERPRISE"


Expand Down
44 changes: 32 additions & 12 deletions docker/Dockerfile.requirements
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
# syntax=docker/dockerfile:1.4
ARG PYTHON_IMAGE=python:3.13-slim-bookworm
ARG PYTHON_IMAGE=ghcr.io/astral-sh/uv:python3.13-bookworm-slim
# BUILD STAGE
FROM $PYTHON_IMAGE as build

RUN apt-get update
RUN apt-get install -y \
build-essential \
curl \
git \
libffi-dev \
libpq-dev \
libxml2-dev \
libxslt-dev \
curl
libxslt-dev

# Install Rust
ARG RUST_VERSION=stable
Expand All @@ -20,27 +21,46 @@ RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
| bash -s -- -y --profile minimal --default-toolchain $RUST_VERSION
ENV PATH="/root/.cargo/bin:$PATH"

COPY requirements.txt /
WORKDIR /pip-packages/
ENV PYCURL_SSL_LIBRARY=openssl
ENV UV_LINK_MODE=copy \
UV_COMPILE_BYTECODE=1 \
UV_PYTHON_DOWNLOADS=never \
UV_PYTHON=python \
UV_PROJECT_ENVIRONMENT=/worker

# Then, add the rest of the project source code and install it
# Installing separately from its dependencies allows optimal layer caching
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv export --no-hashes --frozen --format requirements-txt > requirements.txt

RUN grep -v '^-e ' requirements.txt > requirements.remote.txt

# build all remote wheels
RUN pip wheel -w wheels --find-links wheels -r requirements.remote.txt

# build all local packages to wheels
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv build --all-packages --wheel -o wheels

RUN pip wheel --no-cache-dir -r /requirements.txt
RUN rm -rf /pip-packages/src

# RUNTIME STAGE - Copy packages from build stage and install runtime dependencies
FROM $PYTHON_IMAGE

RUN apt-get update
RUN apt-get install -y \
libpq-dev \
libxml2-dev \
libxslt-dev \
make

WORKDIR /pip-packages/
COPY --from=build /pip-packages/ /pip-packages/
COPY --from=build /wheels/ /wheels/

RUN pip install --no-deps --no-index --find-links=/pip-packages/ /pip-packages/*
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv pip install --no-deps --no-index --find-links=wheels wheels/* --system

RUN addgroup --system application \
&& adduser --system codecov --ingroup application --home /home/codecov
87 changes: 87 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
[project]
name = "worker"
version = "0.1.0"
description = "The codecov worker"
readme = "README.md"
requires-python = "==3.13.*"
dependencies = [
"asgiref>=3.7.2",
"analytics-python==1.3.0b1",
"billiard>=4.2.1",
"boto3>=1.34",
"celery>=5.3.6",
"click>=8.1.7",
"codecov-ribs==0.1.18",
"django>=4.2.16",
"django-postgres-extra>=2.0.8",
"google-cloud-bigquery>=3.27.0",
"google-cloud-bigquery-storage>=2.27.0",
"google-cloud-pubsub>=2.27.1",
"google-cloud-storage>=2.10.0",
"grpcio>=1.66.2",
"httpx>0.23.1",
"jinja2>=3.1.3",
"lxml>=5.3.0",
"mmh3>=5.0.1",
"multidict>=6.1.0",
"openai>=1.2.4",
"orjson>=3.10.11",
"polars==1.12.0",
"proto-plus>=1.25.0",
"psycopg2-binary>=2.9.10",
"protobuf>=5.29.2",
"pydantic>=2.9.0",
"pyjwt>=2.4.0",
"python-dateutil>=2.9.0.post0",
"python-json-logger>=0.1.11",
"python-redis-lock>=4.0.0",
"pyyaml>=6.0.1",
"redis>=4.4.4",
"regex>=2023.12.25",
"requests>=2.32.0",
"sentry-sdk>=2.13.0",
"shared",
"sqlalchemy==1.3.*",
"sqlparse==0.5.0",
"statsd>=3.3.0",
"stripe>=11.4.1",
"test-results-parser",
"timestring",
"zstandard>=0.23.0",
]

[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[tool.setuptools]
py-modules = []

[tool.uv]
dev-dependencies = [
"coverage>=7.5.0",
"factory-boy>=3.2.0",
"mock>=4.0.3",
"pre-commit>=3.4.0",
"pytest>=8.1.1",
"pytest-asyncio>=0.14.0",
"pytest-celery>=0.0.0",
"pytest-cov>=6.0.0",
"pytest-django>=4.7.0",
"pytest-freezegun>=0.4.2",
"pytest-insta>=0.3.0",
"pytest-mock>=1.13.0",
"pytest-sqlalchemy>=0.2.1",
"respx>=0.20.2",
"sqlalchemy-utils>=0.41.2",
"time-machine>=2.16.0",
# NOTE: some weird interaction between existing `vcrpy` snapshots and the way
# `oauth2` / `minio` deal with requests forces us to downgrade `urllib3`:
"urllib3==1.26.19",
"vcrpy==4.1.*",
]

[tool.uv.sources]
timestring = { git = "https://github.com/codecov/timestring", rev = "d37ceacc5954dff3b5bd2f887936a98a668dda42" }
test-results-parser = { git = "https://github.com/codecov/test-results-parser", rev = "190bbc8a911099749928e13d5fe57f6027ca1e74" }
shared = { git = "https://github.com/codecov/shared", rev = "47fa7fd405cd4a37ab6df9f200d6b600795f2786" }
62 changes: 0 additions & 62 deletions requirements.in

This file was deleted.

Loading

0 comments on commit e402935

Please sign in to comment.