1. Overview

In this tutorial, we’ll learn about the act command that can run GitHub Actions Workflow locally.

2. GitHub Actions Workflow

GitHub Actions is a continuous integration and continuous delivery (CI/CD) platform for automating our build and deployment pipeline. We can declaratively define our build and deployment pipeline in a workflow YAML file. The workflow file contains a series of steps the platform will execute to build and deliver our software.

One of the challenges with developing and prototyping with GitHub Actions is the long feedback cycle due to the lack of local execution. Specifically, testing the workflow file involves pushing the changes to github.com. Then, we must trigger the workflow using whatever triggers we’ve specified for our workflow. Triggers that are not trivial, such as merging to a protected main, can cause a longer feedback loop when developing the workflow file. This greatly harms the developer’s productivity as testing the correctness of code involves an arduous process.

Ideally, we would test the workflow file locally similar to a normal software development process. This allows us to quickly experiment and test out the changes before pushing a potential half-bake workflow file to the remote. Furthermore, it reduces the risk of breaking an existing working workflow file.

3. act

The act command is an open-source command-line tool that can run GitHub Actions locally. This allows us to develop and get quick feedback about our workflow file without pushing half-baked code to remote for testing purposes.

3.1. Installation

We can obtain the act binary through the release page of the nektos/act GitHub repository. Then, we choose the latest version and copy the link to the package that matches our system’s architecture. For x86_64 system, we can download the act_Linux_x86_64.tar.gz and untar the package using a one-liner:

$ wget -qO- https://github.com/nektos/act/releases/download/v0.2.64/act_Linux_x86_64.tar.gz | tar xvz

The command above uses the wget command to download the package. Then, we stream the downloaded bytes to the tar command, which unpacks the archives. After we run the command, we’ll get the act binary in our working directory.

We can test out the act program using the –version:

$ ./act --version
act version 0.2.64

If the command executes successfully without any error, we’re ready to go.

3.2. Setting Up a Testing Repository

For demonstration purposes, we’ll use the github-actions-demo repository. We can clone the repository to our local directory using the git clone command:

$ git clone [email protected]:cplee/github-actions-demo.git
Cloning into 'github-actions-demo'...
remote: Enumerating objects: 110, done.
...
Resolving deltas: 100% (39/39), done.

Within the directory, we can find the workflow definition file, main.yml under the .github/workflows directory. Inspecting the file, we can see that it defines a simple workflow that involves a four-step job that builds a NodeJS project:

$ cat .github/workflows/main.yml
name: CI
on: push

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - uses: actions/setup-node@v1
    - run: npm install
    - run: npm test

3.3. Basic Usage

To trigger the workflow of a repository, we must be in the same directory as the .github folder. Let’s change our working directory to the demo repository we’ve cloned and run the act command:

$ cd github-actions-demo && ../act
[CI/test] 🚀  Start image=catthehacker/ubuntu:act-latest
...
[CI/test] ⭐ Run Main actions/checkout@v2
...
[CI/test]   ✅  Success - Main actions/checkout@v2
[CI/test] ⭐ Run Main actions/setup-node@v1
...
[CI/test]   ✅  Success - Main actions/setup-node@v1
[CI/test] ⭐ Run Main npm install
...
[CI/test]   ✅  Success - Main npm install
[CI/test] ⭐ Run Main npm test
...
[CI/test]   ✅  Success - Main npm test
[CI/test] Cleaning up container for job test
[CI/test] 🏁  Job succeeded

The command executes the steps we’ve defined in the workflow file and reports that the job succeeded at the end.

Additionally, the act command takes as a positional argument the event name to simulate a GitHub Actions event. This is especially useful for testing workflow that reacts differently depending on triggering events. For example, we can simulate a release event using the act command:

$ ../act release
Error: Could not find any stages to run. View the valid jobs with `act --list`. Use `act --help` to find how to filter by Job ID/Workflow/Event Name

When we specify the release event to trigger our workflow, the command fails with an error. This is because no workflow is triggered by the release event.

Let’s make a simple workflow file, release.yml to test out the event name argument:

$ cat > .github/workflows/release.yml <EOF
name: CI
on: release

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - run: echo 'on release'
EOF

Then, we can invoke the act command again with the release event name:

$ ../act release
...
[CI/release] ⭐ Run Main echo 'on release'
...
[CI/release]   ✅  Success - Main echo 'on release'
[CI/release] 🏁  Job succeeded

This time, the act command executes the release.yml file due to the event name matching the trigger condition of the workflow.

3.4. Useful Options

The act command supports various useful options in the act command to modify the context of the workflow execution.

For example, we can inject the actor name that triggers the workflow using the –actor option. This would replace the github.actor variable in the workflow execution environment with the actor value we passed:

$ cat .github/workflows/main.yml
name: CI
on: push

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - run: echo "I am ${{ github.actor }}"
$ ../act --actor Baeldung
...
[CI/test] ⭐ Run Main echo "I am Baeldung"
[CI/test]   🐳  docker exec cmd=[bash --noprofile --norc -e -o pipefail /var/run/act/workflow/0] user= workdir=
| I am Baeldung
[CI/test]   ✅  Success - Main echo "I am Baeldung"
...

When GitHub triggers a workflow due to an event, there’s an associated event payload injected into the environment. This allows the workflow file to reference those values in the code. With the act command, we can inject the event payload using the –eventpath option:

$ ../act --eventpath release-event-payload.json

Furthermore, the –secret option allows us to inject secret values into the workflow environment:

$ ../act --secret DOCKER_PASSWORD=password

4. Conclusion

In this tutorial, we’ve briefly learned about the GitHub Actions platform and the Workflow concept in the platform. Then, we’ve explored the act command for running the GitHub Actions Workflow locally. Finally, we’ve demonstrated the act command using the github-actions-demo repository.