Хабрахабр

Поэтапная настройка Continuous Integration (build, test, deploy) для .NET Core WebApp + GitHub

Continuous Integration (CI) давным-давно проник в мир разработки программного обеспечения и для многих является его неотъемлемой частью, которое позволяет создавать более качественный код сохраняя при этом удобство разработки. Всем привет. Если вам интересно, как настроить CI для своего . И, если поначалу, настройка CI требовала значительных усилий и денег, то сейчас это стало намного доступнее, проще и даже бесплатно. NET Core open-source проекта, прошу под кат.

Disclaimer

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

F# выбран т.к. Несмотря на то, что основным языком демонстрационного проекта выбран F#, руководство полностью совместимо с проектами написанными на C#. эта статья и связанный с ней репозиторий является основой для второй публикации — "Строим полноценное веб приложение на F# + Giraffe с нуля.", которая запланирована на июнь.

Оглавление

  • Вступление и необходимые инструменты
  • Создаем репозиторий
  • Новый проект
  • CI Build
  • CI Test
  • CI Deployment
  • Итоги
  • Теги
  • Ссылки

Вступление и необходимые инструменты

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

Если вы хотите повторить то, что написано в статье вам понадобятся:

Создаем свой репозиторий

Tag: InitialMaster

Прежде всего нам нужна какая то система контроля версий. Давайте начинать. Я буду использовать Git и GitHub

.gitignore файл нужен для того, что бы в ваш репозиторий не попадали лишние файлы (например результаты build процесса). Создайте новый репозиторий на GitHub, выберите шаблон для .gitignore файла и лицензию проекта. Для этого проекта я выбрал шаблон VisualStudio и MIT лицензию. Лицензия нужна что бы можно было понять объем разрешенных действий с вашим кодом.

Для этого нужно установить Git локально и выполнить команду: После создания репозитория нам нужно его клонировать — снять его полную копию и поместить на локальную машину.

git clone PATH_TO_YOUR_REPOSITORY

Имейте ввиду, у Git есть неплохая документация, так что, если вы на чем-то споткнетесь — вам сюда. Теперь у вас есть локальный репозиторий, связанный с удаленным репозиторием на GitHub.

Первая VCS появилась уже в 1982 году (хотя некоторые датируют ее появление даже 1972 годом). Система контроля версий не самое новое изобретение. А вот Git появился сравнительно недавно — в 2005 году благодаря Linus Torvald ключевому создателю Linux. Подробнее об истории развития инструмента без которого современная разработка практически невозможна, можно найти здесь.

Новый проект

Tag: NewFSharpProject

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

dotnet new web -lang F#

NET Core SDK. Важно, для того, что бы эта команда сработала вам нужно установить . И если к F# вы пока еще не готовы (а это очень веселый язык, рекомендую), вы можете не передавать параметр lang и тогда dotnet создаст для вас веб приложение на С#. Если вы работаете под Windows, скорее всего вам нужно будет перезапустить ОС для того, что бы система подхватила новые пути для dotnet.exe.

Выполнив эту команду, вы получите три новых файла:

  • Startup.fs — здесь находится конфигурация нашего сервера
  • Program.fs — здесь находится точка старта сервера
  • FSharpWebAppWithCIDemo.fsproj — а это описание структуры проекта

Несмотря на минимализм этого вполне достаточно что бы запустить свой hello world.

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

В итоге у нас должно получиться что-то вроде такой структуры (дальше, все манипуляции с решением я буду делать через Visual Studio):

— FSharpWebAppWithCIDemo // основная папка проекта

— — BLL // проект с основной логикой

— — WebServer // веб сервер и его настройки.

В F# порядок файлов и проектов имеет значение. Важно! Это значит, что наш веб сервер сможет получить доступ к любому из проектов (он в самом низу), а вот проект с бизнес логикой должен будет довольствоваться только своим собственным кодом. Файлы, которые находятся выше по дереву проекта не имеют доступа к файлам, которые находятся ниже по дереву. Зачем, например, базе данных знать о каком-то веб сервере, правильно? С одной стороны, это несколько непривычно, с другой стороны, сразу структурирует код. Другими словами — low coupling high cohision Вообще, чем меньше один модуль знает о других модулях, тем меньше шансов сломать его, работая над каким-то другим модулем.

