We’ve Updated the Current Stuff Too!
As well as adding new functionality, we’ve also taken some time to improve some of the existing components. Some of these improvements are corrections (i.e. making things work like they should have originally), others are brand-new.
Areas that have been improved include: the validator, configuration, source control, the console/service and the RSS feeds.
The validator was originally added in the 1.4.3 release, but unfortunately due to an oversight by the development team (actually, by me!) it was not included in the normal distribution. Instead the code needed to be downloaded and compiled (not good for non-developers!)
This has now been fixed and the validator will be installed as part of the normal server install. As well as the console and uninstall short-cuts, a new short-cut will be added for the validator (CCValidator). Additionally, the validator now has its own separate installer – so it can be installed without also installing the server components (or the dashboard). Hopefully this will make it easier to get the validator and use it.
As well as tidying up the install process, the validator now offers some internal validations. Previously the validator would only validate that the file could be loaded (i.e. there were no load errors), it wouldn’t perform any checks to ensure that the settings were actually valid. Now the validator will start to offer some internal validation, and we certainly plan on improving this in future releases.
This is kind of an overflow from the validator, but we’ve also tried to make errors in the configuration easier to understand. This involved some work on NetReflector (since this is what converts the XML into the .NET objects), and mainly involved adding more meaningful messages.
In a nutshell, we’ve tried to replace any generic exceptions with specific NetReflector exceptions. These exceptions provide some more information on the error (e.g. unable to convert to specified type, base types do not allow attributes, etc.), plus they also include the erroneous XML element. This information will make it easier to track the problem (where do we start with a NullReferenceException!) and hopefully easier to pinpoint the exact cause.
However, this is a work in progress – we can’t guarantee we’ve got all the exceptions covered. So if you find any errors that don’t make sense, feel free to let us know.
In the 1.4.3 release we finally started logging errors with source control. This certainly opened a can of worms as a lot of installations worked on the assumption that source control errors were ignored.
Based on the feedback we’ve added a couple of new options to define how source control errors should be handled.
stopProjectOnReachingMaxSourceControlRetries (yes, it’s a long name) controls what happens in the next stage. If this is set to true, then the project will be stopped. This allows an administrator to work out what is wrong and then fix things without overloading the source control server. Setting it to false means the project will continue running.
sourceControlErrorHandling defines the options for what happens when an error occurs. The valid options are:
- ReportEveryFailure – this is the current functionality of 1.4.3 – every source control exception will be reported.
- ReportOnRetryAmount – only report once when the maximum number of attempts has been made. Any subsequent errors will be ignored.
- ReportOnEveryRetryAmount – only report when the maximum number of attempts has been made. After this the counter is reset and the error reported again after the next number of attempts has failed.
The retry attempt counter is always reset back to zero after a successful source control operation – no matter which option is chosen.
Additionally cleanUp and revert options have been added to the Subversion source control block.
Both the console and the service now have the ability to hot-swap DLLs. This is similar to ASP.NET where a binary can be x-copied into the folder and the application will automatically restart.
This feature has been added to make it easier to upgrade running instances of CruiseControl.NET. Previously the server (either console or service) would need to be stopped, the binaries copied over and then the server restarted. Now it is just a simple matter of copying the new binaries in and the server will take care of the rest.
The only file that cannot be copied over is the application executable (e.g. ccnet.exe or ccservice.exe).
Previously the RSS publisher in CruiseControl.NET only reported on the last build – previous builds were overwritten. The publisher now can publish multiple builds – which allows the feed to have a history of what has happened.
By default, the last twenty builds will be in the RSS feed, but this can be configured by adding an items property to the task.
So, as well as adding new functionality, we’ve been tweaking the existing functionality to make things easier. However these new tweaks and features will remove some of the headaches people have been having.
As always, if you find any issues or problems, please let me know and I’ll look into them.
Now, this pretty much wraps up a lot of the changes for 1.4.4 (excluding bug fixes). At the moment we’re preparing for a second RC and then we will do the final release! So, please try out RC2 when it comes out and let us know if you find any issues. Otherwise, we’re gearing up for 1.5.0 (and that will definitely be an exciting release!)
Gendarme, NDepend and ZIP Files
Previously in CruiseControl.NET we have shied away from adding new tool-based tasks in CruiseControl.NET. This has mainly been because these tools have third-party dependencies, a lot of which we cannot guarantee their availability.
However, this approach has made things harder for administrators. The administrator needs to modify the build script to execute the tool, and then they need to modify the config to merge the results from the tool. It places the onus on the administrator to ensure the correct files are merged.
We are now trying a new approach and started adding some tool-based tasks to CruiseControl.NET. As well as executing the tool, these new tasks will merge all the results from the tool (including non-XML files). Now an administrator just needs to add the relevant task to ccnet.config and everything else is handled (although it is still possible to do things the old way as well).
In the 1.4.4 release we have added two new tasks and a new publisher.
Gendarme is a tool produced by the Mono project to inspect assemblies for common problems. The full details on this tool is available at http://mono-project.com/Gendarme.
This task will run the Gendarme tool and then merge the results. The tool is highly configurable (http://confluence.public.thoughtworks.org/display/CCNET/Gendarme+Task has the full details on what is available). Additionally there are now some Gendarme reports that can be included in the dashboard – including a package to install them.
The following is a brief example of how this tool could be configured:
<gendarme><executable>Tools\gendarme.exe</executable><assemblies><assemblyMatch expr='*.dll' /><assemblyMatch expr='*.exe' /></assemblies><limit>200</limit><failBuildOnFoundDefects>true</failBuildOnFoundDefects></gendarme>
This will run the Gendarme application (tools\Gendarme.exe) and analyse all the .dll and .exe files in the working folder. It will report a maximum of 200 defects and fail the build if any defects are found.
I’ve already posted recently on this task (read it here), so I won’t go into too many details. As the basic details, NDepend is a third party tool to analyse a code base for complexity (their website is http://www.ndepend.com/). This new tool will run the application (again with a full set of options) and then merge the results, plus there is a dashboard package to automatically install the reports.
One of the major enhancements for this task is not in the actual task itself, but in the dashboard. As part of the reporting phase of NDepend it generates a number of helpful images. Previously, these images have not been available in the dashboard (or at least not available with a work-around.) The 1.4.4 release now allows these images to be displayed, so the NDepend reports are available in their full glory.
Since this is a general fix, it also means that images can be displayed for other reports as well. Sometime in the future I’ll write a post on how this works, so other reports can also utilise this functionality.
The following is a brief example of how this task could be configured:<ndepend><project>NDepend-Project.xml</project><executable>tools\NDepend.Console.exe</executable><emitXml>true</emitXml><outputDir>NDepend-Reports</outputDir><baseDir>project\</baseDir></ndepend>
This will run the NDepend application (tools\NDepend.Console.exe) on the NDepend-project.xml file (this will need to be generated using NDepend). The base directory for the tool will be the project folder under the working folder and the results will be written to NDepend-Reports.
Full details on the NDepend task are available at http://confluence.public.thoughtworks.org/display/CCNET/NDepend+Task.
Package (ZIP) Publisher
It has always been possible to generate ZIP packages of files in CruiseControl.NET – just not directly from CruiseControl.NET itself (normally it’s been done via a NAnt, MSBuild or other build script task.) The 1.4.4 release now includes a built-in ZIP package generator.
This publisher will compress the specified files into a single ZIP file. The options include the level of compression, the files to include (including wild-cards), and whether to include the directory structure or not. This will generate the ZIP file, copy it to the artefacts folder and add it to a list of generated packages for the project (this list will be utilised more in future releases.)
One of the additional feature for this publisher is the ability to generate a manifest. A manifest is a list of all the included files, plus additional metadata. CruiseControl.NET uses manifest files in the dashboard packages to control the installation of the package, just to provide one example of how a manifest can be used.
Rather than forcing a set format for the manifest, it is possible to choose a manifest generator (or even write one of your own.) Currently there are only two choices – a custom format that just lists the files plus some build metadata, or a manifest importer. Hopefully in future we’ll expand the number of options (including the ability to generate a dashboard package manifest.)
The following is a brief example of how this publisher could be configured:<package><name>Binaries</name><compression>9</compression><manifest type="defaultManifestGenerator" /><files><file>*.dll</file><file>*.exe</file></files></package>
This will compress all the .dll and .exe files from the working folder and store them in a ZIP file called binaries.zip using maximum compression. Additionally it will generate a CruiseControl.NET style manifest.
Again, full details on this new publisher is available on Confluence at http://confluence.public.thoughtworks.org/display/CCNET/Package+Publisher.
A Quick Wrap-Up
In this post I’ve briefly mentioned the two new tasks and the new publisher for the 1.4.4 release. We are working on adding additional tasks and expanding the current functionality for future releases, so if you think there are other tools we should integrate into CruiseControl.NET let me know.
Looking at the Competition
CruiseControl.NET is not the only Continuous Integration (CI) server available – both on the .NET scene and outside of it. One of the items that people like about some of our competitors is their ease of configuration and simplicity to learn. Of course, I still think CruiseControl.NET is one of the best CI servers around, but they obviously have a good selling point here!
To try and make things easier for people we have added a new plug-in to the dashboard – a web dashboard administration plug-in. This plug-in is designed to simplify administration of the dashboard (sorry, nothing on the main config … yet!)
This plug-in has three main areas:
- remote servers
- reload dashboard
The dashboard is actually independent of the CI server – it doesn’t even need to be on the same machine (by convention a lot of people leave it on there, but it doesn’t need to be.) This is configured by the <remoteServices> element in dashboard.config, and it is possible to not only connect to a remote server, but multiple remote servers.
The new plug-in allows an administrator to add, modify or delete remote servers – all within the plug-in. As soon as a server is added, modified or deleted, the configuration is updated and the new details are available. There is no validation on the servers, but it will be obvious very quickly in the main grid if a server is incorrect!
The second area – packages – is completely new to CruiseControl.NET. Previously, adding a new report or plug-in involved a series of manual steps. These steps could have included copying one or more files and modifying dashboard.config. The problem with a set of manual instructions is the ease at which they can be screwed up (copied the wrong file to the wrong place, or misspelt a configuration element).
To remedy this we have added packages to the dashboard. A package is a ZIP file containing all the required files, plus an instruction manifest telling the dashboard what to do. There is no longer any need to have a manual set of instructions to follow.
Adding a package is a two-step process. First the package must be uploaded to the server (loading a package). This just copies the package file and updates the list of packages – it doesn’t make the new functionality available. To enable the functionality the package must be installed. This is as simple as clicking on the package and choosing install – the dashboard handles everything else!
And another great point about packages – they are reversible! You can uninstall a package (which will remove the files and configuration elements) and even unload it from the server.
Currently the following packages are available:
- Fitnesse Results
- FxCop Results
- Gendarme Results
- Modification History
- MSBuild Results
- MSTest Results
- NAnt Results
- NCover Results
- NDepend Results
- NUnit Results
- Project Configuration Display
- Project Statistics
- Queue Status Display
- Security Configuration Display
- Server Configuration Display
- Server Information Display
- Server Log Display
- Simian Results
- User List
- Web Dashboard Administration
Over time we will add more packages and also additional functionality to the way they work.
As well as using the remote services and packages functionality, it is possible to do a configuration reload. This is needed for one simple reason – the configuration is cached!
For performance reasons, the configuration is only loaded when the application is started. Subsequent calls to the dashboard uses the cached configuration. This then causes a problem when dashboard.config is modified. Unless the web application is reloaded (i.e. by restarting the web server), the new configuration is ignored!
The reload dashboard commands allows us to get around this problem. An administrator can manually modify the config file and then click on reload dashboard to force a reload of the configuration.
This new plug-in is reasonably powerful, but with great power comes great responsibility (guess the movie!) With this plug-in it also makes it incredibly easy for something to screw things up in the dashboard (either by accident or on purpose!) To limit this, it is possible to set a password on the plug-in so only authorised people can access it.
This password is set for the entire dashboard (it is independent of the security changes for 1.5.0) and is set in dashboard.config. To set a password merely add a password attribute to the <administrationPlugin> element. The value of the attribute is the password.
If this element is empty or missing, then anyone can access the plug-in.
Since 1.4.4 is a mainly a fix release this plug-in is not enabled by default. Instead an administrator will need to manually modify dashboard.config. The <administrationPlugin> element will need to be added to the <farmPlugins> element (including setting a password if required).
Once this element has been added, then the web server will need to be restarted to load the configuration. And the new plug-in is ready to go.
So, I hope this makes things easier for any administrators out there (and any plug-in developers). Let me know if there is anything we can do to improve it.
A Quick Intro
As well as a number of bug fixes, we’ve added some new functionality to 1.4.4. Most of this functionality as been around for a while, mainly in the security branch, so I thought I’d review some items. Over my next few blog posts I’ll look at some of the new items that have been added, and the possibilities they open up.
One of the great things about CruiseControl.NET is its flexibility, and if the trunk distribution doesn’t contain what you want, it’s pretty easy to add your own extensions. The only real limitation is the allowed places for extensions – they are limited to being items in the configuration file (ccnet.config), like tasks, source control, triggers to name a few common ones.
With release 1.4.4 it is now possible to build a “global” extension to the server. These extensions have nothing to do with ccnet.config, instead they are added in the application configuration (ccnet.exe.config or ccservice.exe.config).
These extensions work at a deeper level than the older extensions. The older extensions had to work within the context of a build, they could affect the outcome of a build, but not how the actual server worked. The new extensions allow the actual functionality of the server to be modified!
Sounds exciting? I certainly think so!
These extensions now allow developers to influence how the server works, and allows developers to open new channels to the server.
As an example, currently in CruiseControl.NET there are projects and there are queues. It is possible to limit builds, but only by adding projects to a queue. If you wanted to limit the server so only five projects could build, no matter which queue, you were in trouble! Now with server extensions, we can build an extension to allow only five projects to build, no matter which queue they are in (and yes, I have built it).
A second possibility is to extend the logging. For example, an administrator might want to record all the force builds, or maybe just the number of times a project is stopped and started, or how often builds are triggered. Currently, they’d have to go through the log (assuming the correct log level is set) and manually count all the instances. Now, we could build an extension that just counts the number of force builds, stops, starts, etc. (sorry haven’t written this one yet).
The third possibility I can think of is with communications. Currently there is only one communications channel to the server – .NET Remoting (yes, there is HTTP, but this goes via the dashboard and still uses .NET Remoting to connect to the server). The new extensions now allow us to add any types of communications channels we want. I’ve built a simple one that uses WCF as the underlying channel, the only hard part was translating the objects – since I couldn’t add the WCF serialisation attributes to the existing types.
Time to Code
I’ve listed a few possibilities for the new server extensions, over time I’ll try to implement these and add a few more options to the list.
If you want to try and build an extension, I’ve started on the documentation (http://confluence.public.thoughtworks.org/display/CCNET/Server+Extensions), although I still need to work on it. In a nutshell, ThoughtWorks.CruiseControl.Remote.ICruiseServerExtension must be implemented (it only has four methods) and then the extension registered in the application config.
So have a play, let me know what you think. Also, I’m open to any ideas for extensions – just send me the idea and I’ll take a look at it.
A while back Patrick Smacchia from NDepend did an analysis of the code in CruiseControl.NET (read it here). I sent him an e-mail thanking him, and one thing lead to another, and before you know it I had volunteered myself to help integrate NDepend better with CruiseControl.NET.
You Did What? Why?
Now you’re probably wondering why I volunteered my time (yes, I don’t get paid to work on CruiseControl.NET). There’s a very simple reason behind it – I think NDepend is a awesome tool for getting information on what’s happening in your project.
Anyone who has worked in software development for a while knows about spaghetti code. This is code that has become some convoluted and twisted that it is a nightmare to maintain! Now, as a developer, I know we all code with the best of intentions, but sometimes code just seems to get “spaghetti”ed, and it’s even worse when we start talking about open source projects.
NDepend helps open a picture on what is happening in the codebase. It shows many different aspects where code can become twisted (I’m still learning about them) and Patrick has written several blog posts about how to use this information to clean up the code. Additionally, it can also provide an historical analysis. So not only can you see what your code is like, you can also see how well you are doing in making it better!
As you might have guessed, I’m very impressed with NDepend and the details it provides. If you are interested in finding out more, take a look at their website: http://www.ndepend.com/.
While it has always been possible to integrate NDepend into CruiseControl.NET it was a bit of a convoluted process. First, you needed to call NDepend from either Nant or MSBuild. Then you needed to merge the results from NDepend. And finally the dashboard needed to be set up. And to top it all off, it wasn’t possible to view the images from NDepend!
What I have done is added a new NDepend task. This will run the NDepend application (same as the Nant or MSBuild tasks), but directly from a ccnet.config. The added value comes after the execution – the new task will automatically publish the NDepend results, and merge the XML files. This means NDepend now only needs the single task within ccnet.config – instead of modifying the build script and then adding a merge publisher into ccnet.config.
I’ve also put together a package for the dashboard. This simplifies the administrator’s work in adding the results to the dashboard. All the administrator needs to do is go to the admin plug-in and load and install the package. No more messing about with copying files, changing configuration settings and restarting IIS!
As well as the NDepend-specific work, I’ve also fixed a more generic issue – displaying images in the dashboard.
First, a bit of background. CruiseControl.NET is divided into two parts – the CI server and the web dashboard. These can run on the same machine, or totally different machines, so we can’t assume that the dashboard can access any files that the CI server can. Therefore some way is needed to transfer files from one application to another.
To keep things simple, I added a new file transfer mechanism to the CI server. This means a remote client can now request files from the CI Server and they will be transferred using .NET Remoting (not the best way, but .NET Remoting is the only transport channel that the server currently has.) So now there is a way to transfer files, even if they are on different machines.
The second part is to add a new action to the dashboard that uses this file transfer. This is a simple project-based action that takes in a query string parameter saying which file to be transferred. When the action is processed, the file is fetched from the CI server and downloaded to the browser (all via streams, so nothing is stored locally).
To display the images, all I needed to do was to modify the XSL-T template to use the new action (it’s called RetrieveFile.aspx) and pass in the name of the file to display. Now the NDepend reports display all the text data and the images as well!
Tell Me More
The good news is this task made the cut for 1.4.4. So when 1.4.4 is released, the new task, package and image work will be available!
Full details on the new task are available at http://confluence.public.thoughtworks.org/display/CCNET/NDepend+Task. There are some instructions on how to integrate NDepend at http://confluence.public.thoughtworks.org/display/CCNET/Using+CruiseControl.NET+with+NDepend – this covers both the new and the old ways of integration.
Finally, I’m going to write a full tutorial on how to use NDepend and CruiseControl.NET together sometime. This will include a walk-through on how to do this, plus a full example.
And, as a final note, we’re looking to start using NDepend with CruiseControl.NET to tidy up our own code. As I play around with it and figure out things I’ll include them in my blog. (But I’m still catching up on things, so these blog posts might be take a while!)
A Quick Update
I haven’t written a post for while now – not because I haven’t done anything, but because I’ve been focusing on getting a lot of my work into the trunk (that and my son is taking a lot of my time).
So here is a quick update on what has finally made it into the trunk.
Some of my work was able to go into the 1.4.4 release. The following items have been included:
- Server extension points
- Simplified web administration
- Installation packages
- Package publisher
- NDepend task
- Extended source control exception handling
These changes have been added successfully and appear to be stable (let me know if there are any issues). Additionally I’ve also done a little bit of work on making the validator more useful (extended validation, its own installer, etc.)
These will all go out in the next release (hopefully soon!)
This is the exciting one as security has finally made it! We did take a little step back and decided not to add either the messaging or communications client code as yet. Some of the security relies on this code, so it hasn’t been implemented yet (still pending a decision on whether we add this in the 1.5.0 release or wait for a future release).
Additionally I have added the build throttling extension and the task status break-down (just finished tonight).
I’m going to add the dynamic build parameters over the next week or so and then that will be most of my work finally committed to the trunk (with the main exception of messaging/communications client.) After this it will be a time of settling down and resolving any issues that come up (especially with security).
Visual Studio 2008
The other great news is we finally converted to Visual Studio 2008 for the solution and project files. This has both made my life easier (hence the new additions) and also allowed us to start using C# 3.0.
While we have not moved to .NET 3.5 yet, this is still a great step forward!
So a lot of work is happening behind the scenes and we are looking forward to a new release soon!
The End of a Good Thing
This is the third and final part in my series of improving the administration for the web dashboard (the first two parts are here and here). In the first two parts I built a rough admin console, that allowed the following functionality:
- Reload dashboard configuration
- Add/modify/delete remote servers
- Load/install packages
I have now added the finishing touches and committed this to the trunk. In this post I’ll quickly cover what I’ve added.
Since this has the potential to totally screw up the dashboard, we don’t want every body to have access to it. Since I’m planning on releasing this in 1.4.4, now of the security framework is in place.
Since for the moment I’ve added a temporary fix to secure the dashboard admin. In the config file (dashboard.config) an administrator can set a password for this plug-in. This is done by adding a password attribute to the plug-in definition:
<administrationPlugin password="whoareyou" />
This then displays a login screen for the user:
When the user logins it will add a temporary cookie to the browser. This cookie is valid for 30 minutes, after this they will need to login again.
If there is no password, then the user will go straight into the admin page as per previously.
There is also a new Logout button in the commands section – for a secured admin section it will logout the user (i.e. expire the session cookie).
I have also completed the operations on packages. Clicking on an installed package will display the following options:
The Remove button is no longer available – this just made things more complicated.
Clicking on the Uninstall button does exactly that – it will completely uninstall the package:
Again, there is a log so people can see exactly what has been done:
Once a package has been uninstalled the “Remove” command is returned to the package options:
This removes the package from the server so it does not appear in the list anymore:
Which now gives the full load-install-uninstall-remove cycle for packages.
Hopefully this will simplify the maintenance of components within the dashboard, now it’s a simple automated process. This means less work for administrators and also less possibilities for error.
I’ve also made a couple of improvements to the manifest in the packages. First, attributes are included under an element – they can no longer be specified separately. Secondly, it is possible to add a filter to the elements – this handles the scenario where there are multiple elements with the same name (e.g. xslFile, xslReportBuildPlugin, etc.)
The following is an example for the NUnit plug-in:<package><name>NUnit Results</name><description>Display the results of a NUnit run.</description><type>Plugin</type><folders><folder><location>Xsl</location><files><file>unittests.xsl</file><file>tests.xsl</file><file>timing.xsl</file></files></folder></folders><configuration><setting><path>/dashboard/plugins/buildPlugins/buildReportBuildPlugin/xslFileNames</path><filter>.='xsl\unittests.xsl'</filter><name>xslFile</name><value>xsl\unittests.xsl</value></setting><setting><path>/dashboard/plugins/buildPlugins</path><filter>@xslFileName='xsl\tests.xsl'</filter><name>xslReportBuildPlugin</name><attributes><attribute name="description" value="NUnit Details"/><attribute name="actionName" value="NUnitDetailsBuildReport"/><attribute name="xslFileName" value="xsl\tests.xsl"/></attributes></setting><setting><path>/dashboard/plugins/buildPlugins</path><filter>@xslFileName='xsl\timing.xsl'</filter><name>xslReportBuildPlugin</name><attributes><attribute name="description" value="NUnit Timings"/><attribute name="actionName" value="NUnitTimingsBuildReport"/><attribute name="xslFileName" value="xsl\timing.xsl"/></attributes></setting></configuration></package>
This contains both filters and attributes. Without these two changes the package was getting confused and updating the wrong elements! Now it happily updates everything correctly
Some Initial Packages
I’m also in the process of building packages for the existing plugins. So far I have built the following plugins:
- Modification History
- NUnit Results
- Project Configuration Display
- Project Statistics
- Queue Status Display
- Server Configuration Display
- Server Information Display
- Server Log Display
- Web Dashboard Administration
Each of these plugins has a manifest file (these are in the project\WebDashboard\packages) plus a target in the Nant build script to generate the package. Each target will pull the necessary files and the manifest into a single package.
The files come from Project\WebDashboard, so the developers only need to worry about the main files. When the files are changed (e.g templates, supporting XSL, etc.), the build will automatically include the changes in the packages.
I’m still in the process of setting this up, but when I have finished the Nant script will generate all the packages, put them in the correct location and then add them to the installer. By default most of these packages are already installed, so the installer will also reflect this.
While I said this is the last post in the series, the work isn’t quite completed. I need to finish the build script to include the packages in the installer. I also have a few more packages to complete (mainly the build result packages). And then finally, I need to update the documentation.
But it’s already to go. When CCNetLive is back up, try getting one of the latest builds and try it out. Let me know if you find any issues or problems.