Continuous Integration, or CI, is a simple, yet powerful concept. Automatically build, regression test, and deploy a software application to a test environment whenever a developer commits a code change to version control. If the build, regression test, or deployment fails, the problem can be isolated to the code change that triggered the CI build. Once isolated, the source of the failure can be identified and corrected to allow the build to complete successfully.
Today, CI is a practical approach to ensure that a software application always builds while it undergoes development. However, this was not always the case. Until open source
CruiseControl was developed, CI was not possible without creating the necessary infrastructure from scratch.
Years after it was first released, open source CruiseControl remains a popular tool for implementing CI. Not only does CruiseControl trigger CI builds, but it also notifies the
development team of the build results via email and on an easy-to-read dashboard. Getting started with CruiseControl requires some effort to understand the structure and contents of the configuration file. With additional effort, CruiseControl can be optimized to support CI for parallel development of a software application and for software development projects across an enterprise.
Extending CruiseControl to Support Several Projects
Configuring CruiseControl for Continuous Integration Builds describes the steps to configure one CruiseControl project. A CruiseControl project corresponds to a software development effort in which all activity takes place in one codeline in the version control tool. However, it is rare for development to be restricted to one codeline for the duration of a software development project. Typically, parallel development along multiple codelines is the practice used by software development projects.
To implement CI for a software development project, CruiseControl needs to monitor each codeline in which development takes place. This means one CruiseControl project needs to be created for each active codeline. However, the configuration of each CruiseControl project is likely to be similar. The differences among the CruiseControl projects may be limited to the workspace in which the build occurs, the branch of the version control tool used to populate the workspace, and the test environment in which the build is deployed.
Rather than specifying the same configuration information for each CruiseControl project, common configuration settings can be specified once in the CruiseControl configuration file, config.xml, but referenced in each project that uses that information. Plugin preconfiguration is the mechanism provided by CruiseControl for this purpose.
Configuring Plugins to Support Multiple CruiseControl Projects
Typically, the following elements are nested inside the <project> element to define each
CruiseControl project.
- <listeners>
- <bootstrappers>
- <modificationset>
- <schedule>
- <log>
- <publishers>
Recall from Configuring CruiseControl for Continuous Integration Builds that each XML element nested inside the <project> element maps to a plugin that is executed during the build loop. Configuration settings for these elements can be specified using plugin preconfiguration. Rather than including the configuration details in the XML element that is nested inside the <project> element, these details can be specified once at the beginning of the config.xml file.
Configuring CruiseControl for Continuous Integration Builds included the following
example for configuring the <bootstrappers> element.
<bootstrappers>
<accurevbootstrapper
workspace="/home/accurev_user/workspaces/${project.name}"
verbose="true"/>
</bootstrappers>
Notice that the nested <accurevbootstrappers> element specifies values for the workspace and verbose attributes. While the value of the verbose attribute is constant, the value of the workspace attribute is not. However, the value of the workspace attribute is specified using the value of the CruiseControl variable project.name. As written, the configuration of the <accurevbootstrapper> is independent of the project, i.e., the same definition can be used in every project.
Using plugin preconfiguration, the detailed specification of the <accurevbootstrapper> can be removed from the <project>. The accurevbootstrappers plugin is preconfigured at the beginning of the config.xml file by specifying the following.
<plugin
name="accurevbootstrapper"
workspace="/home/accurev_user/workspaces/${project.name}"
verbose="true"/>
By preconfiguring the accurevbootstrappers plugin, each project that uses that plugin only needs to specify the following.
<bootstrappers>
<accurevbootstrapper/>
</bootstrappers>
Not only does plugin preconfiguration prevent identical configuration information from being specified in each project, but it makes it easier to support future changes. If
the configuration information for a plugin ever needs to change, the change can be made in one place in the config.xml file, rather than in each project definition in that file.
Using Plugin Preconfiguration to Support CI for Different Software Applications
Plugin preconfiguration is not limited to CruiseControl projects that correspond to parallel codelines for a software development project. Instead, plugin preconfiguration can be used for CruiseControl projects that implement CI for different software applications under development. The example of preconfiguring the accurevbootstrappers plugin is applicable in an enterprise in which different software development projects use the same version control system.
A configuration management team interested in standardizing CI for Java development projects across an enterprise can make use of plugin preconfiguration for all CruiseControl projects that run in the same CruiseControl instance. As new CruiseControl projects for new software applications are added to the config.xml file, existing preconfigured plugins can be referenced in the new projects. Not only does this
reduce maintenance, but it promotes consistency. All CruiseControl projects in the config.xml file can follow the same pattern.
Using the CompositeBuilder
While CI may begin as an effort to build after changes are committed to a codeline, CI can be extended to validate the deployment process. In the same way that a change to a codeline triggers a CI build, each change to a codeline should trigger a deployment to an integration environment. The deployment should begin once the CI build completes.
Typically, deployments of a software application are scripted so that they can be automated. Scripts that are used to deploy an application to a test environment can be used to deploy each CI build to an integration environment.
One approach for validating the deployment is to configure the CompositeBuilder to invoke the build and deployment scripts as part of the CruiseControl build loop. The CompositeBuilder is configured by nesting the <composite> element inside the <schedule> element. The child elements of <composite> are the elements that invoke the different builders.
One of the child elements of <composite> is <exec>, the element for the ExecBuilder. The ExecBuilder invokes a command from the operating system shell. <exec> can be configured to invoke the top-level script to deploy a build to an integration environment. The example below shows how the deployment script, deploy.sh, is invoked after Ant completes the build. The CompositeBuilder is designed to execute the builders in the order that they are listed. If the script invoked by one of the builders fails, the remaining builders are not executed. In the example below, deploy.sh will not be invoked if build.sh does not complete successfully.
<schedule
interval="300">
<composite>
<ant antscript="/opt/cruisecontrol/build.sh"
antworkingdir="/opt/cruisecontrol/projects/${project.name}"
uselogger="false"/>
<exec
workingdir="/opt/cruisecontrol/projects/${project.name}" command="/opt/cruisecontrol/projects/${project.name}/deploy.sh"/>
</composite>
</schedule>
Maintaining CruiseControl Configuration Files Under Version Control
As more projects are added to CruiseControl, the configuration file config.xml becomes more critical, and more difficult to reconstruct from scratch. In additional to config.xml, other files are created or modified to support CruiseControl projects. Some files are stored in the top-level directory where CruiseControl is installed. Other files reside in the subdirectories that correspond to the CruiseControl projects. For example, project-specific build and deployment scripts are likely to be stored in the subdirectory for a CruiseControl project.
To protect CruiseControl files from accidental loss or corruption, the files should be maintained under version control. To ensure that the files under version control match those in operation, all configuration files, including project-specific files, should be kept in the directory that serves as the workspace for the version control tool.
If CruiseControl is installed on a Unix or Linux server, symbolic links can be created from the CruiseControl installation directory to the configuration files and subdirectories in the directory that contains the workspace for the version control tool. This means the CruiseControl instance is running from the configuration files that are in the workspace of the version control tool. If the workspace is kept synchronized with the version control repository, the files used by the CruiseControl instance are those under version control.
The example below shows symbolic links in the top-level directory where CruiseControl is installed. These links are to a file and subdirectory in the directory on the file system that maintains the workspace for the version control tool.
config.xml
-> /opt/versionControlTool/workspace/config.xml
projects
-> /opt/versionControlTool/workspace/projects
Summary: Optimizing CruiseControl
Implementing CI begins with installing and configuring CruiseControl. Optimizing a CruiseControl installation involves structuring the config.xml file so that it can be extended and maintained to support multiple projects. By using plugin preconfiguration, configuration settings can be specified at the beginning of the config.xml file then referenced in all projects that use this information.
Optimizing a CruiseControl installation also involves using this open source tool to validate deployments. The CompositeBuilder can be used to invoke a script to deploy each successful CI build to an integration environment.
Finally, optimizing a CruiseControl installation entails keeping configuration files under version control to prevent against accidental loss or corruption.