[Перевод] Типовые ситуации при непрерывной интеграции

Вы изучили команды Git, но хотите представлять, как непрерывная интеграция (Continuous Integration, CI) происходит в реальности? Или может вы хотите оптимизировать свои ежедневные действия? Этот курс даст вам практические навыки непрерывной интеграции с использованием репозитория на GitHub. Данный курс не задуман как некий визард, который можно просто прокликать, напротив, вы будете совершать те же действия, что люди на самом деле делают на работе, тем же способом, которым они это делают. Я буду объяснять теорию по мере прохождения вами имеющих к ней отношение шагов.


Что мы будем делать?

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

Этот GIF схематично показывает коммиты в вашем репозитории по мере продвижения по курсу. Как видите, тут нет ничего сложного и только самое необходимое.

Шаги непрерывной интеграции

Вы пройдёте такие стандартные для CI сценарии:


  • Работа над фичей;
  • Применение автотестов для обеспечения качества;
  • Реализация приоритетной задачи;
  • Разрешение конфликта при слиянии ветвей (merge conflict);
  • Возникновение ошибки в продуктивной среде.


Что вы узнаете?

Вы сможете ответить на такие вопросы:


  • Что такое непрерывная интеграция (CI)?
  • Какие типы автотестов используются при CI, и в ответ на какие действия они запускаются?
  • Что такое pull request и когда они нужны?
  • Что такое разработка через тестирование (Test Driven Development, TDD) и как она соотносится с CI?
  • Осуществлять слияние (merge) или применять изменения поверх (rebase)?
  • Откатывать или чинить в следующей версии?


Я вначале везде переводил штуки типа «pull request», но в результате решил вернуть фразы на английском в некоторых местах чтобы снизить градус безумия в тексте. Я порой буду использовать «программистский суржик» вроде чудного глагола «закоммитить» там, где люди на самом деле на работе его используют.


Что такое непрерывная интеграция?

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


Существуют разночтения по поводу этого термина

Предметом спора является частота интеграции. Некоторые утверждают, что объединять код лишь раз в день недостаточно на самом деле интегрироваться непрерывно. В пример приводится команда, где все берут свежий код утром и интегрируются один раз вечером. Хотя это и разумное возражение, всё же в целом считается, что вариант определения «раз в день» достаточно практичен, конкретен, и подходит для команд разных размеров.

Другое возражение состоит в том, что C++ давно не единственный язык, используемый при разработке, и простое требование сборки без ошибок, как способ валидации, слабовато. Некий набор тестов (например, модульных (unit), выполняемых локально) также должен завершиться успешно. В данный момент, сообщество тяготеет к тому, чтобы такое требование было обязательным, и, в будущем «сборка + модульные тесты», видимо, станет общепринятым, если это уже не произошло.

Непрерывная интеграция отличается от непрерывной поставки (Continuous Delivery, CD) тем, что не требует релиз-кандидата после каждого цикла интеграции.


Список шагов, который мы будем использовать на протяжении курса


  1. Pull in the latest code. Create a branch from master. Start working.
  2. Create commits on your new branch. Build and test locally. Pass? Go to the next step. Fail? Fix errors or tests and try again.
  3. Push to your remote repository or remote branch.
  4. Create a pull request. Discuss the changes, add more commits as discussion continues. Make tests pass on the feature branch.
  5. Merge/rebase commits from master. Make tests pass on the merge result.
  6. Deploy from the feature branch to production.
  7. If everything is good in production for some period of time, merge changes to master.

Процесс непрерывной интеграции (вариант)


️ Подготовка


Убедитесь в наличии нужного ПО

Чтобы пройти этот курс вам понадобится Node.js и Git-клиент.


Можете использовать любой Git-клиент, но я буду приводить команды только для командной строки.


Убедитесь, что у вас установлен Git-клиент, поддерживающий командную строку

Если у вас пока не установлен Git-клиент, поддерживающий командную строку, можете найти инструкции по установке здесь.


Подготовьте репозиторий

Вам потребуется создать личную копию (fork) репозитория-шаблона с кодом для курса на GitHub. Давайте договоримся называть эту личную копию репозиторием курса.

Сделали? Если вы не меняли настройки по умолчанию, ваш репозиторий курса скорее всего называется continuous-integration-team-scenarios-students, он находится в вашем аккаунте на GitHub, и URL выглядит так

https://github.com/<ваше имя ползователя на GitHub>/continuous-integration-team-scenarios-students

