Andrew Hanna

Andrew Hanna

Créer une pipeline Salesforce CI/CD avec GitHub Actions

Créer une pipeline Salesforce CI/CD avec GitHub Actions

Salesforce development a beaucoup évolué depuis les Change Sets manuels. Quand les équipes grandissent et que les releases deviennent plus fréquentes, les deployments manuels deviennent rapidement un goulot d'étranglement.

C'est là que CI/CD (Continuous Integration and Continuous Delivery) intervient. Une bonne pipeline valide, teste et promeut automatiquement les changements de development jusqu'à production.

Dans ce guide, nous voyons comment fonctionne Salesforce CI/CD, comment construire une pipeline avec GitHub Actions, et quand une automation DIY commence à montrer ses limites.

Pourquoi CI/CD compte pour Salesforce

Les équipes Salesforce ne livrent pas une application compilée. Elles déploient des metadata et de la configuration:

  • Apex classes et triggers

  • Lightning Web Components

  • Flows et automation

  • Profiles, permission sets, objects, fields et layouts

Sans automation, les équipes rencontrent du drift entre environnements, des dependencies manquantes, des erreurs manuelles et peu de visibilité sur ce qui a réellement changé.

Les pipelines CI/CD répondent à cela en:

  • validant les changements automatiquement

  • lançant les tests avant deployment

  • gardant Git comme source of truth

  • promouvant seulement les changements approuvés

Ce qu'il vous faut avant de commencer

Ce guide suppose un dépôt et des orgs déjà pensés pour l'automatisation. S'il en manque un, comblez ce manque d'abord : une pipeline posée par-dessus ne fait qu'automatiser le manque.

  • Des metadata déjà versionnées, en source format. Tout ce que vous comptez déployer vit sous force-app et possède un historique de commits. La pipeline promeut des commits, pas des orgs : ce qui n'existe que dans une sandbox lui est invisible.

  • Salesforce CLI v2 (sf) sur le runner. Chaque commande de ce guide est en forme v2, installée dans le workflow avec npm install @salesforce/cli --global. L'ancienne CLI sfdx est deprecated.

  • Une org par étape, avec un responsable identifié. Au minimum une sandbox pour valider et l'org dans laquelle vous livrez. La stratégie de branching plus bas associe les branches à ces orgs une pour une.

  • Une Connected App et un integration user dans chaque org cible, avec les digital signatures activées et l'utilisateur pré-autorisé. La mise en place est détaillée plus bas dans Connected App et JWT authentication.

Modèles de Salesforce development

1. Org-based development

C'est encore le modèle le plus courant. Les developers travaillent dans des sandboxes, les metadata sont récupérées dans Git, puis les pipelines CI/CD les promeuvent entre environnements.

Developer Sandbox
      ↓
QA
      ↓
UAT / Staging
      ↓
Production

2. Package-based development

Le package-based development utilise des packages modulaires au lieu de promouvoir tout l'arbre metadata comme un seul bloc. C'est fréquent chez les ISVs, AppExchange partners et grandes équipes enterprise.

Patterns recommandés par taille d'équipe

Petites équipes

Developer Sandbox
      ↓
Retrieve to Git
      ↓
Pull Request validation
      ↓
Build unlocked package version
      ↓
Install in Staging / QA Sandbox
      ↓
Install same package version in Production

Ce modèle fonctionne quand l'équipe est petite, coordonnée et qu'un seul environnement staging ou QA suffit pour le signoff.

Équipes en croissance

Les équipes plus grandes ont souvent besoin de QA et UAT séparés. QA valide les source changes intégrés, tandis que UAT valide l'artifact de release destiné à production.

Qa Devops

Developer Sandbox
      ↓
Feature branch
      ↓
Pull Request validation
      ↓
Merge to develop
      ↓
Deploy source to QA
      ↓
Create release branch
      ↓
Build unlocked package version
      ↓
Install package in UAT
      ↓
Install same package version in Production

ISVs

Les ISVs suivent souvent des principes similaires, mais leurs workflows sont package-led dès le départ.

Scratch Org / Dev Org
      ↓
Source tracked to Git
      ↓
Pull Request validation
      ↓
Package version build
      ↓
Install in internal test org
      ↓
Install in staging / UAT
      ↓
Promote release artifact

