CI

Self-hosted runners

Run Actions jobs on machines you manage: Linux, macOS or Windows computers, build servers, or hardware-in-the-loop rigs with boards attached. A self-hosted runner is GitHub's official runner, actions/runner, unmodified: you download it from GitHub, configure it against GitCafe instead of github.com, and run it. GitCafe presents itself to the runner as a GitHub Enterprise Server.

A runner belongs to an organization (personal accounts too) and serves the repositories its runner group allows, or it belongs to one repository. Organization owners and admins manage organization runners; repository admins manage a repository's runners.

Add a runner

  1. Open your organization's Settings → Runners and choose New runner (or, for a runner that serves one repository, the repository's Settings → CI and Add runner).
  2. In the dialog, choose the machine's operating system and architecture.
  3. Choose Create registration token and run the commands shown on the machine, as the user the runner should run as.

On Linux or macOS the commands are:

sh
1mkdir actions-runner && cd actions-runner
2curl -o actions-runner-linux-x64-2.338.0.tar.gz -L https://github.com/actions/runner/releases/download/v2.338.0/actions-runner-linux-x64-2.338.0.tar.gz
3tar xzf ./actions-runner-linux-x64-2.338.0.tar.gz
4./config.sh --url https://git.cafe/acme --token GCR...
5./run.sh

macOS packages are named actions-runner-osx-<arch>-<version>.tar.gz. On Windows, in PowerShell, download actions-runner-win-x64-2.338.0.zip, extract it and run ./config.cmd and ./run.cmd with the same arguments.

--url is your organization's address on GitCafe, such as https://git.cafe/acme, or a repository's, such as https://git.cafe/acme/firmware, for a runner that serves only that repository. config.sh asks for the runner's name, group, labels and work folder; press Enter to accept the defaults.

From the CLI:

sh
1cafe runner token create --org acme --name rig-1 # prints the config.sh command
2cafe runner token create --repo acme/firmware # a repository runner

A registration token starts with GCR and works for one hour; it can register any number of runners until then. It is shown once. Scripts that create tokens with GitHub's REST API ("create a registration token for an organization" or "for a repository") can do the same against GitCafe: use https://git.cafe/api/v3 as the API URL and a GitCafe API token of an organization or repository admin.

The runner needs HTTPS access to your GitCafe server and, for the actions your workflows use, to api.github.com and codeload.github.com. It keeps the release you installed: GitCafe doesn't update runners.

Labels

Each runner has these labels, which it reports itself:

  • self-hosted;
  • its operating system: Linux, macOS or Windows;
  • its architecture: X64 or ARM64;
  • any labels you add with --labels when you configure it, or at the config.sh prompt, such as --labels gpu,cuda-12.

A job runs on a runner that has every label in its runs-on; letter case doesn't matter. To change a runner's labels, configure it again with ./config.sh --url … --token … --replace and the new --labels.

