Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Настройка TeamCity для новичков

Anna | 17.06.2014 | нет комментариев
Эта статья в первую очередь сгодится тем, кто использует тот же стек спецтехнологий, что и наша команда, а именно: ASP.NET, C#, NUnit, Selenium 2, git, MSBuild. Будут рассмотрены такие задачи, как интеграция с git, сборка C#-планов, NUnit-тесты (как модульные, так и тесты UI), а также деплой на сервер. Однако, наверно найдётся увлекательное и для других пользователей, помимо разве что съевших на этом вопросе собаку. Но они вновь же сумеют обратить внимание на ошибки в статье либо что-то порекомендовать: скажем, как оптимизировать фазу деплоя.

Что такое «постоянная интеграция», отменно рассказано тут и вот тут, повторять эту тему в сотый раз вряд ли необходимо.

Ну и для начала – что может TeamCity (дальше – легко TC)? А может он следующее: при возникновении изменений в указанной ветке репозитория (либо другом событии) исполнить сценарий, включающий в себя, скажем, сборку приложения, прогон тестов, выполнение других сценариев, заливку файлов на удаленный сервер и т.п.

Значимым моментом является то, что «сервер интеграции» и «машина, на которой будет проходить данный процесс», – традиционно (не непременно) различные серверы. Больше того, машинок, на которых запускаются сборки и тесты, может быть несколько, даже много, и все на различных ОС – в всеобщем, есть, где развернуться.

Для запуска процесса сборки применяется программа-шпион, принимающая команды от TC-сервера, запустить ее дозволено на всякий из основных ОС (известность мультиплатформенности Java). На один компьютер дозволено установить несколько шпионов и запускать их параллельно, но значимо помнить, что один шпион одновременно может обрабатывать только один план. При старте задачи TC выбирает 1-й подходящий незанятый шпион, причем дозволено устанавливать «фильтры», скажем, выбирать агента только с ОС Windows либо только с установленным .NET версии не ниже 4.0 и т.п.

Сейчас необходимо придумать сценарий работы. Мы используем в работе следующие ветки:

  1. release – содержит востребованный код, рабочую версию, которая находится на боевом сервере;
  2. dev – в неё идут все новые фичи, позднее вливается в release;
  3. отдельная ветка на всякую фичу, которая отпочковывается от dev и в неё же возвращается.

В всеобщем, фактически типовой git-flow, о котором больше детально дозволено прочитать, скажем, тут.

В связи с этим наш сценарий будет выглядеть так:

  1. забрать свежие метаморфозы из репозитория ветки dev;
  2. скомпилировать план;
  3. если всё прошло удачно на предыдущем шаге – прогнать юнит-тесты;
  4. если всё прошло удачно на предыдущем шаге – прогнать функциональные тесты;
  5. если всё прошло удачно на предыдущем шаге – залить метаморфозы на тестовый сервер.

Для релизной ветки делаем всё то же самое, но на время заливки новых данных приостанавливаем сервер и показываем заглушку.

А сейчас вперёд – реализовывать сценарий!

Забрать свежие метаморфозы из репозитория

Начинается всё с немудрёного создания плана.

Позже – создание «build configuration» (конфигурации сборки). Конфигурация определяет сценарий сборки.

На втором же шаге создания конфигурации нас спросят об примененной VCS, так что отвечаем Добросовестно, что у нас здесь git. У вас может быть иная VCS – не теряйтесь. Добавление нового репозитория производится кнопкой Create and attach new VCS root.

Выходит, ключевые настройки:

  • VCS root ID дозволено не трогать – неповторимый код, как ни верти. Если оставить пустым, генерируется механически;
  • Fetch URL – тот адрес, с которого мы будем забирать содержимое репозитория;
  • Default branch – ветка, с которой будет браться информация;

  • Authentication method – самое увлекательное – метод аутентификации. Здесь может быть и доступ без авторизации (если данные лежат на внутреннем сервере, скажем), и по ключу, и по паролю. Для всякого варианта добавочные поля будут свои, сами понимаете.

Остальное разнообразие опций – на ваш вкус и цвет.

Дальше, необходимо настроить механический запуск задания. Идём в «Build Triggers» (данные сборки) и выбираем условие VCS Trigger – при настройках по умолчанию он будет раз в минуту проверять присутствие новых коммитов в репозитории, а если таковые найдутся – запустит задание на выполнение.

Скомпилировать план

От того что у нас план на ASP.NET в виде Solution’а из Visual Studio – здесь тоже было всё легко.

Идём в меню «Build Steps» (Шаги сборки), выбираем runner type (а их здесь подлинно много) и останавливаемся на MSBuild. Отчего именно на нём? Он даёт довольно примитивный метод описать процесс сборки, даже довольно трудный, добавляя либо удаляя разные шаги в простом XML-файле.

Дальше всё элементарно.

Build file path – путь к sln-файлу.
MSBuild versionMSBuild ToolsVersion и Run platform выбираем под требования своего плана.

Если в плане несколько конфигураций, то дозволено применять опцию Command line parameters для ввода приблизительно такого ключа:

/p:Configuration=Production

