Skip to content

Commit a0467f7

Browse files
authored
pip -> uv, CI and deploy updated accordingly (#7)
* pip -> uv, CI and deploy updated accordingly * mcdocs CI fix * tests CI fix - uv installs python 3.12 now * tests CI fix - uv installs python 3.12 now * ENVPATH fix * uv in docker compose * gh fix - remove backend/app volume mount * more caching, less logs in backend tests ci job * - pinned uv version to 0.9.17 - uv tool run for docs.yml * - uv tool run for docs.yml - uv for security ci * warning fixes * docker base img for all support containers, and updated all other stuff * fixed bake-action stuff in ci * fix dependencies * docker scan fixes * field serializer fix * removed unused dependency * added doc about ci/cd
1 parent feb00fa commit a0467f7

28 files changed

+3431
-414
lines changed

.github/workflows/docker.yml

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,16 @@ jobs:
1313
runs-on: ubuntu-latest
1414
steps:
1515
- uses: actions/checkout@v4
16-
- name: Set up Docker Buildx
17-
uses: docker/setup-buildx-action@v2
16+
- name: Build base image
17+
run: |
18+
docker build -f ./backend/Dockerfile.base -t integr8scode-base:latest ./backend
19+
1820
- name: Build Docker image
19-
uses: docker/build-push-action@v4
20-
with:
21-
context: ./backend
22-
push: false
23-
load: true
24-
tags: integr8scode:test
25-
cache-from: type=gha
26-
cache-to: type=gha,mode=max
21+
run: |
22+
DOCKER_BUILDKIT=1 docker build \
23+
--build-context base=docker-image://integr8scode-base:latest \
24+
-t integr8scode:test \
25+
./backend
2726
- name: Run Trivy vulnerability scanner
2827
uses: aquasecurity/trivy-action@master
2928
with:

.github/workflows/docs.yml

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,13 @@ jobs:
3131
- name: Checkout repository
3232
uses: actions/checkout@v4
3333

34-
- name: Set up Python
35-
uses: actions/setup-python@v5
34+
- name: Set up uv
35+
uses: astral-sh/setup-uv@v5
3636
with:
37-
python-version: '3.12'
38-
39-
- name: Cache pip dependencies
40-
uses: actions/cache@v4
41-
with:
42-
key: mkdocs-${{ hashFiles('mkdocs.yml') }}
43-
path: ~/.cache/pip
44-
restore-keys: mkdocs-
37+
enable-cache: true
4538

4639
- name: Install MkDocs
47-
run: pip install mkdocs-material mkdocs-mermaid2-plugin mkdocs-swagger-ui-tag
40+
run: uv tool install mkdocs --with mkdocs-material --with mkdocs-mermaid2-plugin --with mkdocs-swagger-ui-tag
4841

4942
- name: Download OpenAPI spec
5043
run: |
@@ -53,7 +46,7 @@ jobs:
5346
> docs/reference/openapi.json
5447
5548
- name: Build documentation
56-
run: mkdocs build --strict
49+
run: uv tool run mkdocs build --strict
5750

5851
- name: Upload artifact
5952
uses: actions/upload-pages-artifact@v3

.github/workflows/mypy.yml

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,22 @@ jobs:
1313
runs-on: ubuntu-latest
1414
steps:
1515
- uses: actions/checkout@v4
16-
- name: Set up Python
17-
uses: actions/setup-python@v4
16+
17+
- name: Set up uv
18+
uses: astral-sh/setup-uv@v5
1819
with:
19-
python-version: '3.12'
20-
- name: Install dependencies
20+
enable-cache: true
21+
cache-dependency-glob: "backend/uv.lock"
22+
23+
- name: Install Python and dependencies
2124
run: |
22-
python -m pip install --upgrade pip
23-
pip install mypy
24-
pip install -r backend/requirements.txt
25-
pip install -r backend/requirements-dev.txt
25+
cd backend
26+
uv python install 3.12
27+
uv sync --frozen
28+
2629
- name: Run mypy
2730
env:
2831
SECRET_KEY: ${{ secrets.TEST_SECRET_KEY }}
2932
run: |
3033
cd backend
31-
mypy --config-file pyproject.toml .
34+
uv run mypy --config-file pyproject.toml .

.github/workflows/ruff.yml

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,20 @@ jobs:
1313
runs-on: ubuntu-latest
1414
steps:
1515
- uses: actions/checkout@v4
16-
- name: Set up Python
17-
uses: actions/setup-python@v4
16+
17+
- name: Set up uv
18+
uses: astral-sh/setup-uv@v5
1819
with:
19-
python-version: '3.12'
20-
- name: Install dependencies
20+
enable-cache: true
21+
cache-dependency-glob: "backend/uv.lock"
22+
23+
- name: Install Python and dependencies
2124
run: |
22-
python -m pip install --upgrade pip
23-
pip install ruff
25+
cd backend
26+
uv python install 3.12
27+
uv sync --frozen
28+
2429
- name: Run ruff
25-
run: ruff check backend/ --config backend/pyproject.toml
30+
run: |
31+
cd backend
32+
uv run ruff check . --config pyproject.toml

.github/workflows/security.yml

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ jobs:
1313
runs-on: ubuntu-latest
1414
steps:
1515
- uses: actions/checkout@v4
16-
- name: Set up Python
17-
uses: actions/setup-python@v4
16+
17+
- name: Set up uv
18+
uses: astral-sh/setup-uv@v5
1819
with:
19-
python-version: '3.12'
20-
- name: Install dependencies
21-
run: |
22-
python -m pip install --upgrade pip
23-
pip install bandit safety
20+
enable-cache: true
21+
cache-dependency-glob: "backend/uv.lock"
22+
23+
- name: Install bandit
24+
run: uv tool install bandit
25+
2426
- name: Run bandit
25-
run: bandit -r backend/ -x backend/tests/ -ll
27+
run: uv tool run bandit -r backend/ -x backend/tests/ -ll

.github/workflows/tests.yml

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,19 @@ jobs:
6060
run: |
6161
echo "Pre-pulling base images to speed up builds..."
6262
docker pull python:3.12-slim &
63+
docker pull ghcr.io/astral-sh/uv:0.9.17 &
6364
docker pull alpine:latest &
6465
docker pull confluentinc/cp-kafka:7.5.0 &
6566
docker pull confluentinc/cp-zookeeper:7.5.0 &
66-
docker pull mongo:7 &
67+
docker pull confluentinc/cp-schema-registry:7.5.0 &
68+
docker pull mongo:8.0 &
6769
docker pull redis:7-alpine &
70+
docker pull grafana/grafana:latest &
71+
docker pull jaegertracing/all-in-one:1.52 &
72+
docker pull victoriametrics/victoria-metrics:v1.96.0 &
73+
docker pull otel/opentelemetry-collector-contrib:0.91.0 &
74+
docker pull obsidiandynamics/kafdrop:3.31.0 &
75+
docker pull danielqsj/kafka-exporter:latest &
6876
wait
6977
echo "Base images pulled successfully"
7078
@@ -80,6 +88,8 @@ jobs:
8088
yq eval '.services.backend.environment += ["MONGO_ROOT_PASSWORD=rootpassword"]' -i docker-compose.ci.yaml
8189
# Disable OpenTelemetry SDK during tests to avoid exporter retries
8290
yq eval '.services.backend.environment += ["OTEL_SDK_DISABLED=true"]' -i docker-compose.ci.yaml
91+
# Remove ./backend:/app volume mount - CI doesn't need hot-reload and it creates .venv permission conflicts
92+
yq eval '.services.backend.volumes = [.services.backend.volumes[] | select(. != "./backend:/app")]' -i docker-compose.ci.yaml
8393
8494
# MongoDB service already has defaults in docker-compose.yaml (root/rootpassword)
8595
# No need to override them
@@ -120,6 +130,8 @@ jobs:
120130
*.cache-from=type=gha,scope=buildkit-${{ github.repository }}-main
121131
*.cache-to=type=gha,mode=max,scope=buildkit-${{ github.repository }}-${{ github.ref_name }}
122132
*.pull=true
133+
env:
134+
BUILDKIT_PROGRESS: plain
123135

124136
- name: Start services
125137
run: |
@@ -130,7 +142,7 @@ jobs:
130142
docker compose -f docker-compose.ci.yaml logs
131143
exit 1
132144
)
133-
145+
134146
echo "Services started. Waiting for stabilization..."
135147
sleep 45
136148
@@ -145,7 +157,7 @@ jobs:
145157
146158
echo "Checking backend logs:"
147159
docker compose -f docker-compose.ci.yaml logs backend || echo "backend not found"
148-
160+
149161
# Explicitly check for containers that have exited
150162
if docker compose -f docker-compose.ci.yaml ps | grep -q 'Exit'; then
151163
echo "::error::One or more containers have exited unexpectedly. See logs above."
@@ -171,18 +183,17 @@ jobs:
171183
kubectl get roles -n default
172184
kubectl get rolebindings -n default
173185
174-
- name: Set up Python for Tests
175-
uses: actions/setup-python@v4
186+
- name: Set up uv
187+
uses: astral-sh/setup-uv@v5
176188
with:
177-
python-version: '3.12'
189+
enable-cache: true
190+
cache-dependency-glob: "backend/uv.lock"
178191

