7cb5407bcf
Refactor CI workflow to simplify configuration and improve readability. Consolidate steps, update job dependencies, and enhance linting and testing stages.
203 lines
7.1 KiB
YAML
203 lines
7.1 KiB
YAML
name: CI Pipeline
|
|
|
|
on:
|
|
push:
|
|
branches: [main, develop]
|
|
tags: ['v*', '[0-9]+.*']
|
|
pull_request:
|
|
branches: [main]
|
|
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
|
|
concurrency:
|
|
group: ci-${{ github.ref }}
|
|
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
|
|
env:
|
|
IMAGE_NAME: christianlouis/docuelevate
|
|
|
|
jobs:
|
|
# ══════════════════════════════════════════════════════════════════════════
|
|
# Stage 1: Static Analysis (The "Immediate" Gate)
|
|
# ══════════════════════════════════════════════════════════════════════════
|
|
lint:
|
|
name: Ruff Lint & Format
|
|
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' # Caching enabled
|
|
- name: Install Ruff
|
|
run: pip install ruff
|
|
- name: Check for merge conflict markers
|
|
run: |
|
|
if git grep -rn -E '^(<{7} |>{7} |={7}$)' -- '.'; then
|
|
echo "ERROR: Merge conflict markers found."
|
|
exit 1
|
|
fi
|
|
- run: ruff check app/ tests/
|
|
- run: ruff format --check app/ tests/
|
|
|
|
html-lint:
|
|
name: HTML Accessibility Lint
|
|
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'
|
|
- run: pip install djlint>=1.36.0
|
|
- run: djlint frontend/templates/ --lint
|
|
|
|
# ══════════════════════════════════════════════════════════════════════════
|
|
# Stage 2: Parallel Heavy Lifters (Tests & Mypy)
|
|
# All 3 of these now run at the same time as soon as Linting passes.
|
|
# ══════════════════════════════════════════════════════════════════════════
|
|
|
|
mypy:
|
|
name: Mypy Type Check
|
|
runs-on: ubuntu-latest
|
|
needs: [lint] # Blocks only on fast linting
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: "3.11"
|
|
cache: 'pip'
|
|
- name: Install Dependencies
|
|
run: pip install -r requirements-dev.txt
|
|
- run: mypy app/
|
|
|
|
test-quick:
|
|
name: Quick Tests
|
|
runs-on: ubuntu-latest
|
|
needs: [lint] # Parallel with Mypy
|
|
services:
|
|
redis:
|
|
image: redis:7
|
|
ports: ["6379:6379"]
|
|
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: "3.11"
|
|
cache: 'pip'
|
|
- name: Install Dependencies
|
|
run: pip install -r requirements-dev.txt
|
|
- name: Run Quick Tests
|
|
run: >
|
|
pytest tests/ -v --timeout=120 --cov=app --cov-report=xml
|
|
-m "not e2e and not requires_docker and not requires_external and not slow"
|
|
- name: Upload coverage
|
|
if: always()
|
|
uses: codecov/codecov-action@v5
|
|
with:
|
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
|
|
test-integration:
|
|
name: Integration Tests
|
|
runs-on: ubuntu-latest
|
|
needs: [lint] # NOW PARALLEL (No longer waits for test-quick)
|
|
services:
|
|
redis:
|
|
image: redis:7
|
|
ports: ["6379:6379"]
|
|
rabbitmq:
|
|
image: rabbitmq:3-management
|
|
ports: ["5672:5672", "15672:15672"]
|
|
options: --health-cmd "rabbitmq-diagnostics -q ping" --health-interval 10s --health-timeout 5s --health-retries 5
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: "3.11"
|
|
cache: 'pip'
|
|
- name: Install Dependencies
|
|
run: pip install -r requirements-dev.txt
|
|
- name: Run Integration Tests
|
|
run: >
|
|
pytest tests/ -v --timeout=300
|
|
-m "(requires_docker or requires_external or slow) and not e2e"
|
|
|
|
dependency-scan:
|
|
name: Security Scan
|
|
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'
|
|
- run: pip install pip-audit>=2.7.0
|
|
- run: pip-audit -r requirements.txt --desc on
|
|
|
|
# ══════════════════════════════════════════════════════════════════════════
|
|
# Stage 3: Build & Deploy (Final Quality Gate)
|
|
# ══════════════════════════════════════════════════════════════════════════
|
|
build:
|
|
name: Build & Push
|
|
runs-on: ubuntu-latest
|
|
# This job only runs if EVERYTHING above passed
|
|
needs: [test-quick, test-integration, mypy, dependency-scan, html-lint]
|
|
if: github.event_name == 'push'
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- name: Generate Build Metadata
|
|
run: |
|
|
chmod +x scripts/generate_build_metadata.sh
|
|
./scripts/generate_build_metadata.sh
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
- name: Log in to Registries
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
- name: Build and Push
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: .
|
|
push: true
|
|
tags: ${{ env.IMAGE_NAME }}:latest
|
|
cache-from: type=gha
|
|
cache-to: type=gha,mode=max
|
|
|
|
update-k8s-manifest:
|
|
name: Update Preprod
|
|
runs-on: ubuntu-latest
|
|
needs: [build]
|
|
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
steps:
|
|
- name: Checkout k8s-cluster-state
|
|
uses: actions/checkout@v4
|
|
with:
|
|
repository: christianlouis/k8s-cluster-state
|
|
token: ${{ secrets.GH_PAT }}
|
|
path: k8s-cluster-state
|
|
- name: Update image tag
|
|
uses: mikefarah/yq@v4.44.6
|
|
with:
|
|
cmd: yq -i '.images[0].newTag = "${{ github.sha }}"' k8s-cluster-state/apps/docuelevate/preprod/docuelevate-stack.yaml
|
|
- name: Push changes
|
|
run: |
|
|
cd k8s-cluster-state
|
|
git config user.name "github-actions"
|
|
git config user.email "actions@github.com"
|
|
git add .
|
|
git commit -m "chore: update image to ${{ github.sha }}"
|
|
git push
|