Why build scripts?
Welcome to our weekly MVP series where we discuss some of the most useful solutions, tips & tricks and how to’s on integrating OSS & Microsoft technologies. In case you have any questions, don’t hesitate and drop us a comment below or reach out to us via Twitter and Facebook! Enjoy!
If you are working with .NET and using Visual Studio, it is a common practice (and good idea) to have a script so you can build, test and deploy your project by running the script from the command line.
That way you can integrate easily with CI (continuous integration) tools and also share common tasks among members of your team. Instead of only documenting how to deploy on a wiki it is better to have living documentation on your script that explains what to do, how to do it, and actually does it for you.
Writing a script to manage common tasks will save you lots of time and, without much effort, can become the main source of documentation.
Imagine that you are starting on a new project, get the source control information, clone the repository and now you wonder what to do first. Well, you are in luck! There's a READ.ME file that points to the main build script, how to run it, main tasks, etc. You can build, deploy, etc. event without opening VS!
A bit of history
When I started writing build scripts for my projects the first option I found were MSBuild scripts. After writing XML for a while I wanted (desperately) to find a different solution.
I was already using Rake for Ruby on Rails projects and liked how easy was to use and how clear was the DSL. So I started to use it with my .NET projects. After a while I wondered if perhaps already something existed, and I was right! I found Albacore that provided many of the tasks I wanted out of the box.
This was great but on the downside I had to install Ruby, convince the developers in my team to use it (not always easy) and could not interop with .NET if I needed to.
Enters FAKE
Other solutions appeared like Psake but I didn't want to use PowerShell.
And then I started to work with F# and a new option appeared that made me put everything else behind: FAKE.
FAKE is an open source free tool written in F# in the spirit of make and rake.
In order to use fake you just need to install it and write a build.fsx file (it can be any name of course) using the DSL that comes with FAKE.
Do you think you need to learn lots of F# to use it? Not at all, starting could not be easier!
I am going to use some of the code from the calculator sample that comes with FAKE so you can download it later and play with it.
// include Fake lib
#r @"packages\FAKE\tools\FakeLib.dll"
open Fake
// Default target
Target "Default" (fun _ ->
trace "Hello World from FAKE"
)
// start build
RunTargetOrDefault "Default"
Also I am going to use some code from my Canopy Demo.
As you can probably guess, this script only prints to the console Hello world from FAKE.
Clearly not much _F#_ is required to write it. FAKE uses targets (tasks) to identify runnable bits in your script. In order to define one you just use `Target targetName bodyFn`. In this case the body only send a message to the console.
Target "Build" (fun _ ->
// uses the default config
let defaultCfg = id
// call build with default config and the solution file
build defaultCfg "./DemoKoCoffee.sln"
)
Let's see how to build the solution:
Target "Build" (fun _ ->
// Get env var or use RELEASE by default
let buildMode = getBuildParamOrDefault "buildMode" "Release"
// function that configures the default config by
// changing the 'Configuration' property
let config defaults = {
defaults with Properties = ["Configuration", buildMode]
}
// call the build passing the configuration function and the solution
build config "./DemoKoCoffee.sln"
)
You can also use the environment variables to get the build configuration:
There are more options that you can use to call MSBuild, just check the API documentation for the MSBuildHelper.
I want more!
Just a couple of lines and we get our solution building! Isn't that great?
But building a project is only the start. There's plenty of examples in the FAKE documentation.
Here I will show you one more example that I used to launch IIS express and then run acceptance test with Canopy.
Target "Canopy" (fun _ ->
let hostName = "localhost"
let port = 9099
let buildDir = "AcceptanceApp" @@ "bin" @@ "debug"
let websiteDir = "DemoKoCoffee"
let project = "DemoKoCoffee-Acceptance"
let config = createConfigFile(project, 99, "iisexpress.config", websiteDir, hostName, port)
let webSiteProcess = HostWebsite id config 99
let result =
ExecProcess (fun info ->
info.FileName <- (buildDir @@ "AcceptanceApp.exe")
info.WorkingDirectory <- buildDir
) (System.TimeSpan.FromMinutes 5.)
ProcessHelper.killProcessById webSiteProcess.Id
if result <> 0 then failwith "Failed result from canopy tests"
)
Here I am using FAKE.IIS to create the config file and host the MVC app. Then I am using the ProcessHelper to run my acceptance tests and kill the process after.
Conclusion
Having a descriptive (and quite small) build script can offer lots of benefits over time. It's not only super fast to start working with it, but also a great way to share common tasks and living documentation for your project.
Using .fsx files can be extended to your everyday tasks. It is a great way of scripting repetitive jobs and you can use the extensive FAKE library of helpers that deal with files, file system, executing procs, etc. Once you are comfortable with FAKE why not take it up a notch and use it for scripting in general!
To put the cherry on top FAKE belongs to the .NET ecosystem! That means you can reuse the vast .NET libraries that already exist and you are familiar with, or create your own.
FAKE also has great community support and comes with great explanations, code examples and API documentation for each helper.
Do you think your build is unique and it won't be a good match? You will be surprised! Try it out and even collaborate with FAKE and fix bugs or even submit your own custom target.
Happy building!
Comments
- Anonymous
December 23, 2015
Heads up, broken link for the Canopy Demo