Workflow syntax
Table of contents
- Structure of a workflow
- Main keys
- Expressions and contexts
- Conditions
- Environment variables
- Practical exercises
1 - Structure of a workflow
Complete anatomy
# .github/workflows/example.yml
# Nom du workflow (affiché dans l'UI)
name: CI Pipeline
# Événements déclencheurs
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
# Variables d'environnement globales
env:
NODE_VERSION: '18'
# Définition des jobs
jobs:
build:
name: Build Application
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build
run: npm run build
YAML indentation
# CORRECT - 2 espaces
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Step 1
run: echo "Hello"
# INCORRECT - tabs ou indentation incohérente
jobs:
build: # Tab au lieu d'espaces
runs-on: ubuntu-latest
Important
YAML is indentation-sensitive. Use 2 spaces, never tabs.
🔝 Back to table of contents
2 - Main keys
name
# Nom du workflow
name: My Awesome CI
# Nom du job
jobs:
test:
name: Run Tests
steps:
# Nom du step
- name: Install dependencies
run: npm install
on (triggers)
# Syntaxe simple
on: push
# Syntaxe liste
on: [push, pull_request]
# Syntaxe détaillée
on:
push:
branches:
- main
- 'release/**'
paths:
- 'src/**'
- '!src/**/*.md'
tags:
- 'v*'
pull_request:
types: [opened, synchronize, reopened]
schedule:
- cron: '0 0 * * *' # Tous les jours à minuit
workflow_dispatch: # Exécution manuelle
inputs:
environment:
description: 'Deployment environment'
required: true
default: 'staging'
jobs
jobs:
# Job 1
build:
runs-on: ubuntu-latest
steps:
- run: npm run build
# Job 2 - dépend du job 1
test:
needs: build
runs-on: ubuntu-latest
steps:
- run: npm test
# Job 3 - dépend des jobs 1 et 2
deploy:
needs: [build, test]
runs-on: ubuntu-latest
steps:
- run: ./deploy.sh
runs-on
jobs:
linux:
runs-on: ubuntu-latest # ou ubuntu-22.04
windows:
runs-on: windows-latest # ou windows-2022
macos:
runs-on: macos-latest # ou macos-13
self-hosted:
runs-on: self-hosted # Votre propre runner
labeled:
runs-on: [self-hosted, linux, x64] # Labels multiples
steps
steps:
# Utiliser une action
- uses: actions/checkout@v4
# Avec paramètres
- uses: actions/setup-node@v4
with:
node-version: '18'
# Commande shell
- run: npm install
# Commande multi-lignes
- run: |
npm install
npm run build
npm test
# Avec nom et ID
- name: Run tests
id: test-step
run: npm test
# Avec shell spécifique
- name: PowerShell script
shell: pwsh
run: Write-Host "Hello from PowerShell"
🔝 Back to table of contents
3 - Expressions and contexts
Expression syntax
# Expression simple
${{ expression }}
# Dans run (interpolation)
- run: echo "Branch is ${{ github.ref }}"
# Dans une condition
- if: ${{ github.event_name == 'push' }}
Available contexts
| Context | Description |
|---|---|
github | Information about the workflow |
env | Environment variables |
vars | Repository/org variables |
secrets | Secrets |
job | Information about the current job |
steps | Outputs of previous steps |
runner | Information about the runner |
inputs | Workflow inputs |
matrix | Matrix values |
github context
- run: |
echo "Event: ${{ github.event_name }}"
echo "Ref: ${{ github.ref }}"
echo "SHA: ${{ github.sha }}"
echo "Actor: ${{ github.actor }}"
echo "Repository: ${{ github.repository }}"
echo "Run ID: ${{ github.run_id }}"
echo "Run Number: ${{ github.run_number }}"
Outputs between steps
steps:
- name: Set output
id: step1
run: echo "version=1.0.0" >> $GITHUB_OUTPUT
- name: Use output
run: echo "Version is ${{ steps.step1.outputs.version }}"
Functions
# Fonctions courantes
${{ contains(github.event.head_commit.message, '[skip ci]') }}
${{ startsWith(github.ref, 'refs/tags/') }}
${{ endsWith(github.repository, '-test') }}
${{ format('Hello {0}!', github.actor) }}
${{ join(matrix.os, ', ') }}
${{ toJSON(github) }}
${{ fromJSON(needs.job1.outputs.matrix) }}
🔝 Back to table of contents
4 - Conditions
if syntax
jobs:
deploy:
# Condition sur le job
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- run: echo "Deploying..."
notify:
runs-on: ubuntu-latest
steps:
# Condition sur le step
- name: Notify on failure
if: failure()
run: echo "Something failed!"
Status functions
| Function | Description |
|---|---|
success() | Previous job/step succeeded |
failure() | Previous job/step failed |
cancelled() | Workflow cancelled |
always() | Always run |
steps:
- name: Build
run: npm run build
- name: Cleanup on failure
if: failure()
run: ./cleanup.sh
- name: Always notify
if: always()
run: ./notify.sh
Advanced conditions
# ET logique
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
# OU logique
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
# Négation
if: "!contains(github.event.head_commit.message, '[skip ci]')"
# Opérateur ternaire (via expression)
env:
DEPLOY_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
🔝 Back to table of contents
5 - Environment variables
Definition levels
# Niveau workflow
env:
CI: true
NODE_VERSION: '18'
jobs:
build:
# Niveau job
env:
BUILD_TYPE: release
runs-on: ubuntu-latest
steps:
# Niveau step
- name: Build
env:
DEBUG: '1'
run: |
echo "CI=$CI"
echo "NODE_VERSION=$NODE_VERSION"
echo "BUILD_TYPE=$BUILD_TYPE"
echo "DEBUG=$DEBUG"
Dynamic variables
steps:
- name: Set env dynamically
run: echo "BUILD_DATE=$(date +%Y%m%d)" >> $GITHUB_ENV
- name: Use env
run: echo "Build date is $BUILD_DATE"
Predefined variables
| Variable | Description |
|---|---|
GITHUB_REPOSITORY | owner/repo |
GITHUB_SHA | Commit SHA |
GITHUB_REF | Full ref |
GITHUB_WORKSPACE | Working directory |
GITHUB_TOKEN | Authentication token |
RUNNER_OS | Linux, Windows, macOS |
- run: |
echo "Repo: $GITHUB_REPOSITORY"
echo "SHA: $GITHUB_SHA"
echo "Workspace: $GITHUB_WORKSPACE"
🔝 Back to table of contents
6 - Practical exercises
Exercise 1: Conditional workflow
Create a workflow that deploys only on the main branch:
Solution
name: Deploy
on:
push:
branches: [main, develop]
jobs:
deploy:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- run: echo "Deploying to production..."
Exercise 2: Outputs between steps
Create a workflow that passes a version between two steps:
Solution
name: Version
on: push
jobs:
version:
runs-on: ubuntu-latest
steps:
- name: Generate version
id: version
run: echo "version=$(date +%Y.%m.%d)" >> $GITHUB_OUTPUT
- name: Use version
run: echo "Version is ${{ steps.version.outputs.version }}"
Quiz
Q1. How do you define a dynamic environment variable?
Answer
echo "VAR_NAME=value" >> $GITHUB_ENV
Q2. Which condition runs a step even if the job fails?
Answer
if: always()
🔝 Back to table of contents
Key takeaways
- YAML with 2 spaces of indentation
${{ expression }}for expressions- Contexts:
github,env,steps,secrets - Conditions with
if:and thesuccess(),failure(),always()functions - Environment variables at 3 levels: workflow, job, step
$GITHUB_ENVfor dynamic variables$GITHUB_OUTPUTfor step outputs