Table of Contents
This chapter shows how to use QuickBuild by going through a couple of typical use cases. Most of these use cases have corresponding online demos running at http://livedemo.pmease.com:8081, and most of these online demos uses CVS as sample repository which can be accessed through :pserver:anonymous@cvsdemo.pmease.com:/home/cvsroot with an empty password. You can checkout CVS module for these online demos, to examine detail information such as contents of build files, etc.
![]() | Note |
|---|---|
Although this use case checks out code from CVS, and builds with Ant, QuickBuild is not limited for using with CVS, Ant, or building Java projects. For all supported version control systems and builders, please refer to QuickBuild's feature list. | |
Make sure the following softwares are installed in the computer running QuickBuild:
JDK 1.5 or higher
Apache Ant 1.6 or higher. The JUNIT library
junit.jar should be placed into
${ANT_HOME}/lib directory. The
clover.jar and the license file should be
put into this directory as well if you want to integrate
QuickBuild with Clover (a Java code
coverage tool).
CVS command line tool.
Install QuickBuild following instructions in the readme file. Open a browser and connect to your QuickBuild installation, login as admin, and edit the basic settings tab of the root configuration and change value of variable "cvs" and "ant" based on your CVS and Ant installaion.
From the dashboard, trigger the configuration root.myfirstbuild, the Editing manual trigger settings page will be displayed. For property Build necessary condition,choose menu item Force build from the drop down menu. This will force a build even if there are no changes in CVS repository since the last build. Click on OK, and the build should start running. Wait a while and then refresh the dashboard page; you'll see that the build has finished. If all things go well, this should be a successful build. Click on status icon of the newly generated build, the build log will be displayed. In case the build cannot be generated, you can click on status icon of the configuration, and examine what went wrong in the configuration log.
You now have successfully ran your first build. Let's examine some important aspects of this configuration.
Basic settings
This page shows some basic settings of the configuration. You can set working directory and publish directory for this configuration. Working directory is used to store files and directories specific to the current configuration, for example, configuration logs. In this working directory, a directory named checkouts will be created to hold files and directories checked out from the configured repositories. In the configuration's publish directory, a directory named builds will be created to hold the generated builds, including build logs, published artifacts, etc. If these two directories are set as empty value, they will inherit settings from the parent configuration. If you specify a relative path, it is assumed that the path is relative to the parent's working or publish directory.
Repositories
Create the CVS repository on this page. Pay particular attention to the CVS executable path property which we assign the value ${var["cvs"]}. The expression embedded in ${...} is OGNL expression. Almost all text properties in QuickBuild can embed OGNL expressions as long as they are surrounded by ${...}. Root of the OGNL expression is always the current configuration object. We are referring to the variable of the name "cvs" in the configuration object. For all properties that can be used in your OGNL expression, please refer to OGNL reference section.
Variables can be defined in higher level configuration, and inherited and overrided by descendent configurations. With this nature, it can be used to simplify configuration definitions when there are many configurations to maintain ( for example, by defining CVS executable path as a variable in root configuration, you don't need to change configurations one by one when upgrade to a new version of CVS. Instead, you only need to change the variable definition in root configuration).
Multiple repositories can be defined. Particularly, for the newly created repository, if you choose a name that is the same as another repository defined in ancestor configuration, the newly created repository will override the previously defined one. This is also true for builders and steps. So you can define common objects in ancestor configurations, and define particular objects specific to particular child configurations in descendant configurations. This makes configuring new builds quite simple.
Builders
Create the Ant builder on this page. Here again we use OGNL expressions in Path to Ant executable and Build properties. Take a look at Build properties, we are passing several properties to Ant. Among them, buildVersion is used to pass the current build version; artifactsDir is used to pass the directory path to which your build results should be copied. This directory is a sub directory of the current build publish directory, and it is called artifacts. The current build publish directory is a sub directory named by the build version under the current configuration's publish directory. junitHtmlReportDir is used to pass directory, where you should store your JUNIT html reports. cloverHtmlReportDir is used to pass directory, where you should store your Clover html reports. Of course you can choose property names other than artifactsDir or buildVersion, as long as you refer to these property names in your Ant build script file.
![]() | Note |
|---|---|
Besides copying build results into the directory indicated by OGNL expression ${build.artifactsDir}, you can also use the publish artifacts step to publish build results. | |
Multiple builders can be defined. Particularly, for the newly created builder, if you choose a name that is the same as the name of another builder defined in the ancestor configuration, newly created builder will override the previously defined one.
Let's take a look at what should be done in your Ant
build script file. After you have successfully run the build,
change to directory <QuickBuild installation
directory>\working\root\basic-samples\sample1\checkouts,
and you'll find checked out files and directories from the
configured CVS repository. Change to directory
sample1\build, and open file
build.xml; pay attention to the target
distribute. This target creates
distribution file under the directory defined by property
artifactsDir. Also in target
test, we generate JUNIT html report into
the directory defined by property
junitHtmlReportDir; in target
cloverreport, we generate Clover coverage
report into the directory defined by property
cloverHtmlReportDir. This way, we can
access build results, JUNIT html report, and Clover html
report from QuickBuild's web interface.
![]() | Note |
|---|---|
There are two methods to make build results accessible from QuickBuild's user interface:
| |
![]() | Note |
|---|---|
Clover html report will only be generated if you have installed Clover. | |
Notifiers
Create desired notifiers on this page. We've defined an Email notifier. This notifier will be used when we define the notification step, which is used to send failed build notification to users who has checked in since the last successful build. Message title and body for this notifier can be customized by using Velocity template. Notification sent out using this notifier will contain links to appropriate configuration, build, build log, revision log, and also several lines surrounding the error line in the build log.
![]() | Note |
|---|---|
You can define your notifiers in a high level configuration, so that they can be used by every descendant configuration without need to re-define them. | |
Steps
Create desired steps on this page. We've defined four steps, check out from cvs, build with ant, create label for successful builds, send notification for failed builds and default, respectively. Pay particular attention to the default step. Actually, when the configuration runs, QuickBuild will only locate and execute the default step (will look for this step in ancestor configurations if not found in thecurrent configuration; the same is true about the other steps). As you may have noticed, that the default step is a serial composite step that will trigger other three steps one by one.
Login mappings
This page is used to map repository logins to QuickBuild users. As you see in steps definition, after a failed build, the send notification for failed builds step will collect CVS logins of users who has checked code into CVS repository since the last successful build, and it will send notifications to those users. Before this notification is send, these logins should be mapped to the corresponding QuickBuild users in order to get contact information for those users such as Emails, MSN messenger accounts, etc. When you define repositories, you can refer to these login mappings, so that logins in those repositories can be resolved to the correct users in QuickBuild system.
![]() | Note |
|---|---|
You can define your login mapping objects in a high level configuration, so that they can be used by every descendant configuration without need to re-define them. | |
Child configurations
Create child configurations under the current configuration. Currently it is the only place to create, delete or move configurations.
Access http://livedemo.pmease.com:8081,
trigger the configuration
root.basic-samples.maven-sample with
force build option. QuickBuild should check
out the code from CVS repository and trigger the maven builder.
During the build, Maven publishes generated artifacts to
/maven-repository (configured in file
<current configuration's checkouts
dir>/maven-sample/project.properties). Of course,
you can change the local repository to any other directory if you
like.
You now have successfully ran the build with Maven
integration. On build detail page, you should see several files
are listed there as published artifacts. Please note that these
files are actually located in Maven repository. They appear here
because symbol links to them are created under the artifacts
directory of the current build. This was done by setting
"Is create symbol links" option to
"yes" when define the step of type
publish artifacts (see steps tab of this
configuration). In this step, we specify
/maven-repository/maven-sample/jars as source
directory for publishing, and specify
maven-sample-${build.version}.* as the file
name pattern. Before this publish step runs, OGNL expression in
this pattern will be replaced with the current build version, for
example, 1.0.3, and the publishing file name
pattern will actually be maven-sample-1.0.3.*,
which means all files under the source directory with
the file name starting with maven-sample-1.0.3
will be published in the artifacts directory of the
current build, that is, symbol links to these files have been
created under the artifacts directory.
![]() | Note |
|---|---|
If your build version contains spaces, you should surround the pattern maven-sample-${build.version}.* with double quotes; otherwise, it will be treated as multiple patterns separated by spaces. | |
Maven is using version number managed by QuickBuild as the current version. This is done in two steps:
When you define Maven builder, pass in a property named buildVersion (You can choose other name of course), and set its value to be "${build.version}". Here quotes are used just in case that the evaluated OGNL expression contains white spaces.
In the project definition file (<checkouts
dir>/maven-sample/project.xml here), instruct
Maven to use the value passed in the
buildVersion property as the current
version:
<currentVersion>${buildVersion}</currentVersion>For Maven2, please refer to configuration root.basic-samples.maven2-sample.
Let's assume that we have two Java projects:
productA and componentA.
productA uses build result
(componentA-xxx.jar) of
componentA, and thus depends on
componentA.
Create the configuration for the
componentA, say
root.componentA. This configuration checks
out the code for the componentA from CVS
repository, builds with Ant and generates
componentA-xxx.jar in the current build
artifacts directory. This Jar file is needed by
productA.
Create the configuration for projectA, say root.productA. Set up the following in this configuration:
Create repositories:
This repository is a CVS repository which is used to check out the source code of the productA from CVS.
This repository is a QuickBuild repository which
is used to check out
componentA-xxx.jar from the latest
build of the configuration
root.componentA. Modules
information are set up so that componentA-xxx.jar will
be placed into the directory <configuration
root.productA's checkouts
directory>/productA/componentA.
Create an Ant builder to build productA. In the build script file, it uses Jar file generated by componentA.
Create steps:
This step uses the repository1 to check out the source code of the productA from CVS.
This step uses the
repository2 to check out the
componentA-xxx.jar from CVS.
This step does the following:
Creates a label of the source code of the productA in CVS.
Creates a label of the root.componentA to mark the build number of the componentA whose artifacts are used by this version of the productA.
This step is a serial composition step that runs the above five steps serially.
Now the productA is dependent on the componentA. When the root.productA is triggered, the root.componentA will also be triggered to see if it is necessary to built it, and the build results of the componentA will be checked out to the work space of the productA to accomplish the productA's build.
![]() | Warning |
|---|---|
When you set up a configuration to be dependent on another configuration, you should never let the configuration to share the same working directory. Otherwise, deadlock will happen. See here for the reason. | |
A live demo is available at http://livedemo.pmease.com:8081. In this live demo:
root.basic-samples.sample4.productA represents the root.productA.
root.basic-samples.sample4.componentA represents the root.componentA.
![]() | Note |
|---|---|
This scenario can not be addressed through project dependency use case, because the dependency mechanism only guarantees that build of projectA can trigger the build of the componentA, but not vice versa. | |
Let's assume productA corresponds to configuration root.productA, and componentA corresponds to root.componentA.
Edit configuration root.componentA to add a step of type "trigger build in another configuration" with the following properties:
Specify QuickBuild servlet URL if configuration root.productA runs in a different machine than root.componentA. Otherwise, leave it empty.
root.productA
Specify proper value for all other properties
Configure this step into the execution series of the default step, and set it as the last step. With this step, build in other configurations can be triggered after current build finishes. Of course, you can configure multiple steps of this type to trigger build for more than one configuration.
A live demo is available at http://livedemo.pmease.com:8081. In this demo:
root.basic-samples.sample7.productA represents root.productA.
root.basic-samples.sample7.componentA represents root.componentA.
Let's assume that you want to set up the build for two branches of your product: bugfix and main. First set up a configuration for your product, say root.product1. In this configuration, set up the information such as repositories, builders, and steps. Particularly, for branch property of your repository, set it to: ${var["branch"]}. This means that the value of the branch variable defined in your configuration will be used as actual branch to check out.
Create configuration bugfix under the root.product1. In this configuration, you only need to set up the next build version and define the following variable:
branch=bugfix
This way, the configuration root.product1.bugfix is set up to build against the bugfix branch of your repository.
Create the configuration main under root.product1. For this configuration, you only need to set up the next build version and define the following variable:
branch=
This way, the configuration root.product1.main is set up to build against main branch of your repository.
![]() | Note |
|---|---|
An empty value for the branch field means main branch. | |
A live demo is available at http://livedemo.pmease.com:8081. In this live demo:
root.basic-samples.sample6.bugfix branch represents root.product1.bugfix.
root.basic-samples.sample6.main branch represents root.product1.main.
The configuration root.basic-samples.sample3 running at http://livedemo.pmease.com:8081 is demonstrate this use case. It holds all repository, builder and step definitions. And its child configurations (nightly, test and release) inherits these objects, but have independent working directory and next build version value.
The nightly configuration defines an extra step "label CVS" to override the step with the same name in parent configuration, and the step necessary condition is set to false. In this way, builds in nightly configuration will never create label on source code even when the build is successful.
By default, a newly created configuration will use ${name} as the value of the working directory property. This means that the new configuration will create a sub directory under working directory of its parent configuration, and name of the sub directory will be the same as the name of the newly created configuration. So there will be three different working directories for the nightly, test and release configurations. In order to use the same working directory for these three child configurations, the simplest way is to leave their working directory property empty. Then they will all use the parent configuration's working directory. Of course, you can point them to any arbitrary directory, as long as they all refer to the same directory.
Now the nightly,
test and release
configurations have the same working directory, and there will be
only one copy of the code checked out for the build, which resides
in the <working
directory>/checkouts.
![]() | Note |
|---|---|
For configurations sharing the same working directory, only one configuaration can be executed at the same time. If you trigger other configurations while one configuration is already running, the newly triggered configuration(s) will be put in the queue, until the current one has finished its execution. | |
![]() | Note |
|---|---|
If multiple configurations share the same working directory, and some of them are configured to incremental build, it is highly recommended that all these configurations check out the same set of the source code, build with the same set of builders. Otherwise, increment builds may be incorrect if the code is incrementally updated based on a different code base. | |
In the basic settings tab of the configuration root.basic-samples.sample3, set the value for the property next build version, for example: myproduct-1.0.1 build 1.
For all child configurations under the root.basic-samples.sample3, set an empty value for the property next build version. Then all the child configurations will inherit the next build version from the parent configuration, that is, share the same stream of the build version. If the next build version of the parent configuration is also empty, it will inherit the value from its parent, until non-empty value is found or until the root configuration is reached.
Let's take the test child configuration as example. From the drop down menu of the property next build version, choose date and iteration, a complicated value that contains quite a lot of OGNL expressions will be used for next build version. It will generate versions like 2005-Sep-25.4 as default, where 2005-sep-25 is the date of the build, and 4 means iterations for this date.
If you are not satisfied with this default format, you can modify the value of the next build version. Before doing this, make sure you know the grammar of OGNL expressions as well as date and time properties in QuickBuild. For example, you can add the string myproduct-QA- at the very start of the next build version. Then the version generated will be myproduct-QA-2005-Sep-25.4, myproduct-QA-2005-Sep-25.5, etc.
![]() | Note |
|---|---|
When you choose date and iteration as the next build version, and then you run the configuration, QuickBuild will automatically put two variables in the current configuration, day and dayIterator. For the variables that have not been defined (either in the current configuration or in the ancestor configurations), QuickBuild will assume that it has an empty value when referenced as string, or 0 when referenced as number. QuickBuild will automatically create these variables in the current configuration if they have assigned values. | |
Access http://livedemo.pmease.com:8081, we'll take the configuration root.basic-samples.sample3 for example. The following variables are defined in this configuration:
major_release=myproduct-1.0 next_minor_release=1 next_qa_iteration=1
next build version of configuration root.basic-samples.sample3.QA is defined as:
${var["major_release"]}.${var["next_minor_release"]} QA#${var["next_qa_iteration"].increaseAsInt()}next build version of configuration root.basic-samples.sample3.Release is defined as:
${var["major_release"]}.${var["next_qa_iteration"].setValue(1), var["next_minor_release"].increaseAsInt()}In this way, generated builds in configuration root.basic-samples.sample3.QA (make sure to leave the build as version property as empty when your trigger the configuration) will use versions like: myproduct-1.0.1 QA#1, myproduct-1.0.1 QA#2, myproduct-1.0.1 QA#3, ...., myproduct-1.0.2 QA#1, myproduct-1.0.2 QA#2, ..., and generated builds in configuration root.basic-samples.sample3.Release will use versions like: myproduct-1.0.1, myproduct-1.0.2, myproduct-1.0.3, ...
Open the configuration root.basic-samples.sample5 and check modules definition of its CVS repository setting. You'll find that the label value of the source path sample1 has the value of ${var["label"]}. And in the basic settings tab of this configuration, a variable label was defined with an empty value like this:
label=
It means that this configuration will build against the latest code unless you specify a non-empty value for the variable label.
Now forcibly trigger this configuration, and in the Editing manual trigger settings page provide a different value for the label variable like this:
label=myproduct-1_0_0 This way, the configuration root.basic-samples.sample5 is triggered to be build against the label myproduct-1_0_0.
![]() | Tip |
|---|---|
By using variables, you can override almost any part of repositories, builders, or steps definitions when you manually trigger the build. It is also possible to override these variables in the child configurations, which gives you the flexibility to modify part of objects defined in the ancestor configurations. | |
Define a variable for example cvsServerName in a high level configuration (a proper candidate for this high level configuration can be your department's or team's root configuration), and set its value to server name or ip address of your CVS server.
Refer to the above variable when you define CVS root of your repositories, for example:
:pserver:build@${var["cvsServerName"]}:/cvsrootNow if you want to point all your CVS repositories to the new CVS server, simply modify the value of the variable cvsServerName.
![]() | Tip |
|---|---|
It is a good idea to extract dynamic parts (that maybe changed frequently) of repositories, builders and steps, and then create the variables in higher level configurations. Then you can easily change the property of all affected objects. | |
Create a queue, say queue_department1, with two working threads.
Edit the root configuration, and set the build queue to queue_department1 (This step is necessary in order to use queue_department1 even if administrator of the root.department1 sets the build queue to inherit from parent).
Assign the users of department1 to groups with only queue_department1 authorized.
Then the configuration subtree under the root.department1 is limited to only use queue_department1.
Set up publicly accessible projects under a particular configuration, for example, root.public.
Add a group named anonymous, and configure this group to have View permission on the configuration subtree rooted at root.public.
Then anonymous users can only access the configurations under the root.public, without the permission to build or edit these configurations.
From QuickBuild web interface, switch to "FIND BUILDS" tab, and provide below properties as search criterions:
failed
root.project1
All other search criterion properties should be left empty.
Click the search button, and the matching builds will be presented with an XML button at right side of the search results header.
Paste link of the XML button into your RSS reader. Note that you need to make configuration root.project1 publicly accessible; otherwise your RSS reader should be able to authenticate as proper user against QuickBuild.
Your RSS reader should now be able to pull contents from QuickBuild. Channel name of the RSS is explained here.