Battleship Travis-CI

The What:

There are a lot of CI/CD systems out there. If you’re in .NET land, Azure DevOps has some pretty excellent tooling out there. Jenkins is another that has some extremely robust capabilities. There are oodles more I’ve never even brushed up against, including rolling your own on a virtual machine somewhere in the cloud (or even on your own machine).

But wait. What the heck is a CI/CD pipeline? Why do you need one? If you’re asking either of those questions, please take a look at this recent post of mine.

The Why:

This post is about Travis-CI, because

  • It’s free (for our use case, anyway)
  • It integrates beautifully with GitHub (which is my repo of choice)
  • It’s platform agnostic (works equally well for a variety of tech stacks)

The How:

Step One is to get yourself a Travis account. This is absurdly, almost suspiciously easy: you sign up with your GitHub account.

This means you may need to allow Travis as an authorized connection or app in your GitHub account, because Travis will be accessing your repo in order to detect changes and to clone the repo so it can build the application.

Screencapture of the Travis-ci.org webpage with sign-up buttons
The “Sign Up” button will give you another button to use your GitHub account

You’ll end up at your dashboard, which eventually will display your most recent build and a quick link to your repositories–for now, you shouldn’t see anything.

Step Two is to link a repository, which means you need to access your profile settings. Click your avatar in the top right of the screen, then the “Settings” link.

Screen cap of the travis-ci.org home page with arrows point to the profile menu and settings link

Step Three is to find and switch on your repository so Travis knows to check it for builds. Your public repos are all listed under the “Repositories” tab, which should be the default view (private repos required a paid subscription with travis-ci.com, currently).

Screen capture of the travis-ci.org settings page for jdmac020 with arrows pointing out the repository tab and list

It can take several minutes for your repositories to show up in Travis the first time. You may have to click the “sync account” button. It also may take refreshing the browser window itself–I once waited almost ten minutes to see a repo list and as soon as I refreshed the browser it all showed up.

Find the one you want to activate, and toggle it on.

Screen capture of jdmac020's repository list with arrows pointing out battleship-tdd and the activated toggle switch

Now Travis is going to be scanning that repo through GitHub APIs and looking for a .travis.yml file to get build instructions. Which means…

Step Four is to create a .travis.yml file in the root of your repository. The dot-travis file is, as you might guess from the dot starting the name, a configuration file used by the Travis-CI build system to know what language you’re using, what build environment to use, what commands to run, and any deployment steps. It’s sort of a big deal, and if there’s no .travis.yml file found in the code pushed to GitHub, Travis simply won’t do anything.

Again, you want to create an empty file in the root of your repository–not necessarily the root of your code base. Find the .git folder, and save your yml file there. I do this step typically in VS Code or Notepad++, depending what OS I’m on.

A save file dialogue showing the root of a git repository

Step Five is to define the build configuration. This will vary significantly depending on which language you’re developing in and what flavor of that tech stack you prefer, and the folks at Travis do a really great job documenting what goes in the .travis file.

Screen capture of travis-ci documentation with an arrow pointing to the list of supported languages

The .travis.yml file I will use for this project including some helpful (to me, anyway) comments about what each line means…

language: csharp
# Mono is used to build .NET on Linux--we don't need it with Core.
mono: none
# Needed to run commands in the Xenial CLI
sudo: required
# The version of Ubuntu to run the Travis virtual machine -- needed for .NET Core
dist: xenial
# Your SDK version, not your run-time version
dotnet: 2.2
script: # These commands are executed in the Travis VM just like you would on your local machine
# Use a "cd" command to move the Travis command line prompt into your solution directory
# - cd /home/travis/build/<yourTravisAccount>/<yourRepoRootDirectory>/.../<yourSolutionDirectory>/
  - cd ./BattleshipTDD/
# Use these to build the project without tests
# - dotnet restore
# - dotnet build
# if your project has tests, you can skip "restore" and "build" and just use "test" command -- "test" will run the other two automatically
  - dotnet test

Step Six is to commit the new file and push it up to your repo, where Travis should catch the change and trigger a build.

A computer terminal screen displaying the commands to add, commit, and push the the .travis.yml file to the repository
You could do this in a GUI if you’d prefer, 100%

Step Seven is to review the build in Travis. Even before I was done prepping the terminal photo above for the post, I got an e-mail from Travis saying my build passed–hooray!

When we look at the dashboard we get some key items right away. The repository name and a build badge are at the top, and then the specific build info–what branch was built, the commit message, commit ID, the build number, how long it ran for are all front and center.

Screen capture of Travis-CI dashboard with a passing build

If we keep scrolling down, you can see the actual build logs, starting with info on the build environment–handy for debugging problems, like when your build is fine locally, but fails when Travis tries it.

For instance, if one tries to run a .NET Core app in the default Travis Linux OS, it won’t work–hence needing to specify Xenial to make sure we were running on Ubuntu. Being able to compare the build environment with the suggestion on a help document was key to figuring this out.

A build log with environment info

Scrolling down further we get to the actual build process. Each command you specify in the .travis.yml is listed out separately–you can see on line 246, even the “cd ./BattleshipTDD/” got it’s own result output (and yes, I have seen this fail, especially on complicated solution structures where I was missing a directory level in the path).

The test output is particularly helpful–my one test passes here, but should it fail it outputs the exception message just like any other test runner, letting you know what failed and why.

At the very bottom, the build status gets reported–if any of the commands exited with anything except a 0 code, the entire build is marked as a failure.

A build log showing the results of build tasks

Some examples of unhappy build logs…

Build log displaying a bad change directory command
You get the results of a bad command, guiding you toward a fix
Build log with failing test info
Failing tests give you the output of your testing framework–no guessing what happened

Wrapping It All Up:

What we’ve done here is linked your GitHub to Travis-CI, which will build the project and run tests against it whenever changes are pushed to master. This by itself may not provide a lot of value (I mean, if you’re not running your tests before pushing code, we need to talk) but it does lay an important foundation.

From here, we’re able to automate deployment, headless browser testing, dockerizing, packaging, updating a badge on your repo to tell the world your code is sound, and more. And it happens without having to remember it–push the code, and Travis checks it. It’s one heck of a safety net, if nothing else. It lets you focus more on the code than on the boring devopsy* stuff.

*I mean, I don’t exactly think devops is boring stuff, but no shame if you do–most programmers get into code to write code, not manage deployments and QA etc etc etc.

CI/CD — A Quick Aside

So what is CI/CD, what does it do for you, and do you need it?

I did a quick search on the interwebz before deciding to write this and what I found at a glance fell into 2 categories:

  • People selling a service
  • People hyping a trend

Since my target audience is, largely, a solo dev who doesn’t really have the context needed to parse either of those kinds of posts, I wanted to break it down a little more succinctly.

But First, Some Vocab:

CI (continuous integration):

What it Is: The act of integrating the code being worked on into the main code base on an on-going basis, rather than waiting until a feature is complete and you’re ready to release it. Typically, merging code or pushing local changes triggers a service (a CI system) that will pull the new code, build it, run unit tests, and let you know if you managed to break your application with the latest changes. Code repos like GitHub can be configured to block pull requests that have a failing CI system build. Often, the CI system will archive the built application so it can be used later in deployment.

Problem it Solves: At root, it helps you limit the damage you can do to your code at one time. Rather than checking out a feature branch, working on it for weeks, then trying to merge it back into master and finding out your feature code is incompatible with the master branch with 231 merge conflicts (or failed tests), you can catch issues almost immediately–when they’re much easier to fix. With multiple people in a code base, this gets even more important; everyone gets aligned far more often and reduces the amount of effort needed to keep things moving in the same direction.

CD (continuous delivery/deployment):

Is it Delivery or Deployment? It depends partly on who you’re talking to (I personally don’t view them as different things and will use them interchangeably) and what the context is. If my code is going to some other department that will do the rest of the dev-opsy stuff, it makes more sense to call it continuous delivery–you’re delivering it to someone. But, if your team is responsible for getting it to the users via a webservice or some other process, then it’s more of a deployment of the software. Context is the key, friends.

What it Is: Either way, this is the process of continually putting finished software where it needs to go. This could be a staging environment, a testing environment, or directly to the users if you’re a company like Facebook (or you’re just trying to show off to family like me). A common approach is the CD system will wait for the CI process to successfully complete, and then once it knows the code is good it will either take the output of the CI process (generally referred to as a “build artifact”) and deploy it based on the configured settings, or it creates a whole new artifact for the deployment.

Problem it Solves: In the not-so-distant past, once software shipped it was done, ready or not. Think about all the games you’ve played with crazy bugs and glitches in them that you just don’t see in modern games–games these days can get patched without inconveniencing player or developer. That’s continuous deployment at work. Finish some code, ship some code. It also lets you put a basic application in front of someone, say a client, to get instant feedback–and then just keep adding functionality.

Is It For You?

So if you’re new enough to all this, is CI/CD something worth setting up? I mean, it depends…but my short answer is yes.

It’s not as arduous to setup as it may sound, especially when you look at guides put together by people trying to sell you things. If you do it as one of the first steps in your process, it’s fairly easy to get done–and it really is a velocity accelerator. You won’t get caught by surprise trying to merge in new features (“When did THOSE tests start failing?”) and don’t have to fumble around moving files in order to make sure things work or to show off a weekend of work.

Of course, there’s also the fact that those are the kind of skills that separate someone who can write code and someone who can delivery value to an employer or client. While writing software is a challenging a rewarding pastime, the best program in the world isn’t really any good until someone can put it in front of users.

Blog at WordPress.com.

Up ↑