0

How to run GitHub Actions locally

 4 weeks ago
source link: https://www.mastertheboss.com/ci-cd/how-to-run-github-actions-locally/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

How to run GitHub Actions locally

21 March 2024 by F.Marchioni
AgentGPT Setup (Local) - Agent-GPT ...
AgentGPT Setup (Local) - Agent-GPT | Autonomous AI Agents

GitHub Actions, a powerful tool provided by GitHub, enables developers to automate their workflows directly within their repositories. Whether it’s continuous integration (CI), continuous deployment (CD), or any other custom automation task, GitHub Actions simplifies the process. In this article we will learn how to test your GitHub Actions locally with the act CLI tool.

The challenge of running locally GitHub actions

New to GitHub Actions? check this article: Getting started with GitHub Actions

One challenge developers often face is testing these workflows locally before pushing changes to the remote repository. Historically, this has been cumbersome, requiring developers to push changes to a branch and wait for the GitHub Actions workflow to execute. However, a solution has emerged in the form of “act” – a remarkable CLI tool that allows developers to run GitHub Actions workflows locally.

How does act work?

When you execute act, it scans your GitHub Actions from

.github/workflows/

.github/workflows/ and identifies the set of actions requiring execution. It leverages the Docker API to pull or build the requisite images, as specified in your workflow files, and subsequently establishes the execution flow based on the specified dependencies. Upon determining the execution flow, it utilizes the Docker API to launch containers for each action using the pre-prepared images. The environment variables and filesystem are configured to align with GitHub’s offerings.

Installing Act

Firstly, you need to install the act tool on your machine. There are several options available:

# Linux
curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash
# Window
choco install act-cli
# MacOS
brew install act
# Linux
curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash

# Window
choco install act-cli

# MacOS
brew install act

Then, include the act command line in your system PATH. For example, if you downloaded it from your user’s home directory:

export PATH=$PATH:~./bin
export PATH=$PATH:~./bin

Next, make sure your Docker daemon is up and running:

service docker start
service docker start

Finally, you can run the act tool. The first time you will execute, it will ask you which image you will be using to build your GitHub actions. I have tested the medium size image which should be compatible with most actions:

how to run github actions locally

Your first local GitHub action

Now we are ready to run our first GitHub action locally.

  1. Firstly, clone or download any of your GitHub repository .
  2. Then, add a workflow in the
    .github/workflows
    .github/workflows folder. For example, the
    helloworld.yml
    helloworld.yml:
├── .github
└── workflows
├── helloworld.yml
├── .github
   └── workflows
       ├── helloworld.yml

Here is, for example, the example

helloworld.yml

helloworld.yml file:

name: HelloWorld Action
push:
branches:
- main
jobs:
helloworld-job:
name: HelloWorld Job
runs-on: ubuntu-latest
steps:
- name: Print HelloWorld
run: echo "helloworld"
name: HelloWorld Action
on:
  push:
    branches:
      - main

jobs:
  helloworld-job:
    name: HelloWorld Job
    runs-on: ubuntu-latest
    steps:
      - name: Print HelloWorld
        run: echo "helloworld"

Nothing fancy, this GitHub action merely prints an Hello World Message.

You can test the

act -l

act -l command which shows the list of available jobs in your repository:

act -l
Stage Job ID Job name Workflow name Workflow file Events
0 helloworld-job HelloWorld Job HelloWorld Action helloworld.yml push
act -l
Stage  Job ID          Job name        Workflow name       Workflow file   Events           
0      helloworld-job  HelloWorld Job  HelloWorld Action   helloworld.yml  push   

Then, run your job as follows:

act --job helloworld-job
act --job helloworld-job

The first time you start a job, the act CLI will download the Docker image which you need to run the jobs so it will take a while. At the end of it, you should see the following output:

