Running GitHub Actions .NET and Azure workflows locally with Act

Act is a fantastic tool for testing GitHub actions locally instead of pushing that 10th commit in a row called Testing GitHub Actions (again) but configuring it to work correctly can be a balancing act, so here are some tips for getting Act working with your .NET CI/CD flows.

, by Joe Glombek

Basic setup

You'll need:

  • act
  • Docker (to run a Linux build) or run act from a Windows machine (to run a Windows build)
  • GitHub CLI
  • Azure CLI
  • dotnet

Ensure your GitHub and Azure CLIs are logged in, using az login and gh auth login.

TL;DR

This PowerShell command (running on a Windows machine) will run most .NET/Azure builds:

act push -W '.github/workflows/my-workflow.yml' --var-file '.github/workflows/local/vars.env' --secret-file '.github/workflows/local/secrets.env' -s GITHUB_TOKEN="$(gh auth token)" --artifact-server-path 'C:\Windows\Temp\act-artifacts' -P windows-latest=-self-hosted -e '.github/workflows/local/payload.json'

I tend to save this PowerShell script in .github/workflows/local/act.ps1 inside the repo.

You'll also need to create the files mentioned in here.

vars.env and secrets.env are files in the .env format that must contain any variables or secrets your workflows need to run. Be sure to gitignore the secrets file!

The payload.json file should contain:

{
  "head_commit": {
      "message": "Sample commit message"
  }
}

You will also need to disable any steps that use actions/setup-dotnet or azure/login locally. e.g.

  - name: Setup .NET
    # Prevent this step from running if running locally with act
    if: ${{ !env.ACT }}
    uses: actions/setup-dotnet@v4

The rest of this article will break down why this is needed and how else you might need to modify act.

GITHUB_TOKEN

The -s GITHUB_TOKEN="$(gh auth token)" portion of our command is what provides the workflows with GitHub access. You can pass in a GitHub personal access token if you'd rather, or add the access token to your secrets.env file, but this requires less setup as the PowerShell script automatically inserts the token generated by the GitHub CLI.

Artifact Server

Providing the --artifact-server-path enables the act artifact server emulator. It's needed if you use the actions/upload-artifact and actions/download-artifact actions. This path can be viewed to help diagnose problems with artifacts.

Self-hosted Runners

Using the -P windows-latest=-self-hosted flag tells act to use the local machine as the build agent instead of a Docker container. This is not ideal, but saves complication! It's also the reason we can disable the actions/setup-dotnet or azure/login steps as we assume these are configured correctly locally. These actions are more complicated to configure.

The left hand side of the assignment should match the runs-on: declaration on your workflow and, of course, this should match your local machine. You probaly can't run a windows-latest build on a Mac.

Payload

The -e '.github/workflows/local/payload.json' parameter is a JSON file containing additional information to pass the workflow that act doesn't include by default. The azure/webapps-deploy action when using azure/login for authentication requires head_commit.messagefield to be set. Any null-reference errors in Actions (that, when the source code is viewed, use the GitHub context) can usually be fixed by addding values in this file.

Disabling steps

Act allows you to disable build steps using the if: ${{ !env.ACT }} syntax. This is helpful if you're able to use the self-hosted mode to remove configuration steps that are a pain to get working.

I'll keep this article updated as I work out better ways of working with act. Ideally a Docker container would be used for builds, but it does add an additional layer of complexity. This is the workflow I have working currently.