Skip to content

legal: ajouter LICENSE MIT pour conformité badge README #326

legal: ajouter LICENSE MIT pour conformité badge README

legal: ajouter LICENSE MIT pour conformité badge README #326

Workflow file for this run

name: Build and Deploy
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
# ===== SETUP =====
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Python 3.11
uses: actions/setup-python@v4
with:
python-version: '3.11'
cache: 'pip'
cache-dependency-path: |
requirements-dsfr.txt
requirements-dev.txt
requirements-security.txt
# ===== DEPENDENCIES =====
- name: Install dependencies
run: pip install -r requirements-dsfr.txt
- name: Install dev dependencies
run: pip install -r requirements-dev.txt
- name: Install security tools
run: pip install -r requirements-security.txt
# ===== PRE-COMMIT VERIFICATION =====
- name: Verify pre-commit hooks configuration
run: |
echo "=== Pre-commit Hooks Verification ==="
pip install pre-commit
pre-commit run --all-files || true
echo ""
echo "=== Pre-commit hooks verified ==="
# ===== QUALITY CHECKS =====
- name: Run Black formatter check
run: python -m black --check scripts/
- name: Run Ruff linter
run: python -m ruff check scripts/
- name: Run mypy type checker
run: python -m mypy scripts/ hooks/ --ignore-missing-imports --check-untyped-defs
# ===== SECURITY CHECKS =====
- name: Run Bandit security linter
run: |
echo "=== Bandit Security Analysis ==="
echo "Analyzing scripts/ and hooks/ for security issues..."
echo "(Excluding test files to avoid false positives)"
echo ""
# Generate JSON report (non-blocking)
bandit -r scripts/ hooks/ -ll -x tests/ -f json -o bandit-report.json || true
# Display summary and fail on HIGH/CRITICAL
bandit -r scripts/ hooks/ -ll -x tests/ --format screen
echo ""
echo "=== Bandit analysis complete ==="
- name: Check dependencies vulnerabilities (Safety)
run: |
echo "=== Safety CVE Check ==="
echo "Checking requirements-dsfr.txt for known vulnerabilities..."
echo ""
# Generate JSON report (non-blocking)
safety check -r requirements-dsfr.txt --json > safety-report.json || true
# Fail if vulnerabilities found
safety check -r requirements-dsfr.txt
echo ""
echo "=== No vulnerabilities found ==="
- name: Upload security reports
if: always()
uses: actions/upload-artifact@v4
with:
name: security-reports-${{ github.run_number }}
path: |
bandit-report.json
safety-report.json
retention-days: 90
# ===== TESTS =====
- name: Run unit tests
run: python -m pytest tests/unit/ -v --cov=scripts --cov=hooks --cov-report=term-missing
- name: Run production scripts coverage check (89%+ required)
run: |
python -m pytest \
--cov=scripts \
--cov-report=term-missing \
--cov-report=html \
--cov-fail-under=89 \
tests/unit/scripts/test_calculate_scores*.py tests/unit/scripts/test_enrich_pdf*.py
- name: Run hooks coverage check (100% required)
run: |
python -m pytest \
tests/unit/hooks/test_hooks_*.py \
--cov=hooks \
--cov-config=.coveragerc-hooks \
--cov-report=term-missing \
--cov-report=html:htmlcov-hooks \
--cov-fail-under=100
# ===== BUILD =====
- name: Calculate SPAN scores
run: python scripts/calculate_scores.py
- name: Generate PDF (builds site/ with ReadTheDocs theme for PDF compat)
run: |
ENABLE_PDF_EXPORT=1 mkdocs build --config-file mkdocs-dsfr-pdf.yml
- name: Enrich PDF metadata
run: python scripts/enrich_pdf_metadata.py exports/span-sg.pdf
- name: Build site HTML (strict mode - overwrites site/ with DSFR theme)
run: mkdocs build --config-file mkdocs-dsfr.yml --strict
- name: Verify DSFR theme applied
run: |
if ! grep -q 'fr-header' site/index.html; then
echo "❌ ERREUR: Thème DSFR non appliqué (fr-header manquant)"
exit 1
fi
echo "✅ Thème DSFR correctement appliqué"
- name: Install qpdf
run: sudo apt-get update && sudo apt-get install -y qpdf
- name: Validate PDF structure
run: qpdf --check exports/span-sg.pdf
# ===== BENCHMARK =====
- name: Run benchmark
run: |
echo "Running performance benchmarks..."
python scripts/benchmark.py > benchmark-${{ github.sha }}.json
echo "Benchmark complete"
cat benchmark-${{ github.sha }}.json
- name: Upload benchmark metrics
uses: actions/upload-artifact@v4
with:
name: benchmark-${{ github.run_number }}
path: benchmark-${{ github.sha }}.json
retention-days: 365
# ===== E2E TESTS (run on all events) =====
# Phase 1: E2E native (GitHub Actions environment)
- name: Run E2E tests (native environment)
run: |
echo "🧪 Running E2E tests in native GitHub Actions environment..."
bash tests/e2e/ci_runner.sh
- name: Upload E2E native report
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-native-report-${{ github.run_number }}
path: tests/e2e/report.html
retention-days: 30
- name: Upload E2E native accessibility report
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-native-accessibility-${{ github.run_number }}
path: tests/e2e/accessibility_report.json
retention-days: 30
# Phase 2: E2E Docker (containerized environment)
- name: Install system dependencies for E2E
run: |
sudo apt-get update
sudo apt-get install -y \
libpango-1.0-0 \
libpangocairo-1.0-0 \
libgdk-pixbuf2.0-0 \
libffi-dev \
shared-mime-info
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Cache Docker layers
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ hashFiles('Dockerfile.mkdocs-test', 'requirements-dsfr.txt') }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Build E2E test Docker image (with mkdocs-dsfr)
run: |
docker buildx build \
-f Dockerfile.mkdocs-test \
-t mkdocs-test:latest \
--cache-from type=local,src=/tmp/.buildx-cache \
--cache-to type=local,dest=/tmp/.buildx-cache-new,mode=max \
--load \
.
- name: Move Docker cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache || true
- name: Run E2E tests (Docker environment)
continue-on-error: true # TODO: Remove once Docker environment validated
run: |
docker run --rm -v $PWD:/docs --entrypoint bash mkdocs-test:latest tests/e2e/ci_runner.sh
- name: Upload E2E Docker report
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-docker-report-${{ github.run_number }}
path: tests/e2e/report.html
retention-days: 30
- name: Upload E2E Docker accessibility report
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-docker-accessibility-${{ github.run_number }}
path: tests/e2e/accessibility_report.json
retention-days: 30
# ===== FIX: Rebuild DSFR après E2E tests =====
# CRITIQUE: Les E2E tests (scenario_erreur_markdown.sh) font `mkdocs build --strict`
# sans --config-file ni --site-dir, écrasant site/ avec Material theme.
# Ce rebuild final garantit que l'artifact uploadé contient bien DSFR.
- name: Clean site directory (remove Docker root-owned files)
run: sudo rm -rf site/
- name: Rebuild site HTML (final DSFR, après E2E)
run: mkdocs build --config-file mkdocs-dsfr.yml
- name: Verify DSFR theme applied (final check)
run: |
if ! grep -q 'fr-header' site/index.html; then
echo "❌ ERREUR: Thème DSFR non appliqué (fr-header manquant)"
exit 1
fi
echo "✅ Thème DSFR correctement appliqué (vérification finale)"
# ===== TEST REGRESSION DSFR =====
# Exécuter test dédié après rebuild final (non inclus dans E2E runner)
- name: Run DSFR theme preservation test
run: bash tests/e2e/test_dsfr_theme_preserved.sh
# ===== UPLOAD ARTIFACTS =====
- name: Upload site HTML
uses: actions/upload-artifact@v4
with:
name: site-${{ github.sha }}
path: site/
retention-days: 7
- name: Upload exports PDF
uses: actions/upload-artifact@v4
with:
name: exports-${{ github.sha }}
path: exports/
retention-days: 90
# ===== NOTIFICATIONS =====
- name: Send failure notification
if: failure()
uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 587
username: ${{ secrets.SMTP_USERNAME }}
password: ${{ secrets.SMTP_PASSWORD }}
subject: "[SPAN SG] CI Build Failed - ${{ github.repository }}"
to: alexandra.guiderdoni@gmail.com
from: GitHub Actions
body: |
Build failed for commit ${{ github.sha }}
Branch: ${{ github.ref }}
Workflow: ${{ github.workflow }}
Details: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
deploy-staging:
needs: build-and-test
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment:
name: staging
url: https://alexmacapple.github.io/span-sg/draft/
steps:
- name: Checkout gh-pages branch
uses: actions/checkout@v3
with:
ref: gh-pages
token: ${{ secrets.GITHUB_TOKEN }}
- name: Download site artifact
uses: actions/download-artifact@v4
with:
name: site-${{ github.sha }}
path: site/
- name: Download exports artifact
uses: actions/download-artifact@v4
with:
name: exports-${{ github.sha }}
path: exports/
- name: Deploy to /draft/ (staging)
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# Clean existing /draft/ directory
rm -rf draft
mkdir -p draft
# Copy new build
cp -r site/* draft/
mkdir -p draft/exports
cp -r exports/* draft/exports/
# Commit and push
git add draft
git commit -m "Deploy staging from ${{ github.sha }}" || exit 0
git push origin gh-pages
- name: Deployment summary
run: |
echo "✅ Staging deployment complete"
echo "URL: https://alexmacapple.github.io/span-sg/draft/"
echo "Commit: ${{ github.sha }}"
deploy-production:
needs: [build-and-test, deploy-staging]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment:
name: production
url: https://alexmacapple.github.io/span-sg/
steps:
- name: Checkout gh-pages branch
uses: actions/checkout@v3
with:
ref: gh-pages
token: ${{ secrets.GITHUB_TOKEN }}
- name: Download site artifact
uses: actions/download-artifact@v4
with:
name: site-${{ github.sha }}
path: site/
- name: Download exports artifact
uses: actions/download-artifact@v4
with:
name: exports-${{ github.sha }}
path: exports/
- name: Deploy to / (production)
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# Rename downloaded artifacts to temp names
mv site site-tmp
mv exports exports-tmp
# Clean root (preserve /draft/ and .git only)
find . -mindepth 1 -maxdepth 1 ! -name 'draft' ! -name '.git' ! -name 'site-tmp' ! -name 'exports-tmp' -exec rm -rf {} +
# Deploy new build
cp -r site-tmp/* .
mkdir -p exports
cp -r exports-tmp/* exports/
# Clean temporary directories
rm -rf site-tmp exports-tmp
# Commit and push
git add .
git commit -m "Deploy production from ${{ github.sha }}" || exit 0
# Pull staging changes before push (avoid conflicts)
git pull --rebase origin gh-pages
git push origin gh-pages
- name: Deployment summary
run: |
echo "✅ Production deployment complete"
echo "URL: https://alexmacapple.github.io/span-sg/"
echo "Commit: ${{ github.sha }}"