Files
gh-christianlouis-docuelevate/.github/workflows/ci.yml
T
Christian Krakau-Louis 7cb5407bcf Refactor CI workflow for clarity and efficiency
Refactor CI workflow to simplify configuration and improve readability. Consolidate steps, update job dependencies, and enhance linting and testing stages.
2026-03-02 10:54:05 +01:00

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