GH workflow
github workflow is a way to automate the process of building, testing, and deploying code. It is a set of instructions that you can define in a yaml file. You can define the steps in the workflow and the workflow will run the steps in the order that you define. You can also define the conditions for running the workflow. For example, you can define a workflow to run when a pull request is created or when a push is made to the main branch.
GH workflow syntax
The syntax for a github workflow is defined in a yaml file. The yaml file is a text file that is defined by a set of rules. The rules are defined in the yaml spec.
The following is an example of a yaml file that defines a github workflow.
1
2
3
4
5
6
7
8
9
10
11
12
13
| name: my workflow
on:
push:
branches:
- main
jobs:
my job:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3
- name: run a command
run: echo "hello world"
|
GH default variables
GitHub provides several built-in contexts to access info dynamically:
Variable |
Description |
Usage Example |
GITHUB_WORKFLOW |
The name of the workflow |
$GITHUB_WORKFLOW |
GITHUB_RUN_ID |
Unique ID for the current run |
$GITHUB_RUN_ID |
GITHUB_RUN_NUMBER |
The run number of the workflow |
$GITHUB_RUN_NUMBER |
GITHUB_JOB |
ID of the current job |
$GITHUB_JOB |
GITHUB_ACTION |
Name of the action currently running |
$GITHUB_ACTION |
GITHUB_ACTIONS |
Always set to true in GitHub Actions |
$GITHUB_ACTIONS |
GITHUB_ACTOR |
The user who triggered the workflow |
$GITHUB_ACTOR |
GITHUB_REPOSITORY |
Repository name (e.g. user/repo ) |
$GITHUB_REPOSITORY |
GITHUB_REPOSITORY_OWNER |
Owner of the repository |
$GITHUB_REPOSITORY_OWNER |
GITHUB_EVENT_NAME |
Event that triggered the workflow (e.g., push , pull_request ) |
$GITHUB_EVENT_NAME |
GITHUB_EVENT_PATH |
Path to the event payload JSON file |
$GITHUB_EVENT_PATH |
GITHUB_SHA |
Commit SHA that triggered the workflow |
$GITHUB_SHA |
GITHUB_REF |
Git ref (branch or tag) |
$GITHUB_REF |
GITHUB_REF_NAME |
Short name of the ref |
$GITHUB_REF_NAME |
GITHUB_REF_TYPE |
Type of the ref (branch or tag ) |
$GITHUB_REF_TYPE |
2. File & Directory Paths
Variable |
Description |
Usage Example |
GITHUB_WORKSPACE |
Directory where the repository is checked out |
$GITHUB_WORKSPACE |
GITHUB_ACTION_PATH |
Directory path where the GitHub Action is located |
$GITHUB_ACTION_PATH |
GITHUB_ENV |
File path for setting environment variables in a step |
echo "FOO=bar" >> $GITHUB_ENV |
GITHUB_PATH |
File path to add values to the PATH variable |
echo "/custom/bin" >> $GITHUB_PATH |
Variable |
Description |
Usage Example |
RUNNER_NAME |
Name of the runner executing the job |
$RUNNER_NAME |
RUNNER_OS |
OS of the runner (e.g., Linux, Windows, macOS) |
$RUNNER_OS |
RUNNER_ARCH |
Architecture of the runner (e.g., X64, ARM) |
$RUNNER_ARCH |
RUNNER_TEMP |
Path to a temp directory |
$RUNNER_TEMP |
RUNNER_TOOL_CACHE |
Tool cache directory for actions/tool caching |
$RUNNER_TOOL_CACHE |
4. GitHub Token & Secrets
Variable |
Description |
Usage Example |
GITHUB_TOKEN |
Auto-generated token for the job for API access |
$GITHUB_TOKEN |
secrets.<SECRET> |
Your custom or org-wide secrets (via GitHub UI) |
${{ secrets.MY_SECRET }} |
5. Built-in Workflow Contexts
Context |
Description |
Example Usage |
github |
Metadata about the repository and event |
${{ github.repository }} |
env |
User-defined environment variables |
${{ env.ENV_VAR_NAME }} |
secrets |
Encrypted secrets |
${{ secrets.MY_SECRET }} |
runner |
Runner metadata |
${{ runner.os }} |
job |
Info about current job (e.g., status) |
${{ job.status }} |
matrix |
Matrix values for the current job |
${{ matrix.node_version }} |
strategy |
Matrix strategy values |
${{ strategy.job-index }} |
steps |
Access previous step outputs |
${{ steps.step_id.outputs.some_output }} |
needs |
Access outputs from dependent jobs |
${{ needs.build.outputs.artifact_url }} |
inputs |
Inputs to reusable workflows or workflow_dispatch |
${{ inputs.username }} |
vars |
Repository/organization-level variables |
${{ vars.SITE_NAME }} |
6. GitHub Actions Triggers
Trigger (on: ) |
Description |
push |
Triggered when a commit is pushed to the repository |
pull_request |
Triggered when a pull request is opened, synchronized, etc. |
workflow_dispatch |
Manual trigger via GitHub UI or API |
repository_dispatch |
Triggered from external systems via API call |
schedule |
Triggers at scheduled times using CRON syntax |
check_run |
Triggered for check runs (create, update, rerequest) |
check_suite |
Triggered for check suites (completed, requested) |
create |
Triggered when a branch or tag is created |
delete |
Triggered when a branch or tag is deleted |
deployment |
Triggered when a deployment is created |
deployment_status |
Triggered when the deployment status changes |
discussion |
Triggered on GitHub Discussions activity (created, edited, etc.) |
discussion_comment |
Triggered when a comment is created or edited in a discussion |
fork |
Triggered when someone forks the repository |
gollum |
Triggered when a wiki page is created or updated |
issue_comment |
Triggered when an issue or pull request comment is created/edited/deleted |
issues |
Triggered on issue activities (open, close, label, etc.) |
label |
Triggered when a label is created, edited, or deleted |
member |
Triggered when a collaborator is added, removed, or changed |
merge_group |
Triggered when a merge group is created (GitHub Merge Queue) |
milestone |
Triggered when a milestone is created, closed, or deleted |
page_build |
Triggered when GitHub Pages is built |
project |
Triggered when a project is created, closed, or reopened |
project_card |
Triggered on changes to project cards |
project_column |
Triggered on changes to project columns |
public |
Triggered when a repository is made public |
pull_request_review |
Triggered when a PR review is submitted |
pull_request_review_comment |
Triggered when a PR review comment is made |
pull_request_target |
Same as pull_request but runs in the context of the base repo |
release |
Triggered on release events (created, published, etc.) |
registry_package |
Triggered when a package is published, updated, or deleted |
status |
Triggered when the status of a commit changes |
watch |
Triggered when someone stars the repository |
workflow_call |
Triggered by another workflow using uses: |
workflow_run |
Triggered when another workflow run finishes |
1
2
3
4
5
6
| on:
push:
branches: [main]
pull_request:
types: [opened, reopened, synchronize]
workflow_dispatch:
|
GH workflow steps
A github workflow is defined by a set of steps. Each step is defined in a job. A job is a set of steps that run on the same runner. The steps in a job run in the order that you define them.
The following is an example of a job that defines two steps.
1
2
3
4
5
6
7
8
9
10
11
12
13
| name: my workflow
on:
push:
branches:
- main
jobs:
my job:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3
- name: run a command
run: echo "hello world"
|
GH workflow conditions
You can define conditions for running a workflow. The conditions are defined in the on section of the workflow. The following is an example of a workflow that runs when a pull request is created.
1
2
3
4
5
6
7
8
9
10
11
12
13
| name: my workflow
on:
pull_request:
branches:
- main
jobs:
my job:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3
- name: run a command
run: echo "hello world"
|
GH workflow outputs
You can define outputs for a workflow. The outputs are defined in the jobs section of the workflow. The following is an example of a workflow that defines an output.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| name: my workflow
on:
pull_request:
branches:
- main
jobs:
my job:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3
- name: run a command
run: echo "hello world"
outputs:
my output:
value: hello world
|
GH workflow secrets
You can define secrets for a workflow. The secrets are defined in the jobs section of the workflow. The following is an example of a workflow that defines a secret.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| name: my workflow
on:
pull_request:
branches:
- main
jobs:
my job:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3
- name: run a command
env:
MY_SECRET: ${{ secrets.MY_SECRET }}
run: echo $MY_SECRET
|
GH workflow events
You can define events for a workflow. The events are defined in the on section of the workflow. The following is an example of a workflow that defines an event.
1
2
3
4
5
6
7
8
9
10
11
| name: my workflow
on:
pull_request:
branches:
- main
push:
branches:
- main
release:
types:
- created
|
GH workflow variables
You can define variables for a workflow. The variables are defined in the jobs section of the workflow. The following is an example of a workflow that defines a variable.
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
| name: workflow-variable-demo
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
env:
GLOBAL_MESSAGE: "Hello from the job level"
BUILD_ENV: "production"
steps:
- name: Show job-level variables
run: |
echo "GLOBAL_MESSAGE = $GLOBAL_MESSAGE"
echo "BUILD_ENV = $BUILD_ENV"
- name: Define step-level variables
env:
STEP_MESSAGE: "Hello from the step level"
run: |
echo "STEP_MESSAGE = $STEP_MESSAGE"
- name: Use vars context (requires pre-defined repo/organization variable)
run: |
echo "Repository Variable = ${{ vars.MY_REPO_VARIABLE }} "
|
GH selfhost runners
1
2
3
4
5
6
7
8
| useradd runner -m -d /home/runner -s /bin/bash
su runner
mkdir actions-runner && cd actions-runner
curl -o actions-runner-linux-x64-2.325.0.tar.gz -L https://github.com/actions/runner/releases/download/v2.325.0/actions-runner-linux-x64-2.325.0.tar.gz
echo "5020da7139d85c776059f351e0de8fdec753affc9c558e892472d43ebeb518f4 actions-runner-linux-x64-2.325.0.tar.gz" | shasum -a 256 -c
tar xzf ./actions-runner-linux-x64-2.325.0.tar.gz
./config.sh --url https://github.com/$GITHUB_USERNAME/$REPO --token ${{ secrets.PERSONAL_ACCESS_TOKEN }}
./run.sh &
|
Create a systemd service unit file
1
2
| chmod +x /home/runner/run.sh
sudo nano /etc/systemd/system/github-runner.service
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| [Unit]
Description=GitHub Self-Hosted Runner
After=network.target
[Service]
Type=simple
User=runner
WorkingDirectory=/home/runner
ExecStart=/home/runner/run.sh
Restart=always
[Install]
WantedBy=multi-user.target
|
1
2
3
| sudo systemctl daemon-reload
sudo systemctl enable github-runner
sudo systemctl start github-runner
|
Use this YAML in your workflow file for each job
runs-on: self-hosted
Examples by Use Case
Lint and Test Node.js App
1
2
3
4
5
6
7
8
9
10
11
12
13
| name: Node Lint & Test
on: push
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm ci
- run: npm run lint
- run: npm test
|
Deploy to GitHub Pages
1
2
3
4
5
6
7
8
9
10
11
12
13
| name: Deploy Pages
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
|
Cache Dependencies
1
2
3
4
5
6
7
| - name: Cache Node Modules
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
|
Python Test Example with Matrix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| name: Python Tests
on: [push]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.8, 3.9, 3.10]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- run: pip install -r requirements.txt
- run: pytest
|
Reusable Workflows
Define a reusable workflow:
1
2
3
4
5
6
7
8
9
10
11
12
| # .github/workflows/deploy.yml
on:
workflow_call:
inputs:
env:
required: true
type: string
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- run: echo "Deploying to ${{ inputs.env }}"
|
Call it from another workflow:
1
2
3
4
5
| jobs:
call-deploy:
uses: ./.github/workflows/deploy.yml
with:
env: production
|
Docker Image Push with Secrets
Handling Secrets
- Go to repo Settings β Secrets β Actions
- Add new secret (e.g., AWS_ACCESS_KEY)
- Use in workflow:
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }}
1
2
3
4
5
6
7
8
9
10
11
12
| jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Login to Docker Hub
run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
- name: Build & Push
run: |
docker build -t myimage:latest .
docker tag myimage:latest myrepo/myimage:latest
docker push myrepo/myimage:latest
|
Matrix Strategy for Multiple Versions
1
2
3
4
5
6
7
8
| strategy:
matrix:
node: [14, 16, 18]
steps:
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
|
Trigger Other Workflows
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| name: Trigger Other Workflow
on:
push:
branches: [main]
jobs:
trigger:
runs-on: ubuntu-latest
steps:
- name: Trigger downstream
uses: benc-uk/workflow-dispatch@v1
with:
workflow: test.yml
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
Useful Resources