17 августа 2013 в 19:44

Continuous Integration для самых маленьких tutorial

Вы все еще публикуете проект вручную? Тогда мы идем к вам


Под катом гайдлайн по внедрению CI для .NET проектов «с нуля», включающий:
  1. Автоматические ежедневные сборки
  2. Уведомления о проблемах
  3. Интеграцию с баг-трекером и системой контроля версий
  4. Версионирование продукта
  5. Версионирование базы данных
  6. Автоматизированные выкладки и бекапы


Начнем с того, что же такое «непрерывная интеграция».
Непрерывная интеграция (англ. Continuous Integration) — это практика разработки программного обеспечения, которая заключается в выполнении частых автоматизированных сборок проекта для скорейшего выявления и решения интеграционных проблем.

С практической точки зрения это значит, что в любой момент времени у вас должна быть «живая актуальная версия продукта», которую можно протестировать или продемонстрировать.
Для этого нужно:
  1. Чтобы разработчики вносили свой код в VCS по крайней мере каждый день
  2. Сборка продукта происходила в автоматическом режиме
  3. Выкладка продукта (в том числе, обновление базы данных) происходила в автоматическом режиме
  4. Тестирование продукта происходило в автоматическом режиме (насколько это возможно)

Continuous Integration относится к agile-практикам. Agile предполагает итерационный процесс, с многократным повторением цикла разработки, тестирования и выкладки продукта. Автоматизация рутинных процессов позволяет избежать многократного выполнения рутинных операций.

Работа с VCS

Для начала нам потребуется тестовое окружение для тестирования приложения. Если цикл тестирования достаточно длительный, а разработка ведется быстро, то разумно выделить еще и dev-окружение. Структура VCS будет отражать ваши окружения.
Все разработчики работают с основной веткой разработки, затем определенная версия фиксируется и мержится в тестовую ветку. Из тестовой ветки происходит выкладка на тестовое окружение. Производится тестирование, внесение фиксов и обратный мерж в дев. Протестированная версия отправляется в релизную ветку и от туда публикуется на продакшн. В случае нахождения ляпов на продакшне (к сожалению, такое бывает) чиним в авральном режиме из продакшн ветки и опять мержим в DEV-ветку.

В философии GIT будет немного иначе, так как при работе с GIT не принято комитить в master и даже dev. Вместо этого практикуется подход фича-бренч. Про git workflow можно почитать здесь: habrahabr.ru/post/60030. Вообще, все предлагаемые структуры VCS преследуют одну цель: избежать ситуации, когда ветка разработки не стабильна, а совершенно необходимо что-то быстро «пофиксить» или «допилить» и выложиться. При выборе своей структуры задайте себе вопрос «смогу ли я выложиться на продакшн в течение одного дня и не поломать все. Если ответ «да», то структура вам подходит.

Чтобы не пропускать ошибки на продакшн, следует сделать тестовое окружение на столько похожим на целевое, на сколько это возможно. Обычно, главная сложность это зависимость от сторонних веб-сервисов или других компонентов и операции, связанные с реальными финансовыми транзакциями.

Конфигурации

Как бы мы не старались сделать окружения идентичными, конфигурационные файлы будут отличаться: тестовые и реальные аккаунты, токены, ID, внешние веб-сервисы и другое. .NET предлагает отличное средство поддержание конфигураций в актуальном виде: трансформации конфигов. Почему-то «из коробки» они включены только в веб-приложения. К счастью трансформации достаточно легко добавить и в другие приложения.
  <UsingTask TaskName="TransformXml"
    AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
  <Target Name="AfterCompile" Condition="Exists('App.$(Configuration).config')">
    <!--Generate transformed app config in the intermediate directory-->
    <TransformXml Source="App.config" Destination="$(IntermediateOutputPath)$(TargetFileName).config"
      Transform="App.$(Configuration).config" />
    <!--Force build process to use the transformed configuration file from now on.-->
    <ItemGroup>
      <AppConfigWithTargetPath Remove="App.config" />
      <AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config">
        <TargetPath>$(TargetFileName).config</TargetPath>
      </AppConfigWithTargetPath>
    </ItemGroup>
  </Target>