Settings → Runners lists each runner with its status (Idle, Busy running a job, or Offline when it hasn't polled GitCafe for two minutes), its labels (the ones it added itself, then yours), group, architecture, version and when it was last seen.

Runner groups

Groups decide which repositories may use an organization's runners. Every organization has a Default group that all its repositories may use; new runners join it unless you choose another group with --runnergroup NAME (or at the prompt).

In Settings → Runners → Runner groups, choose New group to create one for all repositories or only selected ones, and a group's edit (pencil) button to rename it or change its repositories. You can delete a group that has no runners; Default can be neither renamed nor deleted.

sh
1cafe runner groups create --org acme --name "HIL rigs" --repos firmware,drivers
2cafe runner groups update "HIL rigs" --org acme --visibility all
3cafe runner groups list --org acme
4cafe runner groups delete "HIL rigs" --org acme --yes

To move a runner to another group, configure it again with --replace and --runnergroup. A repository's Settings → CI lists the groups and runners it can use.

Hardware-in-the-loop rigs

Give each rig labels that say what is attached to it, and target them in runs-on:

sh
1./config.sh --url https://git.cafe/acme --token GCR... --name rig-stm32 --labels hil,stm32 --runnergroup "HIL rigs"
yaml
1jobs:
2 flash-and-test:
3 runs-on: [self-hosted, hil, stm32]
4 concurrency: hil-stm32
5 steps:
6 - uses: actions/checkout@v4
7 - run: ./flash.sh && ./hil-test.sh

A runner takes one job at a time. Use a concurrency group per rig when several workflows target it, so a queued run waits instead of interleaving with another, and a runner group to keep the rig to the repositories that should use it.

Run the runner as a service

./run.sh runs in the foreground until you stop it. To start the runner at boot, install it as a service after configuring it:

  • Linux (systemd): sudo ./svc.sh install, then sudo ./svc.sh start. sudo ./svc.sh status and sudo ./svc.sh stop show and stop it.
  • macOS (launchd): ./svc.sh install, then ./svc.sh start, as the user the runner runs as; the service starts when that user logs in.
  • Windows: answer Y when config.cmd asks whether to run the runner as a service, or pass --runasservice.

Ephemeral and just-in-time runners

./config.sh … --ephemeral registers a runner that takes one job and then unregisters itself, for machines you reset between jobs.

A just-in-time (JIT) runner is created by an API call instead of config.sh, for scripts that start a fresh machine per job:

sh
1curl -X POST https://git.cafe/api/v3/orgs/acme/actions/runners/generate-jitconfig \
2 -H "Authorization: Bearer $GITCAFE_TOKEN" -H "Content-Type: application/json" \
3 -d '{"name": "vm-42", "runner_group_id": 1, "labels": ["hil"]}'

The answer's encoded_jit_config starts the runner without configuring it: ./run.sh --jitconfig <encoded_jit_config>. It is a credential: pass it to the machine privately. The runner is ephemeral. runner_group_id is the group's number, which cafe runner groups list shows. For a repository runner, use the repository's generate-jitconfig endpoint, as on GitHub. The API token must belong to an admin of the organization or repository.

Remove a runner

Choose the remove (trash) button next to the runner in Settings → Runners (or the repository's Settings → CI), or:

sh
1cafe runner list --org acme
2cafe runner remove <runner-id> --org acme --yes

Its credential stops working at once and a job it is running fails. Then delete the runner folder on the machine, after sudo ./svc.sh uninstall (or ./svc.sh uninstall on macOS) if it runs as a service.

You can also remove a runner from the machine itself: ./config.sh remove --token <token> removes it from GitCafe and deletes its configuration. Get the remove token from GitHub's REST API ("create a remove token for an organization" or "for a repository") at https://git.cafe/api/v3, with a GitCafe API token of an admin.

Move a runner from GitHub

One runner installation is registered with one server: it can't serve GitHub and GitCafe at the same time. To move a machine:

  1. On the machine, stop the runner (sudo ./svc.sh stop and sudo ./svc.sh uninstall if it runs as a service).
  2. Remove it from GitHub: ./config.sh remove --token <remove token>, with a remove token from the runner's settings page on GitHub.
  3. Configure the same installation against GitCafe with a GitCafe registration token, keeping its name and labels: ./config.sh --url https://git.cafe/acme --token GCR... --labels <same labels>.
  4. Start it again, or install the service again.

Your workflows' runs-on keeps working when the runner keeps its labels. To try GitCafe without touching a GitHub runner, install a second copy of the runner in another folder.

Troubleshooting

  • The job waits for a runner. Check the runner is Idle and has every label in the job's runs-on, and that its group lets the repository use it (the repository's Settings → CI lists what it can use).
  • config.sh fails with "Http response code: NotFound". The token has expired, or --url names another organization or repository than the token: create a new token from the same page.
  • The runner shows Offline. It hasn't polled GitCafe for two minutes: check it's running and can reach your GitCafe server.
  • Logs. The runner writes its own logs to the _diag folder in its installation directory: Runner_*.log for registration and polling, Worker_*.log for each job.
Read as MarkdownGitCafe documentation
Documentation