Automated Coder

Exploring the Code of CruiseControl.Net

Posts Tagged ‘Web Dashboard’

Parlez-vous Français

Posted by Craig Sutherland on 16 December, 2009

A Long Time Ago…

Back in the 1.4 days, when we were still investigating what to put into 1.5, I looked into adding multi-lingual support to CruiseControl.NET. Basically I had hoped to make CruiseControl.NET available to more people, especially those who did not speak English (or for whom English was not their first language).

As nice as the idea was, there was one major snag – no translators :-( So after a while the idea died a death. Unfortunately, my linguist ability is extremely limited (I’m learning Chinese, but it’s a painful and slow process!) So when we started preparing for the 1.5 release, the multi-lingual changes were dropped.

Recently, one of our users asked how to switch languages in the dashboard. When we told him it couldn’t be done, he came back with an offer of translating into French for us! So I have dusted off some of the old archived code and re-added multi-languages to CruiseControl.NET.

Keeping It Simple

Now the original version of the multi-lingual changes started with the Remote project and worked their way up through Core, Server and then onto the Dashboard (CCTray was bypassed). This meant, in theory, an administrator could completely switch their CC.NET install into a different language.

While this was a grand vision, it had a few detractors. For one, should exceptions be translated? (I said yes, others said no.) What about documentation? (Especially considering our documentation needs some TLC anyway.) What about support? Testing? Etc.

So for this second attempt I have pared it right back. The only thing that is translated is the dashboard – everything to do with the actual CI server is untouched. This, hopefully, bypasses most of the above concerns, while still allowing non-English speakers to use the system.

Additionally, I changed the code slightly. Originally the language was hard-coded – everyone had to use the selected language. The new version uses the language detection in ASP.NET and selects the user’s primary language (as specified by their browser).

Now for the bad news – currently there is only one translation, French, and it is still a work in progress. So, if you speak French, here is what the dashboard looks like currently:

image

And just to show that it is different, if I change my language back to English:

image

Acknowledgements

As I mentioned earlier my linguist ability is virtually nil. Louis-Philippe Carignan is the kind volunteer who provided the French translation. Many thanks Louis-Philippe, I hope this helps you :-)

Posted in CruiseControl.Net | Tagged: | 4 Comments »

Timeline with Historical Data

Posted by Craig Sutherland on 10 December, 2009

After my last post I was asked if the new timeline plug-in works with existing data. The answer is yes – there were no server changes for this plug-in, it uses the existing server interfaces, it just provides a new UI on top the existing infrastructure.

Just to prove this works, I updated the installation at my work. This installation has been running since Apr 2008 (yes, before I started contributing to CC.NET). here is what the timeline looks like during one of our “busy” periods:

image

Again, I will repeat – this required no server changes! I did completely re-install the web dashboard for this plug-in, since it has a number of additional JavaScript and Image files that the package does not include (this “assumes” they are on the server). When we get around to doing some more work on the dashboard packages we can look at building a full package that includes all the additional files – but for now, I’m lazy ;)

Posted in CruiseControl.Net | Tagged: | 1 Comment »

Build Timeline

Posted by Craig Sutherland on 9 December, 2009

What’s Happening?

At my work we are playing around with a JavaScript widget called Simile Timeline (details on the widget are available at http://simile-widgets.org/wiki/Timeline). This is what provides the timeline in sites like http://www.ohloh.net. Basically, it provides a scrollable timeline, with events on it (these can be point events or durations). Clicking on an event will pop up a little “bubble” with extra details in.

Anyway, I thought that this is a nice fit for CruiseControl.NET – after all, builds are events in time. And since I need a change from working on documentation, I thought I’d take a look at what is involved in adding this to the dashboard.

Nice and Easy

Since this is a JavaScript widget, I downloaded the files and added them to the project. Next I added te plugin and action classes to the dashboard.

The action class performs two actions:

The first action is to generate the actual view. This is what the users see, so I added a status bar to provide extra details. This is a plain NVelocity template that generates some HTML. Additionally, there is a <script> section in it that initialises the timeline widget, loads the data and provides the status messages.

The second action is the data retrieval. The widget expects either an XML or JSON data file, so I choose XML (since it is already supported by the dashboard.) This file contains a list of events, the date they happened on, plus a title. For the dashboard, the title is just the status (success or failure), plus the build label.

And that’s all there really is to it. I added a few extra bits and pieces to try and make the user interface a bit more friendly. And like everything else, there is still some room for improvement. Currently clicking on a build just shows the date/time, the title plus a link to go to the view. In future it would be nice to have some extra details in this pop-up, but this will require some work on the back-end.

The Results

Here’s what the timeline view looks like:

image

Clicking on an event pops up the bubble:

image

And of course, the timeline can be scrolled:

image

That’s All Folks

So, that’s all there is to this plug-in. Nice and simple.

I personally like being able to see a timeline of events, what do other people think? If there is interest in this I’ll add it to the 1.5 release, otherwise it’ll wait until some undefined point in the future :-)

