infra / github-actions
Reusable workflows et composite actions
Explication
Ce que vous allez apprendre
- Comprendre le coût de maintenance de la duplication entre plusieurs workflows similaires
- Créer un reusable workflow appelable via
workflow_call, avec entrées, secrets et sorties - Créer une composite action pour factoriser quelques steps récurrents dans un job
- Choisir entre reusable workflow (plusieurs jobs) et composite action (quelques steps)
- Appeler un reusable workflow depuis un autre dépôt, épinglé à une version précise
Dans quel contexte ?
Une entreprise gère cinq microservices, chacun avec son propre pipeline de déploiement. Les cinq fichiers deploy.yml sont quasi identiques : build de l'image Docker, push vers le registre, déploiement sur le cluster. Un jour, il faut changer la façon dont l'authentification au registre fonctionne : la mise à jour doit se faire manuellement dans les cinq fichiers, et un développeur en oublie un, qui continue de pousser avec l'ancienne méthode pendant plusieurs semaines sans que personne ne le remarque. Les reusable workflows et composite actions existent précisément pour éliminer ce genre de duplication dangereuse.
Le problème : la duplication entre pipelines
D'abord, dès qu'un projet a plusieurs workflows, déploiement staging, déploiement production, plusieurs microservices similaires, on retrouve vite les mêmes suites d'étapes copiées-collées d'un fichier YAML à l'autre.
Le coût de cette duplication
Cette duplication devient un vrai coût de maintenance : corriger un bug ou changer une étape doit alors se faire partout, avec le risque d'en oublier une.
Un premier mécanisme de réutilisation
Un "reusable workflow", déclenché via workflow_call, réutilise un fichier de workflow entier, plusieurs jobs, avec des entrées, des secrets, et des sorties typés comme une vraie fonction.
| Mécanisme | Niveau de réutilisation | Déclencheur |
|---|---|---|
| Reusable workflow | Un ou plusieurs jobs entiers | workflow_call |
| Composite action | Quelques steps à l'intérieur d'un job | uses: comme une action classique |
Un deuxième mécanisme, à un niveau plus fin
Une "composite action" réutilise, elle, une suite de quelques étapes à l'intérieur d'un job, plus légère, pensée pour factoriser un bloc récurrent comme "installer Node.js et les dépendances avec cache".
La bonne façon de penser ces deux mécanismes
Il faut les voir comme des fonctions réutilisables : elles déclarent explicitement ce qu'elles attendent en entrée, inputs, secrets, et ce qu'elles renvoient en sortie, outputs.
Prérequis
Cette leçon suppose les triggers (workflow_call, leçon 3) et les jobs/outputs (leçon 4) déjà acquis : un reusable workflow combine directement ces deux notions pour se comporter comme une vraie fonction appelable.
Ce que ça change par rapport au copier-coller
Cela rend le comportement prévisible et testable, contrairement à un simple copier-coller qui diverge silencieusement avec le temps.
Bonne pratique
Dès qu'une même suite d'étapes apparaît dans deux workflows ou plus, extrais-la en reusable workflow ou composite action. C'est le même réflexe que factoriser une fonction dupliquée en programmation classique : corriger un bug une seule fois plutôt que dans cinq fichiers différents.
La portée : locale ou partagée
Un reusable workflow peut être appelé depuis le même dépôt, avec ./, ou depuis un dépôt distinct, épinglé à une version précise, org/repo@v2.
Ce que cette portée élargie permet
C'est un moyen puissant de centraliser des pipelines standards partagés par plusieurs projets d'une même organisation, tout en gardant le contrôle de quelle version est utilisée où.
Maintenant que tu sais factoriser des pipelines, la leçon suivante s'attaque à un besoin d'infrastructure différent : exécuter des jobs sur ta propre machine plutôt que sur celles de GitHub, avec les self-hosted runners.
Commandes & code
Reusable workflows & composite actions
# .github/workflows/reusable-deploy.yml - workflow appelable depuis d'autres workflows
name: Reusable Deploy
on:
workflow_call:
inputs:
environment:
required: true
type: string
secrets:
deploy_token:
required: true
outputs:
deployed_url:
value: ${{ jobs.deploy.outputs.url }}
jobs:
deploy:
runs-on: ubuntu-latest
outputs:
url: ${{ steps.deploy.outputs.url }}
steps:
- uses: actions/checkout@v4
- id: deploy
run: |
./scripts/deploy.sh ${{ inputs.environment }}
echo "url=https://${{ inputs.environment }}.example.com" >> "$GITHUB_OUTPUT"
env:
DEPLOY_TOKEN: ${{ secrets.deploy_token }}# .github/workflows/deploy-staging.yml - appelle le workflow réutilisable ci-dessus
name: Deploy Staging
on:
push:
branches: [main]
jobs:
call-deploy:
uses: ./.github/workflows/reusable-deploy.yml
with:
environment: staging
secrets:
deploy_token: ${{ secrets.STAGING_DEPLOY_TOKEN }}
# Peut aussi appeler un workflow d'un AUTRE dépôt versionné :
# uses: myorg/shared-workflows/.github/workflows/reusable-deploy.yml@v2# .github/actions/setup-project/action.yml - composite action : regroupe des steps répétitifs
name: "Setup project"
description: "Checkout + install Node + install dépendances, avec cache"
inputs:
node-version:
required: false
default: "20"
runs:
using: "composite"
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: "npm"
- run: npm ci
shell: bash # obligatoire pour chaque step "run" d'une composite action# Utilisation de la composite action dans un workflow classique
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-project
with:
node-version: "22"
- run: npm testRésumé
workflow_calltransforme un workflow en composant réutilisable, avec inputs/secrets/outputs typés.- Un reusable workflow peut être appelé localement (
./) ou depuis un autre dépôt (org/repo@ref). - Une composite action regroupe des steps répétitifs en une seule "action" invocable via
uses:. - Chaque step
run:d'une composite action doit précisershell:explicitement.
Exercices pratiques
Mission : cinq pipelines de déploiement à ne plus dupliquer
Objectif : Extraire la logique commune de cinq workflows quasi identiques en un reusable workflow appelable avec des paramètres.
Contexte
Une entreprise gère cinq microservices, chacun avec son propre deploy.yml quasi identique (build de l'image Docker, push vers le registre, déploiement). Un changement récent dans la méthode d'authentification au registre a dû être répliqué manuellement dans les cinq fichiers, et un développeur en a oublié un, qui a continué de pousser avec l'ancienne méthode pendant plusieurs semaines sans que personne ne le remarque.