Run GitHub Actions in Your Local System
Running GitHub Actions is an essential part of software development and continuous integration/continuous deployment (CI/CD) pipelines. However testing these workflows requires pushing code to a remote repository and waiting for the machine to execute the specified workflows. Constantly pushing commits, waiting for the Actions to run, and reviewing the results can be time-consuming and inefficient.
If we can run GitHub actions on the local system it can speed up development, reduce errors, and improve collaboration among team members. Running actions locally allows developers to test and debug their workflows locally before pushing to GitHub.
In this blog post I will show you way to run GitHub Actions locally with library called act.
How act Works
When you run act CLI, it reads your GitHub Actions from .github/workflows/ directory and chooses which actions to execute. It uses the Docker API to either pull or build the images specified in your workflow files, and then determines the execution path based on the dependencies. Once the execution path is determined, it uses the Docker API to launch containers for each action based on the images created earlier. The environment variables and filesystem are all set up to work with what GitHub offers.
Prerequisites
- Docker
Installation
You can install act both manually and using package manager
Manual Installation
Download the latest binary release corresponding to your OS and add the binary into your PATH.
Installation through package managers
With Chocolatey
choco install act-cli
Code language: Java (java)
With Scoop
scoop install act
Code language: Java (java)
With WinGet
winget install nektos.act
Code language: Java (java)
With Homebrew
brew install act
Code language: Java (java)
With AUR
yay -Syu act
Code language: Java (java)
With Bash Script
curl -s https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash
Code language: Java (java)
With Homebrew
brew install act
With MacPorts
sudo port install act
Code language: Java (java)
Usage
When we run act command first time, it will ask us to download image.
Select the medium image. You could also select Large image if you have enough space, which contains all the tools used GitHub Actions.
$ act
? Please choose the default image you want to use with act:
- Large size image: +20GB Docker image, includes almost all tools used on GitHub Actions (IMPORTANT: currently only ubuntu-18.04 platform is available)
- Medium size image: ~500MB, includes only necessary tools to bootstrap actions and aims to be compatible with all actions
- Micro size image: <200MB, contains only NodeJS required to bootstrap actions, doesn't work with all actions
Default image and other options can be changed manually in ~/.actrc (please refer to https://github.com/nektos/act#configuration for additional information about file structure) [Use arrows to move, type to filter, ? for more help]
Large
> Medium
Micro
Code language: Java (java)
Let’s use the act to run the GitHub Actions in local system using the workflow from the https://github.com/sureshgadupu/sb-ghaction-docker repo.
Command Structure
act cli supports following style command.
$ act [<event>] [options]
If no event name passed, will default to "on: push"
If actions handles only one event it will be used as default instead of "on: push"
Code language: Java (java)
You can run following commands from the root of the project
Listing all the actions
You can list all the actions associated with different events.
$ act -l
Stage Job ID Job name Workflow name Workflow file Events
0 publish-app publish-app Docker Multi-Arch docker-image.yaml push,pull_request
Code language: Java (java)
List the actions for a specific event:
$ act push -l Stage Job ID Job name Workflow name Workflow file Events 0 publish-app publish-app Docker Multi-Arch docker-image.yaml push,pull_request
List the actions for a specific job:
$ act -j publish-app -l
Stage Job ID Job name Workflow name Workflow file Events
0 publish-app publish-app Docker Multi-Arch docker-image.yaml push,pull_request
Code language: Java (java)
Run a specific event:
$ act pull_request
Code language: Java (java)
$ act push
Code language: Java (java)
Run a specific job:
$ act -j publish-app
Code language: Java (java)
Run Default Job
$ act
Code language: Java (java)
Testing the Workflow in Local System
Let’s look at the workflow file from the our selected repo.
Below GitHub Action workflow does the following .
1.Checkout the code
2. Setup JVM
3.Build the jar with Maven
4.Login into Docker Hub
5.Build multi arch docker image and push it to hub
name: Docker Multi-Arch
env:
IMAGE_NAME: sureshgkhyd/sb-crud-image
DOCKER_REGISTRY: docker.io
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
publish-app:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: |
echo "IMAGE_NAME_WITH_REGISTRY=$DOCKER_REGISTRY/$IMAGE_NAME" >> $GITHUB_ENV
export IMAGE_NAME_WITH_REGISTRY=$DOCKER_REGISTRY/$IMAGE_NAME
echo "FULL_IMAGE_NAME=$IMAGE_NAME_WITH_REGISTRY:latest" >> $GITHUB_ENV
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: maven
- name: Build with Maven
run: mvn --batch-mode --update-snapshots package
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v2
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ env.FULL_IMAGE_NAME }}
${{ env.IMAGE_NAME_WITH_REGISTRY }}:${{ github.sha }}
Code language: Java (java)
Since we have single workflow in our test repo, we can use the simply act command from the root of the project from terminal.
Note
If we run following command from root of the project
$ act
Code language: Java (java)
It ran workflow but failed as it could not setup the Maven in act docker image.
[Docker Multi-Arch/publish-app] ⭐ Run Main Build with Maven
[Docker Multi-Arch/publish-app] 🐳 docker exec cmd=[bash --noprofile --norc -e -o pipefail /var/run/act/workflow/3] user= workdir=
| /var/run/act/workflow/3: line 2: mvn: command not found
[Docker Multi-Arch/publish-app] ❌ Failure - Main Build with Maven
[Docker Multi-Arch/publish-app] exitcode '127': command not found, please refer to https://github.com/nektos/act/issues/107 for more information
Code language: Java (java)
There are 2 options to resolve the problem.
1.Build the custom act docker image with Maven installed.
2.Install the Maven on the act docker image during the workflow.
In this blog post, we will modify the workflow to install the Maven and use it.
Let’s add following workflow step to install the Maven.
- name: Download Maven
run: |
curl -sL https://www-eu.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.zip -o maven.zip
apt-get update
apt-get -y install unzip
unzip -d /usr/share maven.zip
rm maven.zip
ln -s /usr/share/apache-maven-3.6.3/bin/mvn /usr/bin/mvn
echo "M2_HOME=/usr/share/apache-maven-3.6.3" | tee -a /etc/environment
- name: Build with Maven
run: mvn --batch-mode --update-snapshots package
Code language: Java (java)
Note
Now lets run the act command again.
Now jar is built successfully but workflow fails to log into docker as it requires user name and password / token which are secrets.
[Docker Multi-Arch/publish-app] ⭐ Run Main Login to Docker Hub
[Docker Multi-Arch/publish-app] 🐳 docker cp src=C:\Users\deepika\.cache\act/docker-login-action@v2/ dst=/var/run/act/actions/docker-login-action@v2/
[Docker Multi-Arch/publish-app] 🐳 docker exec cmd=[node /var/run/act/actions/docker-login-action@v2/dist/index.js] user= workdir=
[Docker Multi-Arch/publish-app] ❗ ::error::Username and password required
[Docker Multi-Arch/publish-app] ❌ Failure - Main Login to Docker Hub
Code language: Java (java)
We can pass the secrets using CLI params with -s option.
act -s DOCKER_USERNAME=<username> -s DOCKER_TOKEN=<password/token>
Code language: Java (java)
[Docker Multi-Arch/publish-app] ✅ Success - Post Build and push<br>[Docker Multi-Arch/publish-app] ⭐ Run Post Setup Docker buildx<br>[Docker Multi-Arch/publish-app] 🐳 docker exec cmd=[node /var/run/act/actions/docker-setup-buildx-action@v2/dist/index.js] user= workdir=
Code language: Java (java)
If you need to pass the environment variables you can do with –env <key>=<value> option.
Another option to avoid installation of Maven in workflow is to use Multistage docker build file which already uses JDK and Maven Image to compile and build the application jar file.
You can look at the repo https://github.com/sureshgadupu/sb-ghaction-docker2 to view the multi stage docker image and corresponding the GitHub Action workflow.
If your workflow depends on this token, you need to create a personal access token and pass it to act
as a secret:
act -s GITHUB_TOKEN=[personal access token ]
Code language: Java (java)