Logo Microsoft Fabric

Pipeline CI/CD Microsoft Fabric avec GitHub

Partie 3 : Secrets, scripts Python et workflows GitHub Actions

Cette troisième partie configure les secrets et environnements GitHub puis met en place les briques techniques du pipeline : un script de validation des notebooks, un script de déploiement vers Microsoft Fabric, et trois workflows GitHub Actions (CI, CD DEV, CD PROD).

Étape 4. Configurer les secrets et environnements GitHub

Créer les secrets de dépôt

Les secrets GitHub sont des variables d’environnement chiffrées, stockées dans le dépôt et exposées aux workflows sans apparaître en clair dans le code. Ils sont indispensables pour authentifier GitHub Actions auprès d’Azure et de l’API Microsoft Fabric.

Dans le dépôt GitHub, ouvrez Settings, dépliez Security, puis Secrets and variables et cliquez sur Actions. Cliquez sur New repository secret pour créer les secrets ci-dessous, un par un.

Nom du secret Valeur
AZURE_CLIENT_ID ID d’application du Service Principal
AZURE_CLIENT_SECRET Valeur du secret client généré dans Azure
AZURE_SUBSCRIPTION_ID ID de l’abonnement Azure
AZURE_TENANT_ID ID de l’annuaire Microsoft Entra ID
FABRIC_WORKSPACE_DEV_ID ID du workspace Fabric DEV
FABRIC_WORKSPACE_PROD_ID ID du workspace Fabric PROD

Accès aux paramètres de secrets d'un dépôt GitHub.

Écran d'ajout d'un secret dans GitHub Actions.

Validation d'un secret de dépôt GitHub.

Créer les environnements GitHub

Les environnements GitHub permettent de cibler chaque workflow CD vers une cible distincte. Ils sont référencés dans les fichiers YAML et doivent donc exister dans le dépôt.

  • Dans Settings du dépôt, ouvrir Environments dans le menu de gauche.
  • Cliquer sur New environment et créer un environnement nommé development.
  • Refaire la même opération pour un environnement nommé production.
  • Laisser les options par défaut (pas de protection particulière).

Création d'un environnement GitHub.

Liste des environnements development et production dans GitHub.