Posted in CruiseControl.Net | Tagged: | 2 Comments »

Debugging WebDashboard

Posted by Craig Sutherland on 2 December, 2009

One of the current issues with debugging WebDashboard is a developer needs to attach to the IIS process under which it is running, which assumes the developer has the right version of Visual Studio. Yuck!

Visual Studio 2005 and later comes with its own web server, which can be used for debugging. This is as easy as setting the web project as the start-up project and pressing F5 (or using the appropriate menu command). Everything else is handled automatically for the developer.

Unfortunately this doesn’t work for WebDashboard – instead an error pops up saying a DLL cannot be started directly. The reason for this history – CruiseControl.NET was originally a .NET 1.0 project and it has slowly been migrated over time.

So, why can’t we use the built-in web server? Because the project file has not been configured as a “web application” (does anyone remember those annoying web site projects?), so Visual Studio doesn’t know how to use the web server.

The good news, is this is very easy to change! While I was away I had a situation where I wanted to debug the dashboard, but couldn’t (I was having issues with IIS 5.0 on my laptop). So I poked around in the project configuration a bit and found this line:

<ProjectType>Local</ProjectType>

Looking at .NET 2.0 web projects (or later) they have a different line:

<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>

Things have changed a bit between 1.1 and 2.0 – and obviously the upgrade wizard couldn’t handle it.

So, replacing the first line with the second is all that is needed to upgrade to a proper web application, including being able to use F5 debugging.

Nice and simple, I really should have looked into this earlier!!

Posted in CruiseControl.Net, Inner Workings | Tagged: | Leave a Comment »

I’m Back: Holiday’s Over, Time to Write!

Posted by Craig Sutherland on 17 November, 2009

Back to Life, Back to Reality

I have returned from my annual visit to see the in-laws in China, and once again I have worked on some nice goodies to add to CruiseControl.NET (CC.NET).

This time I was looking at two specific areas:

  • Converting to streams for results
  • A Silverlight RIA

Stream-based Results (Project Ares)

The streams functionality is to try and resolve a long-time issue with running out of memory. Currently CC.NET performs all of its result processing in-memory as strings. This means when a task runs, it generates an in-memory version of the results (e.g. from stdout/stderr or from importing file results). These results are then appended to an ever-increasing copy of the log file, which is finally written out to disk. Now this is fine if 1) the results are small or 2) you have lots of memory, but this can cause problems if these conditions are not met! Additionally the same problem applies not only to generating the results, but retrieving the results!

The solution is simple in concept – instead of writing to memory, write directly to disk instead – hence changing to using streams instead of strings. However like any non-trivial modification, this has a number of far-reaching implications, so it was not as easy as just changing from generating streams to writing to streams.

However, the good news is I got it working, although it still needs a bit of polish to get it working nicely. And the other good news is I documented what I did along the way :-) So over the next few weeks I’ll be reviewing and publishing this documentation on my blog. These posts will be published under Project Ares.

Silverlight Client (Project Capricorn)

The other area I played with was writing a Silverlight 3.0 client for CruiseControl.NET. This was more of a fun project to see what was possible (although it didn’t help that I was offline and had to go by trial and error).

For this project I wanted a similar type of interface to the current dashboard. This allows people to view information at four levels: farm (all monitored servers), server, project and build. More challengingly it allows people to develop their own plug-ins (either via code or XSL-T) and use these within the UI.