Я буду называть этот адрес просто .


Угловые скобки как <тут> будут означать, что вы должны заменить такое выражение на соответствующее значение.

Убедитесь что GitHub actions включены для данного репозитория курса. Если они не будут включены, пожалуйста, включите их, нажав на большую кнопку в середине страницы, на которую вы можете попасть, кликнув Actions в интерфейсе GitHub.


У вас не получится пройти курс, следую моим инструкциям, если GitHub Actions не будут включены.

Включите Github Actions для репозитория курса

Вы всегда можете использовать способность GitHub отображать Markdown чтобы увидеть текущее состояние списка, который мы сочиняем, тут

https://github.com//continuous-integration-team-scenarios-students/blob/master/ci.md


Про ответы

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

Если вы чувствуете, что не понимаете что делать и не можете продолжать, можете подсмотреть в ветку solution, которая есть в вашем стартовом репозитории.
Пожалуйста, не осуществляйте слияние solution в master во время курса. Вы можете использовать эту ветку чтобы разобраться что делать, или чтобы сравнивать свой код с авторским, используя все возможности, которые даёт нам Git. Если вы совсем потерялись, можете полностью заменить свою ветку master на ветку solution и затем сбросить свою рабочую директорию до того шага курса, который вам нужен.


Используйте это только если вам это действительно нужно

Закоммитьте (commit) свой код

git add .
git commit -m "Backing up my work"

Эти команды


  • переименовывают master в master-backup;
  • переименовывают solution в master;
  • переключают (checkout) на новую ветку master и переписывают содержимое рабочей директории;
  • создают ветку «solution» из «master» (которая раньше была «solution») на случай если вам в будущем понадобится ветка «solution».
git branch -m master master-backup
git branch -m solution master
git checkout master -f
git branch solution

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

git reset --hard 

Если вы довольны результатом, в какой-то момент вам понадобится опубликовать вашу версий репозитория в удалённый репозиторий (remote). Не забудьте явно указать удалённую ветку когда будете это делать.

git push --force origin master

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


Starting working

Непрерывная интеграция: Начинаем работать

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


️ Задание: обновите локальный репозиторий, создайте ветку из master, начните работать


  1. Клонируйте репозиторий курса из .
  2. Запустите npm install в каталоге репозитория курса; он нужен нам для установки Jest, который мы используем для запуска тестов.
  3. Создайте ветку и назовите ее feature. Переключитесь на эту ветку.
  4. Добавьте тестовый код в ci.test.js между комментариями с просьбой сделать это.

    it('1. pull latest code', () => {
      expect(/.*pull.*/ig.test(fileContents)).toBe(true);
    });
    
    it('2. add commits', () => {
      expect(/.*commit.*/ig.test(fileContents)).toBe(true);
    });
    
    it('3. push to the remote branch with the same name', () => {
      expect(/.*push.*/ig.test(fileContents)).toBe(true);
    });
    
    it('4. create a pull request and continue working', () => {
      expect(/.*pull\s+request.*/ig.test(fileContents)).toBe(true);
    });

  5. Добавьте текст с первыми 4 шагами в файл ci.md.
    1. Pull in the latest code. Create a branch from `master`. Start working.    
    2. Create commits on your new branch. Build and test locally.  
    Pass? Go to the next step. Fail? Fix errors or tests and try again.  
    3. Push to your remote repository or remote branch.  
    4. Create a pull request. Discuss the changes, add more commits  
    as discussion continues. Make tests pass on the feature branch.  

    Команды

# Клонируйте репозиторий курса
git clone 
cd 

# Выполните npm install в каталоге репозитория курса; он установит Jest, который мы используем для запуска тестов.
npm install

# Создайте ветку и назовите ее feature. Переключитесь на эту в ветку.
git checkout -b feature

# Отредактируйте ci.test.js как описано выше.
# Отредактируйте ci.md как описано выше


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

Мы собираемся настроить тесты чтобы они запускались перед коммитом, а затем закоммитить код.


