At work we use FinalBuilder as our continuous integration server. Essentially it works like CruiseControl etc, but has software you use to build the project files rather than eating your XML raw. The basis of FinalBuilder is assembling “actions” into a build script that is executed either in the FinalBuilder software, or on a build server running FinalBuilder Server.
Now typically, performing path and string manipulation is tricky, because you need to use FinalBuilder actions like “String Trimming”, “String Replace” and “String Pos”. All of which work on the basis that they take the value of a global variable defined in the project, and set the result to another global variable defined in the project. If you have a lot of string work to do, this can quickly become unwieldy.
So instead, I propose ignoring the built-in string and path manipulation actions, and swopping them all for one or two “Run Script” actions with PowerShell scripts. In my case, I have a URL to a Mercurial repository hosted on a Kiln server passed-in to my project, and I want to apply a convention to work out what the local repository path for me to clone to and build from should be. I do this by:
- Adding a single “Run Script” action at the top of my project
- Selecting it
- In the “Script Editor” window (View->Script Editor), select “PowerShell” as the scripting language
- In the script editor window, add the following:
$RepositoriesLocation = $FBVariables.GetVariable("_RepositoriesLocation") # Global variable configured on FB Server
$RepositoryUrl = $FBVariables.GetVariable("RepositoryUrl") # Passed-in at runtime
$uri = New-Object -type System.Uri -argumentlist $RepositoryUrl
$repositoryName = $uri.Segments[$uri.Segments.Length – 1].Trim(‘/’) # Parse the repo name
$projectName = $uri.Segments[$uri.Segments.Length – 3].Trim(‘/’) # Parse the Kiln project name
$WorkingCopyRoot = [System.IO.Path]::Combine($WorkingCopiesLocation, $projectName)
$WorkingCopyRoot = [System.IO.Path]::Combine($workingCopyRoot, $repositoryName)
$FBVariables.SetVariable("WorkingCopyRoot", $workingCopyRoot) # The the global variable for subsequent actions to use
As you can see, this obtains the value passed-in to the project from the HgUrl variable, breaks it up and re-arranges it to produce a local path for the URL. There’s some other stuff about the location of the working copies being in a common location but that’s all there is to it.
I’ve recently gone a bit mad for this approach. How about this method of establishing the solution file to build in any given Hg repository, for example?:
$workingCopyRoot = $FBVariables.GetVariable("WorkingCopyRoot")
$solutionFileFullName = Get-ChildItem $workingCopyRoot -filter *.sln | select-object FullName -first 1
Happy, erm, “PowerShelling”… :)