Posts tagged '.NET'

10

September 2011

Automating Deployment: Building/Deploying a Specific Mercurial Tag on CruiseControl.NET

Over the past few weeks, I've been claiming control of more of the build/deployment processes where I work. I was getting tired of seeing a red icon on CCTray because half of the company projects didn't build, and the few that had unit tests weren't even running them :-(

With all that addressed, I turned my attention to the process of deploying code to the staging servers. We wanted this to be as simple as possible, however it needs to be a conscious decision - we could not just have the public stage systems (used by clients, trainers, etc.) constantly building every time someone commits.

I like the way GitHub works but sadly we have no chatroom/chatbot to order to deploy for us! :-( We decided that a reasonably simple solution was to have a Mercurial tag called "Stage" to act as a flag for deploying. Once we're happy to push to stage, we can just pull the Stage tag up to the correct revision, and the build server can run with it.

To do this, we needed to add another project to CruiseControl.NET. One will build continuously (and update local test sites, for non-devs to test during development), and the other will deploy to the public staging environment. The problem came when I wanted to set up this new project to build from a tag. The CruiseControl.NET documentation (if you can find it - Google is polluted with tons of copies of old/stale documentation!) didn't seem to give any option for checking out a tag, only a branch! I tried putting the tag name in there in the hope it might still work, but sadly, no such luck!

I came across some info online that pointed me to "hg help urls" which shows you can use URL fragments to check out revisions, like this:

hg clone \\myserver\Development\MyRepo#Stage

This worked great on my machine, so I configured CCNet to use this as the repository. Unfortunately the build failed immediately, with this error:

abort: repository \\myserver\Development\MyRepo#Stage not found!

At first I thought maybe CCNet was doing something fruity, but after trying the same command on the build server from a command window, I discovered that this functionality has become broken in a recent version of Mercurial!

I've filed a bug on the Mercurial site and for now, rolled the server down to 1.7.3 (the version I had on my desktop, which I knew worked). This meant uninstalling TortoiseHG, but that's not the end of the world, right? ;-)

Now the CCNet config looks something like this:

<sourcecontrol type="hg">
    <repo>\\myserver\Development\MyRepo#Stage</repo>
    <autoGetSource>true</autoGetSource>
    <workingDirectory>$(WorkingPath)\$(ProjectName)</workingDirectory>
    <purgeModifications>true</purgeModifications>
    <revertModifications>true</revertModifications>
</sourcecontrol>

With this now working, things were starting to come together. To make things even easier, I added an alias in my Mercurial.ini file:

[alias]
stage=tag -f Stage

There's still a little way to go to fully automate the process of extracting the build on the server, but what used to take 30+ minutes is now as simple as:

  1. Type "hg stage"
  2. Go and make a cup of tea for the team
  3. Build server will:
    • Check out the Stage tag
    • Overwrite the AssemblyVersion attribute in a shared AssemblyInfo.cs file with the CruiseControl label
    • Build the project using MSBuild/NANT
    • Run all tests
    • Zip up the resulting build and store it alongside previous versions
    • FTP the zip file up to the staging server ready for deployment
  4. Extract the zip file into the "Latest" folder (this is where most client IIS hosts point)
  5. Profit

Automating the last part is a little more tricky because we'll need something on the server to extract the zip (possibly a web service we can call, or a services that watches the folder for the releases), but if you consider that I deployed 6 times in the last 2 days and it's taken only 4-5 hours to automate this much, it's clear the savings will mount up!

25

July 2011

G+ Notifier 1.3 live, updates posted to Twitter

Version 1.3 of G+ Notifier (for Google+) recently went live. Unfortunately, due to an error with 1.2, you might not be notified about the update by the application unless you leave it running for 12 hours!

Here's some screenshots of the current version:

The notifications window

The balloon notification

Unfortunately, with absolutely no warning, Google suspended the G+ Notifier account I'd created on Google+ to announce updates. I'd asked a number of times whether this was ok, and got no response. As a result, if you want notification of updates without all of my unrelated posts on Google+, the best way is to follow @GPlusNotifier on Twitter. Yeah, really.

Of course, if you don't mind the personal posts, the best place to follow G+ Notifier is my account on Google+.

If you have any ideas and suggestions for G+ Notifier, please submit them to the support site. You can also vote on other peoples suggestions there to influence the things worked on next!

You're also welcome to fork the code and send pull requests. It's a good idea to let me know in advance, just to ensure someone isn't already doing the same thing. There are already a few people (Adam Simmons, The Configurator and Andrew Nurse) contributing to the project!

19

July 2011

G+ Notifier - First Version Live!

The first version of my G+ Notifier is now live, ready to download!

The first version is pretty basic, but it's still incredibly useful. It sits in the notification area and shows how many unread notifications you have (and shows balloons periodically). Double-clicking the icon (or single-clicking a balloon) will launch Google+ in your default browser.

For full info and a download link, visit gplusnotifier.com!

15

July 2011

G+ Notifier - Windows Utility to show notifications from Google+ in the notification area

I recently picked up some domains for my next open source project - G+ Notifier. It's a simple Windows utility that'll sit in the notification area and alert you to notifications from Google+! Similar to my previous Google Wave Notifier, but hopefully Google won't discontinue this service quite so quick!

