Cake — замечательный инструмент для создания конвеера доставки для ваших приложений. Я люблю его, поскольку он позволяет мне писать этот конвеер на языке C#, который я знаю хорошо. Прекрасным свойством Cake, PSake и дургих подобных фреймворков является то, что они создают скрипт, который можно выполнять как на локальной машине разработчика, так и на CI серверах. Здесь я объясню, как организовать взаимодействие скрипта Cake с TeamCity.
Требования
Я буду полагать, что вы уже имеете начальные знания по Cake и TeamCity. В противном случае можете начать с чтения следующих ресурсов:
Для Cake:
Для TeamCity:
Теперь давайте поговорим о взаимодействии Cake и TeamCity.
Логирование
Конвеер Cake обычно состоит из нескольких задач (task). Было бы здорово иметь для каждой такой задачи отдельную секцию в журнале (build log) TeamCity. Я бы хотел получить сворачиваемую секцию для каждой задачи Cake в журнале:
Cake API имеет методы TeamCity.WriteStartBuildBlock и TeamCity.WriteEndBuildBlock. Хотя и возможно использовать их в каждой задаче, но это можно автоматизировать. В Cake есть методы TaskSetup и TaskTeardown, которые вызываются перед и после каждой задачи. Они могут открывать и закрывать блоки журнала TeamCity:
TaskSetup(setupContext =>
{
if(TeamCity.IsRunningOnTeamCity)
{
TeamCity.WriteStartBuildBlock(setupContext.Task.Name);
}
});
TaskTeardown(teardownContext =>
{
if(TeamCity.IsRunningOnTeamCity)
{
TeamCity.WriteEndBuildBlock(teardownContext.Task.Name);
}
});
Здесь свойство TeamCity.IsRunningOnTeamCity используется чтобы определить, выплняется код на TeamCity или нет.
Теперь в нашем журнале есть сворачиваемые блоки для каждой задачи. Но можно добавить еще одно улучшение.
Обычно задачи в Cake имеют короткие имена: Build, Test, Clean. Так их легче запускать из командной строки. Но в журнале TeamCity я бы предпочел иметь более развернутые описания задач Cake. И это возможно сделать. Чтобы дать задаче описание, используйте метод Description:
Task("Clean")
.Description("Create and clean folders with results")
.Does(() => { ... });
Теперь эти описания можно использовать для формирования блоков в журнале:
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);
}
});
Это позволяет повысить его читаемость.
Прогресс выполнения
Если работа скрипта Cake занимает много времени, полезно знать, какая именно задача выполняется в данный момент.
Этого можно достичь с помощью методов TeamCity.WriteStartProgress и TeamCity.WriteEndProgress. Их вызовы можно вставить в те же TaskSetup и 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);
}
});
Результаты тестов
Если вы выполняете тесты в задаче Cake, то TeamCity способна показать вам их результаты.
Это можно сделать с помощью метода TeamCity.ImportData. Он принимает два параметра: строковое описание типа данных и путь к файлу, эти данные содержащему. Например, есть вы используете MSTest, вот как сообщить TeamCity о результатах выполнения тестов:
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 поддерживает несколько типов тестов. Кроме mstest вы можете использовать nunit, vstest и некоторые другие.
Анализ покрытия кода тестами
TeamCity способен показать результат анализа покрытия кода тестами.
На данный момент TeamCity поддерживает интеграцию с DotCover. Позвольте показать, как использовать DotCover в скрипте Cake. Сначала DotCover нужно установить:
#tool "nuget:?package=JetBrains.dotCover.CommandLineTools"
После этого его можно использовать в задачах:
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);
}
});
Как видите, здесь так же прогоняются и тесты. Поэтому мы сразу можем сообщить TeamCity о результатах тестов и результатах анализа покрытия ими кода. Метод TeamCity.ImportDotCoverCoverage именно и делает это последнее.
Публикация артефактов
В TeamCity вы можете опубликовать некоторые артефакты, созданные в процессе работы скрипта Cake. Хорошим кандидатом на эту роль являются NuGet пакеты:
Чтобы сделать это, положите все артефакты, которые хотите опубликовать, в одну папку. Затем можно выполнить публикацию методом TeamCity.PublishArtifacts:
Task("Publish-Artifacts-On-TeamCity")
.Description("Publish artifacts on TeamCity")
.IsDependentOn("Create-NuGet-Package")
.WithCriteria(TeamCity.IsRunningOnTeamCity)
.Does(() => {
TeamCity.PublishArtifacts(artifactsFolder);
});
Заключение
Надеюсь, эти простые примеры кода сэкономят вам время и усилия, если вы хотите, чтобы ваш скрипт Cake работал на TeamCity. Полную версию скрипта и обрабатываемого им приложения можно найти на GitHub. Удачи!
Автор: iakimov