Типовые сценарии, когда тесты запускаются автоматически


  • Локально:
    • Постоянно или в ответ на соответствующие изменения кода;
    • При сохранении (для интерпретируемых или JIT-компилируемых языков);
    • При сборке (когда требуется компиляция);
    • При коммите;
    • При публикации в общий репозиторий.


  • На сервере сборки (build server) или в среде сборки:
    • Когда код публикуется в персональную ветку / репозиторий.
    • Тестируется код в этой ветке.
    • Тестируется потенциальный результат слияния (обычно с master).
    • В качестве этапа непрерывной интеграции/конвейера непрерывной поставки

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


  • Быстрые модульные тесты — при сборке, в конвейере CI
  • Медленные модульные тесты, быстрые компонентные и интеграционные тесты — при коммите, в конвейере CI
  • Медленные компонентные и интеграционные тесты — в конвейере CI
  • Тестирование безопасности, нагрузочное и другие длительные или дорогостоящие тесты — в конвейерах CI/CD, но только в определенных режимах/этапах/конвейерах сборки, например, при подготовке релиз-кандидата или при запуске вручную.


️ Задание

Я предлагаю сначала запустить тесты вручную, используя команду npm test. После этого давайте добавим git hook для запуска наших тестов при коммите. Есть одна загвоздка: Git hooks не считаются частью репозитория и поэтому не могут быть клонированы из GitHub вместе с остальными материалами курса. Чтобы установить hook, вам нужно запустить install_hook.sh или скопировать файл repo/hooks/pre-commit в локальный каталог .git/hooks/.
При коммите вы увидите, что выполняются тесты, и они проверяют, присутствуют ли в списке определенные ключевые слова.


  1. Запустите тесты вручную, выполнив команду npm test в папке репозитория вашего курса. Убедитесь, что тесты были выполнены.
  2. Установите hook на коммит (pre-commit hook), запустив install_hook.sh.
  3. Закоммитьте изменения в локальный репозиторий.
  4. Убедитесь, что тесты выполняются перед коммитом.

Ваш репозиторий должен выглядеть так после выполнения этих действий.
Непрерывная интеграция: первый коммит


Команды

# Установите pre-commit hook выполнив install_hook.sh.  

# Закоммитьте изменения в локальный репозиторий. Используйте "Add first CI steps" в качестве сообщения при коммите.
git add ci.md ci.test.js
git commit -m "Add first CI steps"

# Убедитесь, что тесты запускаются перед коммитом.  


