Skip to main content
Nous publions des mises à jour fréquentes de notre documentation, et la traduction de cette page peut encore être en cours. Pour obtenir les informations les plus actuelles, consultez la documentation anglaise.

Utilisation de la concurrence, d’expressions et d’une matrice de test

Comment utiliser les fonctionnalités avancées de GitHub Actions pour l’intégration continue (CI).

Présentation des exemples

Cet article utilise un exemple de workflow pour illustrer certaines des principales fonctionnalités CI de GitHub Actions. Quand ce workflow est déclenché, il teste votre code à l’aide d’une matrice de combinaisons de test avec npm test.

Le diagramme suivant montre une vue générale des étapes du workflow et comment elles s’exécutent dans le travail :

Schéma d’un événement déclenchant un workflow qui utilise une matrice de test.

Fonctionnalités utilisées dans cet exemple

L’exemple de workflow illustre les fonctionnalités suivantes de GitHub Actions.

FonctionnalitéImplémentation
Exécution manuelle d’un workflow à partir de l’interface utilisateurworkflow_dispatch

Exemple de flux de travail

Le workflow suivant a été créé par l’équipe Ingénierie de documents GitHub. Pour consulter la dernière version de ce fichier dans le référentiel github/docs, consultez test.yml.

Remarque : Chaque ligne de ce workflow est expliquée dans la section suivante, dans « Comprendre l’exemple ».

YAML
name: Node.js Tests

# **What it does**: Runs our tests.
# **Why we have it**: We want our tests to pass before merging code.
# **Who does it impact**: Docs engineering, open-source engineering contributors.

on:
  workflow_dispatch:
  pull_request:
  push:
    branches:
      - main

permissions:
  contents: read
  # Needed for the 'trilom/file-changes-action' action
  pull-requests: read

# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
  group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
  cancel-in-progress: true

jobs:
  test:
    # Run on self-hosted if the private repo or ubuntu-latest if the public repo
    # See pull # 17442 in the private repo for context
    runs-on: ${{ fromJSON('["ubuntu-latest", "self-hosted"]')[github.repository == 'github/docs-internal'] }}
    timeout-minutes: 60
    strategy:
      fail-fast: false
      matrix:
        # The same array lives in test-windows.yml, so make any updates there too.
        test-group:
          [
            content,
            graphql,
            meta,
            rendering,
            routing,
            unit,
            linting,
            translations,
          ]
    steps:
      # Each of these ifs needs to be repeated at each step to make sure the required check still runs
      # Even if if doesn't do anything
      - name: Check out repo
        uses: actions/checkout@v3
        with:
          # Not all test suites need the LFS files. So instead, we opt to
          # NOT clone them initially and instead, include them manually
          # only for the test groups that we know need the files.
          lfs: ${{ matrix.test-group == 'content' }}
          # Enables cloning the Early Access repo later with the relevant personal access token
          persist-credentials: 'false'

      - name: Figure out which docs-early-access branch to checkout, if internal repo
        if: ${{ github.repository == 'github/docs-internal' }}
        id: check-early-access
        uses: actions/github-script@v6
        env:
          BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
        with:
          github-token: ${{ secrets.DOCUBOT_REPO_PAT }}
          result-encoding: string
          script: |
            // If being run from a PR, this becomes 'my-cool-branch'.
            // If run on main, with the `workflow_dispatch` action for
            // example, the value becomes 'main'.
            const { BRANCH_NAME } = process.env
            try {
              const response = await github.repos.getBranch({
                owner: 'github',
                repo: 'docs-early-access',
                BRANCH_NAME,
              })
              console.log(`Using docs-early-access branch called '${BRANCH_NAME}'.`)
              return BRANCH_NAME
            } catch (err) {
              if (err.status === 404) {
                console.log(`There is no docs-early-access branch called '${BRANCH_NAME}' so checking out 'main' instead.`)
                return 'main'
              }
              throw err
            }

      - name: Check out docs-early-access too, if internal repo
        if: ${{ github.repository == 'github/docs-internal' }}
        uses: actions/checkout@v3
        with:
          repository: github/docs-early-access
          token: ${{ secrets.DOCUBOT_REPO_PAT }}
          path: docs-early-access
          ref: ${{ steps.check-early-access.outputs.result }}

      - name: Merge docs-early-access repo's folders
        if: ${{ github.repository == 'github/docs-internal' }}
        run: |
          mv docs-early-access/assets assets/images/early-access
          mv docs-early-access/content content/early-access
          mv docs-early-access/data data/early-access
          rm -r docs-early-access

      # This is necessary when LFS files where cloned but does nothing
      # if actions/checkout was run with `lfs:false`.
      - name: Checkout LFS objects
        run: git lfs checkout

      - name: Gather files changed
        uses: trilom/file-changes-action@a6ca26c14274c33b15e6499323aac178af06ad4b
        id: get_diff_files
        with:
          # So that `steps.get_diff_files.outputs.files` becomes
          # a string like `foo.js path/bar.md`
          output: ' '

      - name: Insight into changed files
        run: |

          # Must to do this because the list of files can be HUGE. Especially
          # in a repo-sync when there are lots of translation files involved.
          echo "${{ steps.get_diff_files.outputs.files }}" > get_diff_files.txt

      - name: Setup node
        uses: actions/setup-node@v3
        with:
          node-version: 16.14.x
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Cache nextjs build
        uses: actions/cache@v3
        with:
          path: .next/cache
          key: ${{ runner.os }}-nextjs-${{ hashFiles('package*.json') }}

      - name: Run build script
        run: npm run build

      - name: Run tests
        env:
          DIFF_FILE: get_diff_files.txt
          CHANGELOG_CACHE_FILE_PATH: tests/fixtures/changelog-feed.json
        run: npm test -- tests/${{ matrix.test-group }}/