As well as implementing a basic dashboard-like UI, I wanted to lever some of the rich functionality that is available in Silverlight – things that are possible in HTML/CSS/Javascript, but are challenging to do.

So, I have put together a very rough implementation of a Silverlight client, although it is very much at a prototype stage. This allows for the basics of the UI (layout, navigation, etc.) plus a plug-in infrastructure for adding new plug-ins. Unfortunately both need work to get up to release level.

So, once I have finished writing about the stream changes I’ll write up about the Silverlight client under Project Capricorn. Hopefully there will be some interest in it, so we can look at completing the project and including it in the official codebase (probably for CC.NET 2.0). Otherwise I’ll move it to the FastForward.NET project and work on it as I have time.

But Wait, There’s More!

Another area that I’ve been slowly working towards for a while now is the ability to make CC.NET distributed. CC.NET as it currently stands has some distributed elements, but it doesn’t really work as a distributed application. Some of the changes I’ve been working on (messaging, hot-upgrades, etc.) have been pieces of the distributed puzzle. The streaming work added a couple more pieces of the puzzle, plus showed a few more challenges to be resolved!

So I’ll be adding a few posts on enhancing CC.NET to be distributed – either some of the issues involved or some of the pieces that have been added. Hopefully by the time we (finally) get to the 2.0 release CC.NET will be able to work as a distributed application :-)

That’s All For Now

So that’s what I’m planning on writing up over the next few weeks. At the same time I’ll be adding the source to SourceForge (under the CCNet2 branch) and hopefully spending some time with the other devs on getting CC.NET ready for the “official” 1.5 release.

Stay tuned…

Posted in CruiseControl.Net, Project Ares, Project Capricorn | Tagged: , , , , | Leave a Comment »

The Dashboard and IIS 7.0 (or later)

Posted by Craig Sutherland on 21 October, 2009

Anyone who has installed CruiseControl.NET under Windows Vista or Server 2008 knows that CruiseControl.NET does not like IIS 7.0 (or later). The problem is very simple – IIS 7.0 uses an integrated pipeline for processing ASP.NET requests, while IIS 6.0 uses an ISAPI filter. This simple change introduced a new section in the web.config for integrated applications – system.webServer.

Just to complicate things the dashboard overrides the .aspx extension, basically so it can do it’s own version of MVC. When IIS 7.0 starts up it attempts to validate the configuration. It comes across the new HTTP handlers and basically says “I don’t know what to do!”.

The solution is actually very simple, just add the following section to web.config:

<system.webServer>
  <validation validateIntegratedModeConfiguration="false" />
  <handlers>
    <add verb="*" path="*.aspx" type="ThoughtWorks.CruiseControl.WebDashboard.MVC.ASPNET.HttpHandler,ThoughtWorks.CruiseControl.WebDashboard" name="CCNetHttpHandler"/>
    <add verb="*" path="*.xml" type="ThoughtWorks.CruiseControl.WebDashboard.MVC.ASPNET.HttpHandler,ThoughtWorks.CruiseControl.WebDashboard" name="CCNetXmlHandler"/>
  </handlers>
</system.webServer>

The validation element tells IIS 7.0 not to validate the old IIS 6.0 settings, while the handlers element adds the required handlers for the dashboard. Simple!

Now, in theory the dashboard should work from an install without anyone needing to change any settings :-)

Posted in CruiseControl.Net | Tagged: | 1 Comment »

Dashboard Caching

Posted by Craig Sutherland on 1 October, 2009

Previously

In my last post (read it here) I took a holistic approach to reducing memory usage on the (server) machine. In it I suggested three items to reduce memory usage:

  1. Caching on the dashboard
  2. Caching on the server
  3. Compressing the build logs

In this post I’ll look at implementing the dashboard caching.

To help with the recap, here is a diagram from my last post:

image

Basically this is stating most of the views to a log will be to the most recent (failed) build, less views to the last successful build and even fewer views for historical builds. This means most of the effort can be focused around caching a very small set of builds.

Introducing Caching

For caching, the first question is what should be cached.

When a request is processed for a build report it goes through this general process:

image

