Les workflows réutilisables permettent de factoriser la logique CI/CD commune. Au lieu de copier-coller les mêmes jobs dans 10 repositories, vous créez un workflow central appelable par tous les autres.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Créer un workflow réutilisable avec le trigger
workflow_call - Définir des inputs, des secrets et des outputs typés
- Appeler un workflow réutilisable depuis un autre dépôt ou en local
- Passer les secrets explicitement ou via
secrets: inherit - Chaîner et versionner vos templates CI/CD
- Connaître les limitations : profondeur d'appel, secrets dynamiques
Ce guide s'adresse à ceux qui maintiennent plusieurs pipelines. Si vous débutez, voyez d'abord Workflows GitHub Actions.
Pourquoi réutiliser des workflows ?
Section intitulée « Pourquoi réutiliser des workflows ? »Problème : vous avez 50 microservices avec des pipelines quasi identiques. Chaque modification (nouvelle version de Node, ajout d'un scan de sécurité) nécessite de modifier 50 fichiers.
Solution : un workflow réutilisable dans un repository central :
org/ci-templates/└── .github/workflows/ ├── node-ci.yml # CI standard Node.js ├── python-ci.yml # CI standard Python └── docker-build.yml # Build et push d'imagesChaque microservice appelle ces templates :
# Dans chaque repo : 5 lignes au lieu de 100jobs: ci: uses: org/ci-templates/.github/workflows/node-ci.yml@v1.0.0 with: node-version: '20' secrets: inheritCréer un workflow réutilisable
Section intitulée « Créer un workflow réutilisable »Un workflow réutilisable est un fichier de workflow comme les autres, à une différence près : son déclencheur le rend appelable par d'autres workflows.
Structure de base
Section intitulée « Structure de base »Un workflow réutilisable utilise le trigger workflow_call :
name: Reusable CI
on: workflow_call: # Ce trigger rend le workflow appelable inputs: node-version: description: 'Version de Node.js' required: false type: string default: '20' secrets: npm-token: description: 'Token NPM pour publish' required: false
jobs: build: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ inputs.node-version }}
- run: npm ci - run: npm testDéfinir les inputs
Section intitulée « Définir les inputs »Les inputs permettent de paramétrer le workflow :
on: workflow_call: inputs: # Input obligatoire environment: description: 'Environnement de déploiement' required: true type: string
# Input optionnel avec valeur par défaut node-version: description: 'Version de Node.js' required: false type: string default: '20'
# Input booléen skip-tests: description: 'Skip les tests' required: false type: boolean default: false
# Input numérique timeout: description: 'Timeout en minutes' required: false type: number default: 30Types d'inputs disponibles : string, boolean, number.
Définir les secrets
Section intitulée « Définir les secrets »Les secrets sont déclarés séparément des inputs :
on: workflow_call: secrets: # Secret obligatoire deploy-key: description: 'Clé SSH de déploiement' required: true
# Secret optionnel slack-webhook: description: 'Webhook Slack pour notifications' required: falseDéfinir les outputs
Section intitulée « Définir les outputs »Les outputs permettent de retourner des valeurs au workflow appelant :
on: workflow_call: outputs: version: description: 'Version buildée' value: ${{ jobs.build.outputs.version }} image-digest: description: "Digest de l'image Docker" value: ${{ jobs.build.outputs.digest }}
jobs: build: runs-on: ubuntu-24.04 outputs: version: ${{ steps.version.outputs.value }} digest: ${{ steps.push.outputs.digest }} steps: - id: version run: echo "value=$(cat VERSION)" >> $GITHUB_OUTPUT
- id: push run: echo "digest=sha256:abc123" >> $GITHUB_OUTPUTAppeler un workflow réutilisable
Section intitulée « Appeler un workflow réutilisable »Côté appelant, un workflow réutilisable s'invoque à la place des steps: d'un
job, avec le mot-clé uses:.
Syntaxe d'appel
Section intitulée « Syntaxe d'appel »Le job appelant ne contient pas de steps:, il délègue entièrement le
travail au workflow réutilisable.
name: CI
on: [push, pull_request]
jobs: call-workflow: uses: owner/repo/.github/workflows/reusable.yml@v1.0.0 with: node-version: '20' environment: 'production' secrets: deploy-key: ${{ secrets.DEPLOY_KEY }}Référencer le workflow
Section intitulée « Référencer le workflow »Plusieurs formats sont possibles :
# Même repository (chemin relatif)uses: ./.github/workflows/reusable.yml
# Repository externe avec branche (mobile, à éviter en production)uses: org/repo/.github/workflows/reusable.yml@main
# Repository externe avec taguses: org/repo/.github/workflows/reusable.yml@v1.0.0
# Repository externe avec SHA (recommandé pour la sécurité)uses: org/repo/.github/workflows/reusable.yml@a1b2c3d4e5f6Passer les secrets
Section intitulée « Passer les secrets »Trois méthodes existent pour passer les secrets au workflow réutilisable.
1. Secrets explicites, vous transmettez nommément ce dont le template a besoin, et rien d'autre :
jobs: call: uses: org/repo/.github/workflows/reusable.yml@v1.0.0 secrets: npm-token: ${{ secrets.NPM_TOKEN }} deploy-key: ${{ secrets.DEPLOY_KEY }}2. Hériter tous les secrets, secrets: inherit transmet l'intégralité des
secrets du dépôt parent. Pratique, mais c'est l'option la plus large :
jobs: call: uses: org/repo/.github/workflows/reusable.yml@v1.0.0 secrets: inherit3. Aucun secret, si le workflow réutilisable n'en a pas besoin, n'en passez aucun :
jobs: call: uses: org/repo/.github/workflows/reusable.yml@v1.0.0Utiliser les outputs
Section intitulée « Utiliser les outputs »Le workflow appelant récupère les valeurs retournées par le workflow
réutilisable via needs.<job>.outputs.
jobs: build: uses: org/repo/.github/workflows/build.yml@v1.0.0
deploy: needs: build runs-on: ubuntu-24.04 steps: - run: | echo "Deploying version ${{ needs.build.outputs.version }}" echo "Image digest: ${{ needs.build.outputs.image-digest }}"Exemple complet
Section intitulée « Exemple complet »Voici un cas réel de bout en bout : un template de CI Node.js et le workflow d'un service qui l'appelle.
Workflow réutilisable (template)
Section intitulée « Workflow réutilisable (template) »Ce template centralise le lint et les tests Node.js, pilotables par des inputs.
name: Node.js CI
on: workflow_call: inputs: node-version: type: string default: '20' working-directory: type: string default: '.' run-tests: type: boolean default: true run-lint: type: boolean default: true secrets: npm-token: required: false outputs: test-passed: description: 'Tests passés' value: ${{ jobs.test.outputs.passed }}
permissions: contents: read
jobs: lint: if: ${{ inputs.run-lint }} runs-on: ubuntu-24.04 defaults: run: working-directory: ${{ inputs.working-directory }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ inputs.node-version }} cache: 'npm' cache-dependency-path: ${{ inputs.working-directory }}/package-lock.json
- run: npm ci - run: npm run lint
test: if: ${{ inputs.run-tests }} runs-on: ubuntu-24.04 outputs: passed: ${{ steps.test.outputs.passed }} defaults: run: working-directory: ${{ inputs.working-directory }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ inputs.node-version }} cache: 'npm' cache-dependency-path: ${{ inputs.working-directory }}/package-lock.json
- run: npm ci
- id: test run: | npm test echo "passed=true" >> $GITHUB_OUTPUTWorkflow appelant
Section intitulée « Workflow appelant »Côté service, le pipeline tient en quelques lignes : il appelle le template puis enchaîne un déploiement conditionnel.
name: CI
on: push: branches: [main] pull_request: branches: [main]
jobs: ci: uses: org/ci-templates/.github/workflows/node-ci.yml@v1.0.0 with: node-version: '20' run-lint: true run-tests: true secrets: inherit
deploy: needs: ci if: github.ref == 'refs/heads/main' runs-on: ubuntu-24.04 steps: - run: | echo "Tests passed: ${{ needs.ci.outputs.test-passed }}" - run: ./deploy.shPatterns avancés
Section intitulée « Patterns avancés »Une fois les bases acquises, ces patterns couvrent les cas que l'on rencontre sur de vrais portefeuilles de projets.
Workflow avec matrix
Section intitulée « Workflow avec matrix »Le workflow réutilisable peut contenir une matrix :
on: workflow_call: inputs: os: type: string default: '["ubuntu-24.04"]' node: type: string default: '["18", "20"]'
jobs: test: strategy: matrix: os: ${{ fromJSON(inputs.os) }} node: ${{ fromJSON(inputs.node) }} runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ matrix.node }} - run: npm ci && npm testAppel avec matrix personnalisée :
jobs: test: uses: org/templates/.github/workflows/reusable-test.yml@v1.0.0 with: os: '["ubuntu-24.04", "windows-latest"]' node: '["18", "20", "22"]'Chaîner plusieurs workflows réutilisables
Section intitulée « Chaîner plusieurs workflows réutilisables »Plusieurs workflows réutilisables s'enchaînent avec needs, exactement comme des
jobs classiques.
jobs: lint: uses: org/templates/.github/workflows/lint.yml@v1.0.0
test: needs: lint uses: org/templates/.github/workflows/test.yml@v1.0.0
build: needs: test uses: org/templates/.github/workflows/build.yml@v1.0.0 with: version: ${{ needs.test.outputs.version }}
deploy: needs: build uses: org/templates/.github/workflows/deploy.yml@v1.0.0 with: image: ${{ needs.build.outputs.image }} secrets: deploy-key: ${{ secrets.DEPLOY_KEY }}Workflow réutilisable avec permissions
Section intitulée « Workflow réutilisable avec permissions »Un workflow réutilisable déclare ses propres permissions:, le workflow
appelant doit lui accorder au moins ce niveau.
on: workflow_call: inputs: environment: type: string required: true
# Permissions déclarées dans le workflow réutilisablepermissions: contents: read id-token: write # Pour OIDC
jobs: deploy: runs-on: ubuntu-24.04 environment: ${{ inputs.environment }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Deploy run: ./deploy.shBonnes pratiques
Section intitulée « Bonnes pratiques »Quatre règles évitent les pièges les plus coûteux quand vos templates sont partagés par de nombreux dépôts.
1. Versionnez vos templates
Section intitulée « 1. Versionnez vos templates »Un workflow réutilisable est du code tiers : il s'épingle exactement comme
une action. N'appelez jamais un template en @main, une référence mobile
que le mainteneur peut faire pointer vers n'importe quoi. Utilisez un tag de
version ou, mieux, un SHA de commit :
# Acceptable : tag de versionuses: org/templates/.github/workflows/ci.yml@v1.2.0
# Le plus sûr : SHA de commituses: org/templates/.github/workflows/ci.yml@a1b2c3d4e5f6Le principe de l'épinglage et son outillage sont détaillés dans le guide Épingler les actions par SHA.
2. Documentez les inputs et outputs
Section intitulée « 2. Documentez les inputs et outputs »Une description claire sur chaque input évite aux équipes consommatrices de
devoir lire le code du template.
on: workflow_call: inputs: environment: description: | Environnement cible pour le déploiement. Valeurs acceptées : staging, production. Défaut : staging. type: string default: 'staging'3. Utilisez des valeurs par défaut sensées
Section intitulée « 3. Utilisez des valeurs par défaut sensées »Des default: bien choisis rendent le template utilisable sans configuration
dans le cas le plus courant.
inputs: node-version: type: string default: '20' # LTS actuel timeout: type: number default: 30 # Raisonnable pour la plupart des builds4. Limitez les permissions
Section intitulée « 4. Limitez les permissions »Déclarez le minimum au niveau du workflow et n'élargissez qu'au niveau du job qui en a réellement besoin.
# Dans le workflow réutilisablepermissions: contents: read # Minimum par défaut
jobs: publish: runs-on: ubuntu-24.04 permissions: contents: read packages: write # Uniquement si nécessaire steps: - run: ./publish.shLimitations
Section intitulée « Limitations »Les workflows réutilisables ont quelques contraintes structurantes, mieux vaut les connaître avant de bâtir toute une architecture dessus.
- Profondeur d'appel : les workflows réutilisables peuvent s'imbriquer, mais sur 4 niveaux maximum
- Nombre d'appels : maximum 20 workflows réutilisables uniques dans l'arbre d'appel
- Secrets : les secrets ne peuvent pas être passés dynamiquement via expressions
- Permissions : le workflow appelant doit avoir au moins les permissions requises par le workflow réutilisable
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À retenir
Section intitulée « À retenir »- Un workflow réutilisable se déclare avec le trigger
workflow_callet s'appelle viauses:à la place dessteps:d'un job. - Les inputs sont typés (
string,boolean,number) ; les secrets se déclarent à part. - Les outputs remontent au workflow appelant, qui les lit via
needs.<job>.outputs. secrets: inherittransmet tous les secrets du dépôt parent, pratique, mais à éviter quand le template n'a besoin que d'un ou deux secrets.- Versionnez vos templates par tag semver ou par SHA, jamais
@mainen production. - Limites à connaître : imbrication sur 4 niveaux maximum, 20 workflows réutilisables uniques par arbre d'appel, pas de secret passé dynamiquement.
Prochaines étapes
Section intitulée « Prochaines étapes »Pour la référence complète, consultez la documentation officielle sur les workflows réutilisables.