Table of Contents
This chapter shows how to use QuickBuild by going through a couple of typical use cases. All use cases are using CVS as sample repository. You can also use other type of repository here. Configurations used in these use cases resides under configuration root.live-samples which will be available after you've installed QuickBuild. You need to edit basic settings of the root configuration, and set value for variable such as ant, cvs, maven according to your environment. These variables will be referenced in child configurations.
![]() | Note |
---|---|
Most of the samples are configured to check out codes from our sample repository :pserver:anonymous@cvsdemo.pmease.com:/home/cvsroot. It will be very helpful to check out these codes and look into them. |
From the dashboard, trigger the configuration root.live-samples.sample1 , 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 there are no changes in CVS repository since last build. Click on OK, and the build should be kicked out and run. After some time, refresh the dashboard page; you'll see 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 has happened in the configuration log.
You now have successfully run the first build. Let's examine some important aspects for 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 stuffs specific to current configuration, for example, configuration logs. In this working directory, a directory named checkouts will be created to hold stuffs checked out from configured repositories. In the configuration's publish directory, a directory named builds will be created to hold generated builds, including build logs, published artifacts, etc. If these two directories are set as empty value, they will inherit settings from parent configuration. If you specify a relative path, it is assumed that they are relative to the parent's working or publish directory.
Repositories
Create the CVS repository in this page. Pay particular attention to the CVS executable path property which we assign it with the value ${var["pathToAnt"]} here. 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 current configuration object. Here we are referring to var property of the configuration object. For properties that can be used in your OGNL expression, please refer to OGNL reference section.
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 configurations, newly created repository will override 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 descendent configurations. In this way, your life of configuring new builds is made simple.
Builders
Create the Ant builder in this page. Here again we use OGNL expressions in Path to Ant executable and Build properties. Take a look at Build properties, we passed several properties to Ant. Among them, buildVersion is used to pass in current build's version; artifactsDir is used to pass in the directory path to which your build results should be copied. This directory is a sub directory of current build's publish directory, and is named as artifacts. Current build's publish directory is a sub directory named by its version under current configuration's publish directory. junitHtmlReportDir is used to pass in directory where you should store your JUNIT html reports. cloverHtmlReportDir is used to pass in 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.
Multiple builders can be defined. Particularly, for the newly created builder, if you choose a name that is the same as another builder defined in ancestor configurations, newly created builder will override 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\live-samples\sample1\checkouts
,
and you'll find checked out stuffs 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 denoted by property
artifactsDir. Also in target
test, we generate JUNIT html report into
the directory denoted by property
junitHtmlReportDir; in target
cloverreport, we generate Clover coverage
report into the directory denoted by property
cloverHtmlReportDir. In 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 in this page. Here we defined an Email notifier. This notifier will be referred to when define the notification step, which is used to send failure build notification to users who has checked in since last successful build. Message title and body for this notifier can be customized through using Velocity template. Notification sent out using this notifier will contain links to affecting configuration, build, build log, revision log, and also several lines arrounding the error line inside the build log.
![]() | Note |
---|---|
You can define your notifiers in a high level configuration, so that they can be used by every descendent configuration without need of re-definition. |
Steps
Create desired steps in this page. Here 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 one. Actually, When the configuration got running, QuickBuild will only locate and execute the default step (will look for this step in ancestor configurations if not found in current configuration. The same is true of other steps). As you may have noticed, 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, upon a failed build, the send notification for failed builds step will collect CVS logins who has checked codes into CVS repository since last successful build, and send notifications to them. Before send this notification, these logins should be mapped to corresponding QuickBuild users in order to get contact information such as Emails, MSN messenger accounts, etc. When define repositories, you can refer to these login mappings, so that logins in those repositories can be resolved to 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 descendent configuration without need of re-definition. |
Child configurations
Create child configurations under current configuration. Currently it is the only place to create, delete or move configurations.
Trigger configuration
root.live-samples.maven-sample with
force build option. QuickBuild should check
out code from CVS repository, 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 local repository to any other directory if you
like, but please do not check
them into QuickBuild's demo CVS, in order not to disturb other
persons using this live sample.
![]() | Note |
---|---|
Do not forget to set property path to maven executable in basic settings of the root.live-samples configuration. |
You now have successfully gotten the build running 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's repository. They
appear here because soft links to them are created under artifacts
directory of current build. This was done by the step of type
publish (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 current build's 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
file name starting with maven-sample-1.0.3
will be published into artifacts directory of current
build, that is, soft links to these files have been created under
artifacts directory.
![]() | Note |
---|---|
If your build version contains spaces, you should surround the pattern maven-sample-${build.version}.* with quotations; otherwise, it will be treated as multiple patterns separated by spaces. |
Also Maven is using version number managed by QuickBuild as current version. This is done in two steps:
When define Maven builder, pass in a property named by buildVersion (You can choose other name of course), and set its value to be "${build.version}". Here quotes are used in case that evaluated OGNL expression contains white spaces.
In the project definition file (<checkouts
dir>/maven-sample/project.xml
here), instruct
Maven to use value of passed in
buildVersion property as current
version:
<currentVersion>${buildVersion}</currentVersion>
In case of Maven2, please refer to configuration root.live-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 configuration for componentA,
say root.componentA. This configuration
checks out code for componentA from CVS
repository, build with Ant and generate
componentA-xxx.jar
into current build's
artifacts directory. This Jar file is needed by
productA.
Create configuration for projectA, say root.productA. Set up the following things for this configuration:
Create below repositories:
This repository is a CVS repository which is used to check out source codes of productA from CVS.
This repository is a QuickBuild repository which
is used to check out
componentA-xxx.jar
from latest
build of configuration
root.componentA. Modules
information are set up so that componentA-xxx.jar will
be put into directory <configuration
root.productA's checkouts
directory>/productA/componentA
.
Create a Ant builder to build productA. In the build script file, it uses Jar file generated by componentA
Create below steps:
This step uses repository1 to check out source codes of productA from CVS.
This step uses repository2 to
check out componentA-xxx.jar
from
CVS.
This step does the following things:
Creates a label on source code of productA in CVS.
Creates a label on root.componentA to mark the build number of componentA whose artifacts are used by this version of productA.
This step is a serial composition step that runs the above five steps serially.
In this way, productA is set up to be dependent on componentA. When root.productA is triggered, root.componentA will also be triggered to see if it is necessary to be built, and build results of componentA will be checked out to work space of productA to accomplish productA's build.
![]() | Warning |
---|---|
When you set up a configuration to be dependent on another configuration, you should never let them 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. Within this live demo:
root.live-samples.sample4.productA represents root.productA we talked about.
root.live-samples.sample4.componentA represents root.componentA we talked about.
Let's assume that you want to set up build for two branches for your product: bugfix and main. First set up a configuration for your product, say root.product1. In this configuration, set up informations such as repositories, builders, and steps. Particularly, for branch property of your repository, set it to be: ${var["branch"]}. This means that value of branch variable defined in your configuration will be used as actual branch to check out.
Create configuration bugfix under root.product1. For this configuration, you only need to set up next build version and define the following variable:
branch=bugfix
In this way, configuration root.product1.bugfix is set up to build against bugfix branch of your repository.
Create configuration main under root.product1. For this configuration, you only need to set up next build version and define the following variable:
branch=
In this way, configuration root.product1.main is set up to build against main branch of your repository.
![]() | Note |
---|---|
An empty value for branch means main branch. |
A live demo is available at http://livedemo.pmease.com:8081. Within this live demo:
root.live-samples.sample6.bugfix branch represents root.product1.bugfix we talked about.
root.live-samples.sample6.main branch represents root.product1.main we talked about.
Open configuration root.live-samples.sample3. This is the top level configuration for our sample project. We define necessary repositories, builders, and steps in this configuration.
Under this configuration, we defined three child configurations nightly, test and release, respectively. For test and release configuration, the only thing need to do is setting proper next build version in the basic settings tab. Other objects are inherited from parent, including repositories, builders and steps. For nightly configuration, the label step is not wanted, so we create a new step in the steps tab, and choose overriding 'Label CVS' from the drop down menu of the name property, and choose never run this step as value for the step necessary condition property. In this way the label CVS step created in parent configuration has been overriden, and will never get chance to run. Another way to avoid labeling is to override the default step, and remove the label CVS step from the serial composition.
![]() | Note |
---|---|
For release and test builds, it is highly recommended to set them as clean builds. For nightly builds, be set as increment builds will speed up the build process. Generally speaking, clean build is more reliable, and increment build is faster. |
Now try to forcibly trigger these three child configurations, you can see all of them should run happily. By examining builds in these three child configurations, you'll find that builds in release and test configuration can be promoted and rebuilt, while builds in nightly configuration can not. The reason is that rebuild and promotion need to repeat the build, which is only possible when labels were created in repository for these builds.
Now suppose that our QA team has thoroughly tested build myproduct-QA-5. We are satisfied with its quality, and want to promote it as a release build. In order to do this, just go to detail page of myproduct-QA-5, click on promote button, the Edit promote settings page will appear. In this page, choose root.live-samples.sample3.release as the destination configuration, and click on OK. Now myproduct-QA-5 is being promoted in release configuration. The new version will be next build version of release configuration, which we assume as myproduct-1.0.5 here. After the promotion, original test build will be deleted, and the new build will create a new label called myproduct-1_0_5 in CVS.
![]() | Note |
---|---|
Under the hood, promotion retrieves sources from repository with label of original build, and go through steps defined in destination configuration to perform the new build. So in order to repeat the original build exactly, source configuration and destination configuration should use the same set of repositories and builders during build. |
![]() | Note |
---|---|
Another way to perform promotion is just to move a build from one configuration into another, this will not trigger a new build. The limitation is that the version attached original build can not be changed. |
By default, a newly created configuration will use ${name} as value of the working directory property. This means new configuration will create a sub directory under working directory of its parent configuration, and name of the sub directory will be the same to name of newly created configuration. So there will be three different working directories for nightly, test and release configuration. In order to use the same working directory for these three child configurations, the simplest way is to left their working directory property as empty. In this way, they will all use parent configuration's working directory. Of course, you can point them to other arbitrary directories, as long as they all refer to the same directory.
Now nightly, test
and release configurations have the same
working directory, and there will be only one copy of codes
checked out for build, which resides in <working
directory>/checkouts
.
![]() | Note |
---|---|
For configurations sharing the same working directory, only one can be executed at one time. If you trigger others while one configuration is already running, the newly triggered configuration will be put into 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 source code, build with the same set of builders. Otherwise, increment builds may be incorrect for codes may be incremental updated based on different code base. |
In basic settings tab of configuration root.live-samples.sample3, set a value for property next build version, for example: myproduct-1.0.1 build 1.
For all child configurations under root.live-samples.sample3, set an empty value for property next build version. In this way, all child configurations will inherit next build version from the parent configuration, that is, share the same stream of build version. If next build version of the parent configuration is also empty, it will inherit the value from its own parent, until non-empty value has been found, or reaches the root configuration.
Let's take test child configuration as example. From the drop down menu of property next build version, choose date and iteration, a complicated value contains quite a lot of OGNL expressions will be set for next build version. It will generate versions like 2005-Sep-25.4 as default, where 2005-sep-25 indicates date of the build, and 4 here means iterations in this date.
If you are not satisfied with the format of this default one, you can modify the value of next build version. Before doing this, make sure you know the grammar of OGNL expressions as well as exposed date and time properties in QuickBuild. For example, you can add the string myproduct-QA- at the very start of next build version, then, the version generated will like myproduct-QA-2005-Sep-25.4, myproduct-QA-2005-Sep-25.5, etc.
![]() | Note |
---|---|
When you choose date and iteration as next build version, and run the configuration, QuickBuild will automatically put two variables in current configuration, viz. day and dayIterator. For variables that have not been defined (either in current configuration or in ancestor configurations), QuickBuild will assume it has an empty value when referenced as string, or 0 when referenced as number. And QuickBuild will automatically create these variables in current configuration if they have been assigned values. |
Define the following variables in configuration root.live-samples.sample3 :
majorRelease=myproduct-1.0 minorRelease=1 iteration=0
Define next build version of root.live-samples.sample3.test configuration as:
${var["majorRelease"]}.${var["minorRelease"]} iteration ${var["iteration"].increaseAsInt()}
Define next build version of root.live-samples.sample3.release configuration as:
${var["majorRelease"]}.${var["iteration"].setValue(1), var["minorRelease"].(increaseAsInt(), value)}
In this way, builds in root.live-samples.sample3.release will get versions like: myproduct-1.0.1, myproduct-1.0.2, myproduct-1.0.3, ..., and builds in root.live-samples.sample3.test will get versions like: myproduct-1.0.1 iteration 1, myproduct-1.0.1 iteration 2, myproduct-1.0.1 iteration 3, ...., myproduct-1.0.2 iteration 1, myproduct-1.0.2 iteration 2, ...
Open configuration root.live-samples.sample5, and check modules definition of its CVS repository setting, you'll find that label value of 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 still build against latest code unless you specify a non-empty value for the variable label.
Now forcibly trigger this configuration, in the appeared Editing manual trigger settings page, provides a different value for label variable like this:
label=myproduct-1_0_0
In this way, configuration root.live-samples.sample5 is triggered to build against label myproduct-1_0_0.
![]() | Tip |
---|---|
By using variables, you can make almost any part of repositories, builders, or steps definition be overridable when manually triggers the build. Also it is possible to override these variables in child configurations, which gives you the flexibility to modify part of objects defined in 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 or team's root configuration), and set its value as server name of ip address of your CVS server.
Refer to the above variable when define CVS root of your repositories, for example:
:pserver:build@${var["cvsServerName"]}:/cvsroot
Now if you want to point all your CVS repositories to the new CVS server, simply modify value of the variable cvsServerName.
![]() | Tip |
---|---|
It is a good idea to extract dynamic parts (maybe changed frequently) of repositories, builders and steps, and then put them as variables in higher level configurations. In this way, you can easily change property of all affected objects. |
Create a queue, say queue_department1, with two working threads.
Edit root configuration, and set the build queue as queue_department1 (This step is necessary that, queue_department1 will still be used even administrator of root.department1 set build queue as inherit from parent).
For users of department1, assign them to groups with only queue_department1 authorized.
In this way, subtree under root.department1 are limited to only use queue_department1.
Set up public accessible projects under a particular configuration, for example, root.public.
Add a group named by anonymous, and configure this group to have View permission on configuration subtree rooted at root.public.
In this way, anonymous users can only access configurations under root.public, without the permission to build or edit these configurations.