Как вы знаете проекты, написанные на . И еще один, пока все еще важный момент, касающийся Linux систем. Но файл описывающий весь наш проект целиком (.sln файл) не совсем кроссплатформенен. NET Core кроссплатформенны, и могут быть выполнены на Linux системах. К сожалению, сейчас это проблема. Поэтому если вы работаете под ОС Windows, пути к проектам в этом файле будут написаны не совсем корректно — с использованием бекслеш символа: "\". Но если, во время сборки, на сервере или у себя на локальной машине вы увидите ошибку вида: Она будет исправлена в ближайшее время.

error MSB4025: The project file could not be loaded. Could not find file ... MySuperProject.fsproj.metaproj.

Скорее всего это значит, что вам нужно зайти в .sln файл и руками изменить "\" на "/".

Соберите его, проверьте что он успешно собирается и давайте идти дальше. Теперь наш проект готов.

Показательно, что примеры кода, описанные в руководстве, уже не собираются последними компиляторами. Корни традиции писать hello world восходят к 1974 году, когда появилось руководство Programming in C: A Tutorial.

CI — Build

Tag: TravisSupport

Можно было бы начать непосредственно разработку, но тогда статья была бы не о том. У нас уже есть работающее веб приложение на F#. Так что мы начнем настройку нашего — CI процесса и начнем ее с самого простого — настройки билда.

Это подход в программировании, основная и упрощенная идея которого заключается в частых коммитах, их автоматической проверке и доставке результата конечному пользователю. Вообще то, CI это не сервис и не инструмент. А результаты всего этого будут отображаться сразу под пулл реквестом, так что мы всегда будем в курсе того, кто и как именно сломал наш проект. Поэтому, когда я говорю о том, что мы будем настраивать CI это значит, что мы настроим автоматический билд процесс при каждом пулл реквесте, запуск тестов и анализ их результатов.

Кстати, если вы делаете какую-то новую фичу ее неплохо делать именно в отдельной ветке, а не в master. Давайте создадим новую ветку и назовем ее TravisSupport. Во-вторых, в своей локальной ветке вы можете делать любые коммиты не боясь, что они попадут в основную ветвь и что-то сломают. Во-первых, вы будете независимы от ваших коллег и их коммитов. Главное, не забудьте потом удалить ветку источник иначе, если продолжите в ней работу и попробуете закоммититься еще раз, можете получить конфликт. И в-третьих, мое любимое преимущество, если сделать merge с флагом --squash то все ваши коммиты сольются в один и будут выглядеть так, как будто и не было этих 100500 попыток, а все получилось с первого раза.

Для CI нам нужен инструмент, который будет собирать наш проект, тестировать его и делать то, что мы попросим. Но, ближе к делу. Он бесплатен для open-source, относительно прост и у меня есть с ним кое-какой опыт. В качестве такого инструмента я выбрал Travis-CI.

Что бы интегрироваться с Travis нам нужно:

  • Дать Travis доступ к нашему репозиторию.
  • Объяснить ему что от него требуется.

Откройте https://travis-ci.org/ и залогиньтесь туда с помощью своего GitHub аккаунта. Первый пункт достаточно прост. Если вы не увидели свой репозиторий, воспользуйтесь кнопкой SyncAccount. Затем добавьте свой репозиторий в список доступных.

Управлением CI процессом travis-a осуществляется с помощью файла .travis.yml. Второй пункт гораздо интереснее. Скопируйте этот файл в корень проекта и давайте разберем что в нем написано. Вот документация.

language: csharp dotnet: 2.1.4
sudo: false env: global: - DOTNET_CLI_TELEMETRY_OPTOUT: 1 script: - dotnet build FSharpWebAppWithCIDemo.sln -c Release

  • language — язык на котором написано приложение. Travis не делает различий между C# и F#, и директивы fsharp нет. Зато этот файл прекрасно подходит и для проектов на C#.
  • dotnet — мы можем сразу указать версию dotnet что бы быть уверенными с чем нас будут собирать.
  • env — эта секция отвечает за переменные окружения. Как видите мы добавили туда DOTNET_CLI_TELEMETRY_OPTOUT что бы выключить передачу телеметрии при билд процессе. Сюда можно записать любую переменную, и она будет передана аргументом в наш билд.
  • script — а эта секция отвечает за то, чего же мы хотим от нашего travis-a. В данном случае мы всего лишь хотим запустить билд в режиме релиза для нашего приложения.

