ServicesÀ proposNotesContact Me contacter →
EN FR
Note

CI/CD pour les packages dbt

Comment configurer le CI/CD pour les packages dbt — tests matriciels sur plusieurs warehouses et versions dbt avec GitHub Actions, gestion des credentials et le workflow de tests d'intégration.

Planté
dbttestingautomation

Le CI/CD pour les packages dbt exécute la suite de tests d’intégration sur chaque combinaison supportée de warehouse et de version dbt, détectant les échecs spécifiques aux adapters et les changements breaking issus des releases dbt Core. GitHub Actions avec une stratégie de matrice est l’approche standard.

Tests matriciels avec GitHub Actions

La stratégie de matrice exécute la même suite de tests sur plusieurs dimensions — warehouses et versions dbt — en parallèle :

.github/workflows/ci.yml
name: CI
on: [pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
warehouse: [snowflake, bigquery, postgres]
dbt-version: ['1.9.0', '1.11.0']
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: pip install dbt-${{ matrix.warehouse }}==${{ matrix.dbt-version }}
- run: |
cd integration_tests/
dbt deps
dbt seed --target ${{ matrix.warehouse }}
dbt run --target ${{ matrix.warehouse }}
dbt test --target ${{ matrix.warehouse }}
env:
SNOWFLAKE_ACCOUNT: ${{ secrets.SNOWFLAKE_ACCOUNT }}
SNOWFLAKE_USER: ${{ secrets.SNOWFLAKE_USER }}
SNOWFLAKE_PASSWORD: ${{ secrets.SNOWFLAKE_PASSWORD }}
BIGQUERY_KEYFILE: ${{ secrets.BIGQUERY_KEYFILE }}

Cette configuration crée 6 jobs parallèles (3 warehouses x 2 versions dbt). Chaque job installe l’adapter dbt approprié, exécute la suite complète de tests d’intégration et rapporte le résultat indépendamment.

Ce que la matrice détecte

Chaque dimension détecte des problèmes différents :

La dimension warehouse détecte :

  • Les différences de syntaxe SQL (SAFE_DIVIDE de BigQuery vs CASE WHEN ... = 0)
  • Les implémentations dispatch manquantes pour des adapters spécifiques
  • Les différences de système de types (INT64 de BigQuery vs NUMBER de Snowflake)
  • Les différences de noms de fonctions (ordre des arguments DATEADD selon les dialectes)

La dimension de version dbt détecte :

  • Les fonctionnalités dépréciées que vous utilisez encore
  • Les changements de comportement dans les macros intégrées
  • Les nouvelles exigences ou changements de configuration dbt Core
  • La compatibilité avec dbt Core 1.x et Fusion 2.x

Sans la matrice, vous livrez un package testé uniquement contre une seule combinaison. Les utilisateurs sur d’autres combinaisons deviennent votre équipe QA.

Configuration des profils

Le projet de test d’intégration a besoin de profils connectant à chaque warehouse. Ceux-ci résident dans integration_tests/profiles.yml ou sont configurés via des variables d’environnement :

integration_tests/profiles.yml
integration_tests:
target: postgres
outputs:
postgres:
type: postgres
host: "{{ env_var('POSTGRES_HOST', 'localhost') }}"
user: "{{ env_var('POSTGRES_USER', 'dbt_test') }}"
password: "{{ env_var('POSTGRES_PASSWORD') }}"
port: 5432
dbname: dbt_test
schema: dbt_test
snowflake:
type: snowflake
account: "{{ env_var('SNOWFLAKE_ACCOUNT') }}"
user: "{{ env_var('SNOWFLAKE_USER') }}"
password: "{{ env_var('SNOWFLAKE_PASSWORD') }}"
role: TRANSFORMER
database: DBT_TEST
warehouse: COMPUTE_WH
schema: dbt_test
bigquery:
type: bigquery
method: service-account
project: "{{ env_var('BIGQUERY_PROJECT', 'my-test-project') }}"
dataset: dbt_test
keyfile: "{{ env_var('BIGQUERY_KEYFILE') }}"

Chaque output correspond à une valeur dans la liste warehouse de la matrice. Le flag --target dans l’étape CI sélectionne le profil à utiliser.

Gestion des credentials

Stockez les credentials warehouse sous forme de GitHub Secrets. Ne commitez jamais des credentials, des chaînes de connexion ou des clés de compte de service dans le dépôt.

Pour BigQuery, le fichier de clé de compte de service nécessite un traitement particulier car c’est un fichier JSON, pas une simple chaîne :

steps:
- name: Write BigQuery keyfile
if: matrix.warehouse == 'bigquery'
run: echo '${{ secrets.BIGQUERY_KEYFILE_JSON }}' > /tmp/bigquery-keyfile.json
env:
BIGQUERY_KEYFILE: /tmp/bigquery-keyfile.json

Stockez l’intégralité de la clé JSON comme secret (BIGQUERY_KEYFILE_JSON) et écrivez-la dans un fichier temporaire dans l’étape CI. Définissez BIGQUERY_KEYFILE au chemin du fichier pour que dbt puisse le lire.

Pour Snowflake, l’authentification par paire de clés est plus sécurisée que l’authentification par mot de passe en CI :

snowflake:
type: snowflake
account: "{{ env_var('SNOWFLAKE_ACCOUNT') }}"
user: "{{ env_var('SNOWFLAKE_USER') }}"
private_key_path: "{{ env_var('SNOWFLAKE_KEY_PATH') }}"
role: TRANSFORMER
database: DBT_TEST
warehouse: COMPUTE_WH
schema: dbt_test

Isolation des schémas en CI

Plusieurs exécutions CI touchant le même warehouse peuvent entrer en collision si elles écrivent dans le même schéma. Utilisez des noms de schémas dynamiques basés sur l’ID d’exécution :

- run: |
cd integration_tests/
dbt deps
dbt seed --target ${{ matrix.warehouse }} --vars "{'my_package_schema': 'ci_${{ github.run_id }}'}"
dbt run --target ${{ matrix.warehouse }}
dbt test --target ${{ matrix.warehouse }}

Ou configurez le profil pour inclure l’ID d’exécution dans le schéma :

schema: "dbt_ci_{{ env_var('GITHUB_RUN_ID', 'local') }}"

Cela empêche les exécutions parallèles de se marcher dessus.

Contrôle des coûts

Exécuter des tests d’intégration sur trois warehouses à chaque PR peut générer des coûts. Quelques stratégies pour garder les factures sous contrôle :

  • Utiliser la configuration de warehouse/slot la plus petite. Les seeds de tests d’intégration sont minuscules — pas besoin de puissance de calcul.
  • N’exécuter la matrice complète que sur les PRs vers main. Les push sur les branches de fonctionnalités peuvent n’exécuter qu’un seul adapter (ex. : Postgres) pour un retour rapide, avec la matrice complète comme barrière de merge.
  • Nettoyer après les exécutions. Supprimez le schéma CI à la fin du workflow pour éviter les coûts de stockage.
- name: Cleanup
if: always()
run: |
cd integration_tests/
dbt run-operation drop_schema --args "{'schema': 'ci_${{ github.run_id }}'}" --target ${{ matrix.warehouse }}

Au-delà des pull requests

Le CI sur les pull requests est le minimum. Pour les packages matures, ajoutez :

  • Exécutions nocturnes contre les dernières pré-releases dbt. Détecte les problèmes de compatibilité avant qu’une release dbt passe en GA, vous donnant le temps de corriger avant que les utilisateurs ne signalent les problèmes.
  • Automatisation des releases. Quand vous taguez une nouvelle version, exécutez automatiquement la matrice complète et ne créez la release GitHub qu’en cas de succès de tous les tests. Cela évite de publier une version défaillante.
  • Génération de changelog. Des outils comme git-cliff peuvent auto-générer des changelogs à partir des messages de commit conventionnels, réduisant l’effort manuel de maintenance du CHANGELOG.md.
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: ubuntu-latest
steps:
# Exécuter d'abord la matrice complète de tests
# Puis créer la release GitHub uniquement en cas de succès
- uses: softprops/action-gh-release@v1
with:
generate_release_notes: true

Le script hubcap du Hub prend en compte les nouvelles releases GitHub en moins d’une heure, de sorte qu’un workflow de release réussi signifie que votre mise à jour est disponible pour les utilisateurs avec un délai minimal.