Si vous utilisez GitHub et que vous vous intéressez un peu au monde du DevOps, vous avez forcément croisé GitHub Actions. Et parfois… on se dit qu’on aurait préféré que nos chemins ne se soient jamais rencontrés.
Sur internet, les avis sont très partagés : certains adorent, d’autres jurent que c’est l’enfer. La vérité, c’est que beaucoup des critiques viennent surtout d’une mauvaise utilisation de l’outil.
Dans cet article, je vous raconte mon parcours avec GitHub Actions, présenté sous la forme d’une “semaine fictive” inspirée de la Genèse : mes débuts chaotiques, mes erreurs, mes découvertes… et comment j’ai fini par passer de l’enfer au paradis.
Jour 1 : La rencontre
Ma première rencontre avec le monde du CI/CD s’est faite avec GitHub Actions. Et, de manière totalement illogique, ma première idée a été de lancer… des tests automatisés. Sauf qu’à l’époque, je n’écrivais quasiment pas de tests. Allez comprendre.
Après une lecture en diagonale de la documentation et quelques essais maladroits, j’ai réussi à obtenir un workflow fonctionnel :
name: CI
on:
push:
branches: [ "master", "dev" ]
pull_request:
branches: [ "master", "dev" ]
# ...
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x, 18.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npx prisma migrate dev --name init
- run: npm run build --if-present
- run: npm test
Tous les voyants étaient au vert. J’étais fier de moi, au sommet de la fameuse “montagne de la stupidité”. J’étais donc encore bien loin d’imaginer la suite.
Avec le recul, je vois bien les problèmes :
- Un seul job fourre-tout : tout était dans “build”, alors que ça faisait plein d’autres choses. Pas très clair.
- Des étapes sans vraie logique : pourquoi lancer une migration Prisma dans un job de CI ?
- Nom trompeur : “build” laissait penser qu’on faisait uniquement de la compilation, alors que c’était un joyeux mélange de build, tests et scripts divers.
Bref, un workflow petit mais déjà bancal. Et comme souvent, quand on commence mal, ça finit rarement bien…
Jour 2 : Les choses sérieuses
Dans GitHub Actions, il y a le mot “action”. Et ça peut vouloir dire deux choses :
- L’action au sens événement → réaction : un push, un pull request, et hop, ça déclenche un workflow.
- L’action au sens GitHub : comme le dit la doc, “une extension réutilisable qui peut simplifier votre workflow”.
L’idée est simple : des éditeurs (ou la communauté) créent et testent ces actions, et nous, développeurs, on peut les intégrer directement dans nos workflows sans réinventer la roue. Tout est disponible sur la Marketplace GitHub.
La philosophie est séduisante : un assemblage de “boîtes noires”, chacune spécialisée dans une tâche bien précise.
Mon cas concret : Docker
Pour l’un de mes projets, je voulais automatiser la construction et le déploiement d’images Docker. Objectif : faire ça dans les règles de l’art. Après une petite exploration de la marketplace… bingo ! Docker fournit ses propres actions officielles. Résultat, j’ai rapidement obtenu ce workflow :
name: Build docker image & deploy
# ...
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: # ...
password: # ...
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: # ...
Sur le papier, c’est nickel. Mais dans les faits… comment je teste que ce workflow fonctionne ?
Le vrai problème : tester
À ce stade, il n’y a qu’une seule solution : commit et push sur le dépôt. Et si ça ne marche pas ? On lit les logs, on change et on recommence.
Imaginez : on vous demande de développer une feature et la seule façon de la tester, c’est de la déployer en production à chaque essai. Vous voyez le souci ?
Alors oui, ce n’est pas dramatique pour un projet perso on s'en fiche sinon avec un peu de stratégie de branches, ça limite la casse. Mais ça reste franchement frustrant.
Et le pire, c’est qu’il n’existe pas de solution native pour tester ses workflows en local (on parlera d’act
un peu plus tard 👀). Résultat : des commits en série, des allers-retours chronophages… et quelques heures de cris et de larmes dans le processus.
Jour 3 : Un peu de clarté
Comme je l’ai mentionné plus tôt, l’une des erreurs les plus courantes avec GitHub Actions, c’est de vouloir tout entasser dans un seul job d’un seul workflow.
Résultat ? On se prive d’une vision claire de ce qui se passe, et le debug devient vite un enfer.
Le problème du “fourre-tout”
Reprenons mon premier exemple : si le job s’appelle build
et qu’il échoue, que s’est-il passé exactement ?
- Est-ce une dépendance qui a cassé ?
- Un problème réseau ?
- Une erreur dans la compilation ?
- Ou bien un test qui a planté ?
Impossible de le savoir sans plonger dans les logs. Et plus votre workflow grossit, plus ça devient pénible.
La bonne pratique : découper
La solution est simple : découper le workflow en plusieurs jobs clairs et indépendants.
Un schéma générique :
test
→ exécuter la suite de testsbuild
→ compiler / packager l’applicationdeploy
→ livrer le produit
⚠️ Attention aux parallèles
Par défaut, GitHub Actions exécute les jobs en parallèle. Ce qui est souvent très bien pour gagner du temps… sauf quand on veut imposer un ordre logique (ex. : déployer uniquement si les tests et le build sont passés).
Pour gérer ça, il suffit d’utiliser l’attribut needs
pour indiquer les dépendances entre jobs. Exemple :
name: CI
on:
...
jobs:
test:
# ...
build:
needs: [test]
# ...
deploy:
needs: [build]
# ...
Avec ça, vos workflows deviennent beaucoup plus lisibles, et vos futurs “vous” (ou vos collègues) vous remercieront le jour où il faudra comprendre pourquoi “ça marche pas”.
Jour 4 : Act, la fausse bonne idée ?
Un jour, au milieu de mes errances, je suis tombé sur ce qui semblait être l’outil qui allait me sauver de mes commits compulsifs et de mes logs interminables.
Son nom : act
.
Sa promesse : exécuter vos workflows GitHub Actions directement en local.
Sur les forums et ur YouTube, tout le monde en parlait. Je me suis dit : “ok, c’est peut-être la lumière au bout du tunnel”.
Mes premiers pas avec act
Au début, j’étais sceptique : encore un outil à installer, encore un truc à apprendre. Mais à force de pleurer sur mes workflows cassés, j’ai fini par céder.
Et je dois avouer : la prise en main est agréable. L’outil est bien conçu, avec un affichage clair et lisible. On sent qu’il y a eu du travail derrière.
… et les ennuis commencent
Mais très vite, les premiers bugs sont apparus.
Un de mes workflows échouait en local alors qu’il passait parfaitement sur GitHub. Après quelques recherches, je suis tombé sur cette issue qui nous explique que certaines images utilisées par act
n’ont pas les mêmes dépendances que les runners GitHub officiels.
Et là, on comprend le problème :
act
n’est pas un outil officiel de GitHub.- Il simule un runner en utilisant des images Docker gigantesques (plusieurs Go).
- Résultat : votre machine locale se transforme en centrale nucléaire juste pour lancer quelques scripts.
- Et pour couronner le tout, certaines actions… ne fonctionnent tout simplement pas.
Mon ressenti
À mon niveau, act
s’est révélé être une fausse bonne idée : une belle machine à gaz, qui promet beaucoup mais qui ne tient pas toujours ses promesses.
Jour 5 : Les actions, deuxième fausse bonne idée ?
Bon… on ne va pas se mentir : jusque-là, c’était pas gagné.
Toujours pas moyen de tester facilement mes workflows, donc commits en rafale, temps perdu, et nerfs mis à rude épreuve.
C’est donc ça la vie, Manny ?
Le vrai problème : les actions elles-mêmes
En prenant du recul, j’ai réalisé que la racine du problème n’était pas GitHub Actions en soi… mais les actions.
Celles qu’on nous vend comme la solution miracle sont en réalité parfois des pièges qui nous enferment et rendent le travail encore plus compliqué.
Attention, je ne dis pas qu’elles sont toutes mauvaises !
- Certaines sont incroyables : par exemple celles qui gèrent les artifacts, super pratiques pour partager des fichiers entre jobs (voire entre workflows).
- Mais d’autres… franchement, leur valeur ajoutée est faible par rapport aux galères qu’elles amènent. Exemple typique : les actions pour builder et pousser une image Docker. Ça peut paraître sexy, mais en pratique, quelques commandes shell suffisent largement.
Ma solution : reprendre la main
À partir de là, j’ai décidé de réduire au maximum ma dépendance aux actions.
J’ai créé un dépôt dédié où je centralise mes scripts Python pour effectuer des tâches génériques (tag, release, docker, etc.), peu importe la techno du projet.
Ça me donne une base testable, réutilisable et indépendante.
Pour lancer un process, il me suffit de cloner le repo, installer les dépendances… et c’est parti !
Mon dépôt est disponible ici :
Exemple d’utilisation dans un workflow :
on:
# ...
jobs:
# ...
release:
runs-on: ubuntu-latest
needs: [test, build, check-version]
if: needs.check-version.outputs.should-release == 'true'
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: ${{ github.sha }}
- name: Install uv
run: |
sudo apt update
sudo apt install -y curl
sudo curl -LsSf https://astral.sh/uv/install.sh | sh
shell: bash
- name: Clone pipelines
run: |
cd ~
git clone https://github.com/CharlyGin/pipelines.git
shell: bash
- name: Install dependencies
run: |
cd ~/pipelines
uv sync
shell: bash
- name: Run Tag & Release
run: |
VERSION=$(jq -r '.version' package.json)
uv run ~/pipelines/scripts/tag_and_release.py --pre-release --tag $VERSION --app $GITHUB_WORKSPACE --build-dir /dist
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
shell: bash
Clarifier les workflows
Autre souci : les petits bouts de scripts shell éparpillés dans les steps.
Ça pollue la lecture des workflows et c’est une nouvelle source de bugs (puisqu’impossible à tester directement).
Ma solution : les déplacer dans des scripts dédiés, par exemple dans un dossier .github/scripts
.
Par conséquent, mes workflows ne contiennent plus de logique. Ils se contentent de déclencher des scripts clairs, testables et versionnés. La lisibilité est bien meilleure, et le debug devient plus simple.
Jour 6 : Un peu (beaucoup) d'organisation
Arrivé à ce stade, j’avais fait du ménage dans mes workflows en externalisant mes scripts. Pourtant, un nouveau problème est apparu. Je me retrouvais avec les mêmes scripts appelés plusieurs fois.
Par exemple :
- une fois pour tester les PRs,
- une fois pour faire une pré-release,
- et encore une autre pour la release finale.
Bref, beaucoup de répétition, et une forte envie de factoriser tout ça.
La solution : workflow_call
Heureusement, GitHub Actions propose une fonctionnalité taillée pour ça : l’événement workflow_call
.
L’idée est simple :
- créer un workflow par fonction (ex. :
test.yml
,build.yml
,deploy.yml
), - leur passer des paramètres (par exemple
is_pre-release
), - et les appeler depuis d’autres workflows.
C’est propre, c’est réutilisable et ça réduit énormément la duplication.
Plus de flexibilité : workflow_dispatch
J’ai ajouté en bonus l’événement workflow_dispatch
.
Pourquoi ? Pour pouvoir lancer un workflow manuellement en cas de besoin (ex. : un bug qui bloque la release automatique).
Autre avantage, les workflows s’exécutent dans l’environnement GitHub et donc avec accès aux secrets définis dans le repo, sans que les autres développeurs aient besoin de les stocker (ni d’y avoir accès, d’ailleurs 😅).
Jour 7 : Conclusion
Beaucoup de rage, quelques larmes et un certain nombre de commits inutiles ont été sacrifiés au cours de cette semaine fictive. Mais comme on dit : après la pluie vient le beau temps.
En chemin, j’ai appris :
- à éviter les jobs fourre-tout,
- à me méfier des fausses bonnes idées (
act
ou certaines actions), - à privilégier mes propres scripts pour garder la main,
- et à organiser mes workflows avec
workflow_call
etworkflow_dispatch
pour plus de clarté et de souplesse.
GitHub Actions vaut clairement le coup. Cet outil peut sembler compliqué au début, mais il est puissant et flexible. Les actions intégrées sont souvent pratiques, mais il ne faut pas hésiter à reprendre la main quand elles deviennent trop contraignantes. Avec de l’organisation et de la patience, on passe vite de l’enfer au paradis.
Vous pouvez trouver un exemple concret de cette structure dans un template de package Python que j’ai créé :