Patterns, and corresponding anti-patterns, are discussed in the following sections. According to Google trends, the most searched for version control tool is Git and the most commonly searched CI software is Jenkins.
Where examples are provided, we will use the Git Command Line Interface commands or Git Plugin hooks for Jenkins. This Refcard will use those two technologies for examples based solely on search popularity.
Build Software at Every Change
One of the most important patterns to remember when talking about CI is to build the project every time a change is merged into master. Traditionally, the project is built on an arbitrary schedule, such as nightly or every weekend. Scheduled builds are an anti-pattern for CI.
One of the goals of building after every code merge is to immediately identify when problems occur. If the newly merged code causes the build process to fail, then developers know which section of code to examine. If builds are scheduled and an error occurs, the exact code change might not be obvious, and fixing it could require significant digging.
A Continuous Integration system should be set up with:
- A shared version control repository (i.e. Git).
- An automated build script or CI server configuration to run when the repository has changed.
- Some sort of feedback mechanism (such as e-mail or chat software).
||Run a software build with every change applied to the Repository.
||Scheduled builds, nightly builds, building periodically, building exclusively on developer's machines, not building at all.
Versioning is one of the central pillars of CI. A good version control system (VCS) will maintain a core functioning codebase. Developers can then build off that main codebase by creating code branches to add features, fixes, and patches without affecting anyone else. Developer branches can then be merged into the main code branch, called mainline or master, when complete.
Here are some important best practices to consider when working with a version control system:
- Private Workspace - Developers should be working on their own machines (real or virtual) with local copies of the repository. Developers should not be working over file systems that allow them to share the same code files, or on the machine serving as a repository host (if the repository is not cloud-based).
- Repository – In line with the point above, all code should be hosted in a repository. No successful Continuous Integration plan will work with a file system hosted project.
- Master - The main branch from which builds are run should be the master, or mainline, branch. This branch should be heavily protected. Developers should be able to merge code into the master branch but should not be able to commit code directly. The master branch will host your project’s main history and milestone builds. No code should ever be added to it directly.
- Branching Policy - All teams working on a CI process should have an agreed-upon branching policy. Developers should branch off of master using a naming convention agreed upon by the team. Code should be merged into master from individual developer branches through pull requests, or some other agreed-upon mechanism. Branches should be pushed to the repository just like master so they can be shared if needed.
Most modern version control software integrates this best practice into its core functionality. A developer moves code into the VCS when they have made enough progress to consider saving it. Usually the process involves adding the changed code files to a commit, and then committing them with a relevant message.
For example, in Git, a task-level commit uses the following commands:
git add -A
git commit -m "message" (i.e., git commit -m "added file object class")
||Organize source code changes by task-oriented units of work and submit changes as a Task-Level Commit.
||Keeping changes local to development for several days and stacking up changes until committing all changes. This often causes build failures or requires complex troubleshooting.
When master has reached an important development or release milestone, give it a name to mark that code state. Typically, this will be, or will incorporate, the release version number using semantic versioning (major.minor.patch, i.e. 1.10.23).
Git uses the term “tagging” instead of “labeling”. To create a tag for the current build, use the following commands:
git tag -a annotation -m "message" (i.e., git tag -a v1.2.12 -m "version 1.2.12")
git push remote --tags
||Tag or Label the build with unique name so that you can refer to run the same build at another time.
||Not labeling builds, using revisions or branches as "labels."