feat: Update CI/CD workflow to use uv for dependency management #44
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI/CD Pipeline | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - feature/uv-ci-test | |
| jobs: | |
| build-and-push: | |
| runs-on: ubuntu-latest | |
| env: | |
| DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Python 3.12 | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.12' | |
| - name: Install uv | |
| run: pip install uv | |
| - name: Generate requirements.txt | |
| run: uv pip compile pyproject.toml -o requirements.txt | |
| - name: Create uv virtual environment | |
| run: uv venv | |
| - name: Install Python dependencies for model training | |
| run: | | |
| uv pip install -r requirements.txt | |
| - name: Create models directory | |
| run: mkdir -p models | |
| - name: Train the model | |
| run: python -m src.model.model_training | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Install Docker Compose | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y docker-compose | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKER_USERNAME }} | |
| password: ${{ secrets.DOCKER_PASSWORD }} | |
| - name: Build and push Docker Compose services | |
| run: docker compose -f config/docker-compose.yml build | |
| - name: Push Docker Compose images | |
| run: | | |
| docker push $DOCKER_USERNAME/breast-cancer-api:latest | |
| docker push $DOCKER_USERNAME/breast-cancer-streamlit:latest | |
| - name: Run Docker Compose services (for testing) | |
| run: docker compose -f config/docker-compose.yml up -d | |
| - name: Wait for services to be ready | |
| run: | | |
| echo "Waiting for Flask API (port 5000)..." | |
| for i in $(seq 1 30); do | |
| if curl -s http://localhost:5000/; then | |
| echo "Flask API is ready!" | |
| break | |
| fi | |
| echo "Waiting for API... (Attempt $i)" | |
| sleep 2 | |
| done | |
| echo "Waiting for Streamlit UI (port 8501)..." | |
| for i in $(seq 1 30); do | |
| if curl -s http://localhost:8501/; then | |
| echo "Streamlit UI is ready!" | |
| exit 0 | |
| fi | |
| echo "Waiting for Streamlit... (Attempt $i)" | |
| sleep 2 | |
| done | |
| echo "Services did not become ready in time." | |
| exit 1 | |
| - name: Test health endpoint | |
| run: curl http://localhost:5000/ | |
| - name: Test prediction endpoint | |
| run: | | |
| cat <<EOF > payload.json | |
| { | |
| "radius_mean": 17.99, | |
| "texture_mean": 10.38, | |
| "perimeter_mean": 122.8, | |
| "area_mean": 1001.0, | |
| "smoothness_mean": 0.1184, | |
| "compactness_mean": 0.2776, | |
| "concavity_mean": 0.3001, | |
| "concave points_mean": 0.1471, | |
| "symmetry_mean": 0.2419, | |
| "fractal_dimension_mean": 0.07871, | |
| "radius_se": 1.095, | |
| "texture_se": 0.3568, | |
| "perimeter_se": 8.589, | |
| "area_se": 153.4, | |
| "smoothness_se": 0.006399, | |
| "compactness_se": 0.04904, | |
| "concavity_se": 0.05373, | |
| "concave points_se": 0.01587, | |
| "symmetry_se": 0.03003, | |
| "fractal_dimension_se": 0.006193, | |
| "radius_worst": 25.38, | |
| "texture_worst": 17.33, | |
| "perimeter_worst": 184.6, | |
| "area_worst": 2019.0, | |
| "smoothness_worst": 0.1622, | |
| "compactness_worst": 0.6656, | |
| "concavity_worst": 0.7119, | |
| "concave points_worst": 0.2654, | |
| "symmetry_worst": 0.4601, | |
| "fractal_dimension_worst": 0.1189 | |
| } | |
| EOF | |
| curl -X POST -H "Content-Type: application/json" -d @payload.json http://localhost:5000/predict | |
| - name: Test Streamlit UI is accessible | |
| run: curl http://localhost:8501/ | |
| - name: Clean up Docker Compose services | |
| if: always() | |
| run: docker compose -f config/docker-compose.yml down |