Sometimes you need to run a step or job only when specific files have changed. For example, you may want to lint and deploy documentation only when a file under docs is modified. GitHub Actions does not natively support this, but you can implement it using git, PowerShell Core, and GitHub Actions expressions.
The approach uses git diff to retrieve the list of modified files, filters them with a regex (straightforward in PowerShell), and then sets a step output using a workflow command.
#Conditional steps
Use the following workflow to run a step conditionally.
.github/workflows/conditional-step.yml (YAML)
name: demo
on:
push:
branches:
- 'main'
jobs:
conditional_step:
runs-on: 'ubuntu-20.04'
steps:
- uses: actions/checkout@v2
with:
# Checkout as many commits as needed for the diff
fetch-depth: 2
- shell: pwsh
# Give an id to the step, so we can reference it later
id: check_file_changed
run: |
# Diff HEAD with the previous commit
$diff = git diff --name-only HEAD^ HEAD
# Check if a file under docs/ or with the .md extension has changed (added, modified, deleted)
$SourceDiff = $diff | Where-Object { $_ -match '^docs/' -or $_ -match '.md$' }
$HasDiff = $SourceDiff.Length -gt 0
# Set the output named "docs_changed"
Write-Host "::set-output name=docs_changed::$HasDiff"
# Run the step only with "docs_changed" equals "True"
- shell: pwsh
# steps.<step_id>.outputs.<output name>
if: steps.check_file_changed.outputs.docs_changed == 'True'
run: echo publish docs
#Conditional jobs
Use the following workflow to run a job conditionally.
.github/workflows/conditional-job.yml (YAML)
name: sample
on:
push:
branches:
- 'main'
jobs:
conditional_job_check_files:
runs-on: 'ubuntu-20.04'
# Declare outputs for next jobs
outputs:
docs_changed: ${{ steps.check_file_changed.outputs.docs_changed }}
steps:
- uses: actions/checkout@v2
with:
# Checkout as many commits as needed for the diff
fetch-depth: 2
- shell: pwsh
id: check_file_changed
run: |
# Diff HEAD with the previous commit
$diff = git diff --name-only HEAD^ HEAD
# Check if a file under docs/ or with the .md extension has changed (added, modified, deleted)
$SourceDiff = $diff | Where-Object { $_ -match '^docs/' -or $_ -match '.md$' }
$HasDiff = $SourceDiff.Length -gt 0
# Set the output named "docs_changed"
Write-Host "::set-output name=docs_changed::$HasDiff"
# Run the job only with "docs_changed" equals "True"
conditional_job:
runs-on: 'ubuntu-20.04'
needs: [ conditional_job_check_files ]
if: needs.conditional_job_check_files.outputs.docs_changed == 'True'
steps:
- shell: pwsh
run: echo publish docs
#Additional resources
Do you have a question or a suggestion about this post? Contact me!