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 exemplepush,pull_request)jobs:— des unités de travail parallèles, chacune sur une VM neuvesteps:— des commandes Shell séquentielles ou des actions réutilisables au sein d’une tâcheruns-on:— l’image de l’exécuteur (nous utilisonsubuntu-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 --versionExé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 directivessourceafin 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 commanderun.$output— sortie standard et sortie d’erreur combinées de la dernière commanderun.$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/batsgit submodule add https://github.com/bats-core/bats-support test/test_helper/bats-supportgit 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 + helpersExé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 (
lintettest) s’exécutent en parallèle, ce qui accélère le retour d’information. - La tâche
testdéclareneeds: lintafin 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-keyspermet 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,pipou 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 availableProtection 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écuteursubuntu-latest. - ShellCheck — préinstallé sur les exécuteurs Ubuntu ; utilisez
findpour découvrir les scripts et--severity=warning -xcomme 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: recursivelors 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
actpour 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
- Tester les fonctions avec Bats-core
- Simuler des commandes et créer des doublures d’outils externes
- Dispositifs de test, environnements temporaires et couverture
- Exécuter des tests Shell dans les pipelines CI