Automated builds play a central role in continuous integration (CI) and are a key enabler of a CI/CD pipeline. They form the first in a series of automated steps designed to alert you as early as possible to any issues in your code caused by your latest changes.
When we talk about a build in this context, we mean more than just the act of compiling and linking the source code to create an executable.
The build process includes a series of checks as well as collating all the pieces required for your program to run; even if you’re working in an interpreted language, you’ll need a build step.
The files output from the build stage – known as the build artifacts – are then progressed through your CI/CD pipeline for further stages of testing followed by staging. If a build passes every step in the pipeline, it is ready for release to live.
Before we look at what build automation involves, let’s consider why an automated build process is important.
If you’re working in an IDE, you can normally trigger a build with a keyboard shortcut, so why automate the process?
For starters, while building locally is handy when you want to sanity-check your work or quickly demo something to your boss, it’s not good practice to use a local build for your CI/CD pipeline.
Using a dedicated build server ensures a clean environment, which will soon flag any missing dependencies that would otherwise cause problems and delays when the output is deployed to a test environment.
Without an automated build to kick off the other stages in the pipeline, CI/CD would be much less reliable. If you have to remember to log into the build server and initiate each build, including any tests, babysit the process in case anything fails, and then move the output to the artifact repository so that it can be deployed to testing, then your process is prone to error.
It’s easy to put off starting the build until you’ve got a few more changes to test, but doing so undermines the benefits of CI/CD.
Finally, the strategy behind a CI/CD pipeline is to fail fast.
The sooner you find out about an issue, the easier it is to fix and the more efficient the process becomes. Automating the build phase is quicker than manually triggering the various steps involved, and a lot faster than moving files and running tests by hand.
By automating the build, you ensure all the steps are performed in the correct order on every single commit (or on a batch of commits) and get the benefit of rapid feedback while freeing up time.
If you’re new to CI/CD, setting up automated builds and triggering them each time anyone in your team commits a change is one of the first things you’ll need to do (after getting everything into source control). You may already have a build script or a definition file, either courtesy of your IDE or which you’ve written yourself.
If you don’t, you’ll need to choose a suitable build tool for the language you’re working in and specify the files to compile, link and package. You can then use a CI server to coordinate the various steps, from the initial trigger to providing feedback, and defining the failure conditions.
Continuous integration involves triggering a build after each commit to master, so that every change is integrated and tested shortly after being made. If the build completes successfully, it then triggers the next step in the process.
Most CI tools allow you to configure additional triggers for the build and to customize the pipeline stages that follow.
For example, you may want to trigger the same set of steps when commits are made to any branches in a particular directory. On the other hand, you may want to schedule a nightly build that is put through additional layers of testing and is used to refresh staging environments. You can also initiate the build stage manually.
It’s good practice to run the build steps on a dedicated build server rather than on your development machine. Building in a clean environment will flag up any missing dependencies and avoids issues along the lines of “but it works on my machine”.
The build step itself invokes your chosen build tool (such as Maven, Ant or Gradle), which executes the tasks specified in the build script or definition file.
Once you have a sense of how long your builds take to run, it’s worth configuring a failure condition for builds that do not complete within a specified period. This practice avoids long-running builds blocking resources.
As well as preparing your code for deployment, the automated build process is an ideal point to run a number of other checks on your code, such as unit tests, and linting and static code analysis. Running these checks as part of every build and addressing any issues as they arise helps you improve the quality of your code.
Although these checks are run before the build artifacts are produced, a failure doesn’t necessarily have to halt the rest of the pipeline. For example, you may decide that you want to publish the build artifact and progress to the next pipeline stage even if linting errors were found. Configuring a quality threshold helps prevent “small” issues from accumulating over time.
The output of the automated build process is build artifacts, which may include installers, WAR files, libraries, and containers. Publishing these files to an artifact repository provides you with a central location from which you can deploy builds to different environments.
After the build, the next stage of a CI/CD pipeline usually involves automated functional tests, which require the build to be deployed to one or more test environments (sometimes together with other components, such as a database or other microservices). If these tests complete successfully, the same build may be used to refresh staging environments and eventually be released to live.
You can view the results of the build phase, including whether the build was created successfully and the results of unit tests and other checks, from your CI tool. Configuring alerts to notify you of failures allows you to react quickly and get your code back into a releasable state.
A CI tool will also collate data from your pipeline so you can analyze trends. Reviewing the build history and metrics such as build duration, success rates and code coverage can provide insights that will help you improve your CI/CD process.