Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Мы в TeamCity всегда уделяли особое внимание .NET, его многочисленным инструментам и фреймворкам тестирования. В этом посте мы хотим рассказать о недавних обновлениях в нашей поддержке .NET и поделиться примером демо-проекта, который их иллюстрирует.
Сейчас поддержка .NET в TeamCity реализована с помощью огромного набора специализированных «ранеров» и «билд фичей». Ранеры обеспечивают интеграцию билда со сторонним софтом, а фичи выступают функциональными надстройками билда.
До версии 2020.1, TeamCity предоставлял следующие .NET компоненты:
- MSBuild – ранер с поддержкой MSBuild и Mono XBuild
- Visual Studio (sln) – ранер, имитирующий Visual Studio IDE (devenv), используя MSBuild
- Visual Studio 2003 – то же что и предыдущий ранер, но с учетом специфики Visual Studio 2003
- Visual Studio Tests – ранер, запускающий Visual Studio и MS тесты
- .NET Process Runner – ранер, запускающий .NET приложения
- .NET CLI Runner – ранер, обеспечивающий интеграцию TeamCity и .NET Core CLI
- NUnit – ранер, запускающий NUnit-тесты
- Набор ранеров для NuGet – поддержка утилиты nuget.exe CLI для Windows
- NuGet Pack
- NuGet Publish
- NuGet Installer
- Встроенный в TeamCity репозиторий пакетов NuGet
- TeamCity symbol server – накапливает и предоставляет отладочную информацию
- Интеграция с Azure DevOps (ранее Team Foundation Server)
- Duplicates Finder (ReSharper) – поиск дублирования кода
- Inspections (ReSharper) – инспекции кода на базе JetBrains Resharper
- FxCop – статический анализ качества кода на базе FxCop
- JetBrains dotTrace – тестирование производительности приложений с dotTrace Command-Line Profiler
- JetBrains dotMemory Unit – тестирование проблем памяти с JetBrains dotMemory Unit
- Поддержка платформы разработки 3D-приложений Unity
Такое разнообразие компонентов позволяет TeamCity использовать весь потенциал .NET, но имеет и минусы. Например, чтобы правильно сгруппировать части проекта и выбрать ранеры, чтобы построить приложения и протестировать их на требуемых ОС, каждый раз приходится учитывать множество факторов:
- Тип проекта
- Целевая платформа
- .NET-фреймворк
- Тестовый фреймворк
- Операционная система для тестирования
и т.д.
К счастью, с появлением .NET Core с открытым кодом и поддержкой кроссплатформенности, Microsoft постарались унифицировать и упорядочить инструменты разработки, объединив их в .NET SDK. Следующим шагом развития стал .NET 5 – он объединил .NET Core, .NET Framework, Xamarin и Mono. С версии 2020.1 TeamCity также объединил большинство своих компонентов, отвечающих за построение, тестирование и развертывание проектов, в один ранер .NET. Он консолидирует возможности ранеров из списка выше и предоставляет унифицированный подход. Мы надеемся, что это сильно упростит работу с .NET для наших пользователей. Новый ранер поддерживает:
- Команды .NET CLI
- Windows и кроссплатформенный MSBuild
- «Честный» Visual Studio IDE (devenv)
- Запуск Windows и кроссплатформенных тестов, в том числе NUnit и XUnit
- Запуск Windows, .NET процессов и командных скриптов на разных операционных системах
- Кроссплатформенную статистику покрытия кода
- Docker
Мы будем ограниченно поддерживать устаревшие ранеры, чтобы обеспечить плавную миграцию проектов на единый ранер .NET, но дальнейшего развития они не получат. Рекомендуем учесть это при создании новых конфигураций и при переходе на .NET 5 из последних версии Visual Studio и Rider.
Структура демо-проекта
Технически, ранер .NET – результат глубокой переработки привычного пользователям раннера .NET CLI. В нём появилась масса новых возможностей, которые мы хотим показать на примере демонстрационного .NET-проекта. Его исходный код и скрипт конфигураций TeamCity находятся в этом репозитории. А уже развернутый проект TeamCity можно посмотреть на этом демо-сервере.
Демо-проект .NET состоит из нескольких .NET проектов:
Название |
Тип проекта |
Описание |
Конфигурации TeamCity |
Развертывание |
Clock |
.NET Standard 1.2 |
Библиотека общей логики |
Создание пакета NuGet публикация |
NuGet |
Clock.IoC |
.NET Standard 1.2 |
Библиотека настройки IoC |
Создание пакета NuGet публикация |
NuGet |
Clock.Tests |
.NET 5.0 |
Тесты общей логики |
Тесты Windows Тесты Linux |
|
Clock.Console |
.NET 5.0 |
Консольное приложение |
Windows x64 Linux x64 Docker Nanoserver Docker Ubuntu Docker multi-arch |
Docker |
Clock.Web |
.NET 5.0 |
Web приложение |
Windows x64 Linux x64 Docker Nanoserver Docker Ubuntu Docker multi-arch |
Docker |
Clock.Desktop |
.NET 4.8 WPF |
Десктопное приложение |
Создание дистрибутива |
дистрибутив Windows |
Clock.Desktop.Uwp |
UAP |
UWP-приложение |
Создание пакета UWP |
пакет UWP |
Clock.Xamarin |
.NET Standard 1.2 |
Общая библиотека представлений Xamarin |
Cоздание Android-пакета |
пакет Android |
Clock.Xamarin.Android |
Xamarin Android |
Мобильное приложение Android |
Cоздание Android-пакета |
пакет Android |
Для настройки CI/CD-процесса, мы используем иерархию из проектов и билд-конфигураций. Хотя TeamCity предоставляет дружественный пользовательский интерфейс, все проекты и конфигурации были созданы средствами TeamCity Kotlin DSL. Так удобнее версионировать настройки проектов, а затем делиться ими. При желании вы сможете использовать их на своем сервере, избежав ручной настройки. Более подробную информацию о том, как создавать конфигурации через код, используя DSL, можно найти здесь (на английском).
Для запуска конфигураций в туториале мы используем 2 типа агентов:
- Windows 10 x64 Pro 10.0.19041
- Visual Studio 2019 Pro 16.8.1
- Docker (Windows container) 19.03.13
- .NET SDK 5.0
- Ubuntu 16.04
- Docker 18.06.3
Первым шагом мы создали и разместили на GitHub стандартный проект на Maven, используя IntelliJ IDEA 2020.2.2 с поддержкой всех его возможностей: подсветкой кода, рефакторингом и т.д. Чтобы сделать поддержку проекта еще более удобной, в его DSL-настройках мы использовали наследование типов Kotlin.
Этот DSL-код нужно подключить к соответствующему проекту .NET в TeamCity. Если вы решите разместить проект у себя на сервере, создайте новый проект в TeamCity с VCS root’ом, указывающим на наш репозиторий с DSL-настройками. Затем, в секции Versioned Settings, включите синхронизацию настроек с системой версионирования и выберите формат настроек “Kotlin”:
После синхронизации настроек, TeamCity подгрузит DSL-код и создаст вложенные подпроекты и конфигурации из него.
В корневой проект .NET входят два подпроекта: «Building» и «Deployment». Они содержат соответствующие их названиям билд-конфигурации.
Помимо них, прямо в корневом проекте .NET лежат две общие билд-конфигурации – Build и Deploy. Первая собирает все приложения и пакеты из подпроектов:
вторая – разворачивает их, в данном случае в репозитории Docker и NuGet:
Все конфигурации сборки объединяет то, что каждая содержит набор системных параметров, передаваемых в .NET-команды в виде пар ключ-значение /p:key=value
. Например, когда в билд-конфигурации определен системный параметр system.configuration=Release
, то при запуске различных команд им передается параметр /p:configuration=Release
. Префикс system.
при этом пропадает, так как в TeamCity он указывает на тип параметра, а за его пределами будет лишним. Все приведенные ниже системные параметры, определенные в наших конфигурациях сборки, не специфичны для TeamCity и описаны в различной документации по .NET:
Параметр | Значение в конфигурациях TeamCity | Описание | |
Все конфигурации сборки | configuration | Release | MSBuild-конфигурация. |
VersionPrefix | 1.0.0 | Используется как базовая версия для приложений и пакетов. | |
VersionSuffix | beta%build.number% | Используется как пререлизная метка в версии для приложений и пакетов. | |
Build console and web | InvariantGlobalization | true | Выполнять приложение без доступа к ресурсам, специфичным культуре. |
Build Windows desktop | PublishDir | ../bin/Clock.Desktop/win/ | Определяет путь публикации приложения. |
AppxPackageDir | ../bin/Clock.Desktop.Uwp/win/ | Определяет путь публикации пакета UWP приложения. | |
Pack | Copyright | Copyright 2020 JetBrains | Метаданные NuGet-пакетов. |
Title | TeamCity .NET sample | ||
RepositoryType | git | ||
RepositoryUrl | https://github.com/JetBrains/teamcity-dotnet-samples.git | ||
RepositoryBranch | refs/heads/master |
Эти параметры можно включить непосредственно в проектные файлы или передавать через параметры командной строки. Лучше использовать системные параметры TeamCity, так как это позволяет не заботиться о деталях передачи специальных символов – TeamCity позаботится об этом сам. Рассмотрим конфигурации тестирования и сборки подробнее.
Конфигурации «Test on Windows и Test on Linux»
Две эти конфигурации тестируют общую логику приложений и собирают статистику покрытия кода в Windows агента #1 и в Linux Docker-контейнере mcr.microsoft.com/dotnet/core/sdk:5.0, используя один шаг сборки .NET. Для сценария Linux Docker, в UI он выглядит так:
В этом сценарии тесты и тестируемые библиотеки собираются и тестируются в Linux Docker-контейнере с .NET SDK 5.0. Конфигурация для тестов под Windows отличается лишь тем, что не использует Docker.
Тестовый проект Clock.Tests является приложением .NET 5.0, поэтому для построения и запуска тестов достаточно одной .NET Core CLI команды test
. Для сбора и анализа статистики покрытия кода используется кроссплатформенный инструмент для оценки покрытия кода JetBrains dotCover из пакета JetBrains.dotCover.DotNetCliTool, который устанавливается как инструмент TeamCity. В DSL, тестовые конфигурации имеют общего предка TestBase и две конфигурации для тестов на Linux и для тестов на Windows.
Конфигурации «Build console and web for win-x64» и «Build console and web for linux-x64»
Эти две TeamCity конфигурации для Linux и для Windows собирают по два проекта Clock.Console и Clock.Web и состоят из двух шагов сборки, соответствующих этим проектам. Конфигурации наследуются от BuildConsoleAndWebBase, который в свою очередь наследуется от базового типа для всех конфигураций сборки приложений – BuildBase. Оба шага можно было бы объединить в один, указав в Projects сразу два проекта, но в этом случае было бы сложно разделить бинарные файлы от разных приложений, как это сейчас сделано через outputDir. Так как оба приложения имеют тип .NET 5.0, как и в предыдущем случае, для построения и публикации достаточно одной .NET Core CLI команды publish
.
Вот как выглядит первый шаг в UI для Linux, который строит и публикует приложение Clock.Console в виде единственного запускаемого файла в папку, определенную в поле Output directory:
Для Windows, данный шаг отличается полем Runtime, в котором определено значение win-x64, и полем Output directory со значением bin/Clock.Console/win-x64.
Второй шаг для построения и публикации приложения Clock.Web для Linux отличается от первого шага, помимо пути к проектному файлу, полем Output directory со значением bin/Clock.Web/linux-x64. После завершения шагов, TeamCity публикует построенные приложения как артефакты билда.
Для win-x64:
- bin/Clock.Console/win-x64/Clock.Console
- bin/Clock.Console/win-x64/Clock.Web
Для linux-x64:
- bin/Clock.Console/linux-x64/Clock.Console
- bin/Clock.Console/linux-x64/Clock.Web
Конфигурация «Build Windows desktop»
В этой конфигурации всего один шаг:
На этом шаге запускается Windows MSBuild из Visual Studio 2019 на агенте #1 для выполнения «таргетов» Restore, Rebuild и Publish последовательно для каждого из двух проектов:
- Clock.Desktop/Clock.Desktop.csproj
- Clock.Desktop.Uwp/Clock.Desktop.csproj
Результаты сборок публикуются в разные директории, определенные в системных параметрах конфигураций PublishDir (для Clock.Desktop) и AppxPackageDir (для Clock.Desktop.Uwp). Эти директории далее публикуются как артефакты билда.
Конфигурация «Build Android app»
Эта конфигурация строит мобильное приложение Android, используя Windows MSBuild из Visual Studio 2019, на агенте #1:
Она аналогична предыдущей конфигурации, но вместо MSBuild «таргета» Publish здесь используется «таргет» SignAndroidPackage, чтобы опубликовать подписанный Android-пакет.
Конфигурация «Pack»
Эта конфигурация создает два NuGet-пакета и содержит один шаг .NET CLI с командой pack
, выполненной последовательно для двух проектов – Clock и Clock.IoC:
Такие метаданные для NuGet-пакетов как название, тип репозитория и т.д., определены через системные параметры конфигурации TeamCity – их список есть в таблице выше. После успешного выполнения этой конфигурации, в артефактах появляются NuGet-пакеты, готовые для отправки в репозиторий на этапе развертывания.
Конфигурация «Build»
Эта особая конфигурация TeamCity не содержит шагов сборки. Она предназначена для того, чтобы собрать все артефакты приложений и пакетов в один TeamCity-билд через артефакт-зависимости на остальные конфигурации сборки:
Конфигурация «Deploy»
Это похожая конфигурация для развертывания, которая не содержит шагов, а только зависимости на другие конфигурации:
- Push image … строит и публикует образы для Linux и Windows
- Push multi-arch image … создаёт и публикует манифесты для мульти-архитектурных образов Docker.
- Publish to NuGet публикует ранее созданные NuGet пакеты в TeamCity NuGet.
Чтобы подключить опубликованные NuGet-пакеты с общей логикой к проектам, можно использовать этот NuGet-источник. Для запуска приложений Clock.Console в Docker используйте команды:
docker pull nikolayp/clock-console
docker run -it --rm nikolayp/clock-console
А для Clock.Web:
docker pull nikolayp/clock-web
docker run -it --rm -p 5000:5000 nikolayp/clock-web
После запуска веб-приложения в контейнере, оно будет доступно по адресу http://localhost:5000/.
Все приложения и пакеты можно посмотреть в артефактах здесь.
Заключение
Microsoft активно развивает .NET 5, ведь он предоставляет разработчикам свободный и единый инструментарий. Мы в TeamCity верим, что наш обновленный ранер .NET позволит сделать непрерывную интеграцию проектов на .NET 5 удобной и предсказуемой.
Если вы уже пробовали новый ранер или просто хотите поделиться мнением о нем, пишите в комментариях. Всегда рады вашей обратной связи.