0Pricing
Linux Command Line & Bash Scripting Mastery · Leçon

Exécuter des tests Shell dans les pipelines CI

Intégrez ShellCheck et Bats à GitHub Actions afin de soumettre chaque modification Shell à des vérifications réussies.

Exécuter des tests Shell dans les pipelines CI est une leçon Linux Command Line & Bash Scripting Mastery gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Linux Command Line & Bash Scripting Mastery, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Linux Command Line & Bash Scripting Mastery comprend 4 leçons au total.

Pourquoi l’intégration continue est importante pour les scripts Shell

Les scripts Shell sont du code et, comme tout code, ils méritent des contrôles qualité automatisés. Sans intégration continue, une faute de frappe dans un script de déploiement peut atteindre silencieusement la production et provoquer une panne à 3 heures du matin.

Un pipeline d’intégration continue solide pour les projets Bash impose deux vérifications sur chaque demande d’intégration :

  • Analyse statique avec ShellCheck — détecte les erreurs de syntaxe, les constructions dangereuses et les problèmes de portabilité POSIX avant même l’exécution du script.
  • Tests unitaires et d’intégration avec Bats (Bash Automated Testing System) — exécute vos fonctions et vérifie leur comportement correct.

Ensemble, ces outils forment un filet de sécurité qui facilite les refactorisations et accélère la prise en main par les nouveaux membres. Cette leçon intègre les deux outils à GitHub Actions, la plateforme d’intégration continue gratuite la plus courante pour les projets open source et les petites équipes.

Introduction à GitHub Actions pour les projets Shell

GitHub Actions est un système d’intégration et de livraison continues piloté par les événements et intégré à GitHub. Un flux de travail est un fichier YAML stocké sous .github/workflows/. Il se déclenche lors d’événements (push, pull_request, etc.) et exécute des tâches sur des exécuteurs hébergés.

Voici les concepts essentiels :

  • on: — le déclencheur (par exemple push, pull_request)
  • jobs: — des unités de travail parallèles, chacune sur une VM neuve
  • steps: — des commandes Shell séquentielles ou des actions réutilisables au sein d’une tâche
  • runs-on: — l’image de l’exécuteur (nous utilisons ubuntu-latest)

Les fichiers de flux de travail doivent être validés dans le dépôt. GitHub les détecte automatiquement : aucune configuration externe n’est nécessaire.

# Minimal skeleton — .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  shell-checks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: echo "Steps go here"

Installer ShellCheck dans un flux de travail

ShellCheck est préinstallé sur les exécuteurs ubuntu-latest ; dans la plupart des cas, vous n’avez donc aucune étape d’installation à ajouter. Toutefois, la version préinstallée peut être en retard sur la dernière version publiée. Pour obtenir des compilations reproductibles, verrouillez une version précise.

Deux stratégies d’installation :

  • Utiliser le binaire préinstallé — la solution la plus simple, suffisante pour la plupart des projets.
  • Installer une version verrouillée depuis l’archive tar de la publication officielle GitHub — garantit la même version de l’analyseur localement et dans l’intégration continue.

L’étape ci-dessous présente l’approche avec version verrouillée, à l’aide d’une chaîne de version fixe stockée comme variable d’environnement, ce qui permet d’effectuer les mises à niveau en modifiant une seule ligne.

# .github/workflows/ci.yml  — ShellCheck install step
- name: Install ShellCheck
  env:
    SC_VERSION: v0.10.0
  run: |
    curl -sSfL \
      "https://github.com/koalaman/shellcheck/releases/download/${SC_VERSION}/shellcheck-${SC_VERSION}.linux.x86_64.tar.xz" \
      | tar -xJf - --strip-components=1 -C /usr/local/bin shellcheck-${SC_VERSION}/shellcheck
    shellcheck --version

Exécuter ShellCheck sur chaque script

Après l’installation, vous devez ajouter une étape qui recherche et analyse tous les scripts Shell du dépôt. Utilisez find pour localiser les fichiers, puis transmettez-les à shellcheck par un pipeline.

