Cake is a great tool for creating a delivery pipeline for your applications. I love it because it allows me to write this pipeline in C #, which I know well. A great feature of Cake, PSake and other similar frameworks is that they create a script that can be executed on the local developer’s machine as well as on CI servers. Here I will explain how to organize the interaction of the Cake script with TeamCity .
I will assume that you already have a basic knowledge of Cake and TeamCity. Otherwise, you can start by reading the following resources:
For Cake:
For TeamCity:
Now let's talk about the interaction of Cake and TeamCity.
Conveyor Cake usually consists of several tasks (task). It would be great to have for each such task a separate section in the log (build log) TeamCity. I would like to get a collapsible section for each Cake task in the log:
Cake API has TeamCity.WriteStartBuildBlock and TeamCity.WriteEndBuildBlock methods. Although it is possible to use them in each task, it can be automated. Cake has TaskSetup and TaskTeardown methods that are called before and after each task. They can open and close the TeamCity journal blocks:
TaskSetup(setupContext => { if(TeamCity.IsRunningOnTeamCity) { TeamCity.WriteStartBuildBlock(setupContext.Task.Name); } }); TaskTeardown(teardownContext => { if(TeamCity.IsRunningOnTeamCity) { TeamCity.WriteEndBuildBlock(teardownContext.Task.Name); } });
Here, the TeamCity.IsRunningOnTeamCity property is used to determine whether the code is executed on TeamCity or not.
Now in our magazine there are collapsible blocks for each task. But you can add another improvement.
Usually tasks in Cake have short names: Build , Test , Clean . So they are easier to run from the command line. But in TeamCity, I'd rather have more detailed descriptions of Cake tasks. And it is possible to do. To give the task a description, use the Description method:
Task("Clean") .Description("Create and clean folders with results") .Does(() => { ... });
Now these descriptions can be used to form blocks in the journal:
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); } });
This improves its readability.
If the work of the Cake script takes a lot of time, it is useful to know exactly which task is being performed at the moment.
This can be achieved using the 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); } });
If you run tests in a Cake task, then TeamCity is able to show you their results.
This can be done using the TeamCity.ImportData method. It takes two parameters: a string description of the data type and the path to the file that contains the data. For example, if you use MSTest, here’s how to tell TeamCity about test 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. In addition to mstest, you can use nunit , vstest and some others .
TeamCity is able to show the result of the analysis of code coverage tests.
Currently TeamCity supports integration with DotCover . Let me show you how to use DotCover in a Cake script. First you need to install DotCover:
#tool "nuget:?package=JetBrains.dotCover.CommandLineTools"
After that it can be used in tasks:
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, tests are also run here. Therefore, we can immediately inform TeamCity about the test results and the results of the analysis of their code coverage. The TeamCity.ImportDotCoverCoverage method does exactly this last.
In TeamCity, you can publish some artifacts created by the Cake script. A good candidate for this role are NuGet packages:
To do this, put all the artifacts you want to publish in one folder. Then you can publish using the TeamCity.PublishArtifacts method:
Task("Publish-Artifacts-On-TeamCity") .Description("Publish artifacts on TeamCity") .IsDependentOn("Create-NuGet-Package") .WithCriteria(TeamCity.IsRunningOnTeamCity) .Does(() => { TeamCity.PublishArtifacts(artifactsFolder); });
I hope these simple code examples will save you time and effort if you want your Cake script to work on TeamCity. The full version of the script and the application it processes can be found on GitHub . Good luck!
Source: https://habr.com/ru/post/432814/
All Articles