Начинающие разработчики часто впадают в ступор при отладке трансформаций Web.config’а на локальных машинах: в отличие от App.config’ов они хранятся на уровне приложения, а не в папке bin, поэтому при локальной сборке трансформации не происходит. Трансформации применяются при публикации проекта. Если вам действительно нужно обойти это ограничение, можно создать файл Web.template.config и добавить трансформацию на PostBuild приложения. Не забудьте только убрать таск трансформации из проекта, иначе трансформация будет применяться дважды.
Если в приложении используют другие технологии, все-равно лучше иметь один основной конфигурационный файл с общими настройками и дополнительные конфигурационные файлы для изменения эталонного конфига. Это избавит вас от копипаста одинаковых настроек.

Добавление файлов, отсутствующих в проекте к выкладке


  <PropertyGroup>
    <CopyAllFilesToSingleFolderForPackageDependsOn>
    CustomCollectFiles;
    $(CopyAllFilesToSingleFolderForPackageDependsOn);
  </CopyAllFilesToSingleFolderForPackageDependsOn>
  </PropertyGroup>
  <Target Name="CustomCollectFiles">
    <!-- Copy JavaScript files -->
    <ItemGroup>
      <CompressedScripts Include="Sources\**\*.js" />
      <FilesForPackagingFromProject Include="%(CompressedScripts.Identity)">
        <DestinationRelativePath>Sources\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
      </FilesForPackagingFromProject>
    </ItemGroup>
    <!-- Copy stylesheets -->
    <ItemGroup>
      <CompressedScripts Include="Sources\**\*.css" />
      <FilesForPackagingFromProject Include="%(CompressedScripts.Identity)">
        <DestinationRelativePath>Sources\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
      </FilesForPackagingFromProject>
    </ItemGroup>
  </Target>


Версионирование продукта

.NET предоставляет 2 атрибута для версионирования сборок
[assembly: AssemblyVersion(«1.0.0.0»)]
[assembly: AssemblyFileVersion(«1.0.0.0»)]
Первые две цифры – это мажорный и минорный номер версии. Эти цифры интерпретируют инкремент изменения функционала. Третья цифра – это, так называемый, номер сборки. Каждый день, пока версия находится в разработке эта версия увеличивается. И последний номер – это номер ревизии. Этот номер увеличивается каждый раз при сборке версии на билд-сервере в течение дня. Подробно о политике версионирования в .NET написано в книге CLR via C# Рихтера.
Автоматическое версионирование может быть настроено разными способами. Подробно эта тема обсуждается здесь: stackoverflow.com/questions/1126880/how-can-i-auto-increment-the-c-sharp-assembly-version-via-our-ci-platform-hudso.