179-
- name: Install Python test dependencies
192+
- name: Install Python and dependencies
180193
run: |
181-
sudo apt-get update
182-
sudo apt-get install -y python3 python3-pip
183194
cd backend
184-
pip3 install -r requirements.txt
185-
pip3 install -r requirements-dev.txt
195+
uv python install 3.12
196+
uv sync --frozen
186197
187198
- name: Run backend tests with coverage
188199
timeout-minutes: 5
@@ -202,7 +213,7 @@ jobs:
202213
echo "Using BACKEND_BASE_URL=$BACKEND_BASE_URL"
203214
echo "Using SCHEMA_SUBJECT_PREFIX=$SCHEMA_SUBJECT_PREFIX"
204215
echo "MongoDB connection will use default CI credentials"
205-
python -m pytest tests/integration tests/unit -v --cov=app --cov-branch --cov-report=xml --cov-report=term --cov-report=term-missing
216+
uv run pytest tests/integration tests/unit -v --cov=app --cov-branch --cov-report=xml --cov-report=term --cov-report=term-missing
206217
207218
- name: Upload coverage to Codecov
208219
uses: codecov/codecov-action@v5

backend/Dockerfile

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,5 @@
1-
FROM python:3.12
2-
WORKDIR /app
3-
4-
# Install required packages
5-
RUN apt-get update && apt-get upgrade -y liblzma-dev liblzma5 xz-utils && \
6-
apt-get install -y libsnappy-dev && \
7-
rm -rf /var/lib/apt/lists/*
8-
9-
## Remove kubectl from runtime image: rely on Python client only
10-
11-
# Install Python dependencies
12-
COPY requirements.txt .
13-
RUN pip install --no-cache-dir --upgrade pip setuptools>=70.0.0 wheel
14-
RUN pip install --no-cache-dir -r requirements.txt
1+
# Backend API service
2+
FROM base
153

164
# Copy application files and configuration
175
COPY ./app /app/app
@@ -33,7 +21,7 @@ CMD bash -c "\
3321
# Use kubeconfig if present, but do not block startup\
3422
if [ -f /app/kubeconfig.yaml ]; then export KUBECONFIG=/app/kubeconfig.yaml; fi && \
3523
WEB_CONCURRENCY=${WEB_CONCURRENCY:-4} WEB_THREADS=${WEB_THREADS:-1} WEB_TIMEOUT=${WEB_TIMEOUT:-60} \
36-
gunicorn app.main:app \
24+
uv run gunicorn app.main:app \
3725
-k uvicorn.workers.UvicornWorker \
3826
--bind 0.0.0.0:443 \
3927
--workers ${WEB_CONCURRENCY} \

backend/Dockerfile.base

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Shared base image for all backend services
2+
# Contains: Python, system deps, uv, and all Python dependencies
3+
FROM python:3.12-slim
4+
5+
WORKDIR /app
6+
7+
# Install all system dependencies needed by any service
8+
RUN apt-get update && apt-get install -y \
9+
gcc \
10+
curl \
11+
libsnappy-dev \
12+
liblzma-dev \
13+
&& rm -rf /var/lib/apt/lists/*
14+
15+
# Install uv
16+
COPY --from=ghcr.io/astral-sh/uv:0.9.17 /uv /uvx /bin/
17+
18+
# Copy dependency files
19+
COPY pyproject.toml uv.lock ./
20+
21+
# Install Python dependencies (production only)
22+
# --no-install-project: don't install project itself, only dependencies
23+
RUN uv sync --frozen --no-dev --no-install-project
24+
25+
# Set Python path so imports work
26+
ENV PYTHONPATH=/app

backend/Dockerfile.test

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@ RUN apt-get update && apt-get install -y \
99
curl \
1010
&& rm -rf /var/lib/apt/lists/*
1111

12-
# Copy requirements
13-
COPY requirements.txt requirements-dev.txt ./
12+
# Install uv
13+
COPY --from=ghcr.io/astral-sh/uv:0.9.17 /uv /uvx /bin/
1414

15-
# Install Python dependencies
16-
RUN pip install --no-cache-dir -r requirements.txt -r requirements-dev.txt
15+
# Copy dependency files
16+
COPY pyproject.toml uv.lock ./
17+
18+
# Install Python dependencies (including dev deps for testing)
19+
RUN uv sync --frozen
1720

1821
# Copy application code
1922
COPY . .
@@ -22,4 +25,4 @@ COPY . .
2225
ENV PYTHONPATH=/app
2326

2427
# Default command runs all tests
25-
CMD ["pytest", "-v", "--tb=short"]
28+
CMD ["uv", "run", "pytest", "-v", "--tb=short"]

backend/app/infrastructure/kafka/events/base.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from typing import Any, ClassVar
33
from uuid import uuid4
44

5-
from pydantic import ConfigDict, Field
5+
from pydantic import ConfigDict, Field, field_serializer
66
from pydantic_avro import AvroBase
77

88
from app.domain.enums.events import EventType
@@ -22,11 +22,11 @@ class BaseEvent(AvroBase):
2222
# Each subclass must define its topic
2323
topic: ClassVar[KafkaTopic]
2424

25-
model_config = ConfigDict(
26-
json_encoders={
27-
datetime: lambda v: v.isoformat()
28-
}
29-
)
25+
model_config = ConfigDict()
26+
27+
@field_serializer('timestamp', when_used='json')
28+
def serialize_timestamp(self, dt: datetime) -> str:
29+
return dt.isoformat()
3030

3131
def to_dict(self) -> dict[str, Any]:
3232
# Use mode='json' to properly serialize datetime objects to ISO strings

0 commit comments

Comments
 (0)