Skip to content

Dev

Dev #28

Workflow file for this run

name: CI
# Triggers:
# - every push to any branch (so feature branches get fast feedback)
# - every PR targeting main or dev (gate for merge)
on:
push:
branches: ["**"]
pull_request:
branches: [main, dev]
# Avoid wasting CI minutes: cancel in-progress runs when a new commit lands on the same branch.
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
# ────────────────────────────────────────────────────────────
# 1. Lint — fast, fails the rest if style is broken
# ────────────────────────────────────────────────────────────
lint:
name: Lint (ruff)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
- name: Install ruff
run: pip install ruff==0.2.0
- name: Run ruff
run: ruff check .
# ────────────────────────────────────────────────────────────
# 2. Tests — full pytest suite with coverage
# ────────────────────────────────────────────────────────────
test:
name: Tests (pytest)
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
- name: Install CPU-only PyTorch
# Doing this separately keeps the image small and avoids CUDA wheels.
run: |
pip install --upgrade pip
pip install torch==2.2.0 --index-url https://download.pytorch.org/whl/cpu
- name: Install project dependencies
run: pip install -r requirements.txt
- name: Prepare data
# data_prep.py validates scenario CSVs and writes derived features.
# Many tests depend on its outputs being present. `all` processes
# weekday, weekend, and holiday_rush in one go.
run: python data_prep.py --scenario all
- name: Run pytest with coverage
run: |
pytest tests/ \
--cov=. \
--cov-report=term-missing \
--cov-report=xml \
--junitxml=pytest-results.xml \
-v
- name: Upload coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage.xml
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: pytest-results
path: pytest-results.xml
# ────────────────────────────────────────────────────────────
# 3. Build Docker images — verifies the Dockerfiles actually build
# ────────────────────────────────────────────────────────────
build-images:
name: Build Docker images
runs-on: ubuntu-latest
needs: test
# Only on push to main/dev — saves CI time on feature branches.
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev')
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build training image
uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile.train
push: false
tags: food-rescue-train:ci-${{ github.sha }}
cache-from: type=gha,scope=train
cache-to: type=gha,scope=train,mode=max
- name: Build serving image
uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile.serve
push: false
tags: food-rescue-serve:ci-${{ github.sha }}
cache-from: type=gha,scope=serve
cache-to: type=gha,scope=serve,mode=max
# ────────────────────────────────────────────────────────────
# 4. Smoke test the serving image — runs /health
# ────────────────────────────────────────────────────────────
smoke-test-serve:
name: Smoke test serving image
runs-on: ubuntu-latest
needs: build-images
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev')
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build serving image (load locally)
uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile.serve
load: true
tags: food-rescue-serve:smoke
cache-from: type=gha,scope=serve
- name: Run container and check /health
run: |
# Start the API in the background; it will boot in degraded mode
# since no policy is mounted and MLflow is not available in CI.
# FOOD_RESCUE_DISABLE_MLFLOW_REGISTRY=1 prevents hanging on MLflow connection.
docker run -d --name api-smoke \
-e FOOD_RESCUE_DISABLE_MLFLOW_REGISTRY=1 \
-p 8000:8000 food-rescue-serve:smoke
# Give uvicorn ~10s to come up
for i in $(seq 1 30); do
if curl -fsS http://localhost:8000/health > /dev/null; then
echo "API is up after ${i}s"
break
fi
sleep 1
done
curl -fsS http://localhost:8000/health
docker logs api-smoke
docker stop api-smoke