Due to the cost of running macOS in particular, you might want to run your GitHub Actions CI on a self-hosted machine locally.

Installing as your logged in user

GitHub does not make it obvious, but running the commands they give you will install the runners as the logged in user! The runners are not containerized. If you also use the machine locally (not just for CI) this is not secure. See “Using self-hosted runners as another user.”

Go to the Settings page of your repository and click New self-hosted runner.

Run the bash commands listed to setup and configure the runner.

GitHub does not make it clear, but runners can only be used for a single repo unless the repo is within a GitHub Organization. This means if you have 2 repos on a personal/pro account, you’ll need to setup 2 entirely separate runners (just put them in different directories.)

Pick a memorable name for your runner like iLoveCheapCI — you’ll need it later.

Running as a service

You’ll probably want to run the self-hosted runner as a service, starting the runner when your mac boots so it’s always available for jobs.

Run the following from your actions-runner directory to set it up on mac and start the service:

./svc.sh install
./svc.sh start

Check out the extensive docs.

Changing your yaml

You’ll need to tell GitHub Actions you want to run on your mac instead.

To do this, edit the matrix section of the config, replacing os: macOS-14 (or whatever you have it set to) with iLoveCheapCI (whatever your machine name is).

The matrix config will forward that iLoveCheapCI value to the job’s runs-on for macOS.

Make sure you have git-lfs installed

This is the git protocol that lets you handle large files efficiently. You’ll need to install it on your local machine.

Via homebrew:

brew install git-lfs

Speed advantages and disadvantages of self-hosted runners

In addition to being able to use more processing power, self-hosted runners also have the advantage of not recreating the entire VM each run. Any dependencies installed via brew, etc, will remain installed.

If you use something like sccache, it also has the advantage of keeping the cache locally, which speeds things up quite a bit.

However, it has the disadvantage of having to reach over the network for all git and CMake dependencies.

Pamplejuce hardcodes the build step to use a max of 4 cores. To use all cores on your machine, remove the --parallel 4 argument in the build step of the yaml.

Using Private Submodules

If you have repositories that are private being used as submodules, you’ll need to pass a Personal Access Token (PAT) to actions/checkout.

      - name: Checkout code
        uses: actions/checkout@v4
        with:
          submodules: true 
          token: ${{ secrets.GH_PAT }}

You get this PAT from your GitHub user settings, under Developer Settings > Personal Access Tokens (classic).

Troubleshooting

You might see this issue when importing the keychain on macOS:

/usr/bin/security create-keychain -p *** signing_temp.keychain
security: SecKeychainCreate signing_temp.keychain: A keychain with the same name already exists.
Error: The process '/usr/bin/security' failed with exit code 48

Please see the open issue. I’m still trying to figure out what the best thing to do here. Since the runner uses your local machine, you can actually just skip the keychain import when self-hosted.

##


Leave a Reply

Your email address will not be published. Required fields are marked *