Vue d’ensemble de l’exemple

 Le tableau suivant explique comment chacune de ces fonctionnalités est utilisée lors de la création d’un workflow GitHub Actions.

Code Explication
YAML
name: Node.js Tests

Nom du workflow tel qu’il apparaît sous l’onglet « Actions » du dépôt GitHub.

YAML
on:

Le mot clé on vous permet de définir les événements qui se déclenchent quand le workflow s’exécute. Vous pouvez définir ici plusieurs événements. Pour plus d’informations, consultez « Déclenchement d’un workflow ».

YAML
  workflow_dispatch:

Ajoutez l’événement workflow_dispatch si vous souhaitez pouvoir exécuter manuellement ce workflow dans l’IU. Pour plus d’informations, consultez workflow_dispatch.

YAML
  pull_request:

Ajoutez l’événement pull_request pour que le workflow s’exécute automatiquement chaque fois qu’une demande de tirage est créée ou mise à jour. Pour plus d’informations, consultez pull_request.

YAML
  push:
    branches:
      - main

Ajoutez l’événement push pour que le workflow s’exécute automatiquement chaque fois qu’un commit est poussé vers une branche correspondant au filtre main. Pour plus d’informations, consultez push.

YAML
permissions:
  contents: read
  pull-requests: read

Modifie les autorisations par défaut octroyées à GITHUB_TOKEN. Cela varie en fonction des besoins de votre workflow. Pour plus d’informations, consultez « Affectation d’autorisations à des travaux ».

YAML
concurrency:
  group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'

Crée un groupe d’accès concurrentiel pour des événements spécifiques, et utilise l’opérateur || afin de définir les valeurs de secours. Pour plus d’informations, consultez « Utilisation de l’accès concurrentiel ».

YAML
  cancel-in-progress: true

Annule tout travail ou workflow en cours d’exécution dans le même groupe d’accès concurrentiel.

YAML
jobs:

Regroupe tous les travaux qui s’exécutent dans le fichier de workflow.

YAML
  test:

Définit un travail ayant l’ID test stocké dans la clé jobs.

YAML
    runs-on: ${{ fromJSON('["ubuntu-latest", "self-hosted"]')[github.repository == 'github/docs-internal'] }}

Configure le travail pour qu’il s’exécute sur un exécuteur hébergé par GitHub ou sur un exécuteur autohébergé, selon le dépôt qui exécute le workflow. Dans cet exemple, le travail s’exécute sur un exécuteur autohébergé si le dépôt se nomme docs-internal, et s’il se trouve dans l’organisation github. Si le dépôt ne correspond pas à ce chemin, il s’exécute sur un exécuteur ubuntu-latest hébergé par GitHub. Pour plus d’informations sur ces options, consultez « Choix de l’exécuteur pour un travail ».

YAML
    timeout-minutes: 60

Définit le nombre maximal de minutes d’exécution du travail avant qu’il ne soit automatiquement annulé. Pour plus d’informations, consultez timeout-minutes.

YAML
    strategy:
Cette section définit la matrice de build de vos travaux.
YAML
      fail-fast: false

L’affectation de la valeur false à fail-fast empêche GitHub d’annuler tous les travaux en cours en cas d’échec d’un travail de matrice.

YAML
      matrix:
        test-group:
          [
            content,
            graphql,
            meta,
            rendering,
            routing,
            unit,
            linting,
            translations,
          ]

Crée une matrice nommée test-group, avec un tableau de groupes de test. Ces valeurs correspondent aux noms des groupes de test qui sont exécutés par npm test.

YAML
    steps:

Regroupe toutes les étapes qui vont s’exécuter dans le cadre du travail test. Chaque travail d’un workflow a sa propre section steps.

YAML
      - name: Check out repo
        uses: actions/checkout@v3
        with:
          lfs: ${{ matrix.test-group == 'content' }}
          persist-credentials: 'false'

Le mot clé uses indique au travail de récupérer l’action nommée actions/checkout. Il s’agit d’une action qui extrait votre dépôt et le télécharge dans l’exécuteur, ce qui vous permet d’exécuter des actions sur votre code (par exemple des outils de test). Vous devez utiliser l’action d’extraction chaque fois que votre workflow s’exécute sur le code du dépôt, ou que vous utilisez une action définie dans le dépôt. Certaines options supplémentaires sont fournies à l’action à l’aide du mot-clé with.