À savoir : sur le plan GitHub Free avec dépôt privé, l’approbation manuelle d’environnement n’est pas disponible. La séparation DEV / PROD est alors assurée par la stratégie de branches (main vers DEV, release/* vers PROD) et la protection de branches.

Étape 5. Créer les scripts Python

requirements.txt

Listez à la racine les dépendances Python utilisées par les scripts et les workflows.

# HTTP et APIs
requests>=2.31.0

# Authentification Azure
azure-identity>=1.15.0

# Tests
pytest>=7.4.0

# Qualité de code
flake8>=6.1.0

scripts/validate.py

Ce script parcourt récursivement le dossier fabric/notebooks et vérifie que chaque fichier .ipynb est un JSON valide. Il est exécuté dans le pipeline CI lors des Pull Requests pour bloquer les notebooks corrompus avant fusion. Il ne valide pas le contenu Jupyter, uniquement la structure JSON.

scripts/deploy.py

Le script deploy.py synchronise les notebooks locaux vers Microsoft Fabric via l’API REST. Il liste les items existants dans le workspace cible, puis effectue une création (POST) ou une mise à jour (PATCH) en fonction du displayName du notebook. L’authentification s’appuie sur un token Azure AD obtenu via az account get-access-token.

import os
import requests
import argparse
import base64

API = "https://api.fabric.microsoft.com/v1"

def get_items(workspace_id, token):
    url = f"{API}/workspaces/{workspace_id}/items"
    headers = {"Authorization": f"Bearer {token}"}
    r = requests.get(url, headers=headers)
    return r.json().get("value", []) if r.status_code == 200 else []

def upsert_notebook(workspace_id, token, path, existing):
    name = os.path.basename(path)
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json"
    }
    with open(path, "rb") as f:
        content = base64.b64encode(f.read()).decode("utf-8")
    payload = {
        "displayName": name,
        "type": "Notebook",
        "definition": {
            "format": "ipynb",
            "parts": [
                {
                    "path": "notebook.ipynb",
                    "payloadType": "InlineBase64",
                    "payload": content
                }
            ]
        }
    }
    found = next((x for x in existing if x["displayName"] == name), None)
    if found:
        url = f"{API}/workspaces/{workspace_id}/items/{found['id']}"
        r = requests.patch(url, headers=headers, json=payload)
        print("UPDATED" if r.ok else r.text)
    else:
        url = f"{API}/workspaces/{workspace_id}/items"
        r = requests.post(url, headers=headers, json=payload)
        print("CREATED" if r.ok else r.text)

def main(workspace_id, token, path):
    notebooks = os.path.join(path, "notebooks")
    existing = get_items(workspace_id, token)
    if not os.path.exists(notebooks):
        print(f"Folder not found: {notebooks}")
        return
    for f in os.listdir(notebooks):
        if f.endswith(".ipynb"):
            upsert_notebook(workspace_id, token, os.path.join(notebooks, f), existing)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--workspace-id", required=True)
    parser.add_argument("--token", required=True)
    parser.add_argument("--artifacts-path", required=True)
    args = parser.parse_args()
    main(args.workspace_id, args.token, args.artifacts_path)

Étape 6. Créer les workflows GitHub Actions

Les workflows sont des fichiers YAML dans .github/workflows/. Trois fichiers couvrent l’ensemble du cycle CI/CD.

Workflow Fichier Déclencheur Objectif
CI .github/workflows/ci.yml Pull Request vers main Lint et validation des notebooks avant merge.
CD DEV .github/workflows/cd-dev.yml Push sur main Déploiement automatique vers le workspace Fabric DEV.
CD PROD .github/workflows/cd-prod.yml Push sur release/* Déploiement contrôlé vers le workspace Fabric PROD.

ci.yml

name: CI
on:
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.10"
      - name: Install dependencies
        run: pip install -r requirements.txt
      - name: Lint
        run: flake8 scripts/
      - name: Validate notebooks
        run: python scripts/validate.py --path fabric/notebooks/

cd-dev.yml

name: CD DEV
on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: development
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.10"
      - run: pip install -r requirements.txt
      - uses: azure/login@v2
        with:
          creds: |
            {
              "clientId": "${{ secrets.AZURE_CLIENT_ID }}",
              "clientSecret": "${{ secrets.AZURE_CLIENT_SECRET }}",
              "subscriptionId": "${{ secrets.AZURE_SUBSCRIPTION_ID }}",
              "tenantId": "${{ secrets.AZURE_TENANT_ID }}"
            }
      - name: Get Fabric token
        id: token
        run: |
          T=$(az account get-access-token --resource https://api.fabric.microsoft.com --query accessToken -o tsv)
          echo "token=$T" >> $GITHUB_OUTPUT
      - name: Deploy DEV
        run: |
          python scripts/deploy.py \
            --workspace-id "${{ secrets.FABRIC_WORKSPACE_DEV_ID }}" \
            --token "${{ steps.token.outputs.token }}" \
            --artifacts-path fabric/

cd-prod.yml

name: CD PROD
on:
  push:
    branches:
      - "release/**"

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.10"
      - run: pip install -r requirements.txt
      - uses: azure/login@v2
        with:
          creds: |
            {
              "clientId": "${{ secrets.AZURE_CLIENT_ID }}",
              "clientSecret": "${{ secrets.AZURE_CLIENT_SECRET }}",
              "subscriptionId": "${{ secrets.AZURE_SUBSCRIPTION_ID }}",
              "tenantId": "${{ secrets.AZURE_TENANT_ID }}"
            }
      - name: Get Fabric token
        id: token
        run: |
          T=$(az account get-access-token --resource https://api.fabric.microsoft.com --query accessToken -o tsv)
          echo "token=$T" >> $GITHUB_OUTPUT
      - name: Deploy PROD
        run: |
          python scripts/deploy.py \
            --workspace-id "${{ secrets.FABRIC_WORKSPACE_PROD_ID }}" \
            --token "${{ steps.token.outputs.token }}" \
            --artifacts-path fabric

Ce qu’il faut retenir avant de continuer

Vous disposez maintenant de tous les éléments fonctionnels du pipeline : secrets, environnements, scripts et workflows. La dernière partie traite la sécurisation des branches, le premier push, et le test de bout en bout du pipeline jusqu’au déploiement en production.

Poursuivre la lecture

Les différentes parties du tutoriel

Retrouvez les quatre parties de ce tutoriel sur la mise en place d’un pipeline CI/CD entre GitHub et Microsoft Fabric, depuis la préparation initiale jusqu’au test de bout en bout.

Partie 1 Présentation, prérequis et dépôt GitHub Comprendre l’architecture, vérifier les accès et créer le dépôt qui hébergera le projet. Partie 2 Service Principal Azure et workspaces Fabric Créer l’identité applicative Azure, les workspaces DEV et PROD, et l’intégration Git. Partie 3 Secrets, scripts Python et workflows GitHub Actions Configurer les secrets, écrire les scripts de déploiement et créer les workflows CI/CD. Partie 4 Protection des branches, déploiement et test Sécuriser les branches critiques, lancer le pipeline et valider le bout en bout.

Rédigé par Achref