Github Actions

Github Actions makes it easy to test, build, and deploy your code into the cloud.

Workflow

A workflow is a configurable automated process that will run one or more jobs. Workflows are defined by a YAML file checked in to your repository and will run when triggered by an event in your repository, or they can be triggered manually, or at a defined schedule.

Events

Events are specific activity that triggers a workflow run. For example, activity such as pushing code to a repository or opening a pull request. You can configure a workflow to run when specific activity on GitHub happens. Common events are push, pull_request, schedule, etc.

Example: push event. Runs your workflow when you push a commit or tag, or when you create a repository from a template.

1
2
on:
push

push event to main and release branches

1
2
3
4
5
on:
push:
branches:
- 'main'
- 'releases/**'

workflow_dispatch event. Allows you to run this workflow manually from the Actions tab. This event will only trigger a workflow run if the workflow file exists on the default branch.

1
2
on:
workflow_dispatch:

schedule. Runs your workflow on a schedule. You can use cron syntax to define the schedule.

1
2
3
on:
schedule:
- cron: "15 4,5 * * *"

You can also combine multiple events to trigger a workflow. For example, you can run a workflow when a pull request is opened or when code is pushed to the main branch.

1
2
3
4
5
on:
pull_request:
branches: [ "main" ]
push:
branches: [ "main" ]

Jobs

A workflow run is made up of one or more jobs, which run in parallel by default.

Use jobs.<job_id> to give your job a unique identifier. To run jobs sequentially, you can define dependencies on other jobs using the jobs.<job_id>.needs keyword.

Dependant jobs will run after the jobs they depend on have completed successfully. If a job fails, the dependant jobs will not run.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
jobs:
setup:
runs-on: ubuntu-latest
steps:
- run: ./setup_server.sh
build:
needs: setup
runs-on: ubuntu-latest
steps:
- run: ./build_server.sh
test:
needs: build
runs-on: ubuntu-latest
steps:
- run: ./test_server.sh

Runners

A runner is a server that runs your jobs. You can use a GitHub-hosted runner, or you can host your own runner. Each job in a workflow run runs on a fresh instance of the runner.

1
runs-on: ubuntu-latest

Steps

Each job in a workflow run is made up of one or more steps. Steps are a sequence of tasks that execute commands. Steps can run commands, run setup tasks, or run an action in your repository, a public repository, or an action published in a Docker registry.

step example

1
2
3
4
- name: install and build
run: |
npm install
npm run build

uses example

Most of the time, you want to use reusable steps.

You can use the uses keyword to run a reusble action in your workflow. An action is a reusable unit of code that can be used in your workflow. You can use actions from the GitHub Marketplace, or you can create your own actions.

1
2
- name: Checkout code
uses: actions/checkout@v4

The name property is optional and defines how the step is displayed in the workflow log.

Here actions/checkout@v4 is a reusable action that checks out your repository under $GITHUB_WORKSPACE, so your job can access it. The action is defined in the actions/checkout repository and is versioned with a tag. You can use the latest version of the action by using the @v4 tag.

format

1
{owner}/{repo}@{ref}

Example

In your repository on GitHub, create a workflow file called github-actions-demo.yml in the .github/workflows directory.

github-actions-demo.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
name: CI

# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the "main" branch
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v4

# Runs a single command using the runners shell
- name: Run a one-line script
run: echo Hello, world!

# Runs a set of commands using the runners shell
- name: List files in repository
run: |
echo "The repository ${{ github.repository }} contains the following files:"
tree -L 1

Commit the file to the main branch of your repository. This will trigger the workflow to run on the next push to the repository.

Expression

Expressions are evaluated at runtime and can be used to access context and set environment variables. You can use expressions to access the context of the workflow run, such as the repository name, the run ID, and the run number.

expression syntax

1
${{ <expression> }}

expression syntax with if. if condition can be applied to jobs, steps, and workflow.

1
2
3
4
5
6
7
8
9
10
- name: print variables
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' }}
run: |
echo "event name is push or pull_request"

jobs:

- name: print variable if it is main branch
if: ${{ github.ref == 'refs/heads/main' }}
run: echo "this is main branch"

build-in functions
Github actions provides a set of built-in functions that can be used in expressions. Some of the most commonly used functions are:

  • contains: Checks if a string contains a substring.
  • startsWith: Checks if a string starts with a substring.
  • endsWith: Checks if a string ends with a substring.
  • format: Formats a string using a template.
  • join: Joins an array of strings into a single string using a separator.
  • toJSON: Converts a value to a JSON string.

Access Context Info

You can access context information about the workflow run using the github context. The github context contains information about the workflow run, such as the repository name, the run ID, and the run number.

You can access the context information using the expression syntax ${{ }} . For example, to access the repository name, you can use ${{ github.repository }}.

1
2
3
- name: print variables
run: |
echo "repo: ${{ github.repository }} runner id: ${{ github.run_id }} runner num: ${{ github.run_number }}"

other contexts:

  • github.actor: The name of the person or app that initiated the workflow run.
  • github.ref: The full Git ref that triggered the workflow run. For example, refs/heads/main for a branch or refs/tags/v1.0 for a tag.
  • github.ref_name: The name of the branch or tag that triggered the workflow run. For example, main for a branch or v1.0 for a tag.
  • github.job: The ID of the job that is currently running.

Environment Variables

You can set environment variables in your workflow file. You can set environment variables at the job level or at the step level.

Define environment variables at the job level

1
2
3
4
5
6
7
8
9
jobs:
build:
runs-on: ubuntu-latest
env:
color: blue
steps:
- name: print env variables
run: |
echo "${{ env.color }}"

Defining outputs for a job

You can define outputs for a job using the jobs.<job_id>.outputs keyword. You can use the ${{ steps..outputs. }} expression to access the output of a step in the job.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
jobs:
job1:
runs-on: ubuntu-latest
# Map a step output to a job output
outputs:
output1: ${{ steps.step1.outputs.test }}
output2: ${{ steps.step2.outputs.test }}
steps:
- id: step1
run: echo "test=hello" >> "$GITHUB_OUTPUT"
- id: step2
run: echo "test=world" >> "$GITHUB_OUTPUT"
job2:
runs-on: ubuntu-latest
needs: job1
steps:
- env:
OUTPUT1: ${{needs.job1.outputs.output1}}
OUTPUT2: ${{needs.job1.outputs.output2}}
run: echo "$OUTPUT1 $OUTPUT2"

References: