See all Resources

Setting up a CLI on GitHub's hosted runners

Problem statement

Many of GitHub’s Technology Partners wish to provide a way for developers to easily access their services via a configured CLI environment on GitHub’s hosted runners, for example, so that it is available in a CI/CD workflow.

The solution should :

  1. Make it simple for developers to precisely describe the version of the CLI to be installed
  2. Support multiple operating systems
  3. Run in an efficient fashion to minimize run-time and associated costs
  4. Work across hosted and self-hosted runners
  5. Leverage community tooling when possible


Technology Partners should solve this by providing an action in a repo they maintain, written in, or compiled / transpiled to JavaScript. The action should be responsible for retrieving a specific version of the CLI, installing it, adding it to the path, and (optionally) caching it. Commonly this variety of action that performs some setup of a tool, is named **setup-$TOOL**. Refer to the examples below to see how this pattern is already in use in multiple ecosystems.

GitHub provides the actions/toolkit set of packages, which makes this process more straightforward across all of GitHub’s hosted runners.

Specifically, the actions/core and actions/tool-cache package expose operations that are commonly required in this scenario, in a cross-platform way.


A simple cross-platform implementation in JavaScript follows, note, the implementation for getDownloadURL is intentionally absent, so that the example remains generic:

const core = require('@actions/core');
const tc = require('@actions/tool-cache');

async function setup() {
  // Get version of tool to be installed
  const version = core.getInput('version');

  // Download the specific version of the tool, e.g. as a tarball
  const pathToTarball = await tc.downloadTool(getDownloadURL());

  // Extract the tarball onto host runner
  const pathToCLI = await tc.extractTar(pathToTarball);

  // Expose the tool by adding it to the PATH

module.exports = setup

Concrete implementation

A concrete implementation of this pattern is available here.


Example where this pattern is employed include:

For more information on creating a JavaScript action, refer to this guide.

See all Resources