[HelloWorld Action/HelloWorld Job] 🚀 Start image=catthehacker/ubuntu:act-latest
INFO[0000] Parallel tasks (0) below minimum, setting to 1
[HelloWorld Action/HelloWorld Job] 🐳 docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true
INFO[0001] Parallel tasks (0) below minimum, setting to 1
[HelloWorld Action/HelloWorld Job] 🐳 docker create image=catthehacker/ubuntu:act-latest platform= entrypoint=["tail" "-f" "/dev/null"] cmd=[] network="host"
[HelloWorld Action/HelloWorld Job] 🐳 docker run image=catthehacker/ubuntu:act-latest platform= entrypoint=["tail" "-f" "/dev/null"] cmd=[] network="host"
[HelloWorld Action/HelloWorld Job] ⭐ Run Main Print HelloWorld
[HelloWorld Action/HelloWorld Job] 🐳 docker exec cmd=[bash --noprofile --norc -e -o pipefail /var/run/act/workflow/0] user= workdir=
| helloworld
[HelloWorld Action/HelloWorld Job] ✅ Success - Main Print HelloWorld
[HelloWorld Action/HelloWorld Job] Cleaning up container for job HelloWorld Job
[HelloWorld Action/HelloWorld Job] 🏁 Job succeeded
[HelloWorld Action/HelloWorld Job] 🚀  Start image=catthehacker/ubuntu:act-latest
INFO[0000] Parallel tasks (0) below minimum, setting to 1 
[HelloWorld Action/HelloWorld Job]   🐳  docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true
INFO[0001] Parallel tasks (0) below minimum, setting to 1 
[HelloWorld Action/HelloWorld Job]   🐳  docker create image=catthehacker/ubuntu:act-latest platform= entrypoint=["tail" "-f" "/dev/null"] cmd=[] network="host"
[HelloWorld Action/HelloWorld Job]   🐳  docker run image=catthehacker/ubuntu:act-latest platform= entrypoint=["tail" "-f" "/dev/null"] cmd=[] network="host"
[HelloWorld Action/HelloWorld Job] ⭐ Run Main Print HelloWorld
[HelloWorld Action/HelloWorld Job]   🐳  docker exec cmd=[bash --noprofile --norc -e -o pipefail /var/run/act/workflow/0] user= workdir=
| helloworld
[HelloWorld Action/HelloWorld Job]   ✅  Success - Main Print HelloWorld
[HelloWorld Action/HelloWorld Job] Cleaning up container for job HelloWorld Job
[HelloWorld Action/HelloWorld Job] 🏁  Job succeeded

Coding a Maven GitHub action locally

The next action we will run is a real one as it includes a Maven build of the project and a staging of the output. Create a YAML file with the following content:

