Still Downtime
We’re still waiting on the 1.4.3 release, so I thought I’d try and implement another of my ideas. At the moment the implementation isn’t perfect – I know it needs some fine-tuning – but it provides another interesting possibility for what we can do with CruiseControl.Net.
Packages
I spent three years working for a university here in New Zealand, so I’ve had some experience with content management in this field. One of the concepts that’s been around for a while is the concept of a package – a set of files that are related, plus a manifest describing these files (and how they can be used). These packages are normally stored as a ZIP file to allow ease of transport.
The reason for a package is to enable blocks of content to be passed around easily. You’re setting up a new course, and discover that someone else has already written a module on one of your topics. Rather than re-writing the whole module, you just import the content package into your Learning Management System.
As you can see packages simplify knowledge transfer and make it easier for people to use it. Now in CruiseControl.Net we’re not interested in learning content (or at least most of us aren’t), but we do have build artefacts – the results of a build process. It would be nice to have some simple and easy way to transfer these around.
Packages for CruiseControl.Net
I thought I’d implement packages for CruiseControl.Net. A package can be defined as a group of files in a ZIP archive, that may or may not include a package manifest. The manifest lists all the files, plus contains a header detailing the build that generated the manifest (this is an area that probably needs a bit more work).
Since I wanted to give people control over what is packaged, I have added a package publisher. This is an example of how a package is defined:
1: <package name="Binaries" manifest="true">2: <files>3: <file>deploy\*.sql</file>4: <file>deploy\*.msi</file>5: </files>6: </package>
The key attribute is the name – this will be the name of the package when it is generated. I’ve made the package so the manifest is optional, and this example shows how to turn it on.
The other important part of the definition is the files element. This defines which files should be included in the package. In the example I’ve shown how a wild card can be used for the file list, additionally individual files can also be specified.
There are a few more options for the publisher. The full list is:
| Name | Type | Description |
| name | string (required) | The name of the package. |
| compression | integer (optional) | The compression level to use. This must be a value from 0-9, where 9 is the highest compression. The default value is 5. |
| always | boolean (optional) | This records whether a package should always be generated. If this is off, then a package is only generated for successful builds. If this is on, then a package is generated whether the build succeeds or not. The default value is false. |
| flatten | boolean (optional) | Whether to flatten the file structure in the package or not. If this flag is off then the directory structure is also included, otherwise just the file names are included. The default value is false. |
| single | boolean (optional) | Whether a package should be generated for each build, or just one package for the project. If this flag is off, then a package file is generated for each build and stored in the artefacts folder under a new folder for the build. This is useful for maintaining a history of the packages, but can result in a large number of packages accumulating. If this flag is on, then only one package will be generated. When the package is published, it overwrites the previous package. The default value is false. |
| fromWorking | boolean (optional) | Sets whether to get the source files from the working folder (true) or the artefacts folder (false). The default value is false. |
| manifest | boolean (optional) | Whether to include a manifest file (true) or not (false). The default value is false. |
| files | string array (required) | The files to include. |
I’ve tried to cover all the most obvious options, but like I said earlier, it still needs a bit of polish.
The following shows the package that is generated in this example:
Since I didn’t set the “single” option, it will be created in its own folder underneath the artefact folder.
Viewing Packages
Generating the packages is only half the group – the other half is to make these packages easier available to the users of the system.
To achieve this there are two places these packages need to be: in the dashboard and in CCTray. As such I’ve made a couple of changes to ICruiseManager to allow transmitting files (I could have done it via a shared folder, but that always assumes folder will be available, which might not be the case over the Internet). I’ve also added a method to retrieve a list of files. I’ll go into the technical details in a future post, but here are some shots of how it works.
First, the package list is available from CCTray by right-clicking on a project:
I have added a menu option called “Packages”, plus a short-cut key for it. Clicking on this option will bring up the list of packages:
This contains some obvious data (name, date and size), plus the build that the package is from. Double-clicking a package, or clicking on the download button (the little globe with an arrow) will first prompt the user for a download location, and then download the package.
The dashboard also allows downloads of packages, although in a slightly different way. Instead the list of packages is included on the project status, and are downloaded by clicking on the link.
Under the Hood
As a final note, I’ve implemented this functionality using #ZipLib from the #Develop team. It works nicely and without any issues.
The transfer of files across .NET Remoting is a little, since passing a stream is not recommended. Instead a stream “rip-off”, that provides similar functionality. This means it’s up to the client to control how data comes across.
Finally, the storage of the files is just in the file system. The more I play around with CruiseControl.Net, the more I question it’s reliance on the file system for all storage. It would be nice to have a centralised data store that could be accessed by the different parts without going through either the file system or the server, but I guess this is a topic to look at in future.
Where’s the Code?
At the moment this code isn’t publicly available. The reason why is simple: I started playing around with this before the change freeze (although I didn’t get far), and as such it’s based on the trunk code. Now that the change freeze is in place, I can’t deploy it until the release
So until the change freeze is lifted, this code will have to wait…
In meanwhile, I’ll look at writing a post that dissects how this functionality works. That way i won’t forget how it works either!
RSS - Posts