GitHub Actions essentials: workflow, job et step
1. Vue d’ensemble
GitHub Actions est un outil CI/CD intégré à GitHub qui vous permet d’automatiser les builds, tests et déploiements sans avoir besoin d’un serveur CI dédié. Cet article explique trois concepts clés : workflow, job et step, avec des exemples concrets pour un projet Spring Boot utilisant Maven.
Après sa lecture, vous saurez écrire un fichier workflow qui exécute les tests automatiquement à chaque push de code, comprendre comment les jobs s’exécutent en parallèle ou séquentiellement, et déboguer quand un workflow échoue.
2. Qu’est-ce qu’un workflow?
Un workflow est un fichier YAML situé dans le dossier .github/workflows/ de votre dépôt. Chaque workflow définit quand exécuter (trigger) et ce qu’il faut faire (jobs).
# .github/workflows/ci.yml
name: CI Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
- name: Build with Maven
run: mvn -B package
Explication :
nameau début du fichier est le nom affiché sur l’onglet Actions de GitHub.ondéclare le trigger : ici le workflow s’exécute lors d’unpushou d’unepull_requestsur la branchemain.jobs.buildest un job unique nommébuild, exécuté sur la machine virtuelleubuntu-latest.
Remarque : Le fichier doit être situé dans le bon chemin
.github/workflows/*.yml, sinon GitHub ne reconnaîtra pas le workflow.
3. Job : unité d’exécution indépendante
Un workflow peut avoir plusieurs jobs. Chaque job s’exécute sur son propre runner (machine virtuelle), par défaut les jobs s’exécutent en parallèle à moins que vous ne déclariez needs.
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: mvn -B test
deploy:
runs-on: ubuntu-latest
needs: test
steps:
- run: echo "Deploying application..."
Explication :
testetdeploysont deux jobs distincts, chaque job a son propre environnement runner sain, sans partage de fichiers système entre eux.needs: testforcedeployà attendre quetestréussisse avant de s’exécuter — créant une relation séquentielle.- Sans
needs, GitHub Actions exécuteratestetdeployen même temps.
3.1. Partager des données entre jobs
Puisque chaque job a son propre runner, pour transférer des fichiers d’un job à un autre, vous devez utiliser artifacts.
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: mvn -B package
- uses: actions/upload-artifact@v4
with:
name: app-jar
path: target/*.jar
deploy:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/download-artifact@v4
with:
name: app-jar
Explication :
upload-artifactenregistre le fichier.jardu jobbuilddans le stockage temporaire de GitHub.download-artifactdans le jobdeployrécupère ce fichier sur le nouveau runner.- C’est l’unique moyen de transférer des données entre jobs (les variables d’environnement ordinaires ne fonctionnent pas).
4. Step : plus petite unité d’action
Une step est une action spécifique dans un job, exécutée séquentiellement de haut en bas. Il existe deux types de steps principaux : utiliser uses (appeler une action prédéfinie) ou utiliser run (exécuter une commande shell).
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Cache Maven dependencies
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
- name: Run tests
run: mvn -B test
- name: Print result
run: echo "Test step finished with status ${{ job.status }}"
Explication :
- La step
Checkout codeutilise l’action prédéfinieactions/checkoutpour récupérer le code source sur le runner. - La step
Cache Maven dependenciesmet en cache le répertoire~/.m2/repository, ce qui accélère les builds suivants en évitant de retélécharger les dépendances. - La
keydu cache est basée sur le hash depom.xml— quandpom.xmlchange, l’ancien cache est rejeté et un nouveau cache est créé. - La dernière step utilise
runpour exécuter une commande shell ordinaire, et peut référencer des contextes comme${{ job.status }}.
5. Variables d’environnement et secrets
Vous avez souvent besoin de transmettre des configurations sensibles (clés API, tokens) au workflow sans les coder en dur dans le fichier YAML.
jobs:
deploy:
runs-on: ubuntu-latest
env:
SPRING_PROFILES_ACTIVE: prod
steps:
- uses: actions/checkout@v4
- name: Deploy to server
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
run: |
echo "Deploying with profile $SPRING_PROFILES_ACTIVE"
curl -H "Authorization: Bearer $DEPLOY_TOKEN" https://api.example.com/deploy
Explication :
envau niveau du job s’applique à toutes les steps de ce job (SPRING_PROFILES_ACTIVE).envau niveau de la step s’applique uniquement à cette step (DEPLOY_TOKEN).secrets.DEPLOY_TOKENest récupéré depuis Settings → Secrets and variables → Actions du dépôt, la valeur réelle n’apparaît jamais dans les logs.
Remarque : Ne jamais afficher directement la valeur d’un secret avec
echo $DEPLOY_TOKENdans les logs — GitHub le masquera automatiquement, mais il est préférable de ne pas afficher les secrets.
6. Matrix : exécuter plusieurs versions en même temps
Quand vous devez tester sur plusieurs versions de Java ou d’OS, matrix vous évite d’écrire des jobs en répétition.
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
java: [17, 21]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java }}
distribution: 'temurin'
- run: mvn -B test
Explication :
strategy.matrix.javadéclare une liste de valeurs[17, 21].- GitHub Actions crée automatiquement 2 jobs en parallèle, chaque job s’exécutant avec une version Java correspondante.
- Cette approche économise les efforts d’écriture YAML répétitif, idéale quand vous devez garantir que le code fonctionne bien dans plusieurs environnements.
7. Tester le workflow avec des tests simples
Le workflow n’est pas testé directement avec JUnit, mais vous devez vous assurer que l’étape mvn test du workflow exécute réellement la suite de tests de votre projet. Voici un exemple de test simple pour OrderService que la CI exécutera :
class OrderServiceTest {
private final OrderService orderService = new OrderService();
@Test
void shouldCalculateTotalPriceCorrectly() {
Order order = new Order("ORD-001", List.of(
new OrderItem("Keyboard", 2, BigDecimal.valueOf(50)),
new OrderItem("Mouse", 1, BigDecimal.valueOf(20))
));
BigDecimal total = orderService.calculateTotal(order);
assertThat(total).isEqualByComparingTo(BigDecimal.valueOf(120));
}
}
Explication :
- Ce test se trouve dans
src/test/javaet sera exécuté parmvn -B testdans la step du workflow automatiquement. - Si le test échoue, la step
Run testssignale une erreur (code de sortie différent de 0), le job s’arrête et les jobs dépendants (needs) ne s’exécutent pas. - C’est pourquoi la CI est utile : le code erroné est bloqué avant sa fusion dans
main.
Résultat lors de l’exécution sur l’interface GitHub Actions (onglet Actions) :
✓ Extraction du code
✓ Configuration de JDK 21
✓ Build avec Maven
✓ Exécution des tests (shouldCalculateTotalPriceCorrectly RÉUSSI)
8. Erreurs courantes
- Mauvaise indentation YAML : GitHub Actions utilise YAML, une mauvaise indentation d’un seul espace fait qu’un job ou une step n’est pas reconnu, ce qui génère généralement une erreur « Invalid workflow file ».
- Oublier
runs-on: chaque job doit obligatoirement avoirruns-on, son absence fait échouer le workflow lors de l’analyse. - Utiliser une variable d’environnement d’un job dans un autre :
envet les variables de sortie ne sont pas automatiquement transmises entre jobs, il faut utiliseroutputsouartifact. - Cache key ne change pas quand les dépendances changent : si la
keydu cache est trop générale (par exemple justemaven-cache), vous utiliserez accidentellement un ancien cache contenant des dépendances obsolètes. - Exécuter un workflow lourd sur chaque push : sans limiter
pathsoubranches, chaque petit commit (modification de README) déclenche toute la pipeline build + test, consommant des minutes d’exécution Actions (avec limite gratuite).
Remarque : Si votre projet n’a besoin que d’un build simple et n’a pas plusieurs environnements, n’utilisez pas
matrixouartifact— ajouter une complexité inutile rendra le workflow difficile à maintenir.
9. Conclusion
Un workflow est un fichier YAML qui définit toute la pipeline, un job est un bloc d’exécution indépendant s’exécutant sur son propre runner, et une step est chaque action spécifique dans un job. Comprendre ces trois niveaux vous aide à organiser votre pipeline CI/CD clairement : quels jobs s’exécutent en parallèle, quels jobs doivent s’attendre mutuellement via needs, et quand utiliser artifact pour partager des données.
Au départ, gardez votre workflow simple (un job, quelques steps de base : checkout, setup Java, test). À mesure que votre projet grandit, ajoutez matrix, cache, et séparez build/test/deploy en jobs distincts pour faciliter la gestion et le débogage.