name: Java CI with Maven
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: maven
- name: Download Maven
run: |
curl -sL https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.zip -o maven.zip
apt-get update
apt-get -y install unzip
unzip -d /usr/share maven.zip
rm maven.zip
ln -s /usr/share/apache-maven-3.9.6/bin/mvn /usr/bin/mvn
echo "M2_HOME=/usr/share/apache-maven-3.9.6" | tee -a /etc/environment
- name: Build with Maven
run: mvn -B package --file pom.xml
- name: Create staging directory
run: mkdir -p staging
- name: Copy JAR files to staging directory
run: cp target/*.jar staging/
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: java-artifacts
path: staging/*.jar
name: Java CI with Maven

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - name: Set up JDK 17
      uses: actions/setup-java@v3
      with:
        java-version: '17'
        distribution: 'temurin'
        cache: maven
    - name: Download Maven
      run: |
        curl -sL https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.zip -o maven.zip
        apt-get update
        apt-get -y install unzip
        unzip -d /usr/share maven.zip
        rm maven.zip
        ln -s /usr/share/apache-maven-3.9.6/bin/mvn /usr/bin/mvn
        echo "M2_HOME=/usr/share/apache-maven-3.9.6" | tee -a /etc/environment        
    - name: Build with Maven
      run: mvn -B package --file pom.xml
    - name: Create staging directory
      run: mkdir -p staging
    - name: Copy JAR files to staging directory
      run: cp target/*.jar staging/
    - name: Upload artifacts
      uses: actions/upload-artifact@v3
      with:
        name: java-artifacts
        path: staging/*.jar    

If you are using the default GitHub actions template, you will notice there’s a difference as here we are downloading Maven in the “Download Maven” step.

If you don’t include this step, the action will fail as it cannot find the mvn tool:

| /github/workflow/3: line 2: mvn: command not found
[Build, Test, and Upload/Java Application Container] ❌ Failure - Compile and Test Using Maven
| /github/workflow/3: line 2: mvn: command not found
[Build, Test, and Upload/Java Application Container]   ❌  Failure - Compile and Test Using Maven

This is discussed in greater detail in this issue. There are several possible solutions to it. In this case, we are installing the Maven tool before using it:

- name: Download Maven
run: |
curl -sL https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.zip -o maven.zip
apt-get update
apt-get -y install unzip
unzip -d /usr/share maven.zip
rm maven.zip
ln -s /usr/share/apache-maven-3.9.6/bin/mvn /usr/bin/mvn
echo "M2_HOME=/usr/share/apache-maven-3.9.6" | tee -a /etc/environment
    - name: Download Maven
      run: |
        curl -sL https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.zip -o maven.zip
        apt-get update
        apt-get -y install unzip
        unzip -d /usr/share maven.zip
        rm maven.zip
        ln -s /usr/share/apache-maven-3.9.6/bin/mvn /usr/bin/mvn
        echo "M2_HOME=/usr/share/apache-maven-3.9.6" | tee -a /etc/environment 

Let’s list again the available Jobs:

act -l
Stage Job ID Job name Workflow name Workflow file Events
0 helloworld-job HelloWorld Job HelloWorld Action helloworld.yml push
0 build build Java CI with Maven maven.yaml push,pull_request
act  -l
Stage  Job ID          Job name        Workflow name       Workflow file   Events           
0      helloworld-job  HelloWorld Job  HelloWorld Action   helloworld.yml  push             
0      build           build           Java CI with Maven  maven.yaml      push,pull_request

Now you can run the build job, by providing also the path where act will upload your artifacts with

artifact-server-path

artifact-server-path :

act --job build --artifact-server-path /tmp/artifacts
act  --job build --artifact-server-path /tmp/artifacts

Your job should successfully complete:

[Java CI with Maven/build] ✅ Success - Main Upload artifacts
[Java CI with Maven/build] ⭐ Run Post Set up JDK 17
[Java CI with Maven/build] 🐳 docker exec cmd=[node /var/run/act/actions/actions-setup-java@v3/dist/cleanup/index.js] user= workdir=
[Java CI with Maven/build] 💬 ::debug::Checking zstd --version
[Java CI with Maven/build] 💬 ::debug::*** zstd command line interface 64-bits v1.4.8, by Yann Collet ***
[Java CI with Maven/build] 💬 ::debug::implicitDescendants 'false'
[Java CI with Maven/build] 💬 ::debug::followSymbolicLinks 'true'
[Java CI with Maven/build] 💬 ::debug::implicitDescendants 'false'
[Java CI with Maven/build] 💬 ::debug::omitBrokenSymbolicLinks 'true'
[Java CI with Maven/build] 💬 ::debug::Search path '/root/.m2/repository'
[Java CI with Maven/build] 💬 ::debug::Matched: ../../../../root/.m2/repository
[Java CI with Maven/build] 💬 ::debug::Cache Paths:
[Java CI with Maven/build] 💬 ::debug::["../../../../root/.m2/repository"]
[Java CI with Maven/build] 💬 ::debug::Archive Path: /tmp/704e9468-8dc9-4c5d-a505-ddd89817fa63/cache.tzst
| [command]/usr/bin/tar --posix --use-compress-program zstdmt -cf cache.tzst --exclude cache.tzst -P -C /home/francesco/git/githubactiondemo --files-from manifest.txt
[Java CI with Maven/build] 💬 ::debug::File Size: 9914711
[Java CI with Maven/build] 💬 ::debug::Reserving Cache
[Java CI with Maven/build] 💬 ::debug::Resource Url: http://192.168.1.5:43793/_apis/artifactcache/caches
ERRO[0021] POST /_apis/artifactcache/caches: already exist module=artifactcache
| Cache saved with the key: setup-java-Linux-maven-b8e7380cd023cf0af45ace7459a151ef98d9da4061dbcd5fb2d0d8ccc0a2ff1c
[Java CI with Maven/build] ✅ Success - Post Set up JDK 17
[Java CI with Maven/build] Cleaning up container for job build
[Java CI with Maven/build] 🏁 Job succeeded
[Java CI with Maven/build]   ✅  Success - Main Upload artifacts
[Java CI with Maven/build] ⭐ Run Post Set up JDK 17
[Java CI with Maven/build]   🐳  docker exec cmd=[node /var/run/act/actions/actions-setup-java@v3/dist/cleanup/index.js] user= workdir=
[Java CI with Maven/build]   💬  ::debug::Checking zstd --version
[Java CI with Maven/build]   💬  ::debug::*** zstd command line interface 64-bits v1.4.8, by Yann Collet ***
[Java CI with Maven/build]   💬  ::debug::implicitDescendants 'false'
[Java CI with Maven/build]   💬  ::debug::followSymbolicLinks 'true'
[Java CI with Maven/build]   💬  ::debug::implicitDescendants 'false'
[Java CI with Maven/build]   💬  ::debug::omitBrokenSymbolicLinks 'true'
[Java CI with Maven/build]   💬  ::debug::Search path '/root/.m2/repository'
[Java CI with Maven/build]   💬  ::debug::Matched: ../../../../root/.m2/repository
[Java CI with Maven/build]   💬  ::debug::Cache Paths:
[Java CI with Maven/build]   💬  ::debug::["../../../../root/.m2/repository"]
[Java CI with Maven/build]   💬  ::debug::Archive Path: /tmp/704e9468-8dc9-4c5d-a505-ddd89817fa63/cache.tzst
| [command]/usr/bin/tar --posix --use-compress-program zstdmt -cf cache.tzst --exclude cache.tzst -P -C /home/francesco/git/githubactiondemo --files-from manifest.txt
[Java CI with Maven/build]   💬  ::debug::File Size: 9914711
[Java CI with Maven/build]   💬  ::debug::Reserving Cache
[Java CI with Maven/build]   💬  ::debug::Resource Url: http://192.168.1.5:43793/_apis/artifactcache/caches
ERRO[0021] POST /_apis/artifactcache/caches: already exist  module=artifactcache
| Cache saved with the key: setup-java-Linux-maven-b8e7380cd023cf0af45ace7459a151ef98d9da4061dbcd5fb2d0d8ccc0a2ff1c
[Java CI with Maven/build]   ✅  Success - Post Set up JDK 17
[Java CI with Maven/build] Cleaning up container for job build
[Java CI with Maven/build] 🏁  Job succeeded

Conclusion

This article provided a set-by-step guide to get started with the act CLI which allows you to test your GitHub actions locally, Act complements this by enabling developers to test their workflows locally, providing a fast and efficient mechanism for validation and debugging.

Found the article helpful? if so please follow us on Socials


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK