Setting up a CI server

Continuous integration servers are a great way to make sure that all changes to master are tested before deploying. CI servers are also great for automating the deployment part. CI servers used to be a real pain to configure. Cloud-based CI servers have simplified things so that now there's no reason not to set one up for any project that needs public deployment.

This page describes setting up Travis CI for a React app that is stored on Github and hosted on Firebase.

Prerequisite: An app on Github

Identify or create an app that you want Travis to handle. Make a repository for it on Github if one doesn't already exist.

One way to make a personal copy of an existing repository is to clone the existing repo, clear its Git data, and reset the cloned repo's remote URL to a new repo. For example, if I have created an empty Github repo called quick-travis, into which I want to put a copy of my Quick, React code repository, I could do this:

git clone https://github.com/criesbeck/quick-react.git quick-travis
cd quick-travis
rm -rf .git
git init
git remote add origin https://github.com/criesbeck/quick-travis.git
git add .
git commit -m "initial commit"
git push -u origin master

You should now have the code on Github, with a fresh commit history.

Verify that the app successfully builds locally.

npm install
npm test
npm run build

Connect Travis to Github

You have to tell Travis where to find your repository. You have to tell Github to give Travis access to the repository. Fortunately, this takes just a few button clicks.

Go to Travis and click the button that says "Sign in with Github".

What happens next can depend on whether you've done this before. If you are redirected to Github, Github will ask if you want to give Travis access, and then if you want to install Travis on Github. If you are the owner of the repository, you can grant access. If you are not the owner, the owner will be sent an email asking for permission. You can progress after it is granted.

If you have granted Travis access before, then you will stay on the Travis site. Click on your Github icon on the Travis page to see your repositories, and change which ones Travis should watch. By default, Travis will watch any new repositories, but not "legacy" repositories in place before Travis was granted access.

Tell Travis how to build your app

Once you've done the above, Travis will notice when you change the main branch on your repository. But it won't be able to do anything until you create a .travis.yml file in your repository that says how to build your app.

.travis.yml is a YAML file. YAML ("YAML Ain't a Markup Language") is a very simple language for configuration files.
Note that the file name starts with a period. That's important but easy to miss. It also means that the file is not displayed when you do ls in a Linux or Unix system, such as MacOS. You need to do ls -a.

First, you must tell Travis to use Node to build and test your React app. Travis is a general CI server for many languages. It assumes your app uses Ruby unless you say otherwise. If you get errors about "Gem not found", you forgot to tell Travis you have a React app.

With React, it's also important to tell Travis to use a recent version of Node. Travis assumes Node 0.10. If you get a long list of warnings from Travis, you probably forgot to tell it to use a modern Node.

I recommend you first try the following .travis.yml:

language: node_js
node_js:
  - "stable"
cache:
  directories:
  - node_modules
script:
  - npm test
  - npm run build

This tells Travis to use the current version of Node. That's Node 12 at the time this was written. If you get errors doing that, but not when you build and test locally, replace "node" with the version of Node you have, e.g., "10".

Travis will use npm to build and test your app, unless it sees a yarn.lock file. Your build will probably fail if yarn is used, so be sure to delete any yarn.lock files.

The Travis YAML file needs to be in the same directory as your app's package.json -- neither higher nor lower. If you get errors about make test exited with 2, it's often because Travis couldn't find package.json.

If your app code is in a subdirectory, you need to tell Travis to change to that directory:

language: node_js
node_js:
  - "stable"
cache:
  directories:
  - node_modules
script:
  - npm test
  - npm run build
before_install:
  - cd subdirectory
  

Test your Travis configuration

Check your YAML file for syntax issues with the Travis YAML checker. Copy and paste your YAML code there. Be sure there are no syntactic errors.

Be careful to paste YAML as plain text. For example, on a Mac, copying YAML from VS Code into the online checker will use RichText format, causing an irrelevant syntax error. Use "Paste and Match Style" to avoid that.

Commit your .travis.yml file in Git, then push your changes to master. If everything is properly set up, then in a few minutes Travis should

  • notice master has changed
  • see the YAML file
  • spin up a virtual machine
  • build your app from scratch
  • run the tests, if any
  • update the build log

If the owner of the repository is , then the results of the build, and a history of previous builds, can be found at the URL .

All this will take several minutes or more. That's fine. Except when first testing your CI configuration, you do not wait to see if your build and tests succeed on the CI server. Just build and test locally, commit and push, and go on to your next task. Travis will let you and the team know if your changes broke master somehow.

Test for re-builds

Make some simple edit to your app that produces a visible change. Commit, push, and verify that Travis successfully builds and then deploys your app to Firebase.

Test for failure

Now make a breaking change that will cause the build to fail, such as a missing import. Test locally by running

npm run build
npm test

If one or both of those fail, commit the change, and see how Travis responds. The build log should show failure, and you should be sent an email.

A simple bug, like a bad variable value, will cause a run-time error, not a build failure. To catch those, you will need to write more tests.

Tell Travis how to deploy your app

The above is continuous integration. All changes to master are tested to make sure that master is not broken. This is the original motivation for CI servers. But mature software development teams with solid testing practices also do continuous deployment. That means that if your changes pass the tests, they are immediately deployed to a development server, or perhaps even production.

Here, we'll assume you are hosting your app on Firebase. If you are deploying elsewhere, search for "travis ci deploy to" and the name of your deployment environment.

Verify that deployment works locally:

npm run build
firebase deploy

When this command completes, you should be able to see the current version of your app running on Firebase.

To automate deployment, you need to give Travis access to the deployment server, and add the appropriate deployment commands to the YAML file.

In the case of Firebase, you give Travis a token generated by Firebase. In a terminal shell in your app directory, run the command

firebase login:ci

This will send you to Firebase to approve the request and generate a token string.

On the Travis web site, create a FIREBASE_TOKEN environment variable with the token string, as described on this page.

Now add the following commands to the YAML file to install the Firebase CLI on Travis, and build and deploy your app:

language: node_js
node_js:
  - "stable"
cache:
  directories:
  - node_modules
script:
  - npm test
  - npm run builds
after_success:
  - npm install -g firebase-tools
  - firebase deploy --token $FIREBASE_TOKEN --non-interactive

Commit and push the changed YAML file to master.

Debugging Travis issues

Setting up Travis CI is a snap, compared to how complicated setting up a CI server used to be. Still, there are several moving parts that can get jammed up.

The first thing to do when a build fails or nothing seems to update is to study the build logs. Any line that has a twist-down triangle on the left is a summary that can be opened to reveal more detail. If a step failed, the detail will usually say why. Even if the summary appears to have succeeded, but the details may show a problem that was not recognized as a build failure. Besides warnings and error messages, look for commands being executed that seem unrelated to your app.

I spent two hours on a deployment problem. I thought it was due to bad authentication tokens. Opening the relevant part of the build log revealed it was a missing directory issue.

Make sure you're looking at the current build, not one of the old jobs in the build history.

Check your .travis.yml file carefully against the model versions presented above. Specifically, check that you

© 2021 Chris Riesbeck
Template design by Andreas Viklund