Following my previous article about GitHub Actions, here is a new one that will explain how to locally test your Actions. Unlike the good old Jenkins on which you can copy/paste your pipeline code in a test job and run it (that’s dirty but it works), GitHub Actions requires to always commit and push your changes and wait for the runner to take it. When you’re like me and using a die and retry development process, it’s a waste of time.

daffy dressed as robin hood crashing in loop on every trees

Yep, that’s my way to do things, I’m more practice than theory - Daffy Duck ยฉ Warner Bros

To answer this problem, I’ve found and tested act, a community tool that allow to run locally a GitHub Actions workflow. Act is based on Docker API, and require it, and uses Ubuntu images installed as GitHub do it for its own runners (environments variables and filesystem are the same). However, it’s a limited tool as it can’t run a Windows or macOS-based runner and some Actions may not work as the default images does not contains all the tools GitHub Actions offers. However, you can still use alternative runners images.

The test material

For this article, I’ve made a quick and dirty test repository that contains an empty Hugo website that will be built and published on GitHub Pages by an Actions workflow.

The workflow is available in the .github/workflows/build_and_publish_site.yml file and is very simple : checkout the repository, use a community Hugo setup action, build the site, and use a community GitHub Page publish Action.

BTW, I’ve was surprised to see there is no official GitHub Actions for a built-in service like Pages…

## this workflow build and publish the Hugo website

name: 'Build and Publish hugo website'

on:
  push:
    branches:
      - master
  workflow_dispatch:

jobs:
  hugo:
    runs-on: ubuntu-latest
    steps:
      - name: 'Checkout code'
        uses: actions/checkout@v3
        with:
          submodules: true
          fetch-depth: 0

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v2
        with:
          hugo-version: '0.97.0'

      - name: Build
        run: hugo

      - name: Deploy
        uses: peaceiris/actions-gh-pages@v3
        if: ${{ github.ref == 'refs/heads/master' }}
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./public

While testing it, this sample workflow became an ideal example for act usage because I’ve had a failure and tried two options. So let’s test it locally and see if it’s working in my container.

Installation with Podman

To install act on Linux, I’ve simply downloaded the latest Linux tgz release and unpacked it in my /usr/local/bin folder.

However, as a Fedora user, I don’t have Docker installed but Podman. Act is clear : Podman is not officially supported, but you can still use it thanks to a few tricks. I’ll let you read the debates in the linked issue, that’s not the purpose of this article and I’ll go straight to the point : I’ve made the following alias in my profile.

alias act='systemctl enable --now --user podman.socket && export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock && act --bind --container-daemon-socket $XDG_RUNTIME_DIR/podman/podman.sock'

And voilร .

Running a Workflow

Reload your environment and go to a repository clone where you have a workflow (in my case, this article example workflow) and try it like this :

act -W .github/workflows/build_and_publish_site.yml
? 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

You’ll notice a question about the image size. I’ve used the medium one.

You’ll also notice the runner is setup in debug mode by default, very helpful. And after a test run, I see I have the same issue as in the official runner (that’s normal, it’s hugo failing, not a GitHub tool).

[Build and Publish hugo website/hugo]   ๐Ÿณ  docker exec cmd=[bash --noprofile --norc -e -o pipefail /var/run/act/workflow/2] user= workdir=
| Start building sites โ€ฆ 
| hugo v0.97.0-c07f3626e7c8160943591f4d209977efa02c3dca linux/amd64 BuildDate=2022-04-14T08:45:07Z VendorInfo=gohugoio
Error: Error building site: TOCSS: failed to transform "ananke/css/main.css" (text/css). Check your Hugo installation; you need the extended version to build SCSS/SASS.: this feature is not available in your current Hugo version, see https://goo.gl/YMrWcn for more information
| Total in 495 ms
[Build and Publish hugo website/hugo]   โŒ  Failure - Build
[Build and Publish hugo website/hugo] exit with `FAILURE`: 255
Error: Job 'hugo' failed

I think that’s just because at a time I’ve added the --minify option and now it’s failing because the Hugo installation is not the extended one and the Ananke theme looks like to require it in some cases. Let’s try to modify the workflow locally by adding the extended: true setting the the Hugo setup action.

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v2
        with:
          hugo-version: '0.97.0'
          extended: true

Let’s fire it again !

act -W .github/workflows/build_and_publish_site.yml
[Build and Publish hugo website/hugo]   ๐Ÿณ  docker exec cmd=[bash --noprofile --norc -e -o pipefail /var/run/act/workflow/2] user= workdir=
| Start building sites โ€ฆ 
| hugo v0.97.0-c07f3626e7c8160943591f4d209977efa02c3dca+extended linux/amd64 BuildDate=2022-04-14T08:45:07Z VendorInfo=gohugoio

|                    | EN  
| -------------------+-----
|   Pages            |  7  
|   Paginator pages  |  0  
|   Non-page files   |  0  
|   Static files     |  2  
|   Processed images |  0  
|   Aliases          |  0  
|   Sitemaps         |  1  
|   Cleaned          |  0  
| 
| Total in 65 ms
[Build and Publish hugo website/hugo]   โœ…  Success - Build

Perfect ! But โ€ฆ

[Build and Publish hugo website/hugo]   ๐Ÿณ  docker exec cmd=[node /var/run/act/actions/peaceiris-actions-gh-pages@v3/lib/index.js] user= workdir=
| [INFO] Usage https://github.com/peaceiris/actions-gh-pages#readme
[Build and Publish hugo website/hugo]   โ“  ::group::Dump inputs
(...)
[Build and Publish hugo website/hugo]   โ“  ::endgroup::
[Build and Publish hugo website/hugo]   โ—  ::error::Action failed with "Cannot read properties of undefined (reading 'fork')"
[Build and Publish hugo website/hugo]   โŒ  Failure - Deploy

I think that’s because the workflow is supposed to use the secrets.GITHUB_TOKEN secret value. If your not familiar with GitHub Actions, the GITHUB_TOKEN is a token generated during runtime used for read and write on the repository with the required grants. As act is a local process, no token was generated, so maybe it’s an authentication issue ?

Using secrets

To try answer this issue, you’ll need to use a Personal Access Token from your account and give it to act. You’ll need at least the repo scope (well, I suppose, the GitHub token scopes are sometimes very cryptic, sometimes too large or too small, if you ask me…).

Now, call back the command and add this option :

act -W .github/workflows/build_and_publish_site.yml -s GITHUB_TOKEN

You’ll be prompted with the expected value. It is possible to give it directly inline like -s GITHUB_TOKEN=mytoken but it’s strongly not recommended as the token may be written in your history. You can also use a file that contain the secrets in the format KEY=VALUE and provide it like this : --secret-file my-secret-file.txt.

However, after adding the token, it looks like the issue is not an authentication problem. But the previous issue is locally fixed, so now we can try in the actual Actions runner and see how is it going.

I’ve committed the fixed workflow and pushed it on GitHub, the workflow is triggered by the Push action on the master branch. And it’s a success !

a success workflow

Neat !

Let’s check the test site.

test site

Neat ! (bis)

So I think the problem I’ve encountered locally is more a compatibility issue than a workflow design. BTW, about the GITHUB_TOKEN, there was still an error because the Action explains to use the personal_token variable instead of github_token when using one. However, it didn’t work, so it seems to be another issue.

Conclusion

act is a nice tool that permit to test and learn GitHub Actions without throwing hundreds of commits in your history (of course, a squash commits merge strategy fix this problem) and without waiting for the workflow to start. It has its limitations, so in case of doubts, try the live version.