Team Foundation Build provides us with a nice editor where we can define parameters (both at design time and queue time) to influence the behavior of our builds and it is really easy to change them.
However sometimes we need to have a parameter shared across several build definitions. Using out of the box features we are forced to place the same value on all build definitions and if we wish to change the value we have to manually change all of them (we can always write some one off code that will replace the value in bulk).
If we want to share a parameter value across more than one build definition we have several choices at our disposal
- “hard code” the value in the build definition template, and when we need to change the value we just have to update the build definition template once. Simple, effective but not very visible since the value is hidden inside the build definition (not to mention it cannot be easily changed by non-power users)
- Store the parameters in a file stored in source control (for example an XML file or a file with an easy to manage format using a simple text editor). This way when the configuration file is changed every build definition that uses will pick it up immediately. This requires that you change your build definition to get the file from source control (you can use the built in activity DownloadFiles) and read the parameters from the file. This also has the traceability advantage (by having the parameters stored in source control, we have history, auditability and the ability to easily revert to previous versions).
- Store the configuration an a SQL database. For this you can write your own activity or use the SQL Server activities from the Community TFS Build Extensions
- Store the configuration on an external system accessible via Web Services (WF has built in support for this)
- Store the configuration in the TFS Registry, I’m not talking about the windows registry. I’m talking about the TFS registry, which is a feature that allows you to store settings (in a hierarchical manner) on a registry. There are two scopes for the registry, a collection registry or a server wide registry (also known as the configuration registry). The advantage of the registry is that it’s stored within TFS. Everything is integrated, when the database is backed so are your settings, everything is self-contained. The disadvantage of this approach is the fact there are no tool (out of the box) to read and write settings into the registry.
This post is all about option 5), to read values stored in the registry from your own build definition templates, you can use an activity that I’ve just committed to the Community TFS Build Extensions. The activity is called GetValueFromRegistry
To use the activity all you have to do is drag it to the canvas and provide two parameters (one of them being optional).
The Path parameter is mandatory and represents the path of the value you wish to read (for example TFS email notification address (if notifications are enabled) is stored in /Service/Integration/Settings/EmailNotificationFromAddress)
There are no rules regarding the use of paths, but it is wise to use a convention (but using /Configuration or /Service is not recommended).
You can use for example /Extensions/<CompanyName>/ as the base path for all your key values.
The Default Value parameter contains the default value that will be returned if the value is not defined (or if the user doesn’t have permission to read it).
The registry value or the default value will be returned on the Result parameter.
All parameters (including return) are strings.
Please notice registry reading as a little quirk. If the user doesn’t has permissions to read a given value no error will be returned, but no value will be returned either. So if the build user doesn’t has permissions to read a given value it will return the default value (or an error if no default value has been defined, see error below). Which means the build may fail if you can’t read a value and if have set the FailBuildOnError parameter to true.
The activity will first attempt to read the value from the collection registry, if no value is found then the server registry is attempted and if not found it will returned the default value (if defined).
Note: this activity is not yet available on the latest released version (v 1.1 released on September 2011), so if you want to use it you will need to download the source code and compile it yourself or wait for the next public release (v 1.2) that is scheduled for December
If you want to learn more about the TFS Registry, some of its semantics and how you can store values on the registry you can read more about on these two posts:
Thanks to Mike Fourie for proofreading and suggesting some improvements to this post.