Run GitHub Actions locally

by Ginko Balboa

Posted on December 14, 2021



1. General info

Why would you like to run your GitHub Actions locally? This is useful for a couple of reasons:

  • No need to commit and push every time you want to test workflow changes.
  • You can use act to additionally automatize your processes.

This post is heavily based on nektos/act GitHub project, with additional things that I struggled with in order to make it work as it is on GitHub.

2. Linux installation

The act project uses the Docker API to pull and build the necessary images. Also, brew is used as a package manager for Linux, check Brew for Linux. To install Docker on Linux visit this link and for Windows check this link.

Next we will see the installation of the required code on a Linux machine.

2.1. Install docker

  • Remove old versions of Docker (if you don't have Docker, it will do nothing).

    sudo apt-get remove docker docker-engine docker.io containerd runc
    
  • Set up the repository.

    sudo apt-get update
    sudo apt-get install ca-certificates curl gnupg lsb-release
    
  • Add Docker official GPG key

    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
    
  • Use the following command to set up the stable repository. To add the nightly or test repository, add the word nightly or test (or both) after the word stable in the commands below.

    echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    
  • Install Docker engine:

    sudo apt-get update
    sudo apt-get install docker-ce docker-ce-cli containerd.io
    

Try if docker works:

docker run hello-world

If the systems complains about the permissions run the following commands:

sudo groupadd docker
sudo usermod -aG docker ${USER}

Then log out, log in and restart docker:

sudo -i
exit
sudo systemctl restart docker

Try if docker works, if it complains again set mod for the docker daemon:

sudo chmod 666 /var/run/docker.sock

After this the docker run hello-world should run.

2.2. Install brew

Brew can be installed by a single command given in the brew website.

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

After which, don't forget to read the info, the installation asks you to run commands:

echo 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"' >> /home/${USER}/.profile
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
sudo apt-get install build-essential

2.3. Install act using brew

This is basically a single command:

brew install act

3. Using act

You are ready to run act, but before running it you must download the Docker image that can run most of the GitHub Actions. If you try to run act it will offer you one of the default docker images. The default images do not contain all the tools that GitHub Actions offers by default in their runners. Many things can work improperly or not at all while running those image, as it is said in the GitHub nektos/act Readme.

3.1. Pull the docker image

Nektos provides an environment that works just like the corresponding GitHub runner. You can use docker to download the image (size is 18.2GB extracted and 6.34GB for download):

docker pull nektos/act-environments-ubuntu:18.04

After downloading the image you can check it.

docker images --all

Where docker will return something like

REPOSITORY                       TAG       IMAGE ID       CREATED         SIZE
hello-world                      latest    feb5d9fea6a5   2 months ago    13.3kB
nektos/act-environments-ubuntu   18.04     8aaea77c344b   22 months ago   18.2GB

3.2. Configure act

Configuration of images for act are in ~/.actrc. If you pulled the default images this file will look something like bellow. To this file add the line (shown here as the latest line) that adds the pulled image to the configuration.

-P ubuntu-latest=node:12-buster-slim
-P ubuntu-20.04=node:12-buster-slim
-P ubuntu-18.04=node:12-buster-slim
-P ubuntu-18.04-ghact=nektos/act-environments-ubuntu:18.04

3.3. Run act

Now you can run act with full support of GitHub Actions. Workflows in github are defined in the .github/workflows folder in .yml files. The blank.yml you get from GitHub explains the basic commands:

# blank.yml
# This is a basic workflow to help you get started with Actions

name: CI

# Controls when the workflow will run
on:
  # Triggers the workflow on push or pull request events but only for the master branch
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2

      # Runs a single command using the runners shell
      - name: Run a one-line script
        run: echo Hello, world!

      # Runs a set of commands using the runners shell
      - name: Run a multi-line script
        run: |
          echo Add other actions to build,
          echo test, and deploy your project.

      - name: Extract branch name
        shell: bash
        run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
        id: extract_branch
        if: github.ref == 'refs/heads/master' || contains(github.ref, 'refs/heads/release_')

The first thing to do when making a local GitHub actions runner is to define the runs-on parameter which for our docker image is ubuntu-18.04-ghact.

After that you would like to run this yaml file only locally from act. This can be achieved by setting custom on parameter, for example locally. With these basic settings you can make the following folder structure in your git repo, with the file local_actions_demo.yml that runs locally:

my_repo/
├── .git/
└── .github/
    └── workflows/
        ├── local_actions_demo.yml
        └── actions.yml

The content of the local_actions_demo.yml is as following.

# local_actions_demo.yml
name: GitHub Actions Demo
on: locally
jobs:
  Explore-GitHub-Actions:
    runs-on: ubuntu-18.04-ghact
    steps:
      - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
      - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
      - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
      - name: Check out repository code
        uses: actions/checkout@v2
      - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
      - run: echo "🖥️ The workflow is now ready to test your code on the runner."
      - name: List files in the repository
        run: |
          ls ${{ github.workspace }}
      - run: echo "🍏 This job's status is ${{ job.status }}."

In order to run only the local_actions_demo.yml run the following command from the my_repo folder:

act locally

This means that only actions that have the on: locally parameter set will run. Finally, you're good to go and do all the wild experimenting on your local machine without the need to commit/push to GitHub every time.

It is possible to run act with an existing image without the need to have the image set up in the .actrc file. Just add the image line from .actrc to the command line when calling act:

act locally -P ubuntu-18.04-ghact=nektos/act-environments-ubuntu:18.04