где Production заменить на необходимый конфиг.

Включить скачивание NuGet-пакетов

Значимый пункт, в случае если вы используете NuGet-пакеты; если нет – дозволено переходить сразу к дальнейшему пункту.

От того что NuGet-пакеты весят много, да и беречь в репозитории бинарники библиотек без специальной необходимости не хочется, дозволено применять восхитительную опцию NuGet Package Restore:

В этой обстановки бинарники библиотек в репозиторий не включаются, а докачиваются по мере необходимости в процессе сборки.

Но MSBuild – подлинный джентльмен и не будет без разрешения делать лишних телодвижений, следственно и докачивать пакеты легко так не будет – ему сей процесс необходимо позволить. Для этого придется либо на заказчике установить переменную окружения Enable NuGet Package Restore в значение true, либо пойти в меню Build Parameters и выставить его там.

Прогнать юнит-тесты

У нас юнит-тесты являются отдельным планом внутри решения. Так что на предыдущем шаге они теснее скомпилированы – осталось их запустить.

Добавляем новейший шаг, только сейчас Runner – это NUnit. Обратите внимание на параметр Execute step: он указывает, при каких условиях необходимо исполнять шаг, и имеет 4 значения:

  • If all previous steps finished successfully (zero exit code) – если все предыдущие шаги завершились без ошибок. При этом проверка выполняется чисто на агенте;
  • Only if build status is successful – подобно предыдущему, но при этом шпион ещё и уточняет у сервера TC ранг билда. Необходимо для больше тонкого управления логикой задания, скажем, если нулевой код возврата определенного шага для нас является оплошностью;
  • Even if some of the previous steps failed – даже если какой-то из предыдущих шагов завершился с оплошностью;
  • Always, even if build stop command was issued – исполнять шаг, даже если подана команда на отмену выполнения сборки.

Тут самое главное – указать правильный путь к сборке с тестами внутри плана в графе Run tests from. У нас, скажем, он выглядит вот так:

%teamcity.build.checkoutDir%\project\project.FuncTests\bin\Dev\project.FuncTests.dll

%teamcity.build.checkoutDir% – это переменная, указывающая на папку, в которую скачиваются данные из репозитория. В тезисе, она не непременна для указывания, т.к. по умолчанию путь идёт именно касательно этой директории, следственно путь дозволено было бы сократить до:

project\project.FuncTests\bin\Dev\project.FuncTests.dll

Отдельно подмечу опцию Run recently failed test first – если в предыдущем прогоне какие-то тесты упали, то в дальнейшем запуске первыми запустятся именно они, и вы стремительно узнаете об успешности последних изменений.

Прогнать тесты интерфейса (функциональные тесты)

Тут все значительно увлекательнее, чем с юнит-тестами. Кэп здесь подсказывает, что, Дабы протестировать план в браузере, его, т.е. план, нужно запустить. Но здесь мы схитрили, запуская веб-сервер прямо из кода тестов Selenium:

	[SetUpFixture]
	class ServerInit
	{
		private const string ApplicationName = "justtest";
		private Process _iisProcess;

		private string GetApplicationPath(string applicationName) {
			var tmpDirName=AppDomain.CurrentDomain.BaseDirectory.TrimEnd('\\');
			var solutionFolder = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(tmpDirName)));
			string result = Path.Combine(solutionFolder, applicationName);
			return result;
		}

		[SetUp]
		public void RunBeforeAnyTests()
		{
			[…]
			var applicationPath = GetApplicationPath(ApplicationName);
			var programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);

			_iisProcess = new Process
			{
				StartInfo =
				{
					FileName = string.Format("{0}/IIS Express/iisexpress.exe", programFiles),
					Arguments = string.Format("/path:\"{0}\" /port:{1}", applicationPath, UrlProvider.Port)
				}
			};
			_iisProcess.Start();
		}

		[TearDown]
		public void RunAfterAnyTests()
		{
			[…]
			if (_iisProcess.HasExited == false)
			{
				_iisProcess.Kill();
			}
		}
	}]

А сам запуск выглядит безусловно верно так же, как на шаге с юнит-тестами.

Залить метаморфозы на тестовый сервер

Сервер, на котором находится шпион TC, и сервер, на котором установлен IIS, – различные серверы, причем, больше того, находятся они в различных сетях. Следственно файлы необходимо как-то на финальный сервер доставить. И вот здесь решение выбрано, может, не дюже изящное, но весьма примитивное. Используем заливку через FTP, причем делает сие за нас MSBuild.

Схема такая:

  1. настраиваем на сервере FTP аккаунт для заливки файлов. Для дополнительной безопасности дозволено запретить заливку для всех IP, помимо внутреннего, если TC-сервер лежит во внутренней сети, безусловно;
  2. устанавливаем на агента MSBuild Community Tasks, Дабы получить вероятность применять задачу «Залить по FTP». Качать здесь;
  3. подготовить файл-сценарий для MSBuild, тот, что будет изготавливать следующие действия:
    1. сборка приложения во временной папке;
    2. подмена конфигурационного файла;
    3. заливка файлов по FTP.
