Setting Up GitHub Actions Locally and Quickly

In software development, a feedback loop that takes time and effort could be a major bottleneck. Especially if we have to run things on remote servers and figuring out what's going on requires lots of effort, debugging could make frustrations. Today, I'm going to introduce a couple of tools that help to debug GitHub Actions workflows from local machines.

Act

With act command, you can run workflows on your local machine. Once you run act command it reads YAML files under .github/workflows and runs the jobs in Docker containers immediately. We can make sure if there's any major problem in the YAML without making commit and pushing to GitHub. Although act does not provide 100% compatible environment with GitHub Actions, it helps a lot when you start writing workflow settings. For example, it is useful to find any errors and mistakes in the YAML file structure, dependencies between jobs, calling actions, and steps written in shell scripts.

Besides, act could be used as a task runner for your local machine instead of repeating similar task definitions for another tool like make. CJ Avilla and I are trying to use act that way (stripe-samples/sample-ci#6).

You can tell how great act is by reading its README. In this article, I'd like to share things to be careful I encountered.

Checkout and PAT

When defining jobs, usually actions/checkout is necessary to check out source code. Since it requires GitHub personal access token (PAT), you have to pass the token as a secret no matter the repository is private/public. act reads .secrets file by default. The easiest way to pass the secret is to create it like below:

GITHUB_TOKEN=...

Differences and Workarounds

Act's built-in images do not have several packages/commands out of the box. For example, there is no sudo, and no Docker. To make the steps on a job compatible with both GitHub Actions and act, some tricky changes might be needed. Act provides a special environment variable ACT. You can use it to tell whether the running environment is act or not like this:

if [ -n "$ACT" ]; then
  # https://docs.docker.com/engine/install/debian/
  # https://docs.docker.com/compose/install/
  curl -fsSL https://get.docker.com | sh -
  curl -L "https://github.com/docker/compose/releases/download/1.28.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  chmod +x /usr/local/bin/docker-compose
fi

docker-compose build...

Also, there is an alternative runner image that corresponding GitHub runner.

Running with Docker Daemon which Enables User Namespace Remapping

If you running Docker daemon with user namespace options for security reasons, fixing file permissions problem, or other reasons; perhaps act needs additional --userns=host option because of the user namespaces’ limitations. Since act uses Docker with host network mode, the containers cannot be run remapping user namespace. Without disabling remapping, you will stumble upon error messages as follows:

Error: Error response from daemon: cannot share the host's network namespace when user namespaces are enabled

User namespace remapping can be disabled temporarily by passing --userns=host when creating a container. I got this error when I tried to run act on my computer for the first time and sent a patch to support that option.

action-tmate

Although act is useful, sometimes we want to know what's going on in the actual running environment. It's great if there's a way to connect to the environment with ssh like Circle CI or Travis CI. action-tmate is an action for this purpose.

Tmate allows you to share terminal sessions. mxschmitt/action-tmate provides a way to debug jobs via SSH using Tmate. All you have to do is call this action around the step you need to investigate and you will be able to connect to the environment with ssh.

- name: Setup tmate session
  uses: mxschmitt/action-tmate@v3
  if: ${{ always() }}

if: ${{ always() }} will be necessary if some of the steps before the action-tmate step are failing. Without it, the following steps of the failing step won't run. Also, you will have to pass sudo: false option if the environment does not have sudo. See the README.md for more details.

About the Combination with Act

action-tmate does not work in act out of the box. As mentioned, the built-in images of act are not 100% compatible with the one that GitHub Actions provides. However, probably Tmate is not necessary when you run jobs locally with act in the first place. You can just insert sleep and start a shell in the container like docker exec CONTAINER_ID /bin/bash.

Gentaro "hibariya" Terada

Otaka-no-mori, Chiba, Japan
Email me

Loves Ruby, Internet, and Programming.