name: Airflow # Piège : la version de Python vient de etl/airflow/.python-version. C'est 3.12 et non 3.14 # (contrairement à backend.yml et ml.yml) : celui de l'image apache/airflow retenue, et les tests # doivent tourner sur le même interpréteur qu'elle. Le 3.14 de ml/ ne vit que dans l'image # Docker, dans son propre environnement (cf. etl/airflow/Dockerfile). # # Piège : l'image COPY les fichiers de dépendances et le code de ml/ et de apps/backend/. Une # modification de l'un ou de l'autre peut donc casser sa construction : le filtre `airflow` de # ci.yml, qui appelle ce workflow, inclut ces chemins alors qu'il ne teste ni le modèle ni l'API. on: workflow_call: permissions: contents: read jobs: verification: name: Lint et intégrité des DAGs runs-on: ubuntu-latest timeout-minutes: 15 defaults: run: working-directory: etl/airflow steps: - name: Récupère le dépôt uses: actions/checkout@v7 # Action tierce, épinglée sur le commit du tag (règle Sonar githubactions:S7637). - name: Installe uv uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 with: enable-cache: true cache-dependency-glob: etl/airflow/uv.lock prune-cache: false - name: Installe l'interpréteur déclaré par .python-version run: uv python install - name: Synchronise les dépendances sur le verrou run: uv sync --all-groups --locked - name: Vérifie le formatage run: uv run ruff format --check . - name: Analyse statique run: uv run ruff check --output-format=github . # Aucun test ne lance de tâche ni de scheduler : DagBag charge les fichiers de dags/ et # vérifie import, planification, plafonds d'exécution et commande de chaque tâche. - name: Tests d'intégrité des DAGs run: uv run pytest image: name: Construction de l'image runs-on: ubuntu-latest timeout-minutes: 25 steps: - name: Récupère le dépôt uses: actions/checkout@v7 - name: Construit l'image (contexte à la racine, elle COPY ml/ et apps/backend/) run: docker build -f etl/airflow/Dockerfile -t enervision-airflow:ci . # Vérifie ce qui ne casse qu'à l'exécution, pas à la construction : libgomp1 absent # (`OSError: libgomp.so.1` au premier import) ou environnement ml/ non figé. - name: Vérifie que le pipeline ML s'importe sans réseau run: > docker run --rm --network none enervision-airflow:ci bash -c "cd /opt/ml && env -u VIRTUAL_ENV uv run --no-sync python -m enervision_ml.train --help" # `--help` sort par argparse avant `get_settings()` : ni base ni secret requis, et # l'import des modules prouve que l'environnement /opt/backend est complet. - name: Vérifie que les quatre commandes backend s'importent sans réseau run: > docker run --rm --network none enervision-airflow:ci bash -c "cd /opt/backend && env -u VIRTUAL_ENV uv run --no-sync python -m app.detection.internal_alerts --help && env -u VIRTUAL_ENV uv run --no-sync python -m app.cli generate-recommendations --help && env -u VIRTUAL_ENV uv run --no-sync python -m app.etl.historical_import --help && env -u VIRTUAL_ENV uv run --no-sync python -m app.etl.mock_api_import --help"