Основные подходы

  1. Использование версии вида 1.0.*.* (плохо сочетается с билд-сервером)
  2. Использование единого файла SharedAssemblyInfo для управления версиями всех сборок из оного места (создается один файл с номером версии и добавляется “as a link” ко всем проектам
  3. Использование msbuild, вместо файла AssemblyInfo
  4. Для TFS можно использовать WWF-Activity

На мой взгляд удобнее всего использовать msbuild и проставлять значение с помощью CI-сервера:
<Major>1</Major>
<Minor>0</Minor>
<Build>$(BUILD_NUMBER)</Build>

Все современные CI-решения предлагают такую переменную во время сборки. Для того, чтобы этот подход работал, нужно добавить импортировать msbuild-таски из msbuildtasks.tigris.org и добавить в конце проекта:
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" Condition="Exists('$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets')" />
  <Target Name="BeforeBuild" Condition="Exists('$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets')">
    <Message Text="Version: $(Major).$(Minor).$(Build).$(Revision)" />
    <AssemblyInfo CodeLanguage="CS" OutputFile="AssemblyFileInfo.cs" AssemblyFileVersion="$(Major).$(Minor).$(Build).$(Revision)" AssemblyConfiguration="$(Configuration)" Condition="$(Revision) != '' " />
  </Target>


Версионирование базы данных

Я не знаю ни одного проекта, в котором не приходилось бы менять базу данных. .NET предлагает следующие решения:

SSDT-проект msdn.microsoft.com/ru-ru/data/tools.aspx

Плюсы: процесс создания и редактирования БД напоминает то, как бы вы это делали с Management Studio.
Минусы: сложность написания миграционных скриптов. Т.к. инкрементальные изменения строит сам проект, сохранность данных обеспечивается за счет pre-deploy и post-deploy-скриптов. Придется опираться на наличие/отсутствие полей в БД или «изобретать» таблицу schema version, уже реализованную в миграционных движках.

ECM7 Migrator code.google.com/p/ecm7migrator

Движок миграций с открытым кодом. Проект поддерживает хабраюзер dima117.
Плюсы: поддерживаются разные СУБД, если что-то вас не устраивает, код открыт. Мигратор поддерживается и обрастает новыми функциями. И, пожалуй, самое важное, поддерживает несколько ключей миграций в одной базе данных. Это может быть очень полезно, если ваше приложение модульное и поддерживает плагины в том или ином виде. Каждый плагин может выполнять свои миграции и при этом использовать одну БД
Минусы: нет плюшек Entity Framework Migrations.

Entity Framework Migrations blogs.msdn.com/b/adonet/archive/2012/02/09/ef-4-3-code-based-migrations-walkthrough.aspx

Плюсы: работает из коробки, автоматически создает миграции по Db-контексту, понимает команды из консоли visual studio, миграции публикуются с помощью стандартного Publish из Visual Studio.
Минусы: зависит от Entity Framework.


Я успел попробовать все 3 решения. Если вы используете EF, выбор – однозначно EF Migrations, для .NHibernate можно воспользоваться ECM7 Migrator. SSDT-проект подойдет любителям визардов и окошек.

Автоматизация публикации приложения

В 2012 студии система публикации web-проектов была значительно улучшена. В первую очередь это касается профилей публикации. Если вы публикуете приложение в azure, то профиль можно просто скачать с портала. В противном случае его нужно будет создать.




Как видно на скриншотах, в последней версии WebDeploy можно запустить EF-миграции с помощью всего одной галочки. Кроме этого публикация из студии умеет заменять строку подключения без использования трансформации.
Подробно про трансформации и публикации написано у Троя Ханта в статье: www.troyhunt.com/2010/11/you-deploying-it-wrong-teamcity.html. Сейчас нас интересует пятый шаг его гайдлайна, а именно, автоматическая публикация с помощью билд-сервера: www.troyhunt.com/2010/11/you-deploying-it-wrong-teamcity_26.html. Я большой фанат TeamCity, поэтому рассмотрим именно эту CI.

Автоматизация публикации Windows-служб

Для автоматического создания windows-служб проще всего воспользоваться командной sc:
sc [<ServerName>] create|stop|start <ServiceName> binpath= <BinPath> start= demand

Единственный тонкий момент – каким образом доставить бинарники в <BinPath>. Это можно сделать разными способами: залить по FTP, воспользоваться PowerShell, использовать xcopy/robocopy или rsync в расшаренную папку на сервере. Выбор зависит от вашего сетевого окружения и требований к безопасности.

TeamCity

Использование средств, описанных выше, сэкономит ваше время. Пойдем дальше и установим билд-сервер. Скачиваем TeamCity: www.jetbrains.com/teamcity и запускаем инсталятор, жмем везде «Ок».
Два основных понятия TeamCity – «проект» и «билд». «Проект» соответствует вашему солюшну, а под билдом понимается любая осмысленная совокупность действий над вашим проектом: будь то сборка, запуск тестов, выкладка на сервер, создание бекапов и так далее.

Автоматизированная выкладка

Первым шагом, дадим возможность выкладывать новую версию тему у кого Visual Studio не устновлена.
Основная идея, это запустить msbuild-шаг с дополнительными параметрами, создайте новый Build Definition и выберите первый шаг Msbuild. В параметры командной строки нужно передать:
/P:Configuration=%env.Configuration%
/P:DeployOnBuild=True
/P:DeployTarget=MSDeployPublish
/P:MsDeployServiceUrl=https://%env.TargetServer%/MsDeploy.axd
/P:AllowUntrustedCertificate=True
/P:MSDeployPublishMethod=WMSvc
/P:CreatePackageOnPublish=True
/P:UserName=AutoDeploy\Administrator
/P:Password=Passw0rd

Эти параметры укажут, куда нужно публиковать.
Для того, чтобы опубликовать миграции потребуется дополнительный шаг Command Line:
SET AssemblyName=MyMvc4App
SET StartUpDirectory=MyMvc4App\bin\
SET ConnectionString=Server=tcp:XXXX.database.windows.net,1433;Database=XXXX;User ID=XXXX;Password=XXXX;Trusted_Connection=False;Encrypt=True;Connection Timeout=30;MultipleActiveResultSets=True
SET ConnectionStringProvider=System.Data.SqlClient
SET ConfigFilePath=%CD%\MyMvc4App\web.config
SET MigrateExe=packages\EntityFramework.5.0.0\tools\migrate.exe
%MigrateExe% %AssemblyName%.dll /startUpDirectory:%StartUpDirectory% /startUpConfigurationFile:"%ConfigFilePath%" /connectionProviderName:"%ConnectionStringProvider%" /connectionString:"%ConnectionString%" /verbose

Сохраняете билд. Теперь кто угодно может опубликовать последнюю версию из VCS. Хорошая практика публиковаться на дев-стенд каждый день до начала рабочего дня. Таким образом вы будете отлавливать интеграционные проблемы максимально быстро.

Rolling builds

Еще одна хорошая практика – настроить триггер на запук билда, который просто будет запускать сборку вашего солюшна после каждого изменения в репо или по таймеру (например, каждые 10 минут), если над проектом работает одновременно очень много разработчиков. К этому билду следует подключить нотификацию. TeamCity поддерживает нотификации по почте, jabber, с помощью плагина для VisualStudio и Tray-приложения. Выберите вариант по вкусу. Мне по душе приложение в трее. Если билд сломался – надо срочно чинить.

Как не ломать билд

Какие бы практики вы не вводили, чтобы не делали, не существует никакого способа дать 100% гарантию, что разработчики не будут вносить в VCS код, который даже не собирается. Этот вопрос должен решаться с помощью административных мер: не уходить с работы, не проверив, что билд после твоих изменений собрался, кто сломал, тот и чинит. В одной компании, где я работал проблема со слишком часто сломанным билдом была решена правилом: сломал билд – принеси тортик. Сначала торты ели каждый день, потом перестали.

Автоматический запуск тестов

Этот шаг следует разделить на 2: юнит-тесты и интеграционные и приемочные тесты. Это важно, потому что юнит-тесты должны работать на любом окружении. Все внешние зависимости заменяются фейками.

Запуск юнит-тестов

Здесь все просто. Выбирайте Build Step “Nunit” или “MsTest”, вводите паттерн **.Test*.dll все остальное TeamCity сделает за вас, при условии, что вы используете паттерн .Tests в названии ваших тестовых проектов.

Запуск интеграционных и приемочных тестов

Эти тесты могут зависеть от многих факторов и их запуск может предполагать накатывание бекапов или скриптов инициализации. Возможно, что вы захотите построить дополнительные отчеты о запуске таких тестов. Лучше не захламлять ваш проект с выкладкой и создать для них специальный билд. TeamCity позволяет создавать цепочки билдов. В Build triggers билда с приемочными/интеграционными тестами вы можете добавить триггер, срабатывающий при удачном прохождении билда с выкладкой. Создание такого билда для запуска приемочных тестов я описал в топике: habrahabr.ru/post/182032.

Бекапы

Создание бекапов при выкладке также может быть автоматизировано. Для бекапа файловой системы, лично я не нашел ничего лучше, чем nnbackup: www.nncron.ru/index_ru.shtml.
nnbackup -n 10 verz -i <Src> -o <Destination> -s -e –v

Команда создает аривирует в zip папку source и копирует архив в destination. Устанавливать nnbackup на целевые машины или вызывать с билд-сервера: вопрос ваших предпочтений, расположения билд сервера, сетевых издержек и безопасности.

Бекапить sql-сервер можно с помощью T-SQL
BACKUP DATABASE AdventureWorks2012 TO DISK='X:\SQLServerBackups\AdventureWorks1.bak', DISK='Y:\SQLServerBackups\AdventureWorks2.bak', DISK='Z:\SQLServerBackups\AdventureWorks3.bak' WITH FORMAT, MEDIANAME = 'AdventureWorksStripedSet0', MEDIADESCRIPTION = 'Striped media set for AdventureWorks2012 database; GO
RESTORE DATABASE AdventureWorks FROM DISK='$(Backup)'

Т.е. для автоматического бекапа, вам потребуется добавить еще один Command Line-шаг. Или вы можете воспользоваться msbuild-тасками из того-же самого community-пакета, а для nnbackup написать свой msbuild-таск.
Можно пойти дальше и поставить триггер на запуск автоматического отката из бекапа, если приемочные тесты не прошли. Тогда у вас будет цепочка билдов: Выкладка » Приемочные тесты » Откат из бекапа.

Интеграция с системой ведение проекта и баг-трекером

До этого момента, мы уже сделали много полезного. Осталась одна неприятная особенность. Билд-сервер все-еще никак не связан с нашим процессом разработки. Он ничего не знает о задачах текущей итерации разработки.
TeamCity поддерживает интеграцию с YouTrack, Jira и Bugzilla. Интеграция выполняется буквально в 2 клика. После этого, указывая номер задачи в комментарии к комиту, вы увидите ссылки на соответствующие задачи в информации о билде.
YouTrack поддерживает обратную интеграцию. Основное преимущество: YouTrack будет автоматически указывать номер билда, в котором баг или фича были закрыты.

Артефакты билда

Если ваше приложение коробочное, то вам, наверняка нужно озаботиться созданием инсталляторов или deploy packages для отгрузки клиентам. Создание инсталляторов – отдельная тема, я не буду ее рассматривать в рамках этого топика. Важно, что для коробочного продукта, инсталлятор или пакет публикации – это самая важная часть релиза. Как раз для этого и придуманы артефакты билда.

Артефакт – это любой файл, являющийся значимым результатом выполнения билда. Для билдов с инсталляторами вы можете указать my-installer.exe или my-package.zip, как маску для артефактов билда и TeamCity отобразит их в соответствующей вкладке.
Вот здесь и пригодится интеграция с Issue Tracker’ом. Тестировщик или менеджер может посмотреть закрытую задачу, перейти по ссылке с билдом и забрать версию с исправлениями из артефактов билда.

В заключение хочу добавить, что процесс разработки сугубо индивидуален для каждой команды. Приведенные практики являются базой. Дальнейшее развитие инструментария должно происходить вместе с развитием продукта. Мы разрабатываем софт, чтобы делать жизнь других людей лучше. Разумно использовать софт и для того, чтобы нам самим было комфортнее работать.
Максим Аршинов @marshinov
карма
85,0
рейтинг 5,6
Управление разработкой бизнес-приложений
Похожие публикации
Самое читаемое Разработка

Комментарии (46)

  • +1
    По поводу миграций — рекомендую обратить внимание на штуку под названием FluentMigrator, позволяет писать миграции вида:
    [MigrationDate (2013, 8, 17, 19, 50)]
    public class MyMigration : Migration
    {
    	public override void Up ()
    	{
    		Create.Table ("GnsTags")
    			.WithColumn ("EntryKind").AsEnum ("Merchandise", "Advertisement").NotNullable ()
    			.WithColumn ("EntityId").AsUInt32 ().NotNullable ()
    			.WithColumn ("Tag").AsString ().NotNullable ();
    		Create.Column ("IsDeleted").OnTable ("GnsGoods").AsBoolean ().NotNullable ();
    	}
    	public override void Down ()
    	{
    		//Тут код отката в том же стиле
    	}
    }
    
    Поддерживает несколько движков БД. Из минусов могу назвать только тот факт, что миграции всё же приходится писать вручную.
    • 0
      Есть программа, которая сама сгенерирует миграции по схеме бд (mssql — другие СУБД не проверял). Правда, я, как новичок в разработке, не могу сказать, насколько оптимально/оптимизировано происходит генерация.
  • 0
    Вообще, все предлагаемые структуры VCS преследуют одну цель: избежать ситуации, когда ветка разработки не стабильно, а совершенно необходимо что-то быстро «пофиксить» или «допилить» и выложиться.


    Лично мне нравится, когда в VCS одна общая ветка, а бранчи создаются из истории при необходимости (а не сразу после релиза). Так значительно проще.
    • 0
      Да, я тоже против создания лишних веток. Где-то на хабре была статья, объясняющая почему Github не использует git workflow: как раз из-за оверхеда с бренчами. Принудительное создание веток хорошо работает, когда разграничены права на публикацию разных окружений или когда разработчиков очень много.
  • +8
    Мне вот интересно, почему в каждой статье про CI забывают упомянуть про то, что бывают gated checkins, когда код, который не проходит тесты, просто не попадает в репозиторий? Это (очень) резко уменьшает количество сломанных билдов в CI и вообще битого кода в репозитории.
    • +1
      Вы когда-нибудь видели GC в крупных проектах, а не коде с одной сборкой? :) Гораздо более распространенная практика — не давать деплоить куда-либо при непрохождении некоего code-quality билда.
      • 0
        Вот по этому и не упомянул.
      • +3
        я видел, на текущем проекте именно так и работаем.
        это адъ.
      • +1
        Я не просто видел, я так работаю. И в чем проблема?

        Как раз наоборот, на коде, где больше одной сборки, это становится критичным, потому что зависимостей больше, и учесть их все становится сложно.
      • 0
        Вижу у себя на работе. Что не так с крупными проектами?
        • +1
          Ну, с точки зрения разработчика все шикарно: пушнул и пол-часа куришь. Время адекватного реагирования на изменения в коде возрастает в разы. И смысла немного. С точки зрения безопасного кода на проде (тесте и и.п. ) гораздо лучше тот вариант, что я описал.
          • 0
            А что мешает мощности-то нарастить? Слава б-гу, билд-сервера дешевле разработчиков.

            Ну и да, правило большого пальца: пречекин должен выполняться за пять минут. Если это не так — вы либо правите тесты, либо сокращаете тесты, либо наращиваете мощности. Либо комбинируете подходы.
            • +2
              Наше бух-приложение хреново работает на 32-процессорном сервере, что мы лохи, что ли, давайте затарим прайват клауд, да, слыхал такое. К успеху идете :)
              • 0
                Специально для таких комментариев был первый пункт: «правите тесты».
                • 0
                  Обычно, при начальной оценке проекта, некоторая доля времени выделяется на не-функциональные риски и нужды(ну там, заболеет кто, инфраструктуру надо настроить, в конце-концов, никто в команде не работает 8 из 8 часов в день и т.п.), но вот правда, ни разу не слышал, чтобы кто-то закладывал время на правку юнит-тестов, потому что они сильно медленные или тяжелые. Какой в этом смысл? Зачем за это платить заказчику? Юнит тесты могут хоть 2 часа работать, главное, чтобы выполняли свою роль, а для долгих тестов всегда есть nightly builds.
                  • 0
                    Знаете, я тоже не слышал, чтобы при начальной оценке проекта закладывали время на правку производительности кода…

                    Ну и да, если вы считаете, что юнит-тесты могут хоть два часа работать — значит, вы не понимаете роли юнит-тестов. Никто не будет гонять тест-сьют, который идет два часа, а значит, весь смысл потерян.
                    • 0
                      Да, я дейтсвительно считаю, что если в проекте есть UT, их много и они в сумме работают 2 часа — то это ОК. Опять же, напомню, мы говорим о больших проектах. Обычный девелопер, работая с модулем ранит небольшой сьют, которые отрабатывает за 2-5 минут, после чего он спокойно может коммитать свои изменения. Ну ОК, про 2 часа я может переборщил, но доводилось видеть .Net проекты, на которых билд с юнит-интегрейшн-тестами длился 1.5 часа. Для других платформ просто билд может идти весьма долго ;)
                      • 0
                        Вот не надо путать юнит-тесты и интеграционные тесты? Если у вас все юнит-тесты на проекте идут два часа — выделяйте BVT и гоняйте только их.

                        (а вообще это все прекрасно описано что у Мезароса, что у Хамбла/Фарли)
                        • 0
                          Да что же Вы все передергиваете? :) Где я по-вашему спутал U|I tests? Верификейшн тесты естественно выделяются и естественно именно они ранятся на code-quality builds. Но, я пытаюсь Вам сказать, что не всегда даже билд укладывается в 5 минут (просто билд без всяких bvt). Если, конечно, у Вас некомпилируемый язык, то тут гораздо все проще.
                          • +1
                            Не укладывается именно билд — ищите железо, ищите способы оптимизации.

                            (знаете, наверное, поговорку про «кто хочет»?)

                            Тут, как бы, очередные весы — либо вы тратите силы на то, чтобы сделать работающий пречекин, либо вы тратите силы на поиск багов на этап позже, чем могли бы. Выбор ваш.

                            Главное — не говорить, что если у вас пречекины не работают, то они нигде не заработают.
                            • 0
                              Заработают, да, на небольшом коде, либо на python'e/php. А по-поводу железа, мне было бы интересно посмотреть за просьбами выделить новый сервер под билд-машину, вернее, посмотреть на лицо ПМа/заказчика в этот момент.

                              ОК, ладно, не буду спорить, я Вашу точку зрения понял.
                              • 0
                                Заказчику до этого вообще дела нет, РП — тоже. Это обычно проблемы собственного инфраструктурного отдела компании, приблизительно того же, где «нам не хватает места на сервере БД» и «дайте сервер под VCS».

                                Когда нам понадобилось, мы сравнительного легко нашли не один, а четыре билд-агента.
                                • +1
                                  А можете поделиться, на каком стеке вы работаете, сколько проектов в солюшне, сколько тестов, сколько агентов, сколько разработчиков, одна ветка разработки или бренч на фичу/команду?
                                  • 0
                                    .net, 35 проектов, 34 тестовых проекта, порядка тысячи тестов, гоняется две трети. Разработка на мейнлайне. Четыре или пять билд-агентов с разными задачами.

                                    Остальное, извините, NDA.
                                    • +1
                                      Что-ж, здорово, что есть позитивный пример такого сетапа. Мне больше нравится подход, когда команда комитит в свой бренч, дальше тимлид/другое ответственное за ревью лицо ревьюирует код только потом идет мерж.
                                      Со временем стал приходить к мысли, что никакие технические ограничения не смогут сделать команду лучше. Если разработчики заливают битый код и уходят домой, то это должно решаться не техническими средствами, а увольнением таких «специалистов».
                                      • +1
                                        К сожалению, ревью кода и мерж — это боттлнек перед релизом. Именно поэтому мы отказались от этой практики.
                      • 0
                        Что-то вы все в кучу валите. С двух часов только юнит-тестов (это их тысяч сто должно быть) перескакиваете на полуторачасовой полный билд. Вы уж определитесь ;).
                        Наш ночной билд исполняется 5 часов (он действительно дофига большой и страшный). При этом GC билд исполняется 7-8 минут (из них юнит-тесты — это пара минут). Зачекинил и работаешь дальше.
                        • 0
                          Юнит тесты могут хоть 2 часа работать

                          Ключевое слово выделил.

                          ОК, какой смысл вашего GC в таком случае? Просто проверить, что код собирается?
                          • 0
                            В минимальном случае — да. При наличии юнит-тестов — проверить, что тесты проходят. Про 2 часа я повторюсь — чтобы юнит-тесты ранались 2 часа, их должно быть ооооочень много (так много, что фактически эти 2 часа становятся нереальными).
          • 0
            1) Если компиляция продукта и прогон юнит-тестов (быстрых!) у вас занимает полчаса, то вы что-то делаете не так.
            2) Курить не нужно. Просто продолжаешь работать дальше.
    • 0
      Бывает, тесты падают случайно, для selenium тестов через интерфейс это вообще не редкость. Так что на GC будет тратится слишком много времени разработчиков.
      • +2
        Во-первых, если тест падает случайно, это плохой тест (потому что ложные срабатывания — это время того, кто с тестом работает, не важно, разработчик это или программист).

        А во-вторых, интерфейсные тесты в пречекин (обычно) не ставятся, потому что медленные.
        • 0
          Во первых, про плохой тест объясните отвалившемуся браузеру, или БД, или неожиданно долгому коннекту, прерванному по таймауту.

          А во-вторых, если тестов мало — разработчик может прогнать локально, а если много, то «потому что медленные», не вижу тогда большого смысла.
          • 0
            Во первых, про плохой тест объясните отвалившемуся браузеру, или БД, или неожиданно долгому коннекту, прерванному по таймауту.

            Если у вас отваливается БД — значит, у вас упал тест. Все нормально, так и должно быть. Следите за своей БД, это помогает.

            Локальный прогон — это совсем не то же самое, что прогон на репозитории, он помогает только при идеальной дисциплине.
  • +12
    В одной компании, где я работал проблема со слишком часто сломанным билдом была решена правилом: сломал билд – принеси тортик. Сначала торты ели каждый день, потом перестали.


    Как-то так…

  • +1
    Я предпочитаю большинство действий делать при помощи MSBuild'a, а TeamCity только запускает нужный таргет.
    Таким образом, я могу из командной строки сделать любое действие над проектом — прогнать тесты, сделать бекап базы, обновить базу, обновить сайт в ИИСе,…
    • 0
      Я тоже так делаю. Заодно и отладить локально можно. Но вот тесты проще билд-степом запускать.
  • +5
    Статья очень, очень хорошая, но не могу не вставить свои пять копеек.

    — Про версии сборок. Хочу обратить внимание, что у Microsoft термины Revision и Build поменяны местами. То есть семантически всё верно: закоммитил исходники — изменилась третья цифра, сбилдил на CI — изменилась четвёртая цифра. В документации с точки зрения смысла всё правильно, но названия параметров поменяны местами. Начинающему CI-мастеру легко запутаться.

    — Про миграции базы данных. Если используется SQL Server (что для .NET частое явление), то можно использовать SMO. Через SMO можно управлять всем функционалом SQL Server, а не только alter на таблички делать. В статье упомянуть об SMO стоило.

    — Про публикацию служб. Для доставки бинарников на сервер подходит тот же MSDeploy. Если в проекте уже используется MSDeploy для публикации web-приложений, то одной командой sync в MSDeploy можно скопировать все бинарники сервиса на целевой сервер. Шаред-папка и FTP это уже не модно :).

    — Параметры в TeamCity. Учите людей плохому. Кучу аргуметов через /P указывать в TeamCity не надо — работать будет, но будут warnings. Специально для этого есть Build Parameters, они прозрачно транслируются в MSBuild скрипт.

    Ну а в целом, если поговорить по душам, меня немного напрягает декларативный синтаксис MSBuild. Если стоит задача после билда сделать пару нетривиальных приседаний, то надо искать сторонные библиотеки с тасками для MSBuild, либо писать эти таски самому.

    Я больше склоняюсь к использованию PowerShell и конкретно psake. Это императивные скрипты, а не декларативный XML как в MSBuild, их не надо компилировать, можно легко править и можно отдать поддержку этих скриптов админам (от них сейчас знание PowerShell стали требовать).

    Что думаете по этому поводу?
    • 0
      Здорово, что разворачивается дискуссия в комментах.
      Про публикацию служб. Для доставки бинарников на сервер подходит тот же MSDeploy. Если в проекте уже используется MSDeploy для публикации web-приложений, то одной командой sync в MSDeploy можно скопировать все бинарники сервиса на целевой сервер. Шаред-папка и FTP это уже не модно :)
      На целевой машине может не быть IIS

      — Параметры в TeamCity. Учите людей плохому. Кучу аргументов через /P указывать в TeamCity не надо — работать будет, но будут warnings. Специально для этого есть Build Parameters, они прозрачно транслируются в MSBuild скрипт

      Может у нас разные настройки TeamCity, я не видел ворнингов, хотя последние большие сборки у меня публиковались с помощью кастомного мсбилда, в который передается только конфигурация и никаких параметров нет.
      Я больше склоняюсь к использованию PowerShell и конкретно psake. Это императивные скрипты, а не декларативный XML как в MSBuild, их не надо компилировать, можно легко править и можно отдать поддержку этих скриптов админам (от них сейчас знание PowerShell стали требовать).

      Никто же не мешает использовать и то и другое или что-то одно по вкусу. Главное, чтобы работало и было просто поддерживать. например, поэтому я чаще всего не пишу отдельные таски, чтобы не тащить за собой бинарники.
      Достаточно много разработчиков, к сожалению, никогда не заглядывает в файл проекта. Я думаю, что важно научиться пользоваться msbuild и редактировать проект не только из студии, но и «ручками», потому что многих вещей из студии просто не сделать.
  • 0
    Версионирование продукта
    На мой взгляд удобнее всего использовать msbuild и проставлять значение с помощью CI-сервера:

    Как решается обратная задача? Пользователь репортит о проблеме, указывает версию продукта (скажем, посмотрев свойства dll'ки в Проводнике): 3.14.159.2. Как узнать, какой ревизии в репозитории соответствует эта версия сборки? Используется DVCS, где для идентификации ревизий применяется 1) немонотонный 20-байтный уникальный идентификатор, и 2) автоинкрементный, но неоднозначный номер (может различаться для одной и той же ревизии в разных клонах репозитория).
    • 0
      Ну, «правильный» способ — это использовать билд-репозиторий, где по версии можно получить бинарники, информацию о билд-процессе (а так же тестах и продвижении), ну и информацию о том, из чего именно эта версия была собрана.
      • 0
        Это означает выделение «избранного» репозитория. Хотелось бы, чтобы клоны были по возможности равноправны, чтобы каждый клон имел всю необходимую информацию, чтобы локального репозитория было достаточно для определения ревизии по версии.
        • 0
          Я, наверное, не очень понятно выразился: билд-репозиторий — это не репозиторий кода, это специальный репозиторий артефактов, к VCS имеющий только то отношение, что он из нее берет исходники.
    • 0
      Идете в TeamCity или в другое CI-решение, которое используете. Находите билд, соответствующий вашей сборке. Для того, чтобы иметь какое-то соответствие, TeamCity предлагает BuildNumberFormat. Вы можете настроить его в соответствие с версионированием вашего приложения.
  • 0
    Не могу не упомянуть опенсорсный CI-сервер CruiseControl.NET. У нас он работает в связке с Redmine.
  • +1
    Для автоматического изменения версий сборок есть еще подход, описанный здесь (основан на использовании build feature «AssemblyInfo patcher»).
    Из преимуществ — сам изменяет номера сборок во всех AssemblyInfo.cs в солюшене, не надо править .csproj как описано в этой статье. Из недостатков — изменяет номера сборок для всех проектов в солюшене, т.е. не позволяет для разных проектов вести различное версионирование.

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.