Pull to refresh

Интеграция Cake и TeamCity

Reading time 4 min
Views 3.4K
Original author: Ivan Iakimov

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. Удачи!

Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
+11
Comments 2
Comments Comments 2

Articles