Les mêmes idées s'appliquent toujours: Git comme source of truth, des étapes de promotion claires, et des release artefacts versioned.

Équipes avancées et packages modulaires

À mesure que l'org Salesforce grandit et devient plus orientée domaine, un seul unlocked package peut devenir trop large. À ce stade, des unlocked packages modulaires ont généralement plus de sens.

Exemples possibles:

  • package sales pipeline et opportunity management

  • package service operations

  • package customer onboarding

  • package core automation

C'est particulièrement utile dans les grandes entreprises où plusieurs équipes travaillent en parallèle sur des domaines différents. À mesure que l'équipe grandit ou que l'org devient plus complexe, le processus DevOps doit grandir avec elle pour préserver vitesse, qualité, visibilité et traceability.

Branching strategy

Avant de construire la pipeline, décidez comment le travail circule dans Git. Les deux modèles courants sont GitFlow et trunk-based development.

GitFlow

main      → production history
develop   → integration branch
feature/* → work item branches
release/* → release candidate branches
hotfix/*  → urgent production fixes

GitFlow convient aux équipes avec QA, UAT, releases planifiées et branches release candidates. Trunk-based development convient mieux aux petites équipes matures avec des tests solides et des deployments fréquents.

Trunk-Based Development

main       → always releasable
feature/*  → short-lived branches merged quickly

Cela fonctionne bien quand:

  • l'équipe est petite

  • les deployments sont fréquents

  • la validation et les tests sont solides

  • l'équipe veut moins de branches longue durée

L'inconvénient est qu'une discipline de tests faible peut vite déstabiliser la branche partagée.

Lequel recommandons-nous ?

Pour beaucoup d'équipes Salesforce org-based, GitFlow est plus facile à adopter car il reproduit le modèle familier Dev → QA → UAT → Prod. Trunk-based development peut bien fonctionner pour des équipes petites et matures avec une automation solide.

L'important n'est pas qu'un modèle soit toujours meilleur. L'important est de choisir un modèle délibérément et de rendre vos environnements, vos approbations et la logique de votre pipeline cohérents avec lui.

Architecture de pipeline recommandée

Pour la plupart des équipes Salesforce en croissance, le flow recommandé est:

Developer Sandbox
      ↓
Retrieve metadata to Git
      ↓
Feature branch
      ↓
Pull Request validation
      ↓
Merge to develop
      ↓
Deploy source to QA
      ↓
Create release branch
      ↓
Build unlocked package version
      ↓
Install package in UAT
      ↓
Regression testing and signoff
      ↓
Install same package version in Production

Le source deploy vers QA est rapide pour les tests d'intégration. La package version devient ensuite l'artifact stable validé en UAT et promu en production.

package.xml vs source tracking vs workflow Serpent

Catégorie Package.xml Source tracking + unlocked packages Workflow Serpent
Modèle Deployment piloté par manifest Développement Git-driven avec package promotion Workflow task-driven autour de Git, environnements et releases
Idéal pour Hotfixes et legacy teams Équipes modernes avec versioned releases Équipes voulant vitesse, visibilité et moins de friction
Sélection de metadata Manuel Source tracking et sélection Git Guidée, basée sur les tasks et consciente des dependencies
Dependencies Manuel Mieux, mais demande de la discipline Assisté par metadata analysis et workflow logic
Traceability en production Limitée Bonne avec les package versions Forte visibilité sur work items, releases et orgs
Clarté du rollback Plus difficile, surtout avec des destructive changes Meilleure avec des packages versioned Plus claire via les release artefacts, l'historique du workflow et la package promotion
Hotfix / back-promotion Utile et souvent nécessaire Peut encore nécessiter package.xml pour la recovery en production Prise en charge dans le workflow de release et le modèle de visibilité
Charge opérationnelle Faible au début, élevée ensuite Modérée Overhead continu plus faible car une grande partie du workflow est native et visible
Collaboration Surtout manuelle Git-centric et developer-friendly Adapté aux developers, admins, testers et release managers
Quand nous le recommandons Cas particuliers et processus legacy Par défaut recommandé pour la plupart des équipes modernes Recommandé quand vous voulez les mêmes principes DevOps avec beaucoup moins de friction

package.xml et source tracking

package.xml est le manifest traditionnel qui liste les metadata à retrieve ou deploy.

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
  <types>
    <members>AccountService</members>
    <name>ApexClass</name>
  </types>
  <version>61.0</version>
</Package>

Il donne un contrôle explicite, mais reste manuel, fragile côté dependencies et plus difficile à maintenir quand le périmètre de release grandit.

Source tracking compare les changements d'une org avec la source locale:

sf project retrieve start
sf project deploy start

Pour la plupart des équipes modernes, source tracking est meilleur pendant development, tandis que les unlocked packages gèrent la release promotion.

Pourquoi nous recommandons source tracking + unlocked packages

Pourquoi ?

  • source tracking offre une meilleure expérience de development au quotidien qu'un manifest manuel

  • les unlocked packages apportent un vrai versioning de release plus loin dans le flow

  • la traceability en production devient beaucoup plus claire grâce aux package versions

  • le rollback et la gestion des destructive changes sont plus faciles à raisonner

Cela dit, package.xml reste utile dans des cas particuliers, donc l'objectif n'est pas la pureté. L'objectif est d'utiliser le bon outil à la bonne étape.

Qu'en est-il de la production ?

C'est en production que les limites du source tracking deviennent importantes. Vous ne pouvez pas traiter la production comme un scratch org et demander à Salesforce de vous dire proprement ce qui a changé là-bas au fil du temps.

Cela signifie que les deployments en production dépendent généralement de:

  • manifests package.xml

  • source directories construites depuis Git

  • versions d'unlocked packages

C'est l'une des raisons pour lesquelles la package promotion versioned a autant de valeur: elle donne à la production une identité de release plus claire que ce que le source tracking seul peut fournir là-bas.

Il ne faut pas trop en exagérer l'intention. Le point pratique est simple: la production ne se comporte pas comme un dev org source-tracked, donc les équipes ont besoin d'un autre moyen de rendre l'état de release explicite. Les unlocked packages sont l'un des meilleurs moyens d'y parvenir.

Sélectionner les feature-level changes

Une sandbox contient souvent plusieurs changements. Le pattern sûr consiste à tout retrieve, sélectionner seulement les composants d'une feature, puis committer ce scope dans une feature branch.

sf project retrieve start
git status
git add force-app/main/default/classes/PricingService.cls
git add force-app/main/default/triggers/OpportunityTrigger.trigger
git commit -m "Feature: pricing approval flow"

Avec Serpent, cela devient plus simple car work items, metadata selection et dependency analysis sont dans le même workflow.

Delta deployments vs full branch deployments

Quand les delta deployments ont du sens

Les delta deployments sont utiles pour une PR validation rapide et les petites features isolées.

Plus précisément, ils sont utiles pour:

  • valider les pull requests rapidement

  • promouvoir des features petites et isolées

  • réduire le temps de validation dans les très grosses orgs

sf sgd source delta \
  --to HEAD \
  --from origin/develop \
  --output-dir delta \
  --generate-delta
sf project deploy validate --source-dir delta --test-level RunLocalTests
sf project deploy start --source-dir delta

Des suites CLI open-source enveloppent ces mêmes commandes derrière un menu guidé, un compromis raisonnable entre scripts bruts et plateforme. Voyez comment Serpent se compare à sfdx-hardis si c'est la voie que vous envisagez.

Quand les full deployments ont plus de sens

Les full deployments sont meilleurs pour destructive changes, revert commits et reset de drift dans les environnements partagés. Il en va de même pour les types qui vivent encore dans de gros fichiers partagés, profiles et permission sets en tête, qui ne se diffent pas proprement et qu'un delta peut manquer ou écraser en partie.

Plus précisément, les full branch deployments sont préférables pour:

  • gérer les suppressions ou destructive changes

  • revenir en arrière sur des commits

  • s'assurer qu'un environnement correspond à un état de branche connu

  • réinitialiser le drift dans un environnement partagé

  • promouvoir des profiles ou permission sets, où le fichier entier doit arriver comme un seul bloc plutôt que comme un diff calculé

Choisissez aussi un full deployment pour les profiles et les permission sets : le fichier doit arriver d'un bloc, pas sous forme de delta calculé.

sf project deploy start --source-dir force-app

En pratique, un processus solide utilise les deux:

  • delta deploys pour la vitesse

  • full deploys pour la certitude quand le type de changement l'exige

Ces deux modes poussent le code vers le haut. Le sens inverse compte autant : dès qu'un hotfix part directement en production, tous les environnements inférieurs sont en retard tant que vous n'avez pas mis en place la back-promotion dans la pipeline, l'étape que la plupart des workflows faits maison sautent.

Serpent aide aussi ici en rendant le flow de deployment moins fragile. Plutôt que chaque équipe ne recrée cette logique dans GitHub Actions à la main, le workflow peut indiquer quand un mouvement ciblé est approprié et quand une promotion plus large est plus sûre.

Unlocked packages pour release versioning

Les unlocked packages rendent les releases explicites: vous promouvez un versioned artifact plutôt qu'un ensemble de metadata. Cela améliore traceability, promotion UAT vers production et planning de rollback.

Cela signifie:

  • des numéros de version clairs pour chaque release

  • une promotion plus simple de UAT vers production

  • une meilleure visibilité sur ce qui est déployé où

  • une gestion des dependencies plus propre

  • un planning de rollback plus prévisible

Flow d'unlocked package recommandé

Pour une grande équipe org-based, le flow de release ressemble généralement à ceci:

Developer Sandbox
      ↓
Retrieve to Git
      ↓
Pull Request validation
      ↓
Deploy source to QA
      ↓
Create release branch
      ↓
Build unlocked package version
      ↓
Install in UAT
      ↓
Regression and approval
      ↓
Install same package version in Production

Pour une très petite équipe, cela peut être plus simple:

Developer Sandbox
      ↓
Retrieve to Git
      ↓
Pull Request validation
      ↓
Build unlocked package version
      ↓
Install in Staging
      ↓
Promote same package version to Production

Exemples de commandes

sf package create --name SalesApp --package-type Unlocked --path force-app
sf package version create --package SalesApp --wait 20 --installation-key-bypass
sf package install --package 04tXXXXXXXXXXXX --target-org myUATOrg --wait 20
sf package install --package 04tXXXXXXXXXXXX --target-org myProdOrg --wait 20

Pourquoi le rollback est plus facile à comprendre

Les unlocked packages ne résolvent pas comme par magie tous les problèmes de rollback, surtout quand des changements de données sont impliqués. Mais comparés au source deployment brut ou à une promotion uniquement basée sur package.xml, ils rendent le rollback plus facile à comprendre parce que:

  • la release est un artifact versioned

  • vous savez exactement quelle package version a introduit le changement

  • vous pouvez comparer plus clairement ce qui a changé entre les versions

  • les destructive changes sont plus faciles à suivre dans le contexte de l'historique de release

Cela compte encore plus en production, où le source tracking ne peut pas vous donner la même visibilité qu'en environnement de development.

Construire la pipeline GitHub Actions

GitHub Actions est un bon choix pour comprendre les mechanics et construire une fondation CI/CD dans le repository. Les workflows sont définis en YAML.

Mapping recommandé branche-vers-environnement

feature/*   → developer work item branches
develop     → deployed to QA
release/*   → package version build
main        → production history
hotfix/*    → urgent production fixes

Exemple de pipeline GitHub Actions complète de bout en bout

L'exemple ci-dessous montre une mise en place pratique de bout en bout utilisant:

  • PR validation vers develop

  • deploy source automatique vers QA au merge sur develop

  • package version build sur release/*

  • package install vers UAT

  • promotion manuelle de la même package version vers Production

name: Salesforce End-to-End CI/CD

on:
  pull_request:
    branches:
      - develop
  push:
    branches:
      - develop
      - 'release/*'
  workflow_dispatch:
    inputs:
      package_version_id:
        description: 'Unlocked package version id to promote to Production'
        required: false
        type: string

env:
  PROJECT_DIR: force-app
  DELTA_DIR: delta
  QA_ALIAS: qa
  UAT_ALIAS: uat
  PROD_ALIAS: prod
  PACKAGE_NAME: SalesApp

jobs:
  pr-validate:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Install Salesforce CLI
        run: npm install @salesforce/cli --global

      - name: Install plugins
        run: |
          sf plugins install sfdx-git-delta
          sf plugins install @salesforce/plugin-packaging

      - name: Create JWT key file
        run: echo "${{ secrets.SF_JWT_KEY_QA }}" > server.key

      - name: Authenticate to QA validation org
        run: |
          sf org login jwt \
            --client-id ${{ secrets.SF_CLIENT_ID_QA }} \
            --jwt-key-file server.key \
            --username ${{ secrets.SF_USERNAME_QA }} \
            --instance-url ${{ secrets.SF_INSTANCE_URL_QA }} \
            --alias $QA_ALIAS

      - name: Generate delta package
        run: |
          sf sgd source delta \
            --to HEAD \
            --from origin/develop \
            --output-dir $DELTA_DIR \
            --generate-delta

      - name: Show generated delta
        run: |
          echo "Delta contents:"
          find $DELTA_DIR || true

      - name: Run PMD scan
        run: |
          pmd -d $PROJECT_DIR -R category/apex/design.xml -f text || true

      - name: Run ESLint
        run: |
          if [ -f package.json ]; then
            npm ci
            npm run lint || true
          fi

      - name: Validate delta deployment against QA
        run: |
          if [ -d "$DELTA_DIR" ]; then
            sf project deploy validate \
              --source-dir $DELTA_DIR \
              --target-org $QA_ALIAS \
              --test-level RunLocalTests
          else
            echo "No delta generated, validating full source instead."
            sf project deploy validate \
              --source-dir $PROJECT_DIR \
              --target-org $QA_ALIAS \
              --test-level RunLocalTests
          fi

  deploy-to-qa:
    if: github.event_name == 'push' && github.ref == 'refs/heads/develop'
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Install Salesforce CLI
        run: npm install @salesforce/cli --global

      - name: Install plugins
        run: |
          sf plugins install sfdx-git-delta

      - name: Create JWT key file
        run: echo "${{ secrets.SF_JWT_KEY_QA }}" > server.key

      - name: Authenticate to QA
        run: |
          sf org login jwt \
            --client-id ${{ secrets.SF_CLIENT_ID_QA }} \
            --jwt-key-file server.key \
            --username ${{ secrets.SF_USERNAME_QA }} \
            --instance-url ${{ secrets.SF_INSTANCE_URL_QA }} \
            --alias $QA_ALIAS

      - name: Generate delta for QA deploy
        run: |
          sf sgd source delta \
            --to HEAD \
            --from HEAD^ \
            --output-dir $DELTA_DIR \
            --generate-delta || true

      - name: Deploy to QA
        run: |
          if [ -d "$DELTA_DIR" ] && [ "$(find $DELTA_DIR -type f | wc -l)" -gt 0 ]; then
            sf project deploy start \
              --source-dir $DELTA_DIR \
              --target-org $QA_ALIAS \
              --test-level RunLocalTests
          else
            echo "Falling back to full branch deploy"
            sf project deploy start \
              --source-dir $PROJECT_DIR \
              --target-org $QA_ALIAS \
              --test-level RunLocalTests
          fi

  build-package-and-install-uat:
    if: github.event_name == 'push' && startsWith(github.ref, 'refs/heads/release/')
    runs-on: ubuntu-latest
    outputs:
      package_version_id: ${{ steps.capture_version.outputs.package_version_id }}

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Install Salesforce CLI
        run: npm install @salesforce/cli --global

      - name: Install packaging plugin
        run: sf plugins install @salesforce/plugin-packaging

      - name: Create Dev Hub JWT key file
        run: echo "${{ secrets.SF_JWT_KEY_DEVHUB }}" > server.key

      - name: Authenticate to Dev Hub
        run: |
          sf org login jwt \
            --client-id ${{ secrets.SF_CLIENT_ID_DEVHUB }} \
            --jwt-key-file server.key \
            --username ${{ secrets.SF_USERNAME_DEVHUB }} \
            --instance-url ${{ secrets.SF_INSTANCE_URL_DEVHUB }} \
            --alias devhub

      - name: Create package version
        run: |
          sf package version create \
            --package $PACKAGE_NAME \
            --target-dev-hub devhub \
            --wait 30 \
            --installation-key-bypass \
            --code-coverage

      - name: Capture latest package version id
        id: capture_version
        run: |
          VERSION_ID=$(sf package version list --packages $PACKAGE_NAME --target-dev-hub devhub --json | jq -r '.result[0].SubscriberPackageVersionId')
          echo "package_version_id=$VERSION_ID" >> $GITHUB_OUTPUT
          echo "Latest package version id: $VERSION_ID"

      - name: Create UAT JWT key file
        run: echo "${{ secrets.SF_JWT_KEY_UAT }}" > server.key

      - name: Authenticate to UAT
        run: |
          sf org login jwt \
            --client-id ${{ secrets.SF_CLIENT_ID_UAT }} \
            --jwt-key-file server.key \
            --username ${{ secrets.SF_USERNAME_UAT }} \
            --instance-url ${{ secrets.SF_INSTANCE_URL_UAT }} \
            --alias $UAT_ALIAS

      - name: Install package in UAT
        run: |
          sf package install \
            --package ${{ steps.capture_version.outputs.package_version_id }} \
            --target-org $UAT_ALIAS \
            --wait 30 \
            --publish-wait 10 \
            --no-prompt

  promote-to-production:
    if: github.event_name == 'workflow_dispatch' && github.event.inputs.package_version_id != ''
    runs-on: ubuntu-latest
    environment: production

    steps:
      - name: Install Salesforce CLI
        run: npm install @salesforce/cli --global

      - name: Create Production JWT key file
        run: echo "${{ secrets.SF_JWT_KEY_PROD }}" > server.key

      - name: Authenticate to Production
        run: |
          sf org login jwt \
            --client-id ${{ secrets.SF_CLIENT_ID_PROD }} \
            --jwt-key-file server.key \
            --username ${{ secrets.SF_USERNAME_PROD }} \
            --instance-url ${{ secrets.SF_INSTANCE_URL_PROD }} \
            --alias $PROD_ALIAS

      - name: Install approved package in Production
        run: |
          sf package install \
            --package ${{ github.event.inputs.package_version_id }} \
            --target-org $PROD_ALIAS \
            --wait 30 \
            --publish-wait 10 \
            --no-prompt

Ce n'est pas le seul design GitHub Actions valide, mais il capture la répartition recommandée entre validation source-based dans les environnements inférieurs et promotion package-based vers UAT et Production.

Pratiques de pipeline complémentaires et guidance opérationnelle

Une pipeline CI/CD n'est qu'une partie d'un processus Salesforce DevOps qui fonctionne. Ce qui détermine souvent le succès ou l'échec, c'est la façon dont les équipes gèrent les détails opérationnels autour du development, des tests, de la promotion et de la coordination des releases.

Gérer les changements au niveau feature en toute sécurité

Un des défis du development Salesforce est que les sandboxes accumulent souvent plusieurs changements à la fois. Un developer peut travailler sur deux ou trois features, mais une seule est prête pour la promotion.

Si vous retrieve simplement toutes les metadata et les déployez telles quelles, vous risquez de promouvoir du travail inachevé.

Le pattern plus sûr est:

Developer Sandbox
      ↓
Retrieve all metadata locally
      ↓
Select only the components belonging to the feature
      ↓
Commit those components to a feature branch
      ↓
Submit a pull request for validation

Exemple de workflow:

sf project retrieve start

git checkout -b feature/pricing-update

git add force-app/main/default/classes/PricingService.cls
git add force-app/main/default/triggers/PricingTrigger.trigger
git add force-app/main/default/lwc/pricingWidget

git commit -m "Feature: pricing update"

Cela garantit que le dépôt reflète une seule feature logique plutôt qu'un mélange de changements sans rapport.

La difficulté est que les metadata Salesforce sont souvent interconnectées. Un Flow peut dépendre de:

  • custom fields

  • Apex classes

  • permission sets

  • record types

Manquer l'une de ces dependencies peut casser la validation du deployment.

Beaucoup d'équipes résolvent cela par l'expérience et des vérifications manuelles. Des plateformes comme Serpent aident en analysant les relations entre metadata et en identifiant automatiquement les dependencies, pour que le bon ensemble de composants avance ensemble.

Sélection de metadata assistée par IA

Les récentes améliorations des outils de development ont introduit de l'assistance IA pour l'analyse de dependencies.

En pratique, cela veut dire:

  • une description de feature peut être analysée

  • les composants de metadata liés peuvent être détectés

  • les dependency graphs peuvent être évalués

  • le scope de metadata le plus probable peut être suggéré

Serpent inclut des AI agents entraînés sur les patterns de metadata Salesforce, qui aident à déterminer l'ensemble logique de composants requis pour une feature, réduisant le risque de deployments incomplets.

Cela ne retire pas le contrôle du developer. Cela rend simplement la sélection plus rapide et plus sûre.

Gérer le sandbox drift

Un autre problème courant dans les environnements Salesforce est le sandbox drift.

Cela arrive quand quelqu'un fait un changement directement dans un environnement partagé comme QA ou UAT qui n'atteint jamais le dépôt Git.

Au fil du temps, l'environnement diverge du source control.

Pour détecter le drift, les équipes font souvent des comparaisons périodiques:

sf project retrieve start
git diff

Si des différences inattendues apparaissent, elles doivent être réconciliées immédiatement en les committant dans Git ou en les supprimant.

Laisser le drift s'accumuler rend les deployments suivants imprévisibles.

Stratégie d'environnements

Chaque environnement doit avoir un but clair.

Environnement But
Developer Sandbox Development de features et tests précoces
QA Tests intégrés sur plusieurs features
UAT Validation métier des release candidates
Production Système en production

Des problèmes surviennent souvent quand les environnements perdent leur but. Si QA devient une autre sandbox de development, il cesse de fonctionner comme un point de contrôle d'intégration fiable.

Stratégie de tests

Un processus CI/CD robuste inclut des tests automatisés à plusieurs niveaux.

  • unit tests pour Apex

  • component tests pour LWC

  • integration tests pour les workflows cross-feature

Les pipelines de PR validation lancent souvent des tests ciblés pour la vitesse, tandis que les pipelines de release lancent des suites de tests plus larges.

Exemple de PR validation:

sf project deploy validate \
  --source-dir delta \
  --test-level RunSpecifiedTests

Exemple de release validation:

sf project deploy validate \
  --source-dir force-app \
  --test-level RunLocalTests

L'objectif est de détecter les problèmes tôt sans ralentir inutilement les cycles de feedback des developers. Décider quelle suite tourne à quelle étape, et où la couverture UI s'intègre, est un sujet à part entière: le guide sur le test automation en CI parcourt les niveaux dans l'ordre.

Visibilité des releases

Un des défis DevOps les plus sous-estimés est simplement de savoir ce qui se trouve dans une release.

Les questions que les équipes posent fréquemment incluent:

  • Quelles features sont incluses dans la prochaine release ?

  • Quels composants ont été déployés en QA hier ?

  • Quelle package version est actuellement installée en production ?

Sans workflow structuré, répondre à ces questions demande souvent de fouiller dans l'historique Git, les logs de pipeline et des release notes manuelles.

Serpent répond à cela en liant les deployments à des work items, rendant les releases plus faciles à comprendre à travers les environnements.

Expérience développeur

La productivité des developers compte aussi.

Beaucoup de developers préfèrent travailler dans VS Code avec les extensions Salesforce et les outils CLI.

Les plateformes DevOps devraient s'intégrer à ce workflow plutôt que de forcer les developers vers des interfaces entièrement séparées.

Serpent inclut une extension VS Code qui permet aux developers de:

  • comparer les metadata

  • valider les deployments

  • gérer les tâches de release

  • déployer les changements

Cela garde les opérations DevOps proches de l'environnement de development.

Connected App et JWT authentication

Les exemples de pipeline ci-dessus supposent que votre runner GitHub Actions peut s'authentifier à Salesforce sans interaction humaine. Le pattern standard est une authentification JWT adossée à une Connected App. Voici la mise en place pratique, de bout en bout.

1. Créer une Connected App dans Salesforce

  1. Créez une Connected App dans Salesforce App Manager.

  2. Définissez la callback URL sur http://localhost:1717/OauthRedirect.

  3. Sélectionnez les OAuth scopes api et refresh_token, offline_access.

  4. Uploadez un certificat et stockez la private key dans GitHub Secrets.

2. Générer le certificat

openssl genrsa -out server.key 2048
openssl req -new -x509 -days 1825 -key server.key -out server.crt

Uploadez server.crt sur la Connected App. Stockez server.key de façon sécurisée - elle va dans GitHub Secrets, jamais dans le dépôt.

3. Ajouter les GitHub Secrets

Dans votre dépôt GitHub, allez dans Settings → Secrets and variables → Actions et ajoutez:

Le workflow ci-dessus s'authentifie auprès de quatre orgs distincts - QA, le Dev Hub, l'UAT et la Production - chaque secret a donc besoin d'une copie par environnement, avec le suffixe _QA, _DEVHUB, _UAT ou _PROD (par exemple SF_CLIENT_ID_QA et SF_CLIENT_ID_DEVHUB). Répétez les quatre secrets ci-dessous pour chaque suffixe, en pointant vers la Connected App et l'org propres à cet environnement:

  • SF_CLIENT_ID_<ENV> - la Consumer Key de la Connected App de cet environnement.

  • SF_USERNAME_<ENV> - le username Salesforce de cet environnement, par exemple [email protected].

  • SF_JWT_KEY_<ENV> - le contenu du fichier server.key de cet environnement.

  • SF_INSTANCE_URL_<ENV> - https://test.salesforce.com pour les sandboxes (QA, UAT, Dev Hub) ou https://login.salesforce.com pour la production.

Erreurs courantes

Error Cause probable Fix
INVALID_LOGIN JWT key ou client ID incorrect Vérifiez les secrets et les trailing newlines.
INSUFFICIENT_ACCESS Permissions Connected App Contrôlez les scopes et l'activation pour l'integration user.
Tests failing on deploy Code coverage sous 75% Lancez sf apex run test localement et améliorez coverage.
Metadata not deploying Structure de projet SFDX incorrecte Vérifiez que sfdx-project.json a les bons packageDirectories.
Job times out mid-deploy Validation longue ou tests full-org Utilisez --test-level RunLocalTests en PR validation. Réservez RunAllTestsInOrg au job de production.

FAQ

Comment GitHub Actions s'authentifie-t-il à une org Salesforce ?

Par une Connected App avec le flow JWT. Vous créez l'app dans App Manager, chargez un certificat et stockez la clé privée et la consumer key dans les GitHub Secrets, puis le workflow s'y connecte avant toute étape de déploiement.

Pourquoi ma pipeline échoue-t-elle en INVALID_LOGIN ?

La clé JWT ou le client ID ne correspond pas à ce qu'attend la Connected App. Vérifiez les secrets caractère par caractère et surveillez le retour à la ligne parasite en fin de clé privée.

Pourquoi mes tests échouent-ils au déploiement ?

Le plus souvent la couverture de code est sous les 75 pour cent. Lancez sf apex run test en local pour voir les classes concernées, et utilisez RunLocalTests en validation de pull request pour garder un job rapide. Quelle suite à quelle étape, c'est le sujet du guide sur le test automation en CI.

Delta deployments ou full deployments ?

Les delta deployments ne poussent que ce qui a changé, ce qui convient à la validation des pull requests et aux petites fonctionnalités dans les grosses orgs. Les full deployments sont plus sûrs pour les suppressions, les reverts et les remises à niveau.

Ai-je besoin de sfdx-git-delta ?

Non, mais il en vaut la peine dès que les déploiements deviennent lents. Associez-le à un full deploy pour les suppressions, afin que les destructive changes soient gérées et non silencieusement ignorées.

Dois-je utiliser sfdx ou sf pour un pipeline Salesforce GitHub Actions ?

Utilisez sf, le CLI Salesforce moderne, car l'ancien CLI sfdx qu'il remplace est deprecated et ne devrait pas être la base d'un nouveau pipeline. Migrer un pipeline existant tient surtout aux noms de commandes : sfdx force:source:deploy devient sf project deploy start, sfdx force:apex:test:run devient sf apex run test, et les plugins se réinstallent via sf plugins install.

Pourquoi valider sur la pull request puis redéployer au merge ?

Le job de pull request prouve que la branche compile et passe ses tests contre l'org cible, sans rien y écrire. Le job de merge est celui qui modifie l'org, et il tourne sur le commit de merge, qui n'est pas l'arbre validé par la pull request.

Conclusion

Salesforce DevOps ne dépend pas d'un seul outil ou d'un format de pipeline parfait. Il s'agit de créer un processus fiable où Git est la source of truth, les changements sont validés automatiquement et les releases sont versioned et traceable.

GitHub Actions aide les équipes à comprendre l'automation sous le capot. Lorsque les environnements Salesforce deviennent plus complexes, des outils comme Serpent aident à garder vitesse, contrôle, visibilité et release confidence.

Articles similaires

Curieux de livrer plus vite avant de vous lancer ? Parlons-en

Sans engagement.