Parameter Example From Craigs Blog

Taken from Craigs Blog (http://csut017.wordpress.com/2009/05/12/dynamic-build-parameters-some-examples)
Copied here for reference and also because the layout on that page is for one reason or another very weird.

A Very Basic Configuration

To keep things simple, I’m only going to work with a very simple configuration (ccnet.config). This is the base config:

 1<cruisecontrol>
 2  <project name="Test Project">
 3    <description>A demonstration project to show the features of the dynamic build parameters.</description>
 4    <sourcecontrol type="svn">
 5      <trunkUrl>svn://svn.mycompany.com/firstproject/trunk</trunkUrl>
 6      <workingDirectory>C:\SourceControl\FirstProject\</workingDirectory>
 7    </sourcecontrol>
 8    <triggers>
 9      <intervalTrigger />
10    </triggers>
11    <tasks>
12      <nant>
13        <buildFile>App.build</buildFile>
14        <targetList>
15          <target>Dev</target>
16        </targetList>
17        <buildArgs>-D:reason=testing</buildArgs>
18      </nant>
19      <gendarme>
20        <assemblies>
21          <assemblyMatch expr="*.dll"/>
22        </assemblies>
23        <limit>100</limit>
24      </gendarme>
25    </tasks>
26    <publishers>
27      <rss />
28      <xmllogger />
29    </publishers>
30  </project>
31</cruisecontrol>

This project uses Subversion as the source code repository, using a repository called firstproject. It has the default interval trigger (checks for modifications every 60 seconds). When a build is triggered it will run an NAnt build script called App.Build and then perform a Gendarme analysis. Finally it will generate an RSS feed and log the XML results (so the dashboard can use it.)

Basically I’m going to add three dynamic parameters:

Define the target to build
Change the reason for the build (a buildArg for the NAnt script)
And vary the limit on the Gendarme analysis

And to finish things off, I’ll show how the same project can be used to generate different builds via a schedule.

So, let’s get the show on the road.

Defining a Target

The first parameter I want to vary is the build type. This is a target in the NAnt script, and I’m going to allow three different targets: Dev, Test and Prod (this could also be done as a buildArg, but I want to leave that for later!)

The first thing to do is to add the parameter to the project. Parameters are defined at the project level for two reasons:

It saves duplicates if the parameter needs to be used in multiple places
It makes it simpler for the server to work out which parameters need to be sent to the client (thus it is faster)

Since the build target can only be one of three values, I’m going to define a range parameter:

 1<parameters>
 2  <rangeParameter name="Type">
 3    <description>The type of build to perform.</description>
 4    <allowedValues>
 5      <value>Dev</value>
 6      <value>Test</value>
 7      <value>Prod</value>
 8    </allowedValues>
 9    <default>Dev</default>
10  </rangeParameter>
11</parameters>

All parameters must be defined within a parameters block within the project. As a minimum definition, each parameter must have a name – which is what is sent to the client.
This definition defines a parameter called “Type”, it is a range parameter with three possible values: “Dev”, “Test” and “Prod”. Finally, the default value is “Dev”. When a force build is triggered, the user will be displayed a combo box (or a drop down list depending on the client) with these three values in it, and “Dev” will be the initial selection.
The next step is to use the parameter in a task (currently they are limited to tasks and publishers, this may change if there is enough support for it.) The following shows how I would modify the <nant> task to use the parameter:

 1<nant>
 2  <!-- Omitted to save space -->
 3  <dynamicValues>
 4    <directValue parameter="Type" 
 5                 property="targetList.target[0]">
 6      <default>Dev</default>
 7    </directValue>
 8  </dynamicValues>
 9</nant>

This simply says replace the first target in the targetList with the parameter value. This is a direct replacement – the entire value will be replaced with whatever value was selected for Type.

Note that there is also a default value here. This is used for when a value has not been selected (i.e. when the interval trigger detects changes).

This is a very simple example of a pre-defined value that entirely replaces the existing value. Now, let’s see some of the other parameter types.

A Numeric Parameter – Gendarme Limit

The next thing I’ll show is how to use a numeric parameter value. Again, this needs to be defined at the project level in the parameters block:

 1<parameters>
 2  <!-- Omitted to save space -->
 3  <numericParameter name="GendarmeLimit">
 4    <description>The limit of Gendarme errors.</description>
 5    <minimum>50</minimum>
 6    <maximum>500</maximum>
 7    <default>100</default>
 8  </numericParameter>
 9</parameters>

This says we want to also have a GendarmeLimit parameter, this is a numeric value and must be between 50 and 500. The default value will be 100.

To use this, it is the same as the target type, just add a direct replacement dynamic value:

 1<gendarme>
 2  <!-- Omitted to save space -->
 3  <dynamicValues>
 4    <directValue parameter="GendarmeLimit" 
 5                 property="limit">
 6      <default>100</default>
 7    </directValue>
 8  </dynamicValues>
 9</gendarme>

Note, the value will automatically be converted into the correct data type for use in the task. If there is a data type mismatch (e.g. a test value is put into a numeric property), then the build will fail with an error.

Now, let’s add one more parameter – one that doesn’t use direct replacement.

A Build Reason

This is a bit of a contrived example, but here we are going to pass a reason for the build into the NAnt task.

First, let’s define the parameter:

 1<parameters>
 2  <!-- Omitted to save space -->
 3  <textParameter name="Reason">
 4    <description>Reason for the build being forced.</description>
 5    <minimum>10</minimum>
 6    <maximum>255</maximum>
 7    <required>true</required>
 8  </textParameter>
 9</parameters>

This is a text parameter with a minimum length of 10 and a maximum length of 255.

This time, to use the parameter we are going to use a replacementValue:

 1<nant>
 2  <!-- Omitted to save space -->
 3  <dynamicValues>
 4    <!-- Omitted to save space -->
 5    <replacementValue property="buildArgs">
 6      <format>-D:"{0}"</format>
 7      <parameters>
 8        <namedValue name="Reason" 
 9                    value="Triggered" />
10      </parameters>
11    </replacementValue>
12  </dynamicValues>
13</nant>

This has the same property attribute, but otherwise is very different. A standard .NET format string is required (internally this is literally passed onto string.Format()!) And there is also a list of parameters to use. As you might have guessed, this dynamic value can use multiple parameters. If a property needs to use more than one parameter, then this is the syntax that is required.

Note for the parameters a namedValue is used. The name is the name of the parameter, while the value is the default value. This is needed because there can be multiple parameters, each with its own default value!

Scheduling A Prod Build

The final item I’ll cover is how to use parameters together with triggers. In this case, I’m going to schedule a build every night that uses the Prod target.

This is fairly easy to do, all we need to do is add a new parameterTrigger that contains the schedule trigger. The following shows how to do this:

 1<triggers>
 2  <intervalTrigger />
 3  <parameterTrigger>
 4    <trigger type="scheduleTrigger">
 5      <time>1:00</time>
 6      <buildCondition>ForceBuild</buildCondition>
 7    </trigger>
 8    <parameters>
 9      <namedValue name="Type" 
10                  value="Prod"/>
11      <namedValue name="Reason" 
12                  value="Scheduled"/>
13      <namedValue name="GendarmeLimit" 
14                  value="500"/>
15    </parameters>
16  </parameterTrigger>
17</triggers>

This will schedule a build every night at 1am and pass in “Prod” for the Type, “Scheduled” for the Reason and 500 for the GendarmeLimit.
The Final Configuration

Hopefully this has provided a quick introduction to how parameters and dynamic values can be used. If you can think of how this can be improved, let me know and I’ll see what I can do.

And to finish up, here is the complete configuration:

 1<cruisecontrol>
 2  <project name="Test Project">
 3    <description>A demonstration project to show the features of the dynamic build parameters.</description>
 4    <sourcecontrol type="svn">
 5      <trunkUrl>svn://svn.mycompany.com/firstproject/trunk</trunkUrl>
 6      <workingDirectory>C:\SourceControl\FirstProject\</workingDirectory>
 7    </sourcecontrol>
 8    <triggers>
 9      <intervalTrigger />
10      <parameterTrigger>
11        <trigger type="scheduleTrigger">
12          <time>1:00</time>
13          <buildCondition>ForceBuild</buildCondition>
14        </trigger>
15        <parameters>
16          <namedValue name="Type" 
17                      value="Prod"/>
18          <namedValue name="Reason" 
19                      value="Scheduled"/>
20          <namedValue name="GendarmeLimit" 
21                      value="500"/>
22        </parameters>
23      </parameterTrigger>
24    </triggers>
25    <tasks>
26      <nant>
27        <buildFile>App.build</buildFile>
28        <targetList>
29          <target>Dev</target>
30        </targetList>
31        <buildArgs>-D:reason=testing</buildArgs>
32        <dynamicValues>
33          <directValue parameter="Type" 
34                       property="targetList.target[0]">
35            <default>Dev</default>
36          </directValue>
37          <replacementValue property="buildArgs">
38            <format>-D:"{0}"</format>
39            <parameters>
40              <namedValue name="Reason" 
41                          value="Triggered" />
42            </parameters>
43          </replacementValue>
44        </dynamicValues>
45      </nant>
46      <gendarme>
47        <assemblies>
48          <assemblyMatch expr="*.dll"/>
49        </assemblies>
50        <limit>100</limit>
51        <dynamicValues>
52          <directValue parameter="GendarmeLimit" 
53                       property="limit">
54            <default>100</default>
55          </directValue>
56        </dynamicValues>
57      </gendarme>
58    </tasks>
59    <publishers>
60      <rss />
61      <xmllogger />
62    </publishers>
63    <parameters>
64      <rangeParameter name="Type">
65        <description>The type of build to perform.</description>
66        <allowedValues>
67          <value>Dev</value>
68          <value>Test</value>
69          <value>Prod</value>
70        </allowedValues>
71        <default>Dev</default>
72      </rangeParameter>
73      <numericParameter name="GendarmeLimit">
74        <description>The limit of Gendarme errors.</description>
75        <minimum>50</minimum>
76        <maximum>500</maximum>
77        <default>100</default>
78      </numericParameter>
79      <textParameter name="Reason">
80        <description>Reason for the build being forced.</description>
81        <minimum>10</minimum>
82        <maximum>255</maximum>
83        <required>true</required>
84      </textParameter>
85    </parameters>
86  </project>
87</cruisecontrol>