YAML
      - name: Figure out which docs-early-access branch to checkout, if internal repo
        if: ${{ github.repository == 'github/docs-internal' }}
        id: check-early-access
        uses: actions/github-script@v6
        env:
          BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
        with:
          github-token: ${{ secrets.DOCUBOT_REPO_PAT }}
          result-encoding: string
          script: |
            // If being run from a PR, this becomes 'my-cool-branch'.
            // If run on main, with the `workflow_dispatch` action for
            // example, the value becomes 'main'.
            const { BRANCH_NAME } = process.env
            try {
              const response = await github.repos.getBranch({
                owner: 'github',
                repo: 'docs-early-access',
                BRANCH_NAME,
              })
              console.log(`Using docs-early-access branch called '${BRANCH_NAME}'.`)
              return BRANCH_NAME
            } catch (err) {
              if (err.status === 404) {
                console.log(`There is no docs-early-access branch called '${BRANCH_NAME}' so checking out 'main' instead.`)
                return 'main'
              }
              throw err
            }

Si le dépôt actuel est le dépôt github/docs-internal, cette étape utilise l’action actions/github-script pour exécuter un script permettant de vérifier s’il existe une branche appelée docs-early-access.

YAML
      - name: Check out docs-early-access too, if internal repo
        if: ${{ github.repository == 'github/docs-internal' }}
        uses: actions/checkout@v3
        with:
          repository: github/docs-early-access
          token: ${{ secrets.DOCUBOT_REPO_PAT }}
          path: docs-early-access
          ref: ${{ steps.check-early-access.outputs.result }}

Si le dépôt actuel est le dépôt github/docs-internal, cette étape extrait la branche du dépôt github/docs-early-access identifié à l’étape précédente.

YAML
      - name: Merge docs-early-access repo's folders
        if: ${{ github.repository == 'github/docs-internal' }}
        run: |
          mv docs-early-access/assets assets/images/early-access
          mv docs-early-access/content content/early-access
          mv docs-early-access/data data/early-access
          rm -r docs-early-access

Si le dépôt actuel est le dépôt github/docs-internal, cette étape utilise le mot clé run pour exécuter les commandes d’interpréteur de commandes afin de déplacer les dossiers du dépôt docs-early-access vers les dossiers du dépôt principal.

YAML
      - name: Checkout LFS objects
        run: git lfs checkout

Cette étape exécute une commande pour extraire les objets LFS du dépôt.

YAML
      - name: Gather files changed
        uses: trilom/file-changes-action@a6ca26c14274c33b15e6499323aac178af06ad4b
        id: get_diff_files
        with:
          # So that `steps.get_diff_files.outputs.files` becomes
          # a string like `foo.js path/bar.md`
          output: ' '

Cette étape utilise l’action trilom/file-changes-action pour regrouper les fichiers changés dans la demande de tirage (pull request) afin qu’ils puissent être analysés à l’étape suivante. Cet exemple est épinglé à une version spécifique de l’action, à l’aide de la valeur SHA a6ca26c14274c33b15e6499323aac178af06ad4b.

YAML
      - name: Insight into changed files
        run: |
          echo "${{ steps.get_diff_files.outputs.files }}" > get_diff_files.txt

Cette étape exécute une commande d’interpréteur de commandes qui utilise une sortie de l’étape précédente pour créer un fichier contenant la liste des fichiers changés dans la demande de tirage.

YAML
      - name: Setup node
        uses: actions/setup-node@v3
        with:
          node-version: 16.14.x
          cache: npm

Cette étape utilise l’action actions/setup-node pour installer la version spécifiée du package logiciel node sur l’exécuteur, ce qui vous permet d’accéder à la commande npm.

YAML
      - name: Install dependencies
        run: npm ci

Cette étape exécute la commande d’interpréteur de commandes npm ci pour installer les packages logiciels npm du projet.

YAML
      - name: Cache nextjs build
        uses: actions/cache@v3
        with:
          path: .next/cache
          key: ${{ runner.os }}-nextjs-${{ hashFiles('package*.json') }}

Cette étape utilise l’action actions/cache pour mettre en cache la build Next.js. Ainsi, le workflow tente de récupérer une mise en cache de la build, au lieu d’effectuer une regénération à partir de zéro à chaque fois. Pour plus d’informations, consultez « Mise en cache des dépendances pour accélérer les workflows ».

YAML
      - name: Run build script
        run: npm run build

Cette étape exécute le script de build.

YAML
      - name: Run tests
        env:
          DIFF_FILE: get_diff_files.txt
          CHANGELOG_CACHE_FILE_PATH: tests/fixtures/changelog-feed.json
        run: npm test -- tests/${{ matrix.test-group }}/

Cette étape exécute les tests à l’aide de npm test. La matrice de test fournit une valeur différente pour ${{ matrix.test-group }} pour chaque travail de la matrice. Elle utilise la variable d’environnement DIFF_FILE pour identifier les fichiers qui ont changé ainsi que la variable d’environnement CHANGELOG_CACHE_FILE_PATH pour identifier le fichier cache du journal des modifications.

Étapes suivantes