Developing Github Actions Locally using act
I have been working in a professional devops/automation role for about 2 years now, the CICD work I've done was mainly with Jenkins. Recently I was asked to automate the deployments for a static site using github actions. I've never worked with github actions before but I wasn't afraid of the challenge.
As I began work on the pipeline i stumbled upon a tool that allows you to run your github actions on your local machine, today I'm sharing that tool with you.
The problem with pipeline-as-code CICD
Coming from a Jenkins background, the ability to run a pipeline locally was amazing. For those that don't know, in order to test out any change in a Jenkins pipeline you must commit and push to a remote repository. Only then can you run a new build to test your Jenkinsfile.
This of course is completely backwards from the norm of...
[Change] -> [Test] > [Commit & Push]
Instead you are following...
[Change] -> [Commit & Push] -> [Test]
When you have to follow this flow, your repository starts to get bloated with endless commits that have minute changes like so:
Workarounds for this include:
- Reseting your previous commit, making a new change, and force pushing..
- Continuing with multiple commits, squashing them all when you're done with your changes, and then force pushing...
For some fairness, Jenkins does include a "Replay" feature where one can rerun a build with a change in the Jenkinsfile without having to commit to your repository, but it subjects you to using what is essentially a plain-text editor with basic syntax-highlighting
No vs code dark theme, no extensions, no shortcuts, no autocompletion, and no auto formatting. In 2024 thats just unnacceptable.
What is act
& how it solves this problem for github actions
act
is a cli tool used locally test your github actions. This solves this huge issue of having to commit and push to test. Now you are free to run as many iterations of your actions locally.
This enables you to rapidly iterate over your action and quickly find what is and is not working.
From act
's repository:
It uses the Docker API to either pull or build the necessary images, as defined in your workflow files and finally determines the execution path based on the dependencies that were defined. Once it has the execution path, it then uses the Docker API to run containers for each action based on the images prepared earlier.
Installation & Setup
act
has several installation methods listed on their website, the simplest of which to follow for me was installing the tool as an extension to the Github CLI
- Follow this documentation to install the github cli for your linux-based system
- Proceed with installing the extension with the command below
gh extension install https://github.com/nektos/gh-act
Once installed you should be able to run gh act
act
will prompt you to select the default docker image size to use for actions, giving you three options
- Micro <200MB
- Medium ~500MB
- Large ~ 17GB
For my use case I selected micro images since the project this was for was small in size. Feel free to increase this if you project has the need for it.
Basic Usage
To test your actions locally, you can use act to simulate a trigger event such as push, release, fork, etc. See full list here
gh act push # Run all workflows with push event
gh act release # Run all workflows with release event**
gh act issue # Run all workflows with issue event**
** For trigger events that also rely on an event payload such as github issues, or releases, you can simulate the payload by passing the flag --eventpath /path/to/event.json
. This file would include the payload for the trigger event you are simulating.
I mainly used the push event, which is the default when running gh act
by itself
Handling Secrets
A crucial part of CICD is credential management & access. Even though we have deployment credentials added onto the Github repository, act
is running locally, so when you reference secrets within your actions file, you must provide act
with the variables to use since it can't reach out to fetch secrets from github.
You can pass these variables to act
by passing them directly to the command like so:
gh act -s MY_SECRET=somevalue
The documentation warns against this, since it might save your secrets as plain text to a history file. To stay on the safe side, a better way to pass variables would be reference a secrets file via the flag:
gh act --secret-file example.env
By passing this flag you'll be able to populate environment variables your deployment depends on. The below is a full example of act
in action :)
Basic Example
name: Deploy to Cloudflare Pages
on:
push:
tags:
- 'release/*'
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Packages
run: 'npx pnpm install'
- name: Build Static Site
run: 'npm run build'
- name: Publish to Cloudflare Pages
uses: cloudflare/pages-action@v1
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
projectName: test-site
directory: build
wranglerVersion: '3'
Quick breakdown of steps
- Checkout Repo that action is running from, uses a predefined step from github
- Install packages with
npx pnpm install
- Run build with
npm run build
, storing the build in a new directory namedbuild
- Using Cloudflare provided step to deploy to cloudflare pages, importantly providing credentials and build directory,
Running Locally
With this I can see that the build is deploying and I can trust that my commit won't be in vain!