Мне нужна помощь с философией и дизайном непрерывной интеграции.
Наша текущая настройка CI использует buildbot. Когда я начинал проектировать его, я унаследовал (ну, не совсем так, как я был вовлечен в его проект годом ранее) сделанный на заказ конструктор CI, который был приспособлен для одновременного запуска всей сборки в одночасье. Через некоторое время мы решили, что этого недостаточно, и начали изучать различные инфраструктуры CI, в итоге выбрав buildbot. Одной из моих целей при переходе на buildbot (помимо получения удовольствия от всех дополнений, связанных со свистом) было преодоление некоторых недостатков нашего сделанного на заказ ночного строителя.
Забавьте меня на мгновение и позвольте мне объяснить, что я унаследовал. Кодовая база для моей компании - это почти 150 уникальных приложений Windows на c ++, каждое из которых зависит от одной или нескольких из дюжины внутренних библиотек (а также от сторонних библиотек). Некоторые из этих библиотек являются взаимозависимыми и имеют зависимые приложения, которые (хотя они не имеют ничего общего друг с другом) должны создаваться с использованием одной и той же сборки этой библиотеки. Половина этих приложений и библиотек считаются «устаревшими» и непереносимыми и должны быть построены с использованием нескольких различных конфигураций компилятора IBM (для которых я написал уникальные подклассы Compile
), а другая половина построена с использованием Visual Studio.ShellCommand
с, так как нет поддержки VSS).
Наш оригинальный ночной конструктор просто взял источник для всего и создал материал в определенном порядке. Не было никакого способа создать только одно приложение, выбрать ревизию или сгруппировать объекты. Было бы запущено виртуальных машин для создания ряда приложений. Это не было очень надежно, это не было распространяемым. Это не было ужасно растяжимо. Я хотел преодолеть все эти ограничения в buildbot.
Первоначально я делал это, создавая записи для каждого приложения, которое мы хотели построить (все 150 из них), затем создавал запускаемые планировщики, которые могли бы создавать различные приложения в виде групп, и затем объединял эти группы в общий планировщик ночных сборок. Они могут работать на выделенных подчиненных устройствах (больше не нужно заниматься виртуальными машинами), и, если я захочу, я могу просто добавить новых подчиненных. Теперь, если мы хотим выполнить полную сборку вне графика, это всего лишь один клик, но мы также можем создать только одно приложение, если захотим.
Однако у этого подхода есть четыре недостатка. Одним из них является сложная сеть зависимостей нашего исходного дерева. Чтобы упростить поддержку конфигурации, все сборщики создаются из большого словаря. Зависимости извлекаются и создаются не слишком ужасно (а именно, отключение определенных вещей в моем словаре целевых сборок). Во-вторых, каждая сборка имеет от 15 до 21 шага сборки, которые трудно просматривать и просматривать в веб-интерфейсе, а поскольку имеется около 150 столбцов, загрузка занимает вечность (от 30 секунд до нескольких минут). В-третьих, у нас больше нет автоматического обнаружения целей сборки (хотя, хотя один из моих коллег говорит мне об этом, я не вижу, что это нас привлекло в первую очередь). В заключение,
Теперь, переходя к новой разработке, мы начинаем использовать g ++ и subversion (не портируя старый репозиторий, обратите внимание - только для новых вещей). Кроме того, мы начинаем проводить больше модульного тестирования («больше» может дать неправильную картину ... это больше похоже на любое ) и интеграционное тестирование (с использованием Python). Мне трудно понять, как вписать их в мою существующую конфигурацию.
Итак, где я ошибся здесь с философской точки зрения? Как мне лучше всего двигаться дальше (с buildbot - это единственная часть головоломки, над которой у меня есть лицензия на работу), чтобы моя конфигурация в действительности поддерживалась? Как мне устранить некоторые недостатки моего дизайна? Что действительно работает с точки зрения стратегий CI для больших (возможно, чрезмерно) сложных баз кода?
РЕДАКТИРОВАТЬ:
Я думал, что объяснил свою проблему, но, очевидно, я не был достаточно ясен. Я не ищу предложений по изменению платформ CI. Этого не произойдет, и ответы, предполагающие, что не будут приняты. Я хочу знать, как другие люди управляют сложными кодами с помощью CI. У меня есть дюжина квадратов различных продуктов, и у меня есть зависимости, разбросанные по ветру, и все они разные. Это то, что я хочу знать, как иметь дело.
Ответы:
Хотя я не сталкивался с такой плохой ситуацией, как вы описали, я поддерживал конфигурацию CI с десятками компонентов, между которыми есть некоторые «простые» зависимости. Я надеюсь, что мой подход может дать вам некоторые подсказки, чтобы продолжить. Проблема определенно связана не только с выбором CI-сервера, но и с общим процессом сборки и структурой проекта.
Я разобью проблему на 2 части: Здание и КИ.
Здание
Под «сборкой» я подразумеваю процесс изменения исходного кода под рукой до конечного артефакта. Наша компания в основном использует Java в разработке, и инструмент для сборки, который мы использовали, - Maven. Возможно, вам не удастся использовать это из-за характера вашего проекта, но в Maven есть одна важная концепция, на которую стоит обратить внимание:
1) В мире Maven каждый артефакт (библиотека, реальная программа и т. Д.) Должен быть четко изолирован и развязан. Зависимости между артефактами должны быть четкими. Я должен подчеркнуть, что беспорядочная зависимость, особенно циклическая зависимость между вашими артефактами сборки, сделает процесс сборки беспорядочным.
Например, я видел несколько java-проектов до этого, хотя после всего процесса сборки было построено несколько JAR-файлов (вы можете рассматривать это как lib / dll в Java), они на самом деле взаимозависимы. Мол, A.jar использует вещи в B.jar, и наоборот. Такая «модульность» совершенно бессмысленна. A.jar и B.jar всегда должны быть развернуты и использоваться вместе. Смысл в том, что позже, если вы захотите разделить их на разные проекты (например, для повторного использования в других проектах), вы не сможете этого сделать, потому что вы не можете определить, какой проект, A или B, построить первым.
Да, это необходимо учитывать при разработке вашего программного обеспечения, но я всегда верю, что вместо того, чтобы тратить время на создание сложных инструментов / моделей здания в грязном проекте, я бы скорее потратил время на реорганизацию дизайна, чтобы использовать простая модель здания.
2) Зависимости должны быть декларативными. Я видел много процессов сборки, которые включали все библиотеки, которые ему нужны локально в проекте. Процесс сборки будет чрезвычайно проблематичным, если некоторые из библиотек на самом деле являются другими артефактами, которые вам нужно собрать.
3) «Централизованное» хранилище для артефактов для получения зависимостей или для развертывания артефактов после их компиляции. Он не должен быть «централизованным» для всего офиса (это будет здорово, если он есть), просто локальный каталог будет в порядке.
Более детально про 2 и 3. Просто для примера, я натолкнулся на проект, который включал 3 независимых проекта. Каждый проект построен на основе исходного кода плюс библиотеки libs в каталоге lib / в исходном каталоге. Проект A построит несколько библиотек, которые, в свою очередь, используются проектами B и C. Есть ряд недостатков: процедура сборки сложна и ее сложнее автоматизировать; управление исходным кодом становится раздутым из-за ненужных дублированных файлов JAR, повторно используемых в другом проекте
В мире Maven это то, что в проектах B и C на самом деле не содержится A.jar (и других зависимостей, как и другие сторонние библиотеки) в исходном коде проекта. Это декларативно. Например, в конфигурации сборки проекта B он просто объявляет, что ему нужно: A.lib v1.0, xyz.lib v2.1 и т. Д., И скрипт сборки будет искать библиотеку из /A/1.0/A. jar и /xyz/2.1/xyz.lib
В мире, отличном от Maven, этот каталог артефактов должен быть одним или двумя каталогами с согласованной структурой каталогов. Вы можете поместить все сторонние библиотеки в общую папку и позволить разработчикам синхронизировать или копировать их на свои локальные машины. В своих проектах на C ++, которые я делал много лет назад, я устанавливаю для lib и заголовка значение $ {artifact_dir} / lib_name / ver, а artifact_id объявляется как переменная среды.
Когда проект A создается, у него будет копия его результата в этом artifact_dir, так что когда мы создаем проект B, B может получить результат A автоматически, без ручного копирования.
4) Не изменяемый выпуск. Как только вы выпустите A.lib 1.0, вот и все, вы не будете ожидать изменения содержимого A.lib 1.0 через 1 месяц, просто есть некоторые исправления ошибок. В таком случае это должен быть A.lib 1.1. Артефакт изменяющейся базы кода должен учитывать специальную «версию», для которой в Maven мы называем ее снимком.
Неизменяемый выпуск - более этическая проблема. Но то, что он решил, ясно: когда у вас много проектов, использующих одну и ту же библиотеку, вы знаете, какую версию этой библиотеки вы используете, и вы будете уверены, что одна и та же версия библиотеки, используемая в разных проектах, действительно одинакова. , Я думаю, что многие из нас столкнулись с проблемой: почему проект X и Y используют lib A, но результат сборки различен? (и оказывается, что библиотека A, используемая X и Y, фактически отличается после копания в содержимом или размере файла библиотеки).
Все это гарантирует, что ваши проекты могут быть построены независимо, без особых ручных трюков, например, сначала собрать проект A, скопировать A.lib в проект B, а затем собрать проект B ...
Выполнив подобное упражнение, например, когда вы создаете проект A, он попытается получить зависимости из централизованного хранилища артефактов. В случае, если некоторые зависимости (которые являются другими проектами вашей компании, например, проектом B) не найдены, вам нужно получить источник проекта B, построить его (который будет успешно развернут в централизованном хранилище), и затем создайте проект A снова.
CI
С простой системой сборки, с четкими зависимостями, CI будет намного проще. Я ожидаю, что ваш CI-сервер выполняет следующие требования:
1) Мониторинг управления исходным кодом, только извлечение + сборка, когда есть изменения в источнике
2) Возможность установить зависимости между проектами
Имея четкую зависимость для проектов, вам просто нужно настроить проекты в CI в соответствии с вашими фактическими проектами, настроить зависимость проекта CI в соответствии с зависимостью ваших проектов. Ваш CI-сервер должен быть настроен на создание зависимых проектов перед сборкой любого проекта (и, конечно, сборка происходит только в том случае, если исходный код проекта действительно изменился).
Если все идет хорошо, у вас должен быть огромный, сложный, но все еще управляемый CI (и, что еще более важно, управляемая структура проекта)
источник
Что сработало в подобных ситуациях для меня:
Я бы посоветовал вам рассматривать сборку как проект разработки программного обеспечения. Это означает, что вам нужно модулировать кодовую базу сборки и написать для нее несколько автоматических тестов (например, собрать известный номер ревизии и проверить, дает ли он правильные результаты).
источник
Я бы рассмотрел Jenkins как CI-сервер, вы можете посмотреть на функции здесь:
https://wiki.jenkins-ci.org/display/JENKINS/Meet+Jenkins
Почему? Его легко установить, он имеет прекрасный интерфейс, его легко настраивать и расширять, и есть МНОЖЕСТВО готовых плагинов практически для всего:
https://wiki.jenkins-ci.org/display/JENKINS/Plugins
Попробуй :)
источник
Теперь мы используем Go by ThoughtWorks, до этого мы использовали CruiseControl.Net . Это было полезно, учитывая, что у нас две команды на полмира друг от друга, и между нами большая разница во времени.
Мы управляем несколькими проектами, и большинство задач связано с дублированием между двумя разработчиками по обе стороны земного шара, поэтому мы должны помнить, что все файлы не должны нарушать чужую сборку.
Кроме того, управление с Go стало проще, и, будучи непоколебимым Agile Process, после установки мы получили меньше головной боли. Тестирование также было интегрировано с Go.
источник