The request comes in, the process retrieves the log from the server, generates the build request (the actual report) and returns it to the client. I’ve put the generation into a black box, because that’s how I’m going to treat it (it is a complex process within the box). With this simplified view, there are two obvious cache options:

image

When the process needs a log, it can check the log cache first. If there is a log there, then this log will be used – otherwise it will fetch the log from the server, store it in the cache and then continue.

The second cache is to bypass the entire process – to cache the result and use it. When I investigated the dashboard further I discovered that build reports are already cached (this is via an action proxy – CachingActionProxy.) This proxy action caches each build response into the cache using the raw URL of the incoming request. Since this is working at the moment, I’m not going to change it. I’m not sure how this will work with security in place – so this will need to be investigated.

Before I delve into the implementation, there is an issue that needs to be considered. Retrieving a log can potentially be long-running processes (i.e. it takes more than a few milliseconds to perform.) The last thing we want is multiple users attempting to access a log almost simultaneously and trigger the same process multiple times! Because of this, the design needs to take into account potential race conditions.

Fetching and Caching the Log

The build logs are loaded in BuildRequestTransformer. This is the class within the dashboard process that is responsible for fetching the logs and generating the results – although it passes on these tasks to two very different places.

Within this class there is one method that needs to be modified – Transform(). This method currently looks like:

string log = buildRetriever.GetBuild(buildSpecifier, sessionToken).Log;
return transformer.Transform(log, transformerFileNames, xsltArgs);

Since I am changing the way the logs are retrieved, I’m going to change it to:

var log = this.RetrieveLogData(buildSpecifier, sessionToken);
return transformer.Transform(log, transformerFileNames, xsltArgs);

Of course, all the fun happens in RetrieveLogData() (the rest is just tidying things up.)

So, what happens in RetrieveLogData()? First, a unique cache key is generated. This is the combination of the server, project and build names, plus the user’s session token (if there is one). The session token means we’re going to a per-user cache, but unfortunately it is required since each user could potentially see different information.

Once the key is generated, the method checks if there is already a log under that key – if so it will use that log. If not, it generates a new instance of a SynchronisedData, adds this to the cache and then loads the log from the server.

And that’s all there really is to it – nice and simple.

What about SynchronisedData?

You might have noticed I have added a new class – SynchronisedData (or you might have just assumed that it already existed – I’m good with either.) This class is responsible for ensuring that only one instance of the data exists (or at least tries to.)

Basically, this class allows data to be added to the cache before it is retrieved. Internally it uses a ManualResetEvent to let any other threads know when it is safe to use the data. There is of course a catch – if a thread does not initialise the instance (e.g. retrieves it from the cache), it must call the WaitForLoad() method before retrieving the data – otherwise there might not be any data to use.

Otherwise this class is very simple, it has a single property – Data, plus a couple of methods – WaitForLoad() and LoadData(). WaitForLoad() just makes sure it is safe to use the Data property, while LoadData() allows the caller to load some data into the property.

The caller that initialises the instance is responsible for loading the data via the LoadData() method, all other callers need to use WaitForLoad() to ensure it is safe to use the data.

A Final Word on Caching

Someone might look at just this post and ask why am I suggesting caching as a solution for memory usage? Caching generally increases memory usage, since a process is generating and storing items, instead of just generating and disposing them.

And I have to agree. I expect memory usage to go up on average with these changes. The key phrase in that sentence is “on average”. The basic problem I think is happening is we are getting memory spikes. A number of people are trying to access the same log at the same time – therefore the server and the dashboard are generating multiple copies of the same log and then generating multiple copies of the same report.

Caching solves this problem by exposing the same log and the same report to all users, rather than a copy of the log and report. It does open some possibilities on race conditions (hence the locking code) and also increases average memory usage. But it should (hopefully) stop out of memory exceptions – which can really ruin someone’s day :-)

And a Final Comment

There was a comment on my last post about clearing the cache when the configuration changes. For the log files, this is not an issue as it will be the same log (always, no matter what, logs NEVER change!) But, the build reports might change. Since this is handled by an already existing handler, I’m not sure whether it will handle config changes (my guess is it won’t.)

In my next post I’ll look at making some changes to the server, so stay tuned…

Posted in CruiseControl.Net | Tagged: | Leave a Comment »

