6. Workflows réutilisables et actions composites
Sections
Réglages de lecture
Voix naturelle enregistrée pour ce cours, la même dans tous les navigateurs.
Aucune voix pour cette langue dans ce navigateur.
Plus de voix
Code et termes techniques en anglais
Désactivé : la voix de la page lit tout, sans pause entre deux voix.
Aucune voix pour cette langue dans ce navigateur.
Plus de voix
D’autres voix : Microsoft Edge propose des voix naturelles en ligne, et Windows (Paramètres › Heure et langue › Voix), macOS et Android en installent d’autres.
Le problème du copier-coller
Section intitulée « Le problème du copier-coller »Après cinq leçons, les mêmes quatre lignes reviennent dans plusieurs workflows : setup-dotnet avec global-json-file, le cache NuGet, dotnet restore --locked-mode. GitHub Actions a deux façons de les partager, que les développeurs C# peuvent rapprocher d’idées familières :
| Action composite | Workflow réutilisable | |
|---|---|---|
| Partage | une suite de steps | des jobs entiers |
| Fichier | action.yml dans son propre dossier |
un workflow dans .github/workflows/ avec on: workflow_call |
| Appelé depuis | un step : uses: ./.github/actions/<name> |
un job : uses: ./.github/workflows/<file>.yml |
| Choisit le runner | non, s’exécute dans le job de l’appelant | oui, chaque job a son propre runs-on |
| Secrets | « Ne peut pas utiliser de secrets » directement — passe-les en inputs | reçoit secrets: ou secrets: inherit |
| Dans le log | « Journalisée comme un seul step même si elle contient plusieurs steps » | chaque job et chaque step journalisés normalement |
| Analogie C# | une méthode utilitaire appelée au milieu de ton code | un template de build complet |
| Azure Pipelines | template de step | template de job ou de stage |
Les citations viennent du tableau comparatif de la documentation. Les deux peuvent vivre dans le même dépôt ou être appelés depuis un autre (owner/repo/path@ref).
Une action composite
Section intitulée « Une action composite ».github/actions/dotnet-restore/action.yml :
# GitHub Actions course, lesson 6: a composite action that installs the SDK and restores with the NuGet cachename: Set up and restore a .NET solutiondescription: Installs the SDK pinned by global.json, then restores with the NuGet cache and the lock files.
inputs: directory: description: Folder that contains global.json, the solution and the packages.lock.json files required: true
outputs: sdk-version: description: The SDK version reported by dotnet --version value: ${{ steps.sdk.outputs.version }}
runs: using: composite steps: - name: Keep NuGet packages in the workspace shell: bash run: echo "NUGET_PACKAGES=$GITHUB_WORKSPACE/.nuget/packages" >> "$GITHUB_ENV" - uses: actions/setup-dotnet@v6 with: global-json-file: ${{ inputs.directory }}/global.json cache: true cache-dependency-path: ${{ inputs.directory }}/*/packages.lock.json - id: sdk shell: bash working-directory: ${{ inputs.directory }} run: echo "version=$(dotnet --version)" >> "$GITHUB_OUTPUT" - shell: bash working-directory: ${{ inputs.directory }} run: dotnet restore --locked-mode- Les
inputsse lisent avec${{ inputs.directory }}; un output doit être relié explicitement à un step interne (value: ${{ steps.sdk.outputs.version }}). - Chaque step
run:d’une action composite a besoin d’unshell:— l’exercice 1 montre ce qui se passe sans. - Le premier step écrit dans
$GITHUB_ENV: la variable existe pour les steps suivants de l’action et pour le reste du job de l’appelant. Une action composite partage la machine, le workspace et l’environnement du job.
Un workflow réutilisable
Section intitulée « Un workflow réutilisable ».github/workflows/gha-06-dotnet-test.yml utilise l’action et lance les tests :
# GitHub Actions course, lesson 6: a reusable workflow that tests the .NET sample on one OSname: "GHA 06: reusable .NET test"
on: workflow_call: inputs: os: description: Runner label type: string default: ubuntu-latest outputs: sdk-version: description: SDK used by the tests value: ${{ jobs.test.outputs.sdk-version }} tested-on: description: Operating system of the runner value: ${{ jobs.test.outputs.tested-on }}
jobs: test: runs-on: ${{ inputs.os }} outputs: sdk-version: ${{ steps.setup.outputs.sdk-version }} tested-on: ${{ runner.os }} steps: - uses: actions/checkout@v7 - id: setup uses: ./.github/actions/dotnet-restore with: directory: code/github-actions/dotnet - run: dotnet test --no-restore working-directory: code/github-actions/dotnet - name: What the called workflow sees shell: bash run: | echo "event_name: ${{ github.event_name }}" echo "github.workflow: ${{ github.workflow }}" echo "github.workflow_ref: ${{ github.workflow_ref }}" echo "job.workflow_ref: ${{ job.workflow_ref }}" echo "COURSE from caller: '$COURSE'" echo "NUGET_PACKAGES: $NUGET_PACKAGES"Les outputs remontent deux niveaux : step → job (jobs.test.outputs) → workflow (on.workflow_call.outputs).
Et l’appelant, .github/workflows/gha-06-reuse.yml :
# GitHub Actions course, lesson 6: calling a reusable workflow with a matrix, and reading its outputsname: "GHA 06: reuse"
on: workflow_dispatch: push: branches: [main] paths: ['.github/workflows/gha-06-reuse.yml', '.github/workflows/gha-06-dotnet-test.yml', '.github/actions/dotnet-restore/**']
env: COURSE: github-actions
jobs: test: strategy: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] uses: ./.github/workflows/gha-06-dotnet-test.yml with: os: ${{ matrix.os }}
summary: needs: test runs-on: ubuntu-latest steps: - run: | echo "COURSE in the caller: '$COURSE'" echo "sdk-version: ${{ needs.test.outputs.sdk-version }}" echo "tested-on: ${{ needs.test.outputs.tested-on }}"Un job qui appelle un workflow réutilisable n’a pas de runs-on ni de steps : seulement name, uses, with, secrets, strategy, needs, if, concurrency, permissions et cache-mode.
Mis bout à bout, l’appelant, le workflow réutilisable et l’action composite forment une chaîne, et les outputs la remontent jusqu’au job summary.
flowchart TB subgraph wfcaller["gha-06-reuse.yml"] test["job test : matrice ubuntu-latest, windows-latest"] summary["job summary : needs test"] end subgraph wfcalled["gha-06-dotnet-test.yml, on: workflow_call"] job["job test : runs-on inputs.os"] end subgraph composite["action composite dotnet-restore"] steps["quatre steps, journalisés comme un seul"] end test -->|"uses, with os"| job job -->|"step setup : uses, with directory"| steps steps -.->|"sdk-version : output du step, puis du job"| job job -.->|"on.workflow_call.outputs"| test test -.->|"needs.test.outputs"| summaryCe que montre l’exécution
Section intitulée « Ce que montre l’exécution »test (ubuntu-latest) / test successtest (windows-latest) / test successsummary successLes jobs s’appellent <caller job> / <called job>. Dans l’API, le job Ubuntu a ces steps :
1 Set up job2 Run actions/checkout@v73 Run ./.github/actions/dotnet-restore4 Run dotnet test --no-restore5 What the called workflow sees9 Post Run ./.github/actions/dotnet-restore10 Post Run actions/checkout@v711 Complete jobLes quatre steps de l’action composite forment un seul step (3), et leurs logs sont des groupes imbriqués à l’intérieur ; les numéros 6 à 8 n’apparaissent pas dans la liste. Le step Post 9 est le step post de setup-dotnet dans l’action — l’enregistrement du cache NuGet, ignoré ici parce que le cache a été trouvé.
Ce que voit le workflow appelé
Section intitulée « Ce que voit le workflow appelé »event_name: pushgithub.workflow: GHA 06: reusegithub.workflow_ref: spareilleux/learn/.github/workflows/gha-06-reuse.yml@refs/heads/mainjob.workflow_ref: spareilleux/learn/.github/workflows/gha-06-dotnet-test.yml@refs/heads/mainCOURSE from caller: ''NUGET_PACKAGES: /home/runner/work/learn/learn/.nuget/packages- Le contexte
githubest celui de l’appelant : même événement, même nom de workflow. Pour savoir quel fichier définit le job en cours, lisjob.workflow_ref. COURSEest vide. La documentation est explicite : « les variables d’environnement définies dans un contexteenvau niveau du workflow dans le workflow appelant ne sont pas propagées au workflow appelé ». Passe les valeurs eninputs, ou utilisevars(variables du dépôt).NUGET_PACKAGESvenait du$GITHUB_ENVde l’action composite et a atteint les steps suivants du job.
Et les caches ? L’action a restauré dotnet-cache-Linux-557e0cce…, le cache enregistré par le workflow de la leçon 5 : même clé, même chemin, même branche — les caches appartiennent au dépôt, pas à un workflow.
Les outputs d’une matrix
Section intitulée « Les outputs d’une matrix »COURSE in the caller: 'github-actions'sdk-version: 10.0.401tested-on: WindowsDeux jobs de matrix définissent tested-on, l’appelant a reçu une seule valeur : Windows, le job qui a fini en dernier (13:25:06, contre 13:24:29 pour Ubuntu). C’est la règle documentée : « l’output sera celui défini par le dernier workflow réutilisable de la matrix à se terminer avec succès et à définir réellement une valeur ». N’utilise pas un output de matrix pour quoi que ce soit qui diffère entre les combinaisons ; envoie plutôt un artefact par combinaison.
Limites à connaître
Section intitulée « Limites à connaître »D’après la référence :
- « Tu peux connecter jusqu’à dix niveaux de workflows » (l’appelant plus neuf niveaux imbriqués) ;
- « Tu peux appeler au maximum 50 workflows réutilisables uniques depuis un même fichier de workflow » ;
- un workflow réutilisable référencé par branche ou par tag peut changer sans prévenir ; un SHA de commit, non. La leçon 7 revient sur l’épinglage.
À retenir
Section intitulée « À retenir »- Steps répétés → action composite, appelée par un step, exécutée dans le job de l’appelant. Jobs répétés → workflow réutilisable, appelé par un job, avec ses propres runners.
- Les steps
run:d’une action composite ont besoin deshell:; les actions et workflows locaux ont besoin d’actions/checkoutd’abord (pour les actions) et d’un chemin commençant par./. - Le workflow appelé voit le contexte
githubde l’appelant mais pas sonenv; utiliseinputs,outputsetjob.workflow_ref. - Avec une matrix, l’output d’un workflow réutilisable est celui du dernier job à finir.
Exercices
Section intitulée « Exercices »- Retire
shell: bashd’un steprun:d’une action composite. Quand l’erreur est-elle détectée, et que dit-elle ?
Solution
Seulement quand un job exécute l’action — le push qui la commite ne signale rien. Vérifié avec gha-06-exercises.yml et une action exercise-no-shell volontairement cassée :
##[error]/home/runner/work/learn/learn/./.github/actions/exercise-no-shell/action.yml (Line: 8, Col: 7): Required property is missing: shell##[error]Failed to load /home/runner/work/learn/learn/./.github/actions/exercise-no-shell/action.ymlDans un workflow, run: a un shell par défaut ; dans une action composite, il n’en a aucun.
- Un job commence directement par
uses: ./.github/actions/dotnet-restore, sansactions/checkout. Que se passe-t-il ?
Solution
##[error]Can't find 'action.yml', 'action.yaml' or 'Dockerfile' under '/home/runner/work/learn/learn/.github/actions/dotnet-restore'. Did you forget to run actions/checkout before running your local action?Une action locale est lue depuis le workspace, qui reste vide jusqu’au checkout. Un workflow réutilisable référencé avec ./ n’a pas ce problème : GitHub le lit dans le dépôt avant le démarrage du job.
- L’appelant passe
configuration: Releasedanswith:, maisgha-06-dotnet-test.ymlne déclare que l’inputos. Quand est-ce que ça échoue ?
Solution
Avant le démarrage de tout job. L’exécution se termine avec la conclusion startup_failure et aucun job ; gh run view dit seulement « This run likely failed because of a workflow file issue », et la page de l’exécution affiche :
The workflow is not valid. .github/workflows/gha-06-invalid-input.yml (Line: 13, Col: 22): Invalid input, configuration is not defined in the referenced workflow.Vérifié sur une branche temporaire, pour qu’un workflow invalide ne fasse pas échouer chaque push sur main (voir la leçon 1). Les inputs sont un contrat vérifié à la création de l’exécution, comme les paramètres d’une méthode à la compilation.