Options importantes à connaître :

  • -e SC2034 — exclut une règle précise (à utiliser avec modération et en l’accompagnant d’un commentaire).
  • --severity=warning — fait échouer l’analyse uniquement pour les avertissements et les niveaux supérieurs (en ignorant les suggestions de style).
  • -x — suit les directives source afin d’analyser également les fichiers inclus.

Si shellcheck détecte un problème, il se termine avec un code différent de zéro, ce qui fait automatiquement échouer l’étape d’intégration continue : aucune logique supplémentaire n’est nécessaire.

# .github/workflows/ci.yml  — ShellCheck lint step
- name: Lint shell scripts
  run: |
    # Find all .sh files and files with a bash/sh shebang
    mapfile -t scripts < <(
      find . -type f -name '*.sh' -not -path './.git/*'
    )
    if [[ ${#scripts[@]} -eq 0 ]]; then
      echo 'No shell scripts found — skipping.'
      exit 0
    fi
    echo "Linting ${#scripts[@]} file(s)..."
    shellcheck --severity=warning -x "${scripts[@]}"

Qu’est-ce que Bats et comment fonctionne-t-il ?

Bats (Bash Automated Testing System) est un cadre de test pour Bash conforme à TAP. Chaque fichier de test est un fichier .bats contenant des blocs @test.

Un test réussit lorsque son corps se termine avec le code 0 et échoue lorsqu’il se termine avec un code différent de zéro. Bats fournit des variables et des fonctions utilitaires :

  • $status — code de sortie de la dernière commande run.
  • $output — sortie standard et sortie d’erreur combinées de la dernière commande run.
  • $lines — tableau des lignes de sortie.
  • run <cmd> — exécute une commande sans faire échouer le test en cas de sortie différente de zéro.

L’utilitaire run est essentiel : sans lui, une commande en échec interromprait le test avant que vous puissiez examiner $status.

#!/usr/bin/env bats
# tests/greet.bats

setup() {
  # Runs before every @test block
  source "${BATS_TEST_DIRNAME}/../lib/greet.sh"
}

@test "greet outputs hello with the given name" {
  run greet "Alice"
  [ "$status" -eq 0 ]
  [ "$output" = "Hello, Alice!" ]
}

@test "greet fails when no argument is provided" {
  run greet
  [ "$status" -eq 1 ]
  [[ "$output" == *"Usage"* ]]
}

Installer Bats-Core via un sous-module Git

La méthode de référence pour ajouter Bats à un projet consiste à utiliser un sous-module Git. Elle verrouille un commit précis, conserve une version identique de l’exécuteur en local et évite de dépendre des gestionnaires de paquets.

Exécutez ces commandes une fois en local, puis validez le résultat :

  • git submodule add https://github.com/bats-core/bats-core test/bats
  • git submodule add https://github.com/bats-core/bats-support test/test_helper/bats-support
  • git submodule add https://github.com/bats-core/bats-assert test/test_helper/bats-assert

Dans l’intégration continue, restaurez les sous-modules avec actions/checkout@v4 et l’option submodules: recursive. L’étape ci-dessous présente la configuration complète de la récupération du dépôt.

# .github/workflows/ci.yml  — checkout with submodules
- name: Checkout repository
  uses: actions/checkout@v4
  with:
    submodules: recursive   # restores bats-core + helpers

Exécuter les tests Bats dans l’intégration continue

Une fois Bats disponible (via un sous-module ou l’installation d’un paquet), l’exécution des tests se fait avec une seule commande. Indiquez-lui un répertoire : Bats découvre récursivement chaque fichier .bats grâce à l’option --recursive.

L’option --formatter tap produit un format TAP (Test Anything Protocol), que de nombreux systèmes d’intégration continue peuvent analyser pour établir les rapports de test. Le formateur pretty par défaut est plus adapté à la lecture humaine dans les journaux bruts.

Utilisez --timing pour repérer rapidement les tests lents : un test qui dure plus de 5 secondes signale généralement un appel réseau indésirable ou l’absence d’un simulacre.

# .github/workflows/ci.yml  — Bats test step
- name: Run Bats tests
  run: |
    # If installed as a submodule:
    ./test/bats/bin/bats \
      --recursive \
      --timing \
      tests/

    # If installed via apt or brew (alternative):
    # bats --recursive --timing tests/

Flux de travail complet : ShellCheck + Bats

Regroupons maintenant tous les éléments dans un fichier de flux de travail prêt pour la production. Les bonnes pratiques appliquées ici sont les suivantes :

  • Deux tâches distinctes (lint et test) s’exécutent en parallèle, ce qui accélère le retour d’information.
  • La tâche test déclare needs: lint afin que les tests ne s’exécutent qu’après la réussite de l’analyse, évitant ainsi de gaspiller des minutes d’exécution sur du code manifestement défectueux.
  • Les versions verrouillées des actions (@v4) évitent les régressions inattendues dues aux mises à jour en amont.
  • Un bloc permissions: limite le jeton du flux de travail au minimum nécessaire.
# .github/workflows/ci.yml
name: Shell CI

on:
  push:
    branches: [main]
  pull_request:

permissions:
  contents: read

jobs:
  lint:
    name: ShellCheck
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run ShellCheck
        run: |
          mapfile -t scripts < <(find . -name '*.sh' -not -path './.git/*')
          [[ ${#scripts[@]} -gt 0 ]] && shellcheck --severity=warning -x "${scripts[@]}"

  test:
    name: Bats Tests
    runs-on: ubuntu-latest
    needs: lint
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive
      - name: Run tests
        run: ./test/bats/bin/bats --recursive --timing tests/

Mettre en cache les dépendances pour accélérer les exécutions

Lorsque les utilitaires Bats ou d’autres outils sont installés via un gestionnaire de paquets dans le flux de travail, la mise en cache accélère considérablement les exécutions suivantes. GitHub Actions fournit pour cela l’action actions/cache.

Points essentiels pour une mise en cache efficace :

  • Utilisez une clé de cache qui inclut le système d’exploitation, le nom de l’outil et le condensat d’un fichier de verrouillage, afin que le cache soit automatiquement invalidé lorsque les dépendances changent.
  • Une solution de restore-keys permet au flux de travail d’utiliser un cache obsolète plutôt que de repartir de zéro en cas d’échec de récupération.
  • Pour les sous-modules Git, la mise en cache est rarement nécessaire, car leur récupération est rapide. Le cache est surtout utile pour npm, pip ou l’installation d’outils compilés.
# .github/workflows/ci.yml  — cache step example
- name: Cache Bats npm helpers
  uses: actions/cache@v4
  with:
    path: ~/.npm
    key: ${{ runner.os }}-bats-${{ hashFiles('package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-bats-

- name: Install helpers
  run: npm ci  # uses cache when available

Protection des branches : imposer des vérifications réussies

Un flux de travail d’intégration continue qui ne bloque pas les fusions est au mieux consultatif. Les règles de protection des branches GitHub transforment vos vérifications en véritables barrières.

Pour les configurer : ouvrez Settings → Branches → Add rule pour main, puis activez :

  • Require status checks to pass before merging — sélectionnez ShellCheck et Bats Tests par leur nom.
  • Require branches to be up to date before merging — empêche qu’une demande d’intégration ayant passé les vérifications sur une base obsolète introduise du code défectueux.
  • Do not allow bypassing the above settings — applique les règles même aux administrateurs du dépôt.

Une fois ces règles en place, la seule voie vers la fusion est une demande d’intégration dont toutes les tâches d’intégration continue sont au vert : exactement le filet de sécurité dont vous avez besoin.

Déboguer localement les étapes d’intégration continue en échec

Lorsqu’une exécution d’intégration continue échoue, le cycle de correction le plus rapide consiste à reproduire l’échec en local avant d’envoyer un autre commit. Deux techniques sont possibles :

  • Exécuter les commandes exactes de l’étape en échec dans votre terminal : l’intégration continue exécute un Shell ordinaire, les commandes peuvent donc être reproduites par copier-coller.
  • Utiliser act — un outil qui exécute localement les flux de travail GitHub Actions dans Docker et offre la correspondance la plus proche possible avec l’environnement de l’exécuteur hébergé.

Une source courante d’échecs propres à l’intégration continue est la différence de version d’un outil entre votre Mac (par exemple find BSD sur macOS et find GNU sur Ubuntu). Testez toujours avec les options --posix ou utilisez act pour exécuter localement l’image Ubuntu.

#!/usr/bin/env bash
# run_ci_locally.sh  — mimic the CI lint step on your machine
set -euo pipefail

echo '=== ShellCheck ==='
mapfile -t scripts < <(find . -name '*.sh' -not -path './.git/*')
if [[ ${#scripts[@]} -eq 0 ]]; then
  echo 'No .sh files found.'
else
  shellcheck --severity=warning -x "${scripts[@]}"
  echo "Linted ${#scripts[@]} file(s) — OK"
fi

echo '=== Bats ==='
./test/bats/bin/bats --recursive --timing tests/

Vérification des connaissances : concepts des pipelines d’intégration continue

Vérifiez votre compréhension de l’intégration de ShellCheck et de Bats à GitHub Actions.

Récapitulatif : intégration continue Shell avec ShellCheck et Bats

Dans cette leçon, vous avez créé un pipeline d’intégration continue complet pour les projets Bash avec GitHub Actions. Voici les notions abordées :

  • Bases de GitHub Actions — le YAML du flux de travail se trouve dans .github/workflows/, se déclenche lors des événements push et pull_request, et exécute des tâches sur des exécuteurs ubuntu-latest.
  • ShellCheck — préinstallé sur les exécuteurs Ubuntu ; utilisez find pour découvrir les scripts et --severity=warning -x comme contrôle pratique d’analyse.
  • Bats via un sous-module — verrouillez bats-core et ses utilitaires comme sous-modules Git ; restaurez-les dans l’intégration continue avec submodules: recursive lors de l’action de récupération.
  • Ordre des tâches — utilisez needs: afin que les tests ne s’exécutent qu’après la réussite de l’analyse, pour obtenir un retour rapide et éviter de gaspiller des ressources de calcul.
  • Protection des branches — imposez les vérifications d’état dans les paramètres GitHub afin qu’aucune demande d’intégration ne puisse être fusionnée sans une intégration continue au vert.
  • Reproduction locale — copiez directement les commandes d’intégration continue dans votre terminal ou utilisez act pour déboguer les échecs sans créer de commits supplémentaires.

Avec ce pipeline en place, chaque modification du Shell est automatiquement validée avant d’atteindre votre branche principale.

Questions Fréquemment Posées

La leçon « Exécuter des tests Shell dans les pipelines CI » est-elle gratuite ?

Oui — le texte complet de « Exécuter des tests Shell dans les pipelines CI » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Linux Command Line & Bash Scripting Mastery, passe à CoddyKit PRO. Le cours Linux Command Line & Bash Scripting Mastery comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Exécuter des tests Shell dans les pipelines CI » ?

Intégrez ShellCheck et Bats à GitHub Actions afin de soumettre chaque modification Shell à des vérifications réussies. Tu pratiques Linux Command Line & Bash Scripting Mastery avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Linux Command Line & Bash Scripting Mastery ?

Aucune expérience préalable n'est requise. Linux Command Line & Bash Scripting Mastery sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.

Combien de temps prend la leçon « Exécuter des tests Shell dans les pipelines CI » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Linux Command Line & Bash Scripting Mastery ?

Oui. Chaque leçon Linux Command Line & Bash Scripting Mastery inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Tester les fonctions avec Bats-core
  2. Simuler des commandes et créer des doublures d’outils externes
  3. Dispositifs de test, environnements temporaires et couverture
  4. Exécuter des tests Shell dans les pipelines CI
← Retour à Linux Command Line & Bash Scripting Mastery