Cutting Down the Memory

Posted by Craig Sutherland on 30 September, 2009

The Problem

This is a continuation on my earlier post on memory issues (read it here). In that post I made some minor changes to reduce memory usage (mainly around string handling). However those changes didn’t fix the underlying problem – CruiseControl.NET is working with large strings in memory.

Now normally the OS and .NET will allow us to play around with large objects in memory without too many issues. Normally…

Sometimes it is possible to use up all the available memory (including swap files, etc.) Why? Because we put too many big strings into memory – and that’s exactly what CruiseControl.NET does. And to make things worse, CruiseControl.NET likes to compound things by the way it works.

So, how does CruiseControl.NET work?

First off, we have the server. This is basically a polling application – every five seconds it checks if a build can start and if so, triggers the build (actually it’s a little bit worse than that, each project has it’s own thread which polls every five seconds, but that’s another matter altogether.) As the build runs it builds up a set of task results, which then get merged together into one big log file:

image

So, it is possible to have multiple projects, each having multiple large task results in memory. Then, when these get merged into the build log, that’s even more memory used. But wait, there’s more!

As well as the project threads, the server is also responsible for serving results to anyone who requests one of these build logs. This is done by loading the log into memory and then returning the entire log (via .NET Remoting) to the client:

image

So, as well as having multiple task results and multiple build logs in memory, it is also possible to have multiple instances of the build logs – one per request handler (although in theory these would be quick requests and shouldn’t hold onto memory.) And yes, there’s still more!

The CruiseControl.NET server only allows .NET Remoting clients – which isn’t very helpful if you need to go through a firewall. Plus, people need some way of seeing the results from the tasks – CCTray doesn’t display them. So to handle these situations there is the Web Dashboard. This functions as a client application and does all sorts of things – including manipulating build logs in memory (normally an XSL-T transform):

image

And where does the Web Dashboard normally sit? On the same machine as the server (unless you’ve changed the default install and installed the dashboard on a separate machine).

So, this gives us a picture of having large strings in memory in several places. The project threads might be okay by themselves, but when you add the communications side, it is very easy to start consuming large amounts of memory with big build logs. Especially when there are a sizeable number of people trying to get results from a build (and what’s the first thing people do when they see a broken build – they go to the server to see what’s broken!)

Pruning Some Memory

Now that we’ve quickly reviewed the possible places where build logs are stored, what can we do to reduce the amount of memory?

Two initial approaches come to mind:

  1. Reduce the size of the log file
  2. Reduce the number of times each log file is loaded into memory

Option #1 can be done either in CruiseControl.NET or externally. First, we can split the mega-log into smaller logs, second we could write less data, third we could compress the data.

I’ve been looking at what I can do to split the mega-log file into build result specific log files, so a client could just grab the data they need (e.g. just the NAnt/NUnit/MSBuild/etc. results) instead of everything at once. Unfortunately this is a MASSIVE change, that will need to modify both the server and the clients in a large number of places. So for the moment I have spun off a “play” branch in the Subversion repository where I will attempt to do this (oh, and resolve all the associated problems with having multiple result files.) So this is a no-go for the current release.

Next, writing less data – well CruiseControl.NET doesn’t put that much CruiseControl.NET-related data into the log files. Most of the data comes from the external tools. So if this needs to be done, then people need to reduce the amount of data the tools generate – hence this becomes an external task.

So, that leaves compressing the data. Personally I like this approach as it would also reduce the amount of network traffic. Unfortunately there are a couple of gottas – there is no guarantee that compression would actually save space and it requires changes to the clients to decompress the data. But I still think the idea has merit.

Returning back to the two initial approaches, the other approach is to reduce the number of times each log is loaded. This is the approach I want to investigate some more.

Log Viewing Usage Patterns

From my experience with CruiseControl.NET, there are two general usage patterns:

  1. THE BUILD HAS BROKEN – what’s wrong?
  2. What happened to an older build?

And typically the second pattern also happens a lot as part of pattern #1 when people try to find out what has changed to cause the build to break. Very rarely do people go and look at a historical build.

The following picture sums up this pattern, with the size of the arrow indicating how much usage a build log would get:

image

