Arguably, one of the most powerful features of UppercuT (UC) is the ability to extend any step of the build process with a pre, post, or replace hook. This customization is done in a separate location from the build so you can upgrade without wondering if you broke the build. There is a hook before each step of the build has run. There is a hook after. And back to power again, there is a replacement hook. If you don’t like what the step is doing and/or you want to replace it’s entire functionality, you just drop a custom replacement extension and UppercuT will perform the custom step instead. Up until recently all custom hooks had to be written in NAnt. Now they are a little sweeter because you no longer need to use NAnt to extend UC if you don’t want to. You can use PowerShell. Or Ruby. Let that sink in for a moment. You don’t have to even need to interact with NAnt at all now. Extension Points On the wiki, all of the extension points are shown. The basic idea is that you would put whatever customization you are doing in a separate folder named build.custom. Each step Let’s take a look at all we can customize: The start point is default.build. It calls build.custom/default.pre.build if it exists, then it runs build/default.build (normal tasks) OR build.custom/default.replace.build if it exists, and finally build.custom/default.post.build if it exists. Every step below runs with the same extension points but changes on the file name it is looking for. NOTE: If you include default.replace.build, nothing else will run because everything is called from default.build. * policyChecks.step * versionBuilder.step NOTE: If you include build.custom/versionBuilder.replace.step, the items below will not run. - svn.step, tfs.step, or git.step (the custom tasks for these need to go in build.custom/versioners) * generateBuildInfo.step * compile.step * environmentBuilder.step * analyze.step NOTE: If you include build.custom/analyze.replace.step, the items below will not run. - test.step (the custom tasks for this need to go in build.custom/analyzers) NOTE: If you include build.custom/analyzers/test.replace.step, the items below will not run. + mbunit2.step, gallio.step, or nunit.step (the custom tasks for these need to go in build.custom/analyzers) - ncover.step (the custom tasks for this need to go in build.custom/analyzers) - ndepend.step (the custom tasks for this need to go in build.custom/analyzers) - moma.step (the custom tasks for this need to go in build.custom/analyzers) * package.step NOTE: If you include build.custom/package.replace.step, the items below will not run. - deploymentBuilder.step Customize UppercuT Builds With PowerShell UppercuT can now be extended with PowerShell (PS). To customize any extension point with PS, just add .ps1 to the end of the file name and write your custom tasks in PowerShell. If you are not signing your scripts you will need to change a setting in the UppercuT.config file. This does impose a security risk, because this allows PS to now run any PS script. This setting stays that way on ANY machine that runs the build until manually changed by someone. I’m not responsible if you mess up your machine or anyone else’s by doing this. You’ve been warned. Now that you are fully aware of any security holes you may open and are okay with that, let’s move on. Let’s create a file called default.replace.build.ps1 in the build.custom folder. Open that file in notepad and let’s add this to it: write-host "hello - I'm a custom task written in Powershell!"
Now, let’s run build.bat.
You could get some PSake action going here. I won’t dive into that in this post though.
Customize UppercuT Builds With Ruby
If you want to customize any extension point with Ruby, just add .rb to the end of the file name and write your custom tasks in Ruby. Let’s write a custom ruby task for UC. If you were thinking it would be the same as the one we just wrote for PS, you’d be right!
In the build.custom folder, lets create a file called default.replace.build.rb.
Open that file in notepad and let’s put this in there:
puts "I'm a custom ruby task!"
Now, let’s run build.bat again.
That’s chunky bacon.
UppercuT and Albacore.NET
Just for fun, I wanted to see if I could replace the compile.step with a Rake task. Not just any rake task, Albacore’s msbuild task. Albacore is a suite of rake tasks brought about by Derick Bailey to make building .NET with Rake easier. It has quite a bit of support with developers that are using Rake to build code.
In my build.custom folder, I drop a compile.replace.step.rb. I also put in a separate file that will contain my Albacore rake task and I call that compile.rb.
What are the contents of compile.replace.step.rb?
rake = 'rake'
arguments= '-f ' + Dir.pwd + '/../build.custom/compile.rb'
#puts "Calling #{rake} " + arguments
system("#{rake} " + arguments)
Since the custom extensions call ruby, we have to shell back out and call rake. That’s what we are doing here. We also realize that ruby is called from the build folder, so we need to back out and dive into the build.custom folder to find the file that is technically next to us.
What are the contents of compile.rb?
require 'rubygems'
require 'fileutils'
require 'albacore'
task :default => [:compile]
puts "Using Ruby to compile UppercuT with Albacore Tasks"
desc 'Compile the source'
msbuild :compile do |msb|
msb.properties = { :configuration => :Release, :outputpath => '../../build_output/UppercuT' }
msb.targets [:clean, :build]
msb.verbosity = "quiet"
msb.path_to_command = 'c:/Windows/Microsoft.NET/Framework/v3.5/MSBuild.exe'
msb.solution = '../uppercut.sln'
end
We are using the msbuild task here. We change the output path to the build_output/UppercuT folder. The output path has “../../” because this is based on every project. We could grab the current directory and then point the task specifically to a folder if we have projects that are at different levels. We want the verbosity to be quiet so we set that as well.
So what kind of output do you get for this? Let’s run build.bat
custom_tasks_replace:
[echo] Running custom tasks instead of normal tasks if C:\code\uppercut\build\..\build.custom\compile.replace.step exists.
[exec] (in C:/code/uppercut/build)
[exec] Using Ruby to compile UppercuT with Albacore Tasks
[exec] Microsoft (R) Build Engine Version 3.5.30729.4926
[exec] [Microsoft .NET Framework, Version 2.0.50727.4927]
[exec] Copyright (C) Microsoft Corporation 2007. All rights reserved.
If you think this is awesome, you’d be right!
With this knowledge you shall build.