Простыми словами, при каждом пулл-реквесте, мы пробуем собрать наш билд. Это самый простой и базовый сценарий CI. Не собирается — мы увидим предупреждение прямо в GitHub и на почте. Собирается — все хорошо. А если вам интересны дополнительные возможности Travis (например, выбор OS) то вам сюда Условия запуска CI процесса легко настраиваются как в самом .travis.yml так и в настройках проекта на сайте.

Еще раз напомню, если во время билда вы столкнетесь с ошибкой: "MSB4025, could not find file… .fsproj.metaproj" попробуйте заменить бекслеши на слеши в .sln файле.

Кстати, если посмотрите на процесс билда, вы увидите, что он проходит под Linux, что не может не радовать.

Его можно найти в вашем Travis CI проекте. И, конечно, не забудьте добавить заслуженный бейджик в readme.

Если вам будет мало — там же можно создать свой собственный бейджик. Если вам нравится наглядность бейджиков, рекомендую заглянуть сюда.

CI Test

Tag: CodeCov

Вообще, принципы TDD мы уже нарушили, не написав тесты до написания кода. Вот и пришло время тестирования. Так что пора все исправить.

В этот же проект установите xUnit
Напомню, что структура нашего проекта теперь должна выглядеть так: Под проектом Bll создайте новый проект BllTest и добавьте туда BllTest.fs.

— FSharpWebAppWithCIDemo

— — Bll

— — BllTest

— — WebServer

В проекте Bll, создайте новый bll.fs файл c модулем Say и функцией hello (мы опять нарушили TDD написав код до тестов)

namespace Bll module Say = open System let hello() = "Hello user #" + Guid.NewGuid().ToString()

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

Важно только их наличие что бы правильно интегрироваться с Travis и CodeCov. На самом деле ни сам код, ни сам тест нам не важны (ведь вы это уже когда-то слышали, не так ли?). После того как у нас появился первый тест, нам нужно, что бы Travis этот тест запустил. Запустите тест вручную, убедитесь, что он проходит и давайте продолжать. Для этого, в .travis.yml нужно добавить еще одну строку в секцию script

- dotnet test -c Release --no-build BllTest/BllTest.fsproj

