Chapter 10. Use cases

Table of Contents

General use cases
Working with your first build
Working with Maven
Working with project dependencies
Working with multiple branches
Working with build promotion
Sharing working directories
Sharing build versions
Using date and iteration as part of build version
Managing major, minor, and iteration part of a version string
Specifying label to build against
Updating information of many projects
Working with build queues
Working with public configurations
Remote and parallel use cases
Building multi-platform products
Working with parallel builds
Performing automation/smoking tests on a machine other than build machine
REST API use cases
Set up real-time continuous integration build
Trigger other builds after build of particular project

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]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.

General use cases

Working with your first build

Check out code from CVS, build them with Ant, and tag the source when build is successful. Also upon a failure build, notification should be sent to users who have checked in codes recently.

  1. 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.

  2. 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]Note

      There are two methods to make build results accessible from QuickBuild's user interface:

      1. Save build results under directory denoted by artifactsDir property. This is what we do in this use case.

      2. Put build results in any directory you want, and use the publish step to create soft links under directory denoted by artifactsDir property. These soft links will point to your build results. This is what we do in next use case.

      [Note]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]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]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.

Working with Maven

Check out code from CVS, and build them with Maven. Instruct Maven to use version managed by QuickBuild, and make artifacts published to Maven repository also accessible from QuickBuild's web interface.

  1. 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]Note

    Do not forget to set property path to maven executable in basic settings of the root.live-samples configuration.

  2. 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]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.

  3. 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>
  4. In case of Maven2, please refer to configuration root.live-samples.maven2-sample.

Working with project dependencies

Some of my products depend on common components. For flexibility, separate build for these components have been set up. Before build those products, common components should be checked first to see if they need to be built.

  1. 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.

  2. 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.

  3. Create configuration for projectA, say root.productA. Set up the following things for this configuration:

    • Create below repositories:

      repository1

      This repository is a CVS repository which is used to check out source codes of productA from CVS.

      repository2

      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:

      check out productA from CVS

      This step uses repository1 to check out source codes of productA from CVS.

      check out build results of componentA

      This step uses repository2 to check out componentA-xxx.jar from CVS.

      create label

      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.

      default

      This step is a serial composition step that runs the above five steps serially.

  4. 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]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.

  5. 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.

Working with multiple branches

I want to set up build for multiple branches of my product. I do not want to input repositories or builders information multiple times for each branch, how can we do that?

  1. 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.

  2. 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.

  3. 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]Note

    An empty value for branch means main branch.

  4. 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.

Working with build promotion

For a particular project, I want to set up nightly build, test build, and release build respectively. Nightly builds should not tag the source in any case, while test and release builds should tag the source whenever there is a successful build. Further more, for particular test build that has passed QA tests for example "myproduct-QA-5", I want to promote it as a release build, and assign it with a formal version, for example "myproduct-1.0.5"

  1. 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.

  2. 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]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.

  3. 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.

  4. 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]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]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.

Sharing working directories

In above use case, every child configuration of "root.live-samples.sample3" has its own working directory and holds its own copy of checked out codes from CVS. For a large project, this may consumes a lot of disk spaces. Is there any way to check out only one copy of codes for these three child configurations?

  1. 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.

  2. 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]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]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.

Sharing build versions

In use case working with build promotion, I want all child configurations share the same stream of build version. That is, if the most recent build (among all child configurations) takes version "myproduct-1.0.1 build 4", then the next happened build should take version "myproject-1.0.1 build5" in regardless of its belonging configuration.

  1. 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.

  2. 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.

Using date and iteration as part of build version

In use case working with build promotion, I want current date and iterations of current date can be embedded into build version of child configurations.

  1. 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.

  2. 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]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.

Managing major, minor, and iteration part of a version string

In use case working with build promotion, I want to define a version schema with major release part, minor release part and iteration part. Major release part will be set manually. The "release" configuration increases minor release part of the version, while "test" configuration increases iteration part of the version. When minor release part of the version changes, iteration part should be reset to 1.

  1. Define the following variables in configuration root.live-samples.sample3 :

    majorRelease=myproduct-1.0
    minorRelease=1
    iteration=0
  2. Define next build version of root.live-samples.sample3.test configuration as:

    ${var["majorRelease"]}.${var["minorRelease"]} iteration ${var["iteration"].increaseAsInt()}
  3. Define next build version of root.live-samples.sample3.release configuration as:

    ${var["majorRelease"]}.${var["iteration"].setValue(1), var["minorRelease"].(increaseAsInt(), value)}
  4. 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, ...

Specifying label to build against

I've set up a configuration to build against latest code of my project. But, when build this project manually, I want to be able to specify the label to build against. Is there anyway to do this?

  1. 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.

  2. 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]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.

Updating information of many projects

I have a CVS server with many projects, and set up dozens of configurations for these projects in QuickBuild. After sometime, server name (or ip address) of our CVS server has been changed. So I need to go through all defined repositories and change server name (or ip address) accordingly. Is there any simple way to do this, or handle such kind of batch processing?

  1. 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.

  2. 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]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.

Working with build queues

I have set up a number of configurations for projects of deparment1, and all of them are under configuration "root.department1". Now I want to make sure that at the same time, only two builds can be performed for this department in order to save CPU resources for other departments.

  1. Create a queue, say queue_department1, with two working threads.

  2. 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).

  3. For users of department1, assign them to groups with only queue_department1 authorized.

  4. In this way, subtree under root.department1 are limited to only use queue_department1.

Working with public configurations

Make artifacts of some projects be publicly accessible, but do not want these projects be modified or built publicly.

  1. Set up public accessible projects under a particular configuration, for example, root.public.

  2. Add a group named by anonymous, and configure this group to have View permission on configuration subtree rooted at root.public.

  3. In this way, anonymous users can only access configurations under root.public, without the permission to build or edit these configurations.