-
Notifications
You must be signed in to change notification settings - Fork 2
Using F# or C# script for build definition in Team Build 2012 2013
A several months ago I faced with necessity to customize build process in Team Build. Microsoft offers visual workflow designer for this purpose. IMHO this is the worst way from all which I can imagine! As for developer it’s much much easier for me to work with some kind of script and I started looking for such alternative.
FAKE (F# Make) looked very promising. Unfortunately FAKE didn’t provide TFS integration out of box. I tried to extend it and encountered some conceptual problems (you could read more details here). But idea itself was great and I decided to write my own implementation – AnFake (Another F# Make).
First we should set-up AnFake.
Then we could define build steps using F# script (actually, C# also supported but has a little more verbose syntax). Below the trivial example which compiles and runs unit-tests:
let out = ~~".out" // ~~ operator converts string to FileSystemPath object
let productOut = out / "product" // FileSystemPath objects can be combined with operator /
let testsOut = out / "tests"
let tests = !!"*/*.Test.csproj" // !! operator creates FileSet object from wildcarded path
let product =
!!"*/*.csproj"
- tests // - operator excludes files from FileSet
// defining target 'Compile'
"Compile" => (fun _ ->
MsBuild.BuildRelease(product, productOut) // run MSBuild for product projects
MsBuild.BuildRelease(tests, testsOut) // run MSBuild for test projects
)
"Test" => (fun _ ->
// run VSTest.Console on all *.Test.dll files from testsOut folder
VsTest.Run(testsOut % "*.Test.dll")
)
"Build" <== ["Compile"; "Test"] // 'Build' consists of 'Compile' and 'Test'
A bit more complex example which looks up a last good build, takes its output, runs performance test, puts result into database, calculate statistical threshold over last 5 measurements and checks new result against this threshold:
let out = ~~".out"
let binOut = out / "bin"
// declaring data contract for performance report
[<DataContract>]
type PerformanceReport () =
[<DataMember>] member val ChangesetId: int = 0 with get, set
[<DataMember>] member val ElapsedTime: double = 0.0 with get, set
[<DataMember>] member val BytesProcessed: int64 = 0L with get, set
"Test.Performance" => (fun _ ->
let buildDefName = MyBuild.GetProp("productBuild") // gets externally passed parameter
// looks up last build with quality 'Unit-Tests Passed' in Team Build
let goodBuild = TfsBuild.QueryByQuality(buildDefName, "Unit-Tests Passed", 1).First()
// copying goodBuild's output to local folder
Files.Copy(goodBuild.GetDropLocationOf(ArtifactType.Deliverables) % "*", binOut)
// building command line arguments for performance meter tool
let reportPath = out / "PerfMeter.report"
let args =
(new Args("--", " "))
.Option("threads", 4)
.Option("report", reportPath)
.ToString()
// running performance meter tool
Process.Run(fun p ->
p.FileName <- binOut / "PerfMeter.exe"
p.Arguments <- args
).FailIfExitCodeNonZero("PerfMeter.exe FAILED.")
|> ignore
// loading performance report
let report = Json.ReadAs<PerformanceReport>(reportPath.AsFile())
report.ChangesetId <- VersionControl.CurrentChangesetId
Nh.MapClass<PerformanceReport>()
Nh.DoWork(fun uow ->
// querying previous 5 measurements from DB
let prevReports =
uow.Query("from PerformanceReport order by id desc")
.SetMaxResults(5)
.List<PerformanceReport>()
// saving new result
uow.Save(report)
uow.Commit()
// calculating and checking threshold
if prevReports.Count = 5 then
let prevSpeeds = prevReports.Select(fun rep -> (double)rep.BytesProcessed / rep.ElapsedTime)
let avg = prevSpeeds.Average()
let sig2 = prevSpeeds.Average(fun x -> (x - avg)*(x - avg))
let speed = (double)report.BytesProcessed / report.ElapsedTime
let threshold = avg - Math.Sqrt(sig2);
if speed < threshold then
MyBuild.Failed(
"The last reported speed {0:F2} KB/s is under threshold {1:F2} KB/s.",
speed / 1024.0, threshold / 1024.0
)
)
)
Of course, AnFake is built by itself – take a look on real-life example of build.fsx or build.csx
To run ‘build.fsx’ in Team Build AnFake provides special build process template ‘AnFakeTemplate.xaml’ which downloads sources from version control then invokes AnFake.exe which runs script. Below the simple example of build summary report in Team Build:
With AnFake all customization are made in script file tracked by version control which makes build definitions much more maintainable.
Right now we are actively using AnFake in our build environment and I think it might be useful for other teams who work with TFS. If you’ve read to the end, please spend one minute more and answer just a couple of questions. This helps me to estimate interest to such tool.
Thank you.