Вот так будет выглядеть данный файл (deploy.xml)

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0" DefaultTargets="Build">

	<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.Tasks.dll"/>
	<Import Project="$(MSBuildExtensionsPath32)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>

    <PropertyGroup>
        <OutputDir>bin</OutputDir>
		<PublishDir>../output</PublishDir>
		<Configuration>Dev</Configuration>
        <TransformInputFile>..\project\project\Web.template.config</TransformInputFile>
        <TransformFile>..\project\project\Web.$(Configuration).config</TransformFile>
        <TransformOutputFile>..\project\output\Web.config</TransformOutputFile>
        <StackTraceEnabled>False</StackTraceEnabled>
    </PropertyGroup>

    <ItemGroup>
        <ProjectToBuild Include="../project/project.sln">
            <Properties>WebProjectOutputDir=$(PublishDir);OutputPath=$(OutputDir);Configuration=Dev</Properties>
        </ProjectToBuild>
    </ItemGroup>

    <Target Name="Build">
        <MSBuild Projects="@(ProjectToBuild)"/>
    </Target>

	<Target Name="CreateWebConfigs" AfterTargets="Build">
	<TransformXml
		Source="$(TransformInputFile)"
		Transform="$(TransformFile)"
		Destination="$(TransformOutputFile)"
	/>
	</Target>

	<Target Name="AfterBuild" AfterTargets="CreateWebConfigs">
		<PropertyGroup>
			<ftpHost>dev.example.com</ftpHost>
			<ftpUser>ЛОГИН</ftpUser>
			<ftpPass>ПАРОЛЬ</ftpPass>
			<LocalDirectory>..\project\output</LocalDirectory>
		</PropertyGroup>
        <FtpUploadDirectoryContent
			ServerHost="$(ftpHost)"
			Port="21"
			Username="$(ftpUser)"
			Password="$(ftpPass)"
			LocalDirectory="$(LocalDirectory)"
			RemoteDirectory=""
			Recursive="true"
        />
	</Target>
</Project>

А так – задание по его вызову:

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

Ещё один подмеченный недочет – при встрече файла с нелатиницей в наименовании падает с оплошностью. Латиница и буквы/цифры обрабатываются типично. Ноги этой задачи, схоже, растут из специфики протокола FTP: тот основан на ASCII, но, как именно кодировать не ASCII-символы, он не описывает, предлагая «делать так, как будет понимать ваш сервер». Соответственно, Дабы вылечить задачу, не меняя схему, необходимо пропатчить MSBuild Community Tasks, благо, исходники открыты. Ну, либо воспользоваться альтернативным методом заливки файлов, скажем через WinSCP.

Остановка и запуск сервера для релизного сценария

Мы её решаем чуть диким, но привлекательным методом. У IIS’а есть специфика: если в корень сайта положить файл с именем app_offline.html, то сайт отрубается, при обращении ко каждому файлам будет выдаваться содержимое этого файла.

Минус – обращение именно что КО КАЖДОМУ файлам, включая неподвижные. Так что, если хочется сделать заглушку с оформлением, CSS и картинками, используйте инлайн-жанры и data:url, ну, либо как вариант – выложите их на отдельном сервере.

Включаем-отключаем мы сервер через WinSCP-сценарий и такие вот файлики:

server_off.cmd

winscp.exe /console /script=server_off.txt
server_on.cmd

winscp.exe /console /script=server_on.txt
server_off.txt

option batch abort
option confirm off

open ftp://ЛОГИН:ПАРОЛЬ@dev.example.com

mv _app_offline.htm app_offline.htm

close

exit
server_on.txt

option batch abort
option confirm off

open ftp://ЛОГИН:ПАРОЛЬ@dev.example.com

rm app_offline.htm

close

exit

Т.е., первоначально файл лежит в корне и именуется _app_offline.html. Когда необходимо заблокировать доступ на время апдейта, мы переименовываем его в app_offline.html. При заливке файлов заливается новейший файл _app_offline.html, а позже окончания – удаляется файл app_offline.html. И получаем именно то, что было первоначально.

В тексте страницы-заглушки весьма рекомендую воспользоваться мета-тегом refresh, тот, что периодично будет обновлять страницу. Если к этому времени процесс обновления завершился, пользователь вернётся обратно в сервис, чему наверно будет несказанно рад.

Вызов сценария включения заглушки (отключение заглушки происходит подобно):

Да, WinCSP лежит в итоге прямо в репозитории. Да, пароли в открытом виде лежат в файле. Да, не самое изящное решение, но, от того что доступ в репозиторий и к виртуальной машине с агентом имеют только разработчики из нашей команды, отчего бы и нет? Да, дозволено было бы беречь файл с паролями, скажем, непринужденно на агенте, но твердо безопасность это не повысило бы, а вот развертку нового агента, скажем, замедлило бы.

Данные настройки применяются нами на протяжении где-то полугода, и пока ни цельной задачи не появилось – всё работает как часы, что не может не радовать.

На этом всё. С удовольствием выслушаю комментарии и советы по совершенствованию этих шагов, а также ваши рассказы о том, какие вероятности TC вы используете у себя.

Источник: programmingmaster.ru
Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB