Rush StackShopBlogEvents
Skip to main content

Enabling CI builds

When you set up a PR build definition for continuous integration, the automated script can run essentially the same commands that a developer invokes manually. But there are some additional options that you may find useful.

If we were invoking these commands manually, it might look something like this:

# Fetch the main branch
git fetch origin main:refs/remotes/origin/main -a

# (optional) Fail if the developer didn't create a required change log.
# By "fail", we mean that the script will stop because Rush returned
# a nonzero exit code.
rush change -v

# Install NPM packages in the common folder, but don't automatically do "rush link"
rush install --no-link

# Run "rush link" explicitly, so your CI system can measure it as a separate step
rush link

# Do a full "ship" build, showing detailed logs in real time
# (We assume "--ship" was defined in common/config/rush/command-line.json)
rush rebuild --ship --verbose

But there's one hitch -- what if your CI environment doesn't come with Rush preinstalled? You might consider sticking a package.json at the root of your repo, and then invoking npm install to install Rush. Unfortunately this would introduce a phantom node_modules folder, which defeats Rush's protection against phantom dependencies.

install-run-rush.js for bootstrapping Rush

Fortunately there's a more elegant solution for getting Rush installed on a CI machine: All Rush repos come with a script common/scripts/install-run-rush.js that will:

  • find your rush.json file
  • read the rushVersion that's specified there
  • automatically install that version of Rush under the common/temp/install-run folder
  • using the appropriate settings from your repo's .npmrc file
  • ...and then invoke the Rush tool, passing along any command-line parameters that you provided

The installation is cached, so this is not any slower than invoking Rush normally. In fact, for CI systems that preserve files from previous runs, install-run-rush.js is faster than npm install because it can cache different versions of Rush depending on the Git branch being built.

Try executing the script from your shell:

~$ cd my-repo
~/my-repo$ node common/scripts/install-run-rush.js --help
~/my-repo$ node common/scripts/install-run-rush.js install

Below we'll show how to incorporate this into a Travis build definition.

install-run.js for other commands

By the way, Rush provides a second script install-run.js that allows you to use this same technology with arbitrary NPM packages. For example, here's a command that prints a QR code for the Rush web site: :-)

~/my-repo$ node common/scripts/install-run.js qrcode@1.2.2 qrcode https://rushjs.io

Note that the install-run.js command line is a little different: It must include the package name and version (which can be a SemVer range, although it's best to avoid nondeterminism). It also needs a second parameter that specifies the name of the executable binary (even though the binary name is often the same as the package name). In the above example, we're invoking the qrcode binary and its command-line parameter is https://rushjs.io.

Of course, a more straightforward approach would be to specify qrcode as an ordinary dependency of a package.json file somewhere, for example a tools/repo-scripts project. That way it can part of your normal installation, and tracked by your repo's shrinkwrap file. But in some cases that is undesirable, for example scripts that are only used by a lightweight CI job that doesn't require a rush install. or Git hooks that need to work correctly even when the rush install state is broken or outdated.

GitHub Actions example from "rush init"

GitHub Actions is a continuous integration build service that integrates with GitHub and is free for open source projects. The rush init command creates a ci.yml pipeline that's a good starting point if you use this service. Note how it uses install-run-rush.js to invoke the Rush tool:

.github/workflows/ci.yml

name: CI
on:
push:
branches: ['main']
pull_request:
branches: ['main']
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Git config user
uses: snow-actions/git-config-user@v1.0.0
with:
name: # Service Account's Name
email: # Service Account's Email Address
- uses: actions/setup-node@v3
with:
node-version: 16
- name: Verify Change Logs
run: node common/scripts/install-run-rush.js change --verify
- name: Rush Install
run: node common/scripts/install-run-rush.js install
- name: Rush rebuild
run: node common/scripts/install-run-rush.js rebuild --verbose --production

For an example of an equivalent setup using an Azure DevOps build pipeline, take a look at the build.yaml file, in the monorepo where Rush is developed.