So, most people only view the logs when something is broken and they primarily focus on the log of the build that actually failed. A smaller set of people would also check the previous successful build to see if there is anything pertinent to the failure. Finally a very small set of people might go through older logs to see what has happened (your manager is checking up on the amount of work you’ve been doing, etc.)

This sounds like a very good scenario for caching. Since there is a (potentially) small amount of data, this could be cached on the server, the dashboard or even both.

Bring on the Cache(s)

On the server side, we could just cache the log files – although we wouldn’t want to cache too many big ones.

The dashboard offers us a few different possibilities for caching. First, we could take the same approach as for the server and cache the the log files. Second, we could cache the parsed XML documents (since the entire document must be loaded and parsed before it can be transformed). Finally, we could cache the transformed output.

However, like anything in the dashboard, the way the build logs are transformed is not a simple process. Instead we have a number of interfaces and their implementations to go through. The build report generation is a plug-in, which generates multiple actions. Each action can have one or more style sheets, which actually get loaded and processed by a class in the Core library.

To Be Continued…

I’ve gone back and reviewed the memory usage scenarios for CruiseControl.NET with a view of reducing the usage on the server. This took a step back and viewed the wider picture, with a view of all the items that CruiseControl.NET is doing on a (server) machine. Unlike my previous post, this takes into account multiple users doing similar things at the same time.

I’ve come up with a couple of ideas for reducing memory usage – caching and compression – and both of them have some gottas that need to be investigated.

So rather than making this an even longer post, I’m going to stop at this point and look into caching and compression in some future posts.

So stay tuned, more fun to come :-)

Posted in CruiseControl.Net | Tagged: , | 5 Comments »

Migration Wizard

Posted by Craig Sutherland on 6 July, 2009

I have completed the first cut of the migration wizard. This wizard is now included in the installer – screenshots on how this looks are available here.

The wizard will migrate the following items when converting from 1.4.3 or 1.4.4:

  • State and log files on the server are moved to ProgramData for both the console and the service
  • E-mail groups configuration changed to use multiple notification types instead of a single attribute
  • Dashboard configuration and packages are moved to ProgramData

The wizard will migrate the following items when converting from 1.4.2 or older (up to 1.4.0):

  • Convert statistics file so it doesn’t cause double tabs
  • Plus all the above migrations from 1.4.3/1.4.4

At the moment, I have only tested this on Windows machines – this will probably fail on *nix-based machines due to the slightly different folder structure.

Let me know if there are any issues.

Posted in CruiseControl.Net | Tagged: , , | 5 Comments »

Migration Woes

Posted by Craig Sutherland on 25 June, 2009

Oops, We’ve Broken Some Eggs

As we slowly move forward and add new features or fix broken features, it is inevitable that we make some breaking changes. Sometimes it is possible to work within the current structures and file formats, other times it is either inefficient, very painful or downright impossible. So, where possible we don’t make breaking changes, but sometime we have no choice.

While this is a common feature of software development, this can still cause pain to our users. Generally, people don’t like to think, even less so when it is painful thinking! And often, people just don’t read the upgrade notes – they just expect it to work.

Moving to 1.5.0 of CruiseControl.NET, we are making some major changes to the underlying storage locations. This is because all older versions assume the Program Files is readable and writable! Unfortunately, with Windows Vista, Windows Server 2008 and newer versions, this is no longer the case. We’ve been locked out! So, if we want to write data to disk, we need to move to a new location.

While this is a minor change for new users, it does have a major impact on existing users. They will need to move all their files that are stored in Program Files to the new local (e.g. ProgramData, All Users, etc.) Knowing how people don’t read the upgrade notes, we’re going to get a lot of queries about this.

A New Wizard

While I know we’re not going to be able to totally avoid the pain, I’d like to reduce it as much as possible. Originally I had added a check to the dashboard to enforce the migration, but this was disliked. So, instead I’ve added a new WinForms application to handle the migration.

At this point I should mention, this wizard is still in the very early days of development! DO NOT USE it for production systems, you have been warned!!!

This wizard will provide a step-by-step process for collecting user details on what they want to migrate. Once this has finished, it will migrate everything for them. If it runs into any errors in the migration process, it will (theoretically) roll-back any migration changes.

