Jobs and steps
Table of contents
- Execution architecture
- Job configuration
- Dependencies between jobs
- Step configuration
- Sharing data
- Practical exercises
1 - Execution architecture
Execution flow
Characteristics
| Element | Environment | Execution |
|---|---|---|
| Workflow | Repository | Triggered by an event |
| Job | Dedicated runner | Parallel by default |
| Step | Same runner | Sequential |
Isolation
jobs:
job1:
runs-on: ubuntu-latest # Runner A
steps:
- run: echo $HOME # /home/runner
job2:
runs-on: ubuntu-latest # Runner B (différent!)
steps:
- run: echo $HOME # /home/runner (autre machine)
Important
Each job runs on a different runner. Files are not shared between jobs.
🔝 Back to table of contents
2 - Job configuration
Complete structure
jobs:
build:
name: Build Application # Nom affiché
runs-on: ubuntu-latest # Runner
timeout-minutes: 30 # Timeout
permissions: # Permissions GITHUB_TOKEN
contents: read
packages: write
env: # Variables d'environnement
NODE_ENV: production
defaults: # Défauts pour les steps
run:
shell: bash
working-directory: ./src
steps:
- uses: actions/checkout@v4
Permissions
jobs:
build:
permissions:
contents: read # Lecture du repo
packages: write # Écriture packages
issues: write # Écriture issues
pull-requests: write # Écriture PR
id-token: write # OIDC token
| Permission | Usage |
|---|---|
contents | Read/write the repo |
packages | GitHub Packages |
issues | Issues and comments |
pull-requests | PRs and reviews |
id-token | OIDC (cloud auth) |
Concurrency
jobs:
deploy:
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: true
runs-on: ubuntu-latest
steps:
- run: ./deploy.sh
Environment
jobs:
deploy:
environment:
name: production
url: https://myapp.com
runs-on: ubuntu-latest
steps:
- run: echo "Deploying to production"
🔝 Back to table of contents
3 - Dependencies between jobs
needs
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: npm run build
test:
needs: build # Attend que build soit terminé
runs-on: ubuntu-latest
steps:
- run: npm test
deploy:
needs: [build, test] # Attend build ET test
runs-on: ubuntu-latest
steps:
- run: ./deploy.sh
Visualization
Conditions on needs
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: npm run build
notify-success:
needs: build
if: success() # Seulement si build réussi
runs-on: ubuntu-latest
steps:
- run: echo "Build succeeded!"
notify-failure:
needs: build
if: failure() # Seulement si build échoué
runs-on: ubuntu-latest
steps:
- run: echo "Build failed!"
cleanup:
needs: build
if: always() # Toujours exécuté
runs-on: ubuntu-latest
steps:
- run: echo "Cleaning up..."
Outputs between jobs
jobs:
build:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- id: version
run: echo "version=1.0.${{ github.run_number }}" >> $GITHUB_OUTPUT
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- run: echo "Deploying version ${{ needs.build.outputs.version }}"
🔝 Back to table of contents
4 - Step configuration
Types of steps
steps:
# Action depuis le Marketplace
- uses: actions/checkout@v4
# Action avec paramètres
- uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
# Commande shell
- run: npm install
# Commande multi-lignes
- run: |
npm install
npm run build
npm test
# Action locale
- uses: ./.github/actions/my-action
Step options
steps:
- name: Install dependencies # Nom affiché
id: install # ID pour référencer
if: success() # Condition
continue-on-error: true # Ne pas échouer le job
timeout-minutes: 10 # Timeout
env: # Variables d'environnement
NODE_ENV: production
working-directory: ./app # Répertoire de travail
shell: bash # Shell à utiliser
run: npm install
Available shells
| Shell | OS | Command |
|---|---|---|
bash | Linux, macOS | bash --noprofile --norc |
sh | Linux, macOS | sh -e |
pwsh | All | PowerShell Core |
powershell | Windows | PowerShell Desktop |
cmd | Windows | cmd /D /E:ON |
python | All | Python script |
steps:
- name: Bash script
shell: bash
run: echo "Hello from bash"
- name: PowerShell script
shell: pwsh
run: Write-Host "Hello from PowerShell"
- name: Python script
shell: python
run: |
import os
print(f"Hello from Python on {os.name}")
🔝 Back to table of contents
5 - Sharing data
Between steps (same job)
jobs:
build:
runs-on: ubuntu-latest
steps:
# Méthode 1: Fichiers
- name: Create file
run: echo "data" > myfile.txt
- name: Read file
run: cat myfile.txt
# Méthode 2: Outputs
- name: Set output
id: step1
run: echo "result=success" >> $GITHUB_OUTPUT
- name: Use output
run: echo "${{ steps.step1.outputs.result }}"
# Méthode 3: Environment
- name: Set env
run: echo "MY_VAR=value" >> $GITHUB_ENV
- name: Use env
run: echo "$MY_VAR"
Between jobs (artifacts)
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo "content" > artifact.txt
- uses: actions/upload-artifact@v4
with:
name: my-artifact
path: artifact.txt
test:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: my-artifact
- run: cat artifact.txt
Between jobs (outputs)
jobs:
job1:
runs-on: ubuntu-latest
outputs:
data: ${{ steps.generate.outputs.data }}
steps:
- id: generate
run: echo "data=hello" >> $GITHUB_OUTPUT
job2:
needs: job1
runs-on: ubuntu-latest
steps:
- run: echo "${{ needs.job1.outputs.data }}"
🔝 Back to table of contents
6 - Practical exercises
Exercise 1: Sequential pipeline
Create a build → test → deploy pipeline:
Solution
name: Pipeline
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo "Building..."
test:
needs: build
runs-on: ubuntu-latest
steps:
- run: echo "Testing..."
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- run: echo "Deploying..."
Exercise 2: Sharing outputs
Pass a version between two jobs:
Solution
name: Version
on: push
jobs:
generate:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.ver.outputs.version }}
steps:
- id: ver
run: echo "version=1.0.0" >> $GITHUB_OUTPUT
use:
needs: generate
runs-on: ubuntu-latest
steps:
- run: echo "Version is ${{ needs.generate.outputs.version }}"
Quiz
Q1. How do you make a job wait for two other jobs?
Answer
needs: [job1, job2]
Q2. What is the difference between jobs and steps for sharing files?
Answer
Steps share the same filesystem, jobs require artifacts.
🔝 Back to table of contents
Key takeaways
- Jobs run in parallel by default
needsto create dependencies- Steps run sequentially within a job
$GITHUB_OUTPUTfor step outputs- Artifacts to share between jobs
continue-on-error: trueto ignore failurestimeout-minutesto limit execution