Master Branch Must Be Read-Only

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

Непрерывная интеграция — это просто. Скачайте Jenkins, установите, создайте задачу, нажмите кнопку и получите приятное письмо, сообщающее о том, что ваша компиляция сломана (предполагается, что ваша компиляция автоматизирована). Затем исправьте сломанные тесты (предполагается, что у вас есть тесты) и получите гораздо более приятное письмо, сообщающее, что ваша компиляция прошла успешно.

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

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

Тем не менее, все мы знаем, что модульное тестирование не для команды, работающей с сроками, верно?

Ошибочно. Непрерывная интеграция может и должна работать.

В настоящее время разработка программного обеспечения ведется командами. Мы разрабатываем функционал в отдельных ветках и изолируем изменения во время их разработки. Затем мы сливаем ветки в master. После каждого слияния мы тестируем весь продукт, выполняя все доступные модульные и интеграционные тесты. Это называется непрерывная интеграция (или “CI”).

Иногда некоторые тесты не проходят. Когда это происходит, мы говорим, что наша “сборка сломана”. Такая ошибка является положительным побочным эффектом контроля качества, потому что она сразу же сигнализирует о наличии ошибки в master.

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

Continuous Delivery by Jez Humble et. al. идеально объясняет этот подход в главе 7, страницы 169–186.

На рынке есть несколько хороших инструментов, которые автоматизируют процедуры DevOps. Некоторые из них являются открытым программным обеспечением, вы можете их скачать и установить на свои собственные серверы. Например: Jenkins, Go и CruiseControl. Некоторые из них доступны в виде облачных сервисов, таких как: Travis, Shippable, Wercker и многие другие.

CI отлично, но чем больше команда (и кодовая база), тем чаще сборки ломаются. И, чем дольше их ремонт. Я видел много примеров, когда работоспособная команда начинает игнорировать красные флаги, поднятые Дженкинсом, спустя несколько недель попыток не отставать.

Команда просто не в состоянии исправить все ошибки вовремя. В основном потому, что у бизнеса есть другие приоритеты. Владельцы продукта не понимают важность “чистой сборки”, а технические лидеры не могут выделить время на исправление модульных тестов. Более того, код, который их сломал, уже находится в master, и, в большинстве случаев, уже развернут на производстве и доставлен конечным пользователям. Какая срочность исправления некоторых тестов, если бизнес-ценность уже была доставлена?

В конечном итоге, большинство разработчических команд не относятся серьезно к оповещениям о непрерывной интеграции. Для них Дженкинс или Трэвис - просто модные инструменты, которые не играют никакой роли во всем процессе разработки и доставки. Независимо от того, что говорит сервер непрерывной интеграции, мы все равно доставляем новые функции нашим конечным пользователям. Мы исправим нашу сборку позже. И это логично.

Четыре года назад, в 2010 году, я опубликовал статью в [phpArchitect](https://www.phparch.com/magazine/2010-2/august/) под названием “Предотвращение конфликтов в распределенных Agile проектах на PHP”. В статье было предложено решение (полная статья в формате PDF) для Subversion и PHP.

С тех пор я экспериментально использовал этот подход в различных проектах с открытым исходным кодом и нескольких коммерческих проектах с PHP, Java, Ruby и JavaScript, Git и Subversion. Во всех случаях мой опыт был только положительным, и именно поэтому родился rultor.com (о нем позже).

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

Другими словами, мы должны поднять красный флаг до того, как код попадет в master. Мы должны обвинить автора за неудачные тесты.

Предположим, я разрабатываю функцию в своей собственной ветке. Я закончил разработку и случайно сломал несколько тестов. Это случается, мы все ошибаемся. Я не могу слить свои изменения в master. Git просто отклоняет мою команду push, потому что у меня нет соответствующих разрешений. Все, что я могу сделать, это вызвать волшебный скрипт, попросив его слить мою ветку. Скрипт попытается выполнить слияние, но перед тем, как сделать коммит в master, он запустит все тесты. И если хотя бы один из них сломается, моя ветка будет отклонена. Мои изменения не будут слиты. Теперь это моя ответственность - исправить их и вызвать скрипт снова.

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

Некоторые CI-серверы предлагают функцию предварительной сборки (pre-flight builds), которая означает тестирование веток перед их слиянием в master. Travis, например, имеет эту функцию, и она очень полезна. Когда вы делаете новый коммит в ветку, Travis сразу же пытается собрать его и сообщает о проблемах в запросе на слияние в GitHub.

Обратите внимание, что предварительные сборки не выполняют слияние. Они только проверяют, чиста ли ваша индивидуальная ветка. После слияния она может легко нарушить master. И, конечно, этот механизм не гарантирует, что никакие участники не смогут сделать коммиты прямо в master, случайно нарушив его. Предварительные сборки - это мера предосторожности, но не решают проблему полностью.

Для начала работы, как описано выше, всё, что вам нужно сделать, это отозвать права на запись для ветки master (или /trunk в Subversion).

К сожалению, в GitHub это невозможно. Единственным решением является работа через форки и pull-запросы. Просто удалите всех из списка “соавторов”, и они будут вынуждены отправлять изменения через pull-запросы.

Затем начните использовать Rultor.com, который поможет вам тестировать, объединять и отправлять каждый pull-запрос. По сути, Rultor - это скрипт, о котором мы говорили выше. Он доступен как бесплатный облачный сервис.

ps. Краткая версия этой статьи также опубликована на devops.com.

Translated by ChatGPT gpt-3.5-turbo/42 on 2023-12-17 at 16:15

sixnines availability badge   GitHub stars