So, that’s the theory, here’s what I have put together so far.

Following the Yellow Brick Road

Page1

When the user starts the wizard, they will get a general introduction window. I’ve tried to put relevant information on it, and hopefully not too much information.

Page2

Clicking on next will prompt you to enter which version you are migrating from. Currently, I only handle migrating from 1.4.4 to 1.5.0, but I plan to add additional migrations from older versions (up to 1.4.0). This is because we added a number of breaking changes through the various versions, so it would be nice to allow the wizard to handle all of them. Hopefully, this will also encourage users of older versions to upgrade.

Page3

Once the user has selected the version, we enter into the meat of the settings. First off, the user has the choice of just which items they want to migrate. Here, they are being prompted if they want to migrate the server settings. The wizard also asks where the user wants to migrate from, since they may have installed in a different location (I’m not aware of an easy way to find the location, and I don’t want to try and scan for it!)

Migrating the server settings will move any state files, the overall projects state file and any project folders. If the working or artefact folders are not set in the config, they are added under the server folder, which is why they need to be moved.

Each page has validation checks built in. In this case, since we are asking for a folder location, it will validate the folder is valid and that it contains a ccnet.config file (this is needed later on).

Page4

Next, the user will be prompted if they want to migrate the configuration settings. This will change ccnet.config so it works in 1.5.0. Sometimes, but not very often, we are forced to change the layout of ccnet.config, this will handle the changes automatically.

On this page, the user is also prompted if they want to backup their original configuration. This is because the wizard will actually modify the file (as opposed to just move it), so they might like the safety of seeing their original file is preserved.

Now for the bad news, I’m not actually doing anything with these settings yet. But I know we do have some breaking changes, I just need to track them down and then add them to the wizard.

Page5

Next, the user is asked if they also want to migrate the web dashboard. A lot of times, the web dashboard is installed on the same machine as the server, but sometimes they are on different machines. Here we give the user the choice of whether to migrate both, one or the other.

Again, the user is prompted for the current location – they might have installed it to a non-default folder. The wizard will default to the standard location, but as you can see in my example, it is easy to change (I don’t have CruiseControl.NET installed on my machine, I have several development copies of the source instead.)

Page6

The user is then asked to confirm the settings. Currently it is just a text blob with all the details in it, I might see if I can figure out a better way to display it.

Page7

When they click on next, it then begins the migration. This is done on a background thread, so the user can still interact with the wizard. In time, I’d like to add the ability to cancel a migration part-way through (this would perform a rollback), but I haven’t gotten around to it yet.

Also, if you noticed the (Not Responding) message on this title bar, it’s just because the process is so fast on my machine, the only way I could take this snapshot was putting a breakpoint in the code! Normally it does respond (and very nicely).

Page8

Finally, the user will told what has happened. I’m trying to keep this very minimalistic – just the statuses for each item, plus any warnings or errors.

If the user wants to see the full log, this is available by clicking on the View Log button:

Log

This is pretty much all the messages that are displayed in the progress window.

Welcome to the Wizard

So, that’s a quick tour of the wizard from start to end, at least in terms of its UI. The next question is what does it actually do?

Currently, it will move the following folders and files:

  • Project working and artefact folders (if under Program Files)
  • Project state files
  • Overall project states (started/stopped statuses)
  • Web dashboard configuration
  • Web dashboard packages

I am also going to look at moving the log files, but this also require modifying the app.config files,so I want to be able to do this in a reversible manner.

I will also update ccnet.config to handle any breaking changes, but I need to find out what these are first.

And finally, I need to go through the old change logs to see if there are any other breaking changes, and then add them in.

Additional Features

I’ve also tried to build this with a few additional features in mind, but I can’t guarantee that I will add them. These are:

  • Command-line execution (i.e. no UI)
  • Cancelling migration part-way through migration
  • Saving the log file
  • Migrating to a different location

Plus whatever other people want to suggest…

So, this is what I am currently working on. I’ll add it to Subversion, so anyone who is brave can try it out, but I won’t add it to the installer until it is nearly complete.

Let me know what you think about the wizard.

Posted in CruiseControl.Net | Tagged: , , | 2 Comments »