This repository serves as a comprehensive collection of GitHub Actions workflow examples.
It provides a variety of workflow configurations that demonstrate different use cases and
best practices for automating CI/CD processes using GitHub Actions. Each
example includes a name for the workflow, a list of trigger events, and a set of jobs. Each
job contains a list of steps that execute in order when the job runs. These steps may access
environment variables, conditions, expressions, and secrets to perform various actions,
such as checking out the source repository, running scripts, and setting up a tmate
session
for debugging purposes. Examples cover different areas of functionality, such as job
matrix, parallel jobs, job ordering, context variables, expression evaluation, outputting
variables, and event triggers.
GitHub Actions is a CI/CD platform for automatic build, test, and deployment. GitHub Actions allows you to run workflows when a push
, pull request
, or other event
happens in your repository. You can use virtual machines provided by GitHub or manage your own runners in your own infrastructure.
Workflow is a process that runs one or more jobs. They can be run either in parallel or in sequential order.
Workflow basics:
- One or more
events
that will trigger the workflow.Event
is a specific activity in a repository. - One or more
jobs
, each of which will execute on arunner
machine and run a series of one or moresteps
. By default, every job is independent - Each
step
can either run a script that you define or run anaction
, which is a reusable extension that can simplify your workflow - Each
Runner
is a newly-provisioned virtual machine. GitHub provides Ubuntu Linux, MS Windows, and macOS runners. You can host your runner as well. Every runner executes a single job.
Workflow files are yaml
files and are placed in the .github/workflows
directory in your repository on GitHub.
Note By default, all workflows will be executed on the ubuntu-latest
image unless otherwise specified
Get familiar with basic workflow syntax
This example workflow prints current path
, Hello world
, followed by Step 1…
, Step 2…
, Step 3…
, and finally Goodbye
.
Elements of current workflow:
-
Name of workflow (optional element)
name: hello-world-example
-
The
on
section defines what event triggers the workflow. Here, the trigger event ispush
. The optional parameterpaths
allows to run a workflow based on what files or directories are changed.on: push: paths: - '.github/workflows/01-hello-world.yml'
-
Job. The job name is
say-hello
. The keywordruns-on
configures the job to run on the latest version of an Ubuntu Linux runner.jobs: say-hello: runs-on: ubuntu-latest
-
Steps
are a list of commands to run. Theuses
keyword specifies the action used in this job:actions/checkout
versionv2
. This is an action that checks out your repository onto the runner. You should use thecheckout action
any time your workflow will run against the repository's code. The Next step sets the optionworking-directory
to the indicated path and prints the current path.steps: - uses: actions/checkout@v3 - name: Print current path working-directory: ./01-hello-world run: pwd
-
Pipe
|
is used to start multiple strings in ayaml
file- name: Do stuff run: | echo "Step 1..." echo "Step 2..." echo "Step 3..." echo "Step 4..."
This example demonstrates how to trigger workflow on different events
The on
section defines what event triggers the workflow. List of events you can see here.
Optionally, you may include/exclude branches
, tags
, or paths
that trigger workflow by indicating their name or pattern to match.
You may define multiple events and options for them to customize your workflow run. Also, it is possible to set a schedule to run your workflow,
specified with POSIX cron syntax.
on:
push:
branches:
- '02-develop'
- '02-foo/*'
- '02-foo/**'
- '!02-foo/*/456' #except
tags:
- '*'
paths:
- '.github/workflows/02-event-triggers.yml'
pull_request:
branches:
- '02-develop'
paths:
- '.github/workflows/02-event-triggers.yml'
schedule:
- cron: '*/15 * * * *'
Step prints the event name that triggered it.:
- name: Event
run: echo "Triggered by $GITHUB_EVENT_NAME"
This example demonstrates the usage of different actions type in one workflow
Actions reduce number of steps by providing reusable code
for common tasks, such as checkout to gitHub repository or installing node.
To run an action include keyword uses
pointing to a GitHub repo with the pattern {owner}/{repo}@{ref}
or {owner}/{repo}/{path}@{ref}
. A ref
can be a branch, tag or SHA. Some actions have required or optional parameters.
GitHub officially supports many common actions.
Example of usage of the different actions in workflow:
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '15.8.0'
In these steps :
- actions/checkout checks out your repo into the working directory at the event that triggered workflow (e.g., branch push)
- actions/setup-node sets up your workflow with a specific node version, and makes node and npm available in the following steps.
Using environment variables in different contexts
Environment variables can be:
- default. Find the list of default variables here and defined by the user.
- or custom for:
- a single workflow. Use the
env
key within the workflow file to create a variable for a single workflow. The scope of the variables can be: the entire workflow, job, or a specific step. The variable's scope is limited to the element in which it is defined. - multiple workflows. Variables and secrets can be created at different levels: organization, repository and environment levels.
- a single workflow. Use the
Job:
jobs:
use-env-vars:
runs-on: ubuntu-latest
env:
VIDI: 'I saw'
Step:
steps:
...
- name: Show me the vars
run: echo "$VENI, $VIDI, $VICI"
env:
VICI: 'I conquered'
Also, you can set new environment variables by adding it to GITHUB_ENV. The variable will be available in next steps.
- name: Create env var
run: echo "foo=bar" >> $GITHUB_ENV
Get values of the environment variables:
- name: Useful default vars
run: |
echo "Workflow name: $GITHUB_WORKFLOW"
echo "Workspace: $GITHUB_WORKSPACE"
echo "Event: $GITHUB_EVENT_NAME"
echo "SHA: $GITHUB_SHA"
echo "Ref: $GITHUB_REF"
Get list of all environment variables:
- name: Show env variables list
run: env
Running jobs in parallel
Multiple jobs are running in parallel by default and have a particular runner:
jobs:
job-a:
runs-on: ubuntu-latest
steps:
- run: echo "Doing work"
job-b:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
By default, all jobs are running in parallel. To force job ordering use the needs
keyword
It is possible to wait for one or more jobs:
job3:
runs-on: ubuntu-latest
needs: job1
steps:
- run: echo "job1 done, running job3"
job4:
runs-on: ubuntu-latest
needs: [job2, job3]
steps:
- run: echo "job2 & job3 done, running job4"
job5
will run even if job1
will fail
job5:
runs-on: ubuntu-latest
if: ${{ always() }}
needs: job1
steps:
- run: echo "job1 completed with status ${{ needs.job1.result }}, running job5
The diagram of the job running sequence is provided
%%{init: {'flowchart': {"curve":"linear"} } }%%
graph LR
A[job1] --> |on success| C[job3]
B[job2] & C[job3] --> |on success| D[job4]
A[job1] --> |always| E[job5]
You can run multiple jobs with different configurations by using a job matrix. Jobs defined by matrix run in parallel by default
The matrix
keyword is how you define a job matrix. Each user-defined key is a matrix parameter. Here we’ve defined two parameters: os
, for the
runner's OS, and node
, to indicate the node version. Each value of the parameters from the list is used in a cartesian product
to create jobs.
This section defines a 2 x 3 matrix of 6 jobs, each with a different combination of os
and node
. The exclude
keyword prevents jobs with
specific configurations from running. The include
allows you to add new jobs to the matrix. Note that the include
rules are always
evaluated after the exclude
rules.
my-job:
strategy:
matrix:
os: [ubuntu-18.04, ubuntu-22.04]
node: [14, 16, 18]
exclude:
- os: ubuntu-18.04
node: 14
Example 07a: Self-hosted runners for multiple jobs
A runner
is a server that runs your workflows when they're triggered. Each runner can run a single job at a time. GitHub provides Ubuntu Linux, Microsoft Windows, and macOS runners to run your workflows; each workflow run executes in a fresh, newly-provisioned virtual machine. If you need a different operating system or require a specific hardware configuration, you can host your own runners.
A self-hosted runner is a system that you deploy and manage to execute jobs from GitHub Actions on GitHub.com.
Output data can be shared between jobs
and steps
.
Create outputs for a step by writing to stdout in the format of =:
- name: Do Work
run: |
echo "FAV_NUMBER=3" >> $GITHUB_OUTPUT
echo "FAV_COLOR=blue" >> $GITHUB_OUTPUT
id: abc
A step can have multiple outputs. Steps that create outputs must have a unique id
.
Use the steps context variable and step id
to get the value ${{steps.<step_id>.outputs.<step_output_name>}}
:
- name: Read output
run: |
echo "${{steps.abc.outputs.FAV_NUMBER}}"
echo "${{steps.abc.outputs.FAV_COLOR}}"
Create outputs for a job that will be available to other jobs that need it (see Job Ordering). You can include output from steps that ran for the job.
job1:
outputs:
fav-animal: tiger
fav-number: ${{steps.abc.outputs.FAV_NUMBER}}
Use context expressions to grab outputs from a job included in needs
needs: <job_name>
, to address output ${{needs.<job_name>.outputs.<job_output_name>}}
:
job2:
runs-on: ubuntu-latest
needs: job1
steps:
- run: |
echo "${{needs.job1.outputs.fav-animal}}"
echo "${{needs.job1.outputs.fav-number}}"
Contexts
are a way to access information about workflow runs, variables, runner environments, jobs, and steps. Each context is an object that contains properties, which can be strings or other objects. Context variables are accessible outside the run commands.
Using values of the matrix
context:
env:
GREETING: ${{ matrix.greeting }}
Accessing value of the secret USERNAME
defined in the GitHub:
env:
A_SECRET: ${{ secrets.USERNAME }}
Using event name in expression:
if: ${{ github.event_name == 'pull_request' }}
Workflows support evaluating expressions,comparisons and simple functions.
String comparison:
- name: Print if 'Hello'
if: ${{ matrix.greeting == 'Hello' }}
run: echo "greeting is Hello"
- name: Print if starts with 'He'
if: ${{ startsWith(matrix.greeting, 'He') }}
run: echo "greeting starts with He"
- name: Print if ends with 'y'
if: ${{ endsWith(matrix.greeting, 'y') }}
run: echo "greeting ends with y"
- name: Print if contains 'ow'
if: ${{ contains(matrix.greeting, 'ow') }}
run: echo "greeting contains ow"
Formatting:
- name: Print formatted greeting
run: |
echo "${{ format('{0} says {1}', github.actor, matrix.greeting) }}"
Working with JSON
:
- name: To JSON
run: echo 'Job context is ${{ toJSON(job) }}'
- name: From JSON
env: ${{ fromJSON('{"FAVORITE_FRUIT":"APPLE", "FAVORITE_COLOR":"BLUE"}') }}
run: echo "I would like a ${FAVORITE_COLOR} ${FAVORITE_FRUIT}"
Running basing on previous results:
- name: Success
if: ${{ success() }}
run: echo "Still running..."
- name: Always
if: ${{ always() }}
run: echo "You will always see this"
- name: Cancelled
if: ${{ cancelled() }}
run: echo "You canceled the workflow"
- name: Failure
if: ${{ failure() }}
run: echo "Something went wrong..."
The Tmate
session will be started after fail on the previous step. Use this failing workflow for training
The workflow will fail on the following step because npm
is not installed and no node action is used in this workflow.
- name: Run tests
working-directory: ./11-tmate
run: npm test
Open the tmate
session using the HTTP link from your workflow logs.
If tmate
is installed on your machine you may also connect to the session throw terminal. The command is provided in your logs as well.
Run npm install:
npm ci
and check if tests will pass:
npm test
continue workflow run by creating a file:
touch /continue
This example workflow configures a PostgreSQL
service container, and automatically maps port 5432
in the service container to a randomly chosen available port on the host
. The job context
is used to access the number of the port that was assigned on the host.
Create a secret at the repository level with the name POSTGRES_PASSWORD
jobs:
postgres-job:
runs-on: ubuntu-latest
services:
postgres:
image: postgres
env:
POSTGRES_PASSWORD: postgres
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
ports:
# Maps TCP port 5432 in the service container to a randomly chosen available port on the host.
- 5432
Get a value of the secret with the name NEW_SECRET
. If the secret does not exist value will be empty. Please create a secret with the same name or replace name with the one of an existing secret
steps:
- name: Echo secret's value
run: |
echo "Masked: "
echo ${{ secrets.NEW_SECRET }}
echo "Unmasked: "
echo ${{ secrets.NEW_SECRET }} | sed 's/./& /g'
sudo apt install act
To install Nektos Act
on other OS follow the instructions from section
To run the following commands you should clone a GitHub project with existing GitHub Actions workflows and go to its directory. You can use the current project, too.
- View all jobs that are triggered by pull_request event
act -l
- View all jobs triggered by events, e.g. by the
pull_request
act <event-name> -l
act pull_request -l
or in the certain workflow file, e.g. in main.yaml
act <file-name> -l
act main.yaml -l
- Run a job with a specific name:
act -j <job-name>
- You may also explicitly indicate the workflow and job to run using flags
--workflow
and--job
, respectively, flag--verbosity
enables additional logging.
act --workflows .github/workflows/main.yml --verbose --job my-job
- Use an alternative environment to run your workflows.
runner-image-name
- should be the same as in the workflowyaml
file
act -P <runner-image-name>=<image-to-be-used>
act -P ubuntu-latest=catthehacker/ubuntu:act-20.04
- If your workflow file has a
tmate
section (See Example 11) you may access it using docker commands
watch docker ps
copy the first three symbols of the container's ID and run the command
docker exec -it <XYZ> sh
- GitHub Actions workflows
- GitHub Actions workflows basics, examples and a quick tutorial
- Trigger a workflow
- Job environments
- Expressions in GitHub Actions
- GitHub Actions contexts
- GitHub Actions variables
- GitHub Actions common actions
- Good security practices for using GitHub Actions features
- Encrypted secrets
- Outputs for jobs
- Output commands
- Tmate actions
- Job services