I'm not sure if I'll be able to launch the application before Google+ gets a public API, but I'll do some investigation over the coming days.

If you want to be kept informed with the progress of the app, please follow G+ Notifier on Google+, I'll post all updates on that account :-)

The website for the application is gplusnotifier.com and will also be updated regularly. Full source code will be hosted on Bitbucket!

09

May 2011

Adding Tab-Expansion to Andrew Nurse's PSGet (NuGet Powershell Module)

If you subscribe to my blog or follow me on Twitter you'll probably know I'm quite a fan of NuGet. Recently I was playing around with Andrew Nurse's PSGet module that wraps NuGet.exe for PowerShell (which, by the way, is an awesome idea, and should be added as built-in functionality!). I decided a good way to learn a little more about PowerShell would be to try and add Tab Expansion to PSGet, similar to the functionality in the Visual Studio Package Manager Console.

Note: I forked Andrew Nurse's PSGet project to make these changes, though I'll see if he's interested in pulling them back into his, and updating the NuGet package. That way people will have a single source for PowerShell/NuGet goodness. Until then, if you want my Tab Expansion, you can grab the module from here.

Disclaimer: I've only been using PowerShell for around a week, so I'm sure there are much better ways to do what I've done. I did what I could with the (little) knowledge I have and some Googling. If you can see better ways of doing things, please let me know so I can learn, and update my code (send me a pull request on Bitbucket if you want).

Show me the code!

Tab Expansion in PowerShell works via the TabExpansion method. This function is called and provided with the current line in addition to the last word typed. I couldn't find a way to hook TabExpansion for just the commands we're interested in, so I had to hijack the whole lot. This doesn't seem to be a problem, as falling back to the default behaviour seemed pretty simple by keeping a copy of the function:

# Copy the current Tab Expansion function so we can fall back to it if we're not supposed to handle a command
Copy Function:\TabExpansion Function:\OriginalTabExpansion

function TabExpansion([string] $line, [string] $lastword)
{
    # Only run for "Get-PSPackage" or "Install-PSPackage"
    if (somecondition)
    {
        # Do cool NuGet stuff here
    }
    # Otherwise, fall back to default TabExpansion function
    else
    {
        OriginalTabExpansion $line $lastword
    }
}
Export-ModuleMember -Function TabExpansion

We need our NuGet code to run only for two specific commands, for the first parameter. The easiest way seemed to be to check that $line is equal to one of our commands followed by the $lastword. This probably isn't the best way, but it seems to do the job for the obvious cases.

# Only run for "Get-PSPackage" or "Install-PSPackage" where we're typing the first argument
if ($line -eq "Get-PSPackage $lastword" -or $line -eq "Install-PSPackage $lastword")
{
    # ...
}

Inside this block, we need to query the OData feed for NuGet packages. Rather than hard-coding the URI, we're supposed to go through a Microsoft fwlink (https://go.microsoft.com/fwlink/?LinkID=206669), but because we can't append parameters to the end, we need to resolve this redirect. I found some code in the NuGet issue tracker written by David Ebbo to do just this. I converted it to PowerShell and added a $defaultSource variable:

# Follows redirects and returns the final URI. Used to support fwlink as package source.
function GetRedirectedUri($uri)
{
    $req = [System.Net.HttpWebRequest] [System.Net.WebRequest]::Create($uri)
    $req.AllowAutoRedirect = $FALSE; # Don't follow redirects, to save bandwidth/roundtrip
    $resp = $req.GetResponse()
    if ($resp.StatusCode -eq [System.Net.HttpStatusCode]::Redirect)
    {
        $resp.Headers["Location"]
    }
    else
    {
        $uri;
    }
}
# Set the default NuGet source
$defaultSource = GetRedirectedUri("https://go.microsoft.com/fwlink/?LinkID=206669")

With this done, we just needed to call the feed with some search parameters and parse the results. Luckily, parsing OData is pretty trivial, and with Fiddler and Visual Studio, it was easy to find the syntax for searching for packages with IDs that start with a given string :)

The final step was to pipe through Get-Unique because the OData feed returns multiple entries for packages with multiple versions (but the ID is the same):

# Construct a URI to fetch the top 30 matching packages, sorted by download count
$uri = "$($defaultSource)Packages()?`$filter=startswith(tolower(Id),'$($lastword)')&`$orderby=DownloadCount%20desc,Id&$`skip=0&`$top=30"

# Fetch the data, return as XML
$wc = New-Object Net.WebClient
$data = [xml]$wc.DownloadString($uri)

# Pipe result through Get-Unique because there could be multiple versions with the same ID
$(
    # Loop, just grabbing the ID from Properties
    foreach ($entry in $data.feed.entry)
    {
        $entry.properties.Id
    }
) | Get-Unique

And viola, Tab Expansion! Now when you type "Install-PSPackage x" or "Get-PSPackage x" you can use tab to cycle through the matching packages (sorted by download count, in an attempt to give the most likely result first).

The full module is is up on Bitbucket, but maybe with a little tidying up we can get Andrew Nurse to pull the functionality into his repository and update PSGet on NuGet.

« Older posts