Introduction
Cake is a great tool for organizing a delivery pipeline for your application. I like it because it lets me write the pipeline using C#, the language I know well. The great property of Cake, PSake and other similar frameworks is that they allow as to use the same building script on a local development machine and on CI servers. Here, I'll explain how to integrate Cake with TeamCity.
Requirements
I'll assume you have initial knowledge of Cake and TeamCity. Otherwise, you can start with reading:
Now let's talk about Cake and TeamCity together.
Logging
Cake pipeline usually consists of several tasks. It would be good to have a separate section for each such task in the TeamCity build log. I want to have a collapsible section for each Cake task in the log:
Cake
API contains methods TeamCity.WriteStartBuildBlock
and TeamCity.WriteEndBuildBlock
. Although it is possible to use them in each task, it can be automated. In Cake
, there are TaskSetup
and TaskTeardown
methods that will be called before and after execution of each task. They can be used to start and end TeamCity
block:
TaskSetup(setupContext =>
{
if(TeamCity.IsRunningOnTeamCity)
{
TeamCity.WriteStartBuildBlock(setupContext.Task.Name);
}
});
TaskTeardown(teardownContext =>
{
if(TeamCity.IsRunningOnTeamCity)
{
TeamCity.WriteEndBuildBlock(teardownContext.Task.Name);
}
});
Here TeamCity.IsRunningOnTeamCity
property is used to execute the code only if it runs on TeamCity
.
Now we have collapsible blocks in the build log. But still, we can improve it a little bit more.
Usually, tasks of Cake
tend to have short names like Build
, Test
, Clean
. In this case, it is easier to run them from the command line. But in the build log, I'd prefer to have more expanded descriptions of Cake
tasks. And it is possible to provide such descriptions. To set description of a task, use Description
method:
Task("Clean")
.Description("Create and clean folders with results")
.Does(() => { ... });
Now, these descriptions can be used to form build log blocks:
TaskSetup(setupContext =>
{
if(TeamCity.IsRunningOnTeamCity)
{
TeamCity.WriteStartBuildBlock(setupContext.Task.Description ?? setupContext.Task.Name);
}
});
TaskTeardown(teardownContext =>
{
if(TeamCity.IsRunningOnTeamCity)
{
TeamCity.WriteEndProgress(teardownContext.Task.Description ?? teardownContext.Task.Name);
}
});
It allows improving readability of the build log.
Progress Indication
If running a Cake
script takes a lot of time, it would be great to see which task is executing now.
It can be done using TeamCity.WriteStartProgress
and TeamCity.WriteEndProgress
methods. Their calls can be inserted into the same TaskSetup
and TaskTeardown
:
TaskSetup(setupContext =>
{
if(TeamCity.IsRunningOnTeamCity)
{
TeamCity.WriteStartBuildBlock(setupContext.Task.Description ?? setupContext.Task.Name);
TeamCity.WriteStartProgress(setupContext.Task.Description ?? setupContext.Task.Name);
}
});
TaskTeardown(teardownContext =>
{
if(TeamCity.IsRunningOnTeamCity)
{
TeamCity.WriteEndProgress(teardownContext.Task.Description ?? teardownContext.Task.Name);
TeamCity.WriteEndBuildBlock(teardownContext.Task.Description ?? teardownContext.Task.Name);
}
});
Tests Results
If you run some tests in your Cake
task, it would be great to show the results of their execution in TeamCity
.
It can be done using TeamCity.ImportData
method. This method accepts two parameters: string
description of data type and path to a file with data. For example, if MSTest is used for tests, here is how you can execute tests and inform TeamCity
about their results:
Task("Run-Tests")
.Description("Run tests")
.IsDependentOn("Clean")
.IsDependentOn("Build")
.Does(() => {
var testDllsPattern = string.Format("./**/bin/{0}/*.*Tests.dll", configuration);
var testDlls = GetFiles(testDllsPattern);
var testResultsFile = System.IO.Path.Combine(temporaryFolder, "testResults.trx");
MSTest(testDlls, new MSTestSettings() {
ResultsFile = testResultsFile
});
if(TeamCity.IsRunningOnTeamCity)
{
TeamCity.ImportData("mstest", testResultsFile);
}
});
TeamCity
supports several types of tests. Instead of mstest
, you can use nunit
, vstest
and several more.
Code Coverage Analysis
TeamCity can show results of code coverage by tests.
Now TeamCity supports integration with DotCover tool. Let me show how to use DotCover in your Cake script. First of all, DotCover must be installed by adding:
#tool "nuget:?package=JetBrains.dotCover.CommandLineTools"
Now it can be used in your task:
Task("Analyse-Test-Coverage")
.Description("Analyse code coverage by tests")
.IsDependentOn("Clean")
.IsDependentOn("Build")
.Does(() => {
var coverageResultFile = System.IO.Path.Combine(temporaryFolder, "coverageResult.dcvr");
var testDllsPattern = string.Format("./**/bin/{0}/*.*Tests.dll", configuration);
var testDlls = GetFiles(testDllsPattern);
var testResultsFile = System.IO.Path.Combine(temporaryFolder, "testResults.trx");
DotCoverCover(tool => {
tool.MSTest(testDlls, new MSTestSettings() {
ResultsFile = testResultsFile
});
},
new FilePath(coverageResultFile),
new DotCoverCoverSettings()
.WithFilter("+:Application")
.WithFilter("-:Application.*Tests")
);
if(TeamCity.IsRunningOnTeamCity)
{
TeamCity.ImportData("mstest", testResultsFile);
TeamCity.ImportDotCoverCoverage(coverageResultFile);
}
});
As you can see, during this task, tests were also run. So we can inform TeamCity both about test results and coverage analysis results. Method TeamCity.ImportDotCoverCoverage
does the last thing.
Publishing Artifacts
TeamCity allows you to publish some artifacts that will be available for each build. A good candidate for such artifacts is a NuGet package created during the build process:
In order to do it, place all your artifacts in a folder. Then you can publish this folder using TeamCity.PublishArtifacts
:
Task("Publish-Artifacts-On-TeamCity")
.Description("Publish artifacts on TeamCity")
.IsDependentOn("Create-NuGet-Package")
.WithCriteria(TeamCity.IsRunningOnTeamCity)
.Does(() => {
TeamCity.PublishArtifacts(artifactsFolder);
});
Conclusion
I hope these short code snippets will save you some time and effort if you want to run your Cake script on TeamCity. You can find the full version of the Cake script and application at GitHub. Good luck!
You can read more of my articles on my blog.