Опубликуйте код в удаленный репозиторий или удаленную ветку

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


  • При использовании форков разработчик клонирует удаленный общий репозиторий, создавая его личную удаленную копию, также известную как форк. После этого он клонирует этот личной репозиторий, чтобы работать с ним локально. Когда работа завершена и коммиты созданы, он помещает их в свой форк, где они доступны другим и могут быть интегрированы в общий репозиторий. Этот подход обычно используется в проектах с открытым исходным кодом на GitHub. Он также используется в моем расширенном курсе [Team Work and CI with Git] (http://devops.redpill.solutions/).
  • Другой подход состоит в том, чтобы использовать только один удалённый репозиторий и считать только ветку master совместно используемого репозитория «защищенной». В этом сценарии отдельные разработчики публикуют свой код в ветки удаленного репозитория, чтобы другие могли этот код посмотреть, если все в порядке, объединить с master общего репозитория.

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

Давайте опубликуем наш код.


️ Задание


  • Опубликуйте изменения в удаленную ветку с тем же именем, что и ваша рабочая ветка


Команды

git push --set-upstream origin feature


Создайте pull request

Создайте pull request с названием Steps review. Установите feature как «head branch» и master как «base branch».


Убедитесь, что вы установили master в своем форке репозитория в качестве «base branch», я не буду отвечать на запросы на изменения в репозиторий с материалами курса.

На сленге GitHub «base branch» — это ветка, на которой вы основываете свою работу, а «head branch» — это ветка, содержащая предлагаемые изменения.


Обсудите изменения, добавьте новые коммиты по мере продолжения обсуждения


Pull request (PR)

Pull request (PR) — это способ обсудить и задокументировать код, а также провести проверку (code review) кода. Pull request названы в честь общего способа интеграции отдельных изменений в общий код. Обычно человек клонирует удаленный официальный репозиторий проекта и работает над кодом локально. После этого он помещает код в свой личный удаленный репозиторий и просит ответственных за официальный репозиторий забрать (pull) его код в свои локальные репозитории, где они просматривают и, возможно, интегрируют (merge) его. Это понятие известно и под другими названиями, например, merge request.

На самом деле вам не обязательно использовать функцию pull request GitHub или аналогичных платформ. Команды разработчиков могут использовать другие способы связи, включая личное общение, голосовые звонки или электронную почту, но есть всё же ряд причин использовать такие pull requests в стиле обсуждения на форуме. Вот некоторые из них:


  • организованные обсуждения, связанные с конкретными изменениями в коде;
  • как место для просмотра отзывов о незавершенной работе как от автотестов, так и от коллег;
  • формализация проверок кода;
  • чтобы позже можно было выяснить причины и соображения, стоящие за тем или иным фрагментом кода.

Обычно вы создаете pull request когда вам нужно что-то обсудить или получить обратную связь. Например, если вы работаете над функцией, которая может быть реализована несколькими способами, вы можете создать запрос на внесение изменений еще до написания первой строки кода, чтобы поделиться своими идеями и обсудить свои планы с соавторами. Если работа более проста, pull request открывается, когда что-то уже сделано, зафиксировано и может быть обсуждено. В некоторых сценариях вы можете открыть PR только из соображений контроля за качеством: чтобы запустить автоматические тесты или инициировать проверку кода. Что бы вы ни решили, не забывайте @упоминать людей, одобрение которых требуется в вашем pull request’е.

Обычно при создании PR вы делаете следующее.


  • Указываете, что вы предлагаете изменить и где.
  • Пишете описание, объясняющее цель изменений. Вы можете захотеть:
    • добавить что-нибудь важное, что не является очевидным из кода, или что-нибудь полезное для понимания контекста, например соответствующие #баги и номера коммитов;
    • @упомянуть всех, с кем хотите начать работать вместе, или вы можете @упомянуть их в комментариях позже;
    • попросить коллег помочь с чем-то или проверить что-либо конкретное.

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

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


️ Добавьте замечание о произвольности списка шагов CI

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


️ Задание: создание pull request для данного примечения


  1. Переключитесь на ветку master.
  2. Создайте ветку с именем bugfix.
  3. Добавьте текст примечания в конец файла ci.md.
    > **GitHub flow** is sometimes used as a nickname to refer to a flavor of trunk-based development  
    when code is deployed straight from feature branches. This list is just an interpretation  
    that I use in my [DevOps courses](http://redpill.solutions).  
    The official tutorial is [here](https://guides.github.com/introduction/flow/).
  4. Закоммитьте изменения.
  5. Опубликуйте ветку bugfix в удалённый репозиторий.
  6. Создайте pull request с именем Adding a remark с головной веткой bugfix и базовой веткойmaster.


Убедитесь, что вы установили master в своем форке репозитория в качестве «base branch», я не буду отвечать на запросы на изменения в репозиторий с материалами курса.

Вот как должен выглядеть ваш репозиторий.
Непрерывная интеграция: исправление


Команды

# Переключитесь на ветку master. Создайте ветку bugfix.
git checkout master

# Создайте ветку bugfix-remark.
git checkout -b bugfix

# Добавьте текст примечания внизу ci.md.

# Закоммитьте изменения
git add ci.md
git commit -m "Add a remark about the list being opinionated"

# Опубликуйте ветку bugfix в удалённый репозиторий.
git push --set-upstream origin bugfix

# Создайте pull request при помощи интерфейса GitHub как описано выше


️ Задание


  1. Создайте pull request.
  2. Нажмите «Merge pull request».
  3. Нажмите «Confirm merge».
  4. Нажмите «Delete branch», она нам больше не нужна.

Это диаграмма коммитов после слияния.
Непрерывная интеграция: объединение исправления с мастером


️ Продолжайте работать и добавлять тесты

Совместная работа над pull request часто приводит к необходимости дополнительной работы. Обычно это результат проверки кода или обсуждения, но в нашем курсе мы собираемся смоделировать это, добавив новые элементы в наш список шагов CI.

При непрерывной интеграции обычно применяется некоторое тестовое покрытие. Требования к покрытию тестами различаются и обычно находятся в документе с названием вроде «руководство для авторов»(contribution guidelines). Мы поступим просто и добавим по тесту для каждой строки в нашем контрольном списке.

При выполнении заданий сначала попробуйте закоммитить тесты. Если вы правильно установили pre-commit hook ранее, только что добавленный тест будет запущен, не будет пройден, и ничего не будет закоммичено. Обратите внимание: так мы узнаем, что наши тесты действительно что-то проверяют. Любопытно, что если бы мы начали с кода до тестов, прохождение тестов могло означать либо то, что код работает так, как ожидалось, либо что тесты на самом деле ничего не проверяют. Кроме того, если бы мы не написали тесты в первую очередь, мы могли бы вовсе их забыть, поскольку ничто не напоминало бы нам об этом.


Разработка через тестирование (TDD)

TDD рекомендует писать тесты перед кодом. Обычный процесс работы с использованием TDD выглядит так.


  1. Добавьте тест.
  2. Запустите все тесты и убедитесь, что новый тест не проходит успешно.
  3. Напишите код.
  4. Запустите тесты, убедитесь, что все тесты проходят успешно.
  5. Проведите рефакторинг кода.
  6. Повторите.

Поскольку результаты работы тестов, которые не были пройдены успешно, обычно отображается красным, а выполненные успешно — зеленым, цикл также известен как «красный-зеленый-рефакторинг»(red-green-refactor).


️ Задание

Сначала попробуйте закоммитить тесты и дать им завершиться неуспешно, затем добавьте и закоммитьте сам текст списка шагов CI. Вы увидите, что тесты проходят («зеленые»).
Затем опубликуйте новый код в удалённый репозиторий и посмотрите, как выполняются тесты в интерфейсе GitHub в нижней части обсуждения запроса на внесение изменений, и обновляется статус PR.


  1. Переключитесь на ветку feature.
  2. Добавьте эти тесты в ci.test.js после последнего вызова it (...);.

    it('5. Merge/rebase commits from master. Make tests pass on the merge result.', () => {
      expect(/.*merge.*commits.*tests\s+pass.*/ig.test(fileContents)).toBe(true);
    });
    
    it('6. Deploy from the feature branch to production.', () => {
      expect(/.*Deploy.*to\s+production.*/ig.test(fileContents)).toBe(true);
    });
    
    it('7. If everything is good in production for some period of time, merge changes to master.', () => {
      expect(/.*merge.*to\s+master.*/ig.test(fileContents)).toBe(true);
    });

  3. Попробуйте закоммитить тесты. Если pre-commit hook установлен, попытка коммита завершится ошибкой.
  4. После добавьте этот текст в ci.md.
    5. Merge/rebase commits from master. Make tests pass on the merge result.  
    6. Deploy from the feature branch with a sneaky bug to production.
    7. If everything is good in production for some period of time, merge changes to master. 
  5. Внесите и закоммитьте изменения локально.
  6. Опубликуйте изменения в ветку feature.

Теперь у вас должно получиться что-то вроде этого
Непрерывная интеграция: продолжаем работу


Команды


# Переключительна ветку feature
git checkout feature

# Добавить тесты в ci.test.js как описано выше

# Добавьте в индекс ci.test.js чтобы позже закоммитить
git add ci.test.js

# Попытайтесь закоммитить тесты. Если pre-commit hook установлены, коммит не произойдёт.
git commit

# Теперь добавьте текст в ci.md как описано выше

# Внесите изменения и закоммитьте их
git add ci.md
git commit -m "Add the remaining CI steps"

# Опубликуйте изменения в ветку feature
git push


Конфликт слияния

Перейдите к запросу на внесение изменений Steps review.

Несмотря на то, что мы не сделали ничего плохого, и тесты для нашего кода прошли успешно, мы все еще не можем осуществить слияние ветки feature и master. Это потому, что другая ветка bugfix была объединена с master пока мы работали над этим PR.
Это создает ситуацию, когда удаленная ветка master имеет более новую версию, чем та, на которой мы основывали ветку feature. Из-за этого мы не можем просто перемотать HEAD master до конца ветки feature. В этой ситуации нам нужно либо осуществить слияние (merge), либо применить коммиты feature поверх (rebase) master. GitHub на самом деле может выполнять автоматическое слияние, если нет конфликтов. Увы, в нашей ситуации обе ветки имеют конкурирующие изменения в файле ci.md. Эта ситуация известна как конфликт при слиянии (merge conflict), и нам нужно разрешить ее вручную.


Merge или rebase


Merge


  • Создает дополнительный коммит слияния (merge commit) и сохраняет историю работы.
    • Сохраняет исходные коммиты веток с исходными отметками времени и авторами.
    • Сохраняет SHA коммитов и ссылки на них в обсуждениях запросов на изменения.
  • Требует однократного разрешения конфликтов.
  • Делает историю нелинейной.
    • Историю может быть трудно читать из-за большого количества веток (напоминает кабель IDE).
    • Усложняет автоматическую отладку, например, делает git bisect менее полезным — он только найдет коммит слияния.


Rebase


  • Воспроизводит коммиты из текущей ветки поверх базовой один за другим.
    • Формируются новые коммиты с новыми SHA, в результате чего коммиты в GitHub соотносятся с исходными pull requests, но не с соответствующими комментариями.
    • Коммиты могут быть рекомбинированы и изменены в процессе или даже объединены в один.
  • Может потребоваться разрешить несколько конфликтов.
  • Позволяет поддерживать линейную историю.
    • Историю может быть проще читать, если только она не является слишком длинной без разумных на то причин.
    • Автоматическая отладка и устранение неполадок несколько проще: делает возможным git bisect, может сделать автоматические откаты более чёткими и предсказуемыми.
  • Требуется публикации ветви с перенесёнными коммитами с флагом --force при использовании с запросами на внесение изменений.

Обычно команды соглашаются всегда использовать одну и ту же стратегию, когда им нужно объединять изменения. Это может быть «чистое» слияние или «чистый» применение коммитов поверх или что-то промежуточное, например, выполнение применение коммитов поверх интерактивном режиме (git rebase -i) локально для веток, не опубликованных в общем репозитории, но слияние (merge) для «общедоступных» веток.

Здесь мы будем использовать слияние.


️ Задание


  1. Убедитесь, что код в локальной ветке master обновлён из удалённого репозитория.
  2. Переключитесь на ветку feature.
  3. Инициируйте слияние с веткой master. Будет сообщено о конфликте слияния, связанном с конкурирующими изменениями в ci.md.
  4. Разрешите конфликт так, чтобы в тексте остался и наш список шагов CI, и замечание о нем.
  5. Опубликуйте коммит слияния в удаленную ветку feature.
  6. Проверьте статус pull request’а в пользовательском интерфейсе GitHub, дождитесь пока слияние не будет разрешено.


Команды

# Убедитесь, что код в локальное ветке `master` обновлён из удалённого репозитория.
git checkout master
git pull

# Переключитесь на ветку feature
git checkout feature

# Инициируйте слияние с веткой master 
git merge master

# A merge conflict related to concurrent changes to ci.md will be reported
# => Auto-merging ci.md
#    CONFLICT (content): Merge conflict in ci.md
#    Automatic merge failed; fix conflicts and then commit the result.

# Разрешите конфликт так, чтобы и наш список шагов CI, и замечание о нем остались в тексте.
# отредактируйте ci.md чтоб он не содержал маркеров конфликта слияния
git add ci.md
git merge --continue
# при коммите можете оставить сообщение по умолчанию

# Опубликуйте коммит слияния в удаленную ветку feature.
git push

# Проверьте статус запроса на изменения в пользовательском интерфейсе GitHub, дождитесь пока слияние не будет разрешено.


Отличная работа!

Вы закончили работу со списком, и теперь вам нужно утвердить pull request в master.


️ Задание: Утвердите pull request «Steps review»


  1. Откройте pull request.
  2. Нажмите «Merge pull request».
  3. Нажмите «Confirm merge».
  4. Нажмите «Delete branch», так как она нам больше не нужна.

Это ваш репозиторий в данный момент
Непрерывная интеграция: интеграция фичи


Ошибка на продуктиве

Говорят, что «тестирование можно использовать, чтобы показать наличие ошибок, но никогда чтобы показать их отсутствие». Несмотря на то, что у нас были тесты, и они не показали нам никаких ошибок, коварная ошибка прокралась в продакшн.

В подобном сценарии нам нужно позаботиться о:


  • том, что развёрнуто на продуктиве;
  • коде в ветке master с ошибкой, с которого разработчики могут начинать новую работу.


Откатывать или исправлять в следующей версии?

«Откатывание»(rolling back) — это развертывание заведомо исправной более ранней версии в продуктивную среду и отмена (revert) коммитов, содержащих ошибку. «Исправление в следующей версии»(fixing forward) — это добавление исправления в master и развертывание новой версии как можно скорее. Поскольку API и схемы баз данных меняются по мере развертывания кода в производственной среде, при непрерывной поставке и наличии хорошего покрытия тестами, откатывание, как правило, намного сложнее и рискованнее, чем исправление в следующей версии.

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


  • исправить ошибку на продуктиве как можно скорее;
  • сделать код в master сразу пригодным для начала новой работы.


️ Задание


  1. Переключитесь на ветку master локально.
  2. Обновите локальный репозиторий из удалённого репозитория.
  3. Отмените коммит слияния PR Steps review в master.
  4. Опубликовать изменения в удалённый репозиторий.

Это история репозитория с отмененным коммитом слияния
Непрерывная интеграция: отмена слияния


Команды

# Переключитесь на ветку master.
git checkout master

# Обновите локальный репозиторий из удалённого репозитория.
git pull

# Отмените коммит слияния PR Steps review в master.
# Мы отменяем коммит слияния, поэтому нам нужно выбрать ветку истории, которую мы захотим оставить
git show HEAD

# предположим, что коммит, который был последним в ветке master до слияния, был отображён предыдущей командой первым
git revert HEAD -m 1
# можете не менять сообщения коммитов

# Опубликуйте изменения в удалённый репозиторий
git push


️ Самопроверка

Убедитесь, что ci.md больше не содержит текста «sneaky bug» после отмены коммита слияния.


Исправить список шагов CI и вернуть его в master

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

Мы можем подойти к задаче по-разному:


  • отменить (revert) коммит, которая отменяет слияние feature с master;
  • перенести коммиты из бывшей feature.

Разные команды разработчиков в данном случае используют разные подходы, мы же перенесём полезные коммиты в отдельную ветку и создадим отдельный pull request для этой новой ветки.


️ Задание


  1. Создайте ветку под названием feature-fix и переключитесь на нее.
  2. Перенесите все коммиты из бывшей ветки feature в новую ветку. Разрешите конфликты слияния, которые возникли при переносе.

    Непрерывная интеграция: возвращаем коммиты feature


  3. Добавьте регрессионный тест в ci.test.js:

    it('does not contain the sneaky bug', () => {
    expect( /.*sneaky\s+bug.*/gi.test(fileContents)).toBe(false);
    });

  4. Запустите тесты локально, чтобы убедиться, что они не завершаются успешно.
  5. Удалите текст » with a sneaky bug» в ci.md.
  6. Добавьте в индекс изменения тестов и изменения в списке шагов и закоммитьте их.
  7. Опубликуйте ветку в удалённый репозиторий.

У вас в результате должно получиться что-то похожее
Непрерывная интеграция: исправленная фича


Команды

# Создайте ветку под названием feature-fix и переключитесь на нее.
git checkout -b feature-fix

# Перенесите все коммиты из бывшей ветки feature в новую ветку. Разрешите конфликты слияния, которые возникли при переносе.
# используйте историю чтобы узнать хэши коммитов:
# - предшествующего коммиту с первой частью списка: C0
# - добавляющего последние элементы списка: C2
git log --oneline --graph
git cherry-pick C0..C2
# разрешите конфликты слияния
# - отредактируйте ci.md и/или ci.test.js
# - добавьте файлы в индекс
# - выполните "git cherry-pick --continue", можете не менять сообщение коммита

# Добавьте регрессионный тест в ci.test.js
# Запустите тесты локально, чтобы убедиться, что они не завершаются успешно.

# Удалите текст " with a sneaky bug" в ci.md.

# Добавьте в индекс изменения тестов и в списке шагов и закоммитьте их.
git add ci.md ci.test.js
git commit -m "Fix the bug in steps list"

# Опубликуйте ветку в удалённый репозиторий.
git push --set-upstream origin feature-fix


Создайте pull request.

Создайте pull request с названием Fixing the feature. Установите feature-fix как «head branch», а master как «base branch».
Пожалуйста, подождите, пока завершатся тесты. Вы можете увидеть статус тестов в нижней части обсуждения PR.


Убедитесь, что вы установили master в своем форке репозитория в качестве «base branch», я не буду отвечать на запросы на изменения в репозиторий с материалами курса.


Утвердите pull request «Fixing the feature»

Спасибо за исправление! Пожалуйста, утвердите изменения в master из pull request.


️ Задание


  1. Нажмите «Merge pull request».
  2. Нажмите «Confirm merge».
  3. Нажмите «Delete branch», так как она нам больше не нужна.

Это то, что у вас должно быть в данный момент
Непрерывная интеграция: исправление интегрировано в master

Вы выполнили все действия, которые люди обычно совершают в процессе непрерывной интеграции.

Если вы заметили какие-либо проблемы с курсом или знаете как его улучшить, создайте issue в репозитории с материалами курса. У этого курса также есть интерактивная версия использующая GitHub Learning Lab в качестве платформы.

© Habrahabr.ru