билд артефакты уже получены на предыдущем шаге) чем экономим себе время. Здесь все очевидно — мы запускаем тесты без билда (т.к.

Нам нужна статистика покрытия кода. Но этого мало. Откройте вкладку Nuget (или запустите команду из консоли) и установите этот пакет для BllTest проекта. Для этого нам пригодится coverlet.msbuild прекрасный инструмент который встраивается в msbuild и создает отчеты в разных форматах, в том числе и в нужном нам opencover. После этого поменяйте предыдущую строку в .travis.yml на эту: В других проектах он не нужен.

- dotnet test -c Release --no-build BllTest/BllTest.fsproj /p:CollectCoverage=true /p:CoverletOutputFormat=opencover

Напомню, что полную версию .travis.yml можно забрать тут

Заодно вы увидите текущий code coverage своего проекта. Можно запустить эту же команду и из-под консоли что бы убедиться что все работает.

Но и этого тоже недостаточно. Итак, тесты у нас есть, они запускаются и даже видно какой-то отчет о покрытии кода. Здесь нам пригодится Codecov который, тоже бесплатен для OpenSource проектов. Теперь нам нужен кто-то еще, кто сможет обработать этот отчет и сообщить о его результатах. Наконец, в последний раз обновляем .travis.yml — добавляем новую секцию after_script. Логинимся в Codecov с помощью аккаунта GitHub и добавляем нужный проект.

after_script: - bash <(curl -s https://codecov.io/bash)

До этого я убил часа три на то что бы запустить отправку отчета в coverall, а здесь все оказалось настолько просто… Спасибо ребята, что сделали меня счастливым. Когда я увидел этот пример я зарыдал.

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

Автором TDD некоторые называют Kent Beck, однако сам он говорит, что всего лишь открыл заново методику, о которой читал давным-давно в какой-то древней книге по программированию.

CI Deployment

Tag: DeployToAzure

Мы начинаем приготовления к deployment процессу. Вздохните, выпейте кофе, конец инфраструктурных работ уже близок.

Это можно делать руками, или в автоматическом режиме, что как человеку ленивому мне нравится гораздо больше. Если кратко, deployment это процесс доставки результатов нашей работы (build artefacts) для выполнения. Если вам это не подходит, вы можете использовать build артефакты, которые для вас подготовит Travis. Я покажу как настроить деплой в Azure (но это только потому что у меня там уже есть аккаунт и еще осталось пара долларов). Достаточно поменять dotnet build на dotnet publish и отправить полученные результаты на ваш сервер, например:

  • AWS S3
  • GITHUB PAGES
  • NPM
  • HEROKU
  • GOOGLE APP ENGINE

И многое другое

Настройка деплоймента относительно проста и (что самое приятное) управляется извне самой Azure. Но сейчас не про это, а про Azure. Сейчас расскажу.

Делается это очень просто. Для начала нам нужно создать свое веб приложение. Там выбираем имя нашего будущего сайта, подписку (подписка это то место откуда у вас будут списываться деньги, так что лучше выбрать бесплатную, например для студентов) и ОС где наш сервер будет развернут. Заходим в Azure, затем Create a resource -> Web App или просто по этой ссылке. Я выбираю Windows так как мне комфортнее, но в целом разницы нет. Поскольку мы используем core можно выбрать как Linux так и Windows. Для этого, в корневую папку проекта нужно добавить два файла: Создайте свой веб сайт, проверьте что он действительно работает и давайте начнем настройку деплоймента.

  • .deployment // описывает что нам нужно вызвать для деплоймента)
  • build.cmd // описывает что именно делать во время деплоймента

На первый взгляд, build.cmd выглядит довольно страшно, но внутри происходят вполне тривиальные вещи:

  • Проверяется наличие Node.js // вы не поверите, но в процессе деплоймента Microsoft использует Node.js
  • Выставляются переменные с путями // где будут лежать наши файлы и файлы сервера
  • Устанавливается kudusync // утилита для копирования артефактов в папку сервера
  • Выполняется команда dotnet publish // компилируем наш код
  • Результаты паблиша копируются в wwwroot папку. // отдаем результат серверу для запуска нашего приложения

Для этого выбираем наше приложение, затем DeploymentOptions -> Github -> Project -> Branch. После того, как мы добавили эти файлы, нам осталось только связать наше веб приложение с репозиторием на GitHub. Все, теперь осталось дождаться пока все синхронизируется и задеплоится. Кстати там же можно настроить и нагрузочные тесты.

Кодовое название проекта, который потом превратился в Azure было "Project Red Dog".

Git хуки

Тем более, что именно хуки являются тем инструментом, благодаря которым стали возможны описанные в статье возможности. Говорить о CI и не упомянуть о git hooks наверное было бы не правильно.

С помощью них вы можете модифицировать коммиты, вести change log, делать автоматическое форматирование и вообще все, на что хватит прав в системе. Git hooks, или перехватчики — это специальный механизм, который позволяет выполнять пользовательские сценарии до или сразу после важных событий в вашем репозитории. По умолчанию, они находятся в .git/hooks.

Они так же позволяют выполнять пользовательские сценарии. Немного не в стиле, но в dotnet тоже есть хуки, такие как pre-build и post-build.

Итоги

Однако один из главных вопросов все еще остался без ответа — а надо ли вам CI как таковой. Сегодня, мы научились настройке полного цикла CI для проекта основанного на Git репозитории. С одной стороны:

… времени пение берет самую малость, а пользы от этого пения, между прочим, целый вагон… ©

С другой стороны, если вы делаете POC или если у вас сроки уже давно сгорели, наверное, CI придется не код двору.

Но если вы его еще не пробовали — рекомендую к дегустации. Другими словами — использовать CI или не использовать решать именно вам.

Теги

  • InitialMaster
  • NewFSharpProject
  • TravisSupport
  • CodeCov
  • DeployToAzure

Ссылки

Со всем почтением.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть