Мастер-класс по CI/CD
Часть 1. Основы CI/CD
Что такое методология CI/CD?
Материал основан на Что такое CI/CD | Дока.
Простыми словами, CI/CD (Continuous Integration, Continuous Delivery — непрерывная интеграция и доставка) — это технология автоматизации тестирования и доставки новых модулей разрабатываемого проекта заинтересованным сторонам (разработчики, аналитики, инженеры качества, конечные пользователи и др.).
Основные принципы CI/CD
- Сегрегация ответственности заинтересованных сторон. Участники процесса разработки и потребители готового проекта разделяют между собой ответственность за ту или иную стадию жизненного цикла продукта. Разработчики и дизайнеры проектируют бизнес-логику, а также обеспечивают положительный пользовательский опыт взаимодействия с готовой системой. Инженеры по качеству вводят сквозные функции и приемочные тесты, DevOps-инженеры организуют логистику кода, а пользователи — дают обратную связь по результатам использования системы.
- Снижение риска. Каждая группа участников процесса разработки минимизирует возможные риски при прохождении продукта через стадии жизненного цикла (контроль целостности бизнес-логики, пользовательского опыта, оптимизация хранения и обработки данных, миграции и пр.).
- Короткий цикл обратной связи. В коммерческой разработке скорость реакции на возникновение ошибок, либо запросов нового функционала закладывает основу конкурентоспособности будущей системы. Чтобы добавлять в продукт новый функционал быстрее конкурентов, необходимо стремиться к автоматизации сборки и тестирования кода. Однако, в ситуациях, когда для решения необходимо участие человека, автоматизация может только навредить. Для таких с итуаций рекомендуется сокращать число информационных посредников, обеспечивая короткий цикл обратной связи.
- Реализация среды. Команде разработки требуется единое рабочее окружение для контроля версий и построения вспомогательных веток для целей контроля качества, приемлемости, масштабируемости и отказоустойчивости производимого кода. По мере контроля протестированные модули должны перемещаться в основную ветку проекта и поступать на тестирование и сборку в составе единого решения. На этапе финального тестирования код также оценивается с позиций безопасности.
Этапы CI/CD
Типичную итерацию процесса разработки с применением CI/CD (источник doka.guide/tools/ci-cd):

Детализированное описание этапов:
- Написание кода. Каждый из разработчиков пишет код своего модуля, проводит ручное тестирование, а затем соединяет результат работы с текущей версией проекта в основной ветке. Для контроля версий используется система Git, либо аналогичные решения. Когда участники команды опубликуют код своих модулей в основной ветке, начнется следующий этап.
- Сборка. Система контроля версий запускает автоматическую сборку и тестирование проекта. Триггеры для начала сборки настраиваются командой индивидуально — фиксация изменений в основной ветке проекта, сборка по расписанию, по запросу и т.д. Для автоматизации сборки используется Jenkins, либо аналогичный продукт.
- Ручное тестирование. Когда CI система успешно проверила работоспособность тестовой версии, то код отправляется тестировщикам для ручного обследования. При этом тестовая сборка получает номер кандидата для дальнейшего релиза продукта (например, v.1.0.0-1).
- Релиз. По итогам ручного тестирования сборка получает исправления, а итоговый номер версии кандидата повышается (например, после первого исправления версия v.1.0.0-1 становится v.1.0.0-2). После этого выпускается версия кода для клиента (например, v.1.0.0) и начинается следующий этап цикла.
- Развертывание. На этом этапе рабочая версия продукта для клиентов автоматически публикуется на production серверах разработчика. После этого клиент может взаимодействовать с программой и ознакомиться с ее функционалом как непосредственно через готовый интерфейс, так и через облачные сервисы.
- Поддержка и мониторинг. Конечные пользователи начинают работать с продуктом. Команда разработки поддерживает его и анализирует пользовательский опыт.
- Планирование. На основе пользовательского опыта формируются запросы на новый функционал для продукта, готовится план доработок. После этого цикл замыкается и переходит в начальную стадию — написание кода. Далее начинается новая итерация CI/CD разработки.

Пару слов про DevOps
Материал основан на Что такое DevOps: зачем он нужен, где применяется и в чём его плюсы и минусы | Блог Яндекс.Практикума.
В любом процессе разработки участвует три команды:
- Dev — программисты, которые непосредственно пишут код;
- QA/QC — тестировщики, которые выявляют ошибки в коде, вручную или автоматически;
- Ops — инженеры, которые поддерживают инфраструктуру для написания кода, например сервера, а также берут уже рабочий код и запускают на реальные сервера, чтобы клиент получил доступ к сайту, сервису или приложению.
При классическом подходе к разработке все эти команды работают независимо друг от друга. У каждой своя зона ответственности, а код от других команд они получают не в потоке, а порциями. Из-за этого возникают задержки и недопонимание: тестировщики тестируют неактуальную сборку кода, сисадмины сидят без работы, пока код не будет готов, разработчики не задумываются о результате.
Чтобы избавиться от этих задержек и недопонимания, была придумана методология DevOps — особый подход к организации команд разработки. Он позволяет выстроить конвейер, на котором разработчики, тестировщики и сисадмины работают в едином потоке и вместе отвечают за результат — код, выпущенный в релиз для пользователей.
Методология DevOps — это комбинация из двух факторов:
- особой философии, принципов работы DevOps: налаженного общения между командами, совместных KPI, общей ответственности за результат;
- набора инструментов, который позволяет создать этот самый конвейер: автоматических систем тестирования, инфраструктуры для написания и развёртывания кода, программ для передачи кода между разными командами.
Ключевые инструменты, без которых внедрить подход DevOps нельзя:
- Системы контроля версий. Обычно используют Git. Это среда, в которую вносят код в процессе написания и разработки. В ней можно видеть все внесённые изменения, быстро откатить приложение к предыдущей конфигурации и сливать вместе разные версии кода, если над одной и той же функцией работает несколько программистов.
- CI/CD-системы. CI/CD — это комбинация непрерывной интеграции и непрерывного ра звёртывания контента. В этом и есть суть подхода DevOps, при котором все процессы происходят параллельно. Чтобы обеспечить автоматическую передачу кода, нужны CI/CD-системы, например GitLab или Jenkins. Они позволяют настраивать скрипты и сразу получать обратную связь на переданный дальше по конвейеру код.
- Системы мониторинга. Они автоматически проверяют сервера и приложения, собирают логи с ошибками, отправляют сообщения о проблемах. Обычно это комплексные приложения типа Grafana и Prometheus.
Инструменты для CI/CD
Материал основан на Что такое методология разработки CI/CD | Академия Selectel.
Разработчики программного обеспечения используют различные инструменты для автоматизации тестирования и доставки кода своих проектов конечным пользователям.
- GitLab. Среда позволяет управлять репозиториями проекта, документировать функциональность и результ аты доработок и тестов, а также отслеживать ошибки и работать с CI/CD pipeline.
- GitHub. Среда позволяет управлять репозиториями проекта, документировать функциональность и результаты доработок и тестов, а также отслеживать ошибки и работать с CI/CD с помощью GitHub Actions.
- Travis-CI. Инструмент подключается к репозиториям в GitHub при минимуме настроек. Решение облачное и не требует локальной установки. Кроме того, оно бесплатно для open-source проектов.
- Circle-CI. Продукт также использует бесшовную интеграцию с GitHub. Предлагается веб-интерфейс для отслеживания версий сборок и ведения задач. Также решение поддерживает отправку оповещений по почте, slack и другим каналам связи.
- Jenkins. Довольно популярный инструмент в DevOps среде. Заслужил свою репутацию благодаря работе с различными плагинами, позволяющими гибко настраивать CI/CD процессы под требования разработки конкретного продукта.
- TeamCity. В бесплатном режиме позволяет работать только с 3 агентами сборки, техническая поддержка предоставляется по подписке.
- PHP Censor. CI-сервер для автоматизации сборки PHP-проекто в, работающий с репозиториями GitLab, GitHub, Mercurial и др. Для тестирования используются библиотеки Atoum, PHP Spec, Behat и др. Проект хорошо документирован, но предполагает самостоятельную настройку и хостинг.
- Rex. Предназначен для автоматизации CI процессов в дата-центрах. Функционирует на Perl-скриптах.
- Open Build Service (OBS). Предназначен для автоматизации CI/CD в разработке дистрибутивов приложений.
- Buildbot. CI-система, позволяющая автоматизировать сборку и тестирование приложений. Поддерживает современные VCS и позволяет гибко настраивать сборку за счет Python-компонентов.
И это лишь малая часть инструментов для CI/CD.
Инструменты для CI/CD (источник harness.io/blog):

Преимущества и недостатки
Преимущества:
- Инструменты CI/CD позволяют быстро выводить программный продукт на рынок, исправлять ошибки, внедрять новую функциональность.
- Автоматизация позволяет снизить нагрузку на членов команды, облегчает тестирование и уменьшает количество ошибок в каждой итерации. Главный плюс — это быстрая обратная связь.
- Гибкий план позволяет быстро перераспределять ресурсы команды на решение действительно важных задач.
Недостатки:
- Часто инструменты CI/CD воспринимаются как швейцарский нож, который может справиться с любыми задачами. При недостатке опыта это может приводить к существенному усложнению процессов в команде.
- Инструменты CI/CD не могут решить проблемы взаимодействия внутри команды, обо всём придётся договариваться.
- Все члены команды должны работать в единой экосистеме.
Подробнее о CI/CD:
Часть 2. GitLab CI/CD
GitLab — популярный веб-сервис для совместной разработки и поддержки программного обеспечения. Вы можете работать с Git-репозиториями, управлять задачами, обсуждать правки с вашей командой, писать wiki-документацию, оценивать качество, выпускать релизы и даже мониторить работающие программы — и всё это в одном месте.
GitLab CI — инструмент, встроенный в GitLab для автоматизации рутинных задач, возникающих в процессе разработки программного обеспечения. Спектр таких задач огромен и отличается от проекта к проекту, но основные — это тестирование, статический анализ, проверка стиля написания кода и деплой (выпуск) приложения. GitLab CI — конкурент другого популярного инструмента, GitHub Actions. Эти два сервиса во многом похожи, но есть некоторые отличия.
Пример
Допустим, мы договорились в команде об особых правилах оформления кода при помощи EditorConfig, установили его как дев-зависимость и сделали его доступным с помощью команды npm run editorconfig. Можно запускать проверку каждый раз п еред коммитом, но всегда будут ситуации, когда это забудут сделать, и код, оформленный неправильно, попадёт в репозиторий. Здесь приходит на помощь GitLab CI/CD — достаточно создать в корне проекта файл .gitlab-ci.yml со следующим содержанием:
EditorConfig:
  image: node:lts
  script:
    - npm ci
    - npm run editorconfig
И теперь каждый раз, когда в репозиторий попадает новый код, он будет проверяться на соответствие правилам, а ошибки будут видны в интерфейсе GitLab.
Как пользоваться
Основные понятия
Основной сущностью в GitLab CI/CD является конвейер (pipeline) — конвейер, который может состоять из:
- джобов (jobs), описывающих что нужно выполнить;
- этапов (stages), указывающих когда или в какой последовательности нужно выполнить джобы.
Джобы в одном этапе обычно выполняются параллельно. Если все джобы завершились успешно, выполнение переходит к следующему этапу и так далее. Если любой из джобов завершился ошибкой, то выполнение останавливается, и весь конвейер (обычно) считается проваленным.
Создаём .gitlab-ci.yml
GitLab CI полностью конфигурируется с помощью одного файла в формате YAML, который нужно создать в корне проекта — .gitlab-ci.yml.
Джобы часто могут иметь одинаковые свойства, например, образ среды, в которой выполняются действия, предварительные команды и т. д. Чтобы не повторять их каждый раз, нужно объявить их в секции default. Если какому-то джобу нужны другие параметры, можно указать их внутри этого джоба, и они перезапишут глобальные параметры.
В первую очередь нужно указать Docker-образ, в котором будут выполняться джобы. Для Node.js, например, это node:lts — это означает, что наши команды будут выполняться внутри операционной системы Linux с установленными Node.js, npm и даже Yarn. Про буквы lts можно почитать в разделе про версионирование Node.js.
default:
  image: node:lts
Задаём подготовительные команды
При работе с CI/CD во фронтенд-проектах чаще всего перед выполнением основного действия необходимо установить зависимости. Для этого мы можем указать их в секции before_script — эти команды будут выполняться в каждом джобе перед основным действием.
default:
  image: node:lts
  before_script:
    - npm -v
    - npm install
Указываем этапы
Предположим, что мы хотим запускать сначала проверку кодовой базы с помощью EditorConfig и Stylelint, а потом, если они обе завершатся успешно, запустить тесты. В этом примере можно выделить два этапа: стиль кода и тесты. Определить этапы можно при помощи ключевого слова stages:
stages:
  - Стиль кода
  - Тесты
Описываем джобы и задаём команду
Теперь укажем все три джоба. Для этого мы вначале указываем название джоба, указываем его этап при помощи ключевого слова stage и передаём список команд в script. В нашем примере каждый джоб будет запускать по одному npm-скрипту.
default:
  image: node:lts
  before_script:
    - npm -v
    - npm ci
stages:
  - Стиль кода
  - Тесты
EditorConfig:
  stage: Стиль кода
  script:
    - npm run editorconfig
Stylelint:
  stage: Стиль кода
  script:
    - npm run stylelint
Автотесты:
  stage: Тесты
  script:
    - npm run test
А вот схематичное представление конфигурации выше:
Схема конвейера (источник: doka.guide):

Конфигурация сначала проверяет стиль кода и, если он верный, запускает тесты.
Джобы должны иметь уникальные имена — если указать два джоба с одинаковым именем, то из них выполнится только последний — он перезапишет все предыдущие джобы с таким именем!
Продвинутое использование
Если мы хотим запускать определённый джоб вручную, то нужно добавить when: manual:
job:
  script: npm run deploy
  when: manual
Продолжение при провале
По умолчанию при провале любого джоба весь конвейер отмечается как проваленный, и оставшиеся джобы не выполнятся. Однако бывают ситуации, когда этого поведения хочется избежать. Например, мы добавили джоб с тестами в только что появившейся версии Node.js и просто хотим видеть проблемы, которые потенциально нужно исправить в будущем. Здесь придёт на помощь allow_failure: true:
job:
  image: node:latest
  script: npm run test
  allow_failure: true
Выполнение джобов по условию
GitLab даёт доступ к большому количеству переменных окружения с полезной информацией. Например, $CI_COMMIT_BRANCH содержит текущую ветку, $CI_COMMIT_SHORT_SHA — короткий хеш коммита, $CI_PIPELINE_SOURCE — источник вызова текущего конвейера и так далее. С их помощью мы можем запускать определённые джобы при соблюдении заданных условий. Для этого нужно объявить одну или несколько секций rules.
Вот такой джоб будет выполняться только для коммитов в ветку main:
job:
  script: npm run deploy-to-production
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
Запуск по расписанию
В отличие от GitHub Actions, в GitLab CI/CD запуск конвейеров по расписанию настраивается только в веб-интерфейсе. Для этого нужно открыть страницу репозитория и выбрать CI/CD → Schedules. Перед нами откроется список уже существующих правил и кнопка добавления нового. В форме добавления можно указать название правила, выбрать интервал из списка или указать свой в синтаксисе Cron. Последним важным полем является ветка — при срабатывании правила конвейер запустится, как будто был запушен код в этой ветке. Отличие в том, что переменная $CI_PIPELINE_SOURCE будет содержать значение schedule.
Серия джобов
Ещё одна типичная задача — прогнать тесты в разных версиях Node.js. Можно для каждой версии создать вручную джоб, а можно указать список переменных:
Unit Tests:
  script: node -v
  image: ${NODE_VERSION}
  parallel:
    matrix:
      - NODE_VERSION: ["node:14", "node:16", "node:17"]
В примере выше мы объявили список NODE_VERSION из трёх элементов. GitLab создаст три джоба с именами: Unit Tests [node:14], Unit Tests [node:16] и Unit Tests [node:17], а потом в каждом джобе заменит все места использования переменной NODE_VERSION. Поэтому image в каждом джобе будет разный.
Часть 3. Закрепление основных концепций GitLab CI/CD
Основано на материале Get started with GitLab CI/CD | GitLab
CI/CD - это непрерывный метод разработки программного обеспечения, при котором вы непрерывно создаете, тестируете, развертываете и отслеживаете итеративные изменения кода.
Этот итеративный процесс помогает снизить вероятность того, что вы разработаете новый код на основе баг или неудачных предыдущих версий. GitLab CI/CD может выявлять ошибки на ранних стадиях цикла разработки и помогает гарантировать, что весь код, развертываемый в рабочей среде, соответствует установленным вами стандартам кода.
Файл .gitlab-ci.yml
Чтобы использовать GitLab CI/CD, вы начинаете с .gitlab-ci.yml файла в корневом каталоге вашего проекта, который содержит конфигурацию для вашего конвейера CI/CD. Этот файл соответствует формату YAML и имеет свой особый синтаксис.
Вы можете назвать этот файл как угодно, но .gitlab-ci.yml это наиболее распространенное имя.
В .gitlab-ci.yml файле вы можете определить:
- Задачи, которые вы хотите выполнить, например, протестировать и развернуть ваше приложение.
- Другие файлы конфигурации и шаблоны, которые вы хотите включить.
- Зависимости и кэши.
- Команды, которые вы хотите запускать последовательно, и те, которые вы хотите запускать параллельно.
- Местоположение для развертывания вашего приложения.
- Независимо от того, хотите ли вы запускать скрипты автоматически или запускать любой из них вручную.
Раннеры
Раннеры - это агенты, которые выполняют ваши задания. Эти агенты могут выполняться на физических машинах или виртуальных экземплярах. В вашем .gitlab-ci.yml файле вы можете указать образ контейнера, который хотите использовать при выполнении задания. Программа-исполнитель загружает образ, клонирует ваш проект и запускает задание либо локально, либо в контейнере.
Если вы используете GitLab.com, раннеры SaaS в Linux, Windows и macOS уже доступны для использования. И вы можете зарегистрировать свои собственные раннеры на GitLab.com, если хотите.
Если вы не используете GitLab.com, вы можете:
- Зарегистрируйте раннеры или используйте уже зарегистрированные раннеры для вашего самоуправляемого экземпляра.
- Создать раннер на своем локальном компьютере.
Конвейеры
Конвейеры (Pipelines) состоят из заданий и этапов:
- Задания определяют, что вы хотите сделать. Например, протестировать изменения кода или выполнить развертывание в промежуточной среде.
- Задания сгруппированы по этапам. Каждый этап содержит по крайней мере одно задание. Типичными этапами могут быть build,testиdeploy.
Переменные CI/CD
Переменные CI/CD помогают настраивать задания, делая доступными для них значения, определенные в другом месте. Они могут быть жестко запрограммированы в вашем .gitlab-ci.yml файле, настройках проекта или динамически сген ерированы.
Компоненты CI/CD
Компоненты CI/CD - это повторно используемые единицы конфигурации отдельного конвейера. Используйте их для создания конфигурации всего конвейера или небольшой части более крупного конвейера.
Часть 4. Создание и запуск конвейера GitLab CI/CD
Основано на материале Tutorial: Create and run your first GitLab CI/CD pipeline | GitLab.
Предварительные требования
Перед началом работы убедитесь, что у вас есть:
- Информаци я о том, как подключиться в приватному GitLab и как получить доступ к публичному GitLab. Информацию об этом можно получить от преподавателя.
- Проект в GitLab (в частном или публичном).
- Вы можете также бесплатно создать общедоступный проект на https://gitlab.com.
 
- Роль сопровождающего (maintainer) или владельца (owner) проекта.
Убедитесь, что у вас есть доступные раннеры В GitLab исполнители - это агенты, которые выполняют ваши задания CI / CD.
Чтобы просмотреть доступные раннеры
Чтобы просмотреть доступные раннеры:
- 
Перейдите в Settings > CI/CDи развернитеRunners.
- 
Пока у вас активен хотя бы один бегун с зеленым кружком рядом с ним, у вас есть бегун, доступный для обработки ваших заданий:  
Теперь создайте .gitlab-ci.yml файл. Это файл YAML, в котором вы указываете инструкции для GitLab CI/CD.
В этом файле вы определяете:
- Структура и порядок заданий, которые должен выполнять раннер.
- Решения, которые должен принимать пользователь при возникновении определенных условий.
Чтобы создать .gitlab-ci.yml файл:
- 
На левой боковой панели выберите Code > Repository.
- 
Над списком файлов выберите ветку, к которой вы хотите привязаться. Если вы не уверены, оставьте masterилиmain. Затем выберите значок плюса (+) иNew file: 
- 
В качестве имени файла введите .gitlab-ci.ymlи в увеличенном окне вставьте этот пример кода:build-job:
 stage: build
 script:
 - echo "Hello, $GITLAB_USER_LOGIN!"
 test-job1:
 stage: test
 script:
 - echo "This job tests something"
 test-job2:
 stage: test
 script:
 - echo "This job tests something, but takes more time than test-job1."
 - echo "After the echo commands complete, it runs the sleep command for 20 seconds"
 - echo "which simulates a test that runs 20 seconds longer than test-job1"
 - sleep 20
 deploy-prod:
 stage: deploy
 script:
 - echo "This job deploys something from the $CI_COMMIT_BRANCH branch."
 environment: productionВ этом примере показаны четыре задания: build-job,test-job1,test-job2иdeploy-prod. Комментарии, перечисленные вechoкомандах, отображаются в пользовательском интерфейсе при просмотре заданий. Значения для предопределенных переменных$GITLAB_USER_LOGINи$CI_COMMIT_BRANCHзаполняются при выполнении заданий. 
- Выберите Commit changes.
Конвейер запускается и выполняет задания, определенные вами в файле .gitlab-ci.yml:

Изучение состояния конвейера и заданий
Теперь взгляните на ваш конвейер и задания внутри него.
- 
Перейдите в Build > Pipelines. Должен отображаться конвейер с тремя этапами:
- 
Просмотрите визуальное представление вашего конвейера, выбрав идентификатор конвейера:  
- 
Просмотрите подробные сведения о задании, выбрав название задания. Например, deploy-prod: 
Вы успешно создали свой первый конвейер CI/CD в GitLab! Теперь вы можете приступить к настройке вашего .gitlab-ci.yml и определению более сложных заданий.
Советы по созданию .gitlab-ci.yml
Вот несколько советов, чтобы начать работу с .gitlab-ci.yml файлом:
- Спецификацию .gitlab-ci.ymlвы можете изучить в официальной документации.
- Используйте редактор конвейеров для редактирования вашего .gitlab-ci.ymlфайла.
- Каждое задание содержит раздел сценария и относится к этапу:
- stageописывает последовательное выполнение заданий. Если доступны исполнители, задания на одном этапе выполняются параллельно.
- Используйте ключевое слово needsдля выполнения заданий вне последовательности этапов. Это создает ориентированный ациклический граф (DAG).
 
- Вы можете задать дополнительную конфигурацию, чтобы настроить выполнение ваших заданий и этапов:
- Используйте rulesключевое слово, чтобы указать, когда запускать или пропускать задания.
- Сохраняйте информацию о заданиях и этапах на постоянной основе в конвейере с помощью cacheиartifacts. Эти ключевые слова являются способами хранения зависимостей и выходных данных задания, даже при использовании эфемерных исполнителей для каждого задания.
- Используйте defaultключевое слово для указания дополнительных конфигураций, которые применяются ко всем заданиям. Это ключевое слово часто используется для определенияbefore_scriptиafter_scriptразделов, которые должны выполняться в каждом задании.
 
- Используйте 
Часть 5. Создание и запуск усовершенствованного конвейера GitLab CI/CD
В данной части предстоит:
- Добавить в репозиторий проект с юнит-тестами.
- Настроить конвейер в GitLab:
- Статический анализ кода.
- Моду льное тестирование.
- Сборка проекта в бинарник и публикация в артефакты Releases.
- Настройка раннеров.
 
- Активация настроенных конвейеров.
Подготовка проекта
Создайте новый проект GitLab в указанном преподавателем месте.
Мы воспользуемся проектом, который рассматривали на предыдущим практическом задании. Доработаем его для того, чтобы мы могли посмотреть дополнительные возможности GitLab CI/CD.
Структура проекта будет выглядеть следующим образом:
awesome-project
├── calculator.py
├── README.md
├── .gitignore
├── calculator_tests.py
└── requirements.txt
Файл .gitignore мы можем заполнить по примеру из репозитория github/gitignore.
Содержимое calculator.py:
import math
# Рассчитать гипотенузу
def get_hypotenuse(a, b):
    return math.sqrt(math.pow(a, 3) + math.pow(b, 3))
# Получить площадь прямоугольного треугольника
def get_area(a, b):
    return a * b
if __name__ == "__main__":
    print("Введите a:")
    a = int(input())
    print("Введите b:")
    b = int(input())
    print("c =", get_hypotenuse(a, b))
    print("S =", get_area(a, b))
Для тестирования методов, представленных calculator.py, подготовлены модульные тесты в calculator_tests.py.
Если вам не знакомы модульные тесты Python, то рекомендуется ознакомиться со статьей Тестируем на Python: unittest и pytest. Инструкция для начинающих | Tproger.
Узнать о том, что такое модульные тестирование, можно узнать в статье Юнит-тесты: что это такое, зачем они нужны и как их проводят | Блог Яндекс.Практикума.
Файл calculator_tests.py выглядит следующим образом:
import unittest
from calculator import get_hypotenuse, get_area
class CalculatingHypotenuseTestCase(unittest.TestCase):
    def test_case_1(self):
        res = get_hypotenuse(3, 4)
        self.assertEqual(res, 5)
    def test_case_2(self):
        res = get_hypotenuse(5, 12)
        self.assertEqual(res, 13)
    def test_case_3(self):
        res = get_hypotenuse(8, 15)
        self.assertEqual(res, 17)
class CalculatingAreaTestCase(unittest.TestCase):
    def test_case_1(self):
        res = get_area(3, 4)
        self.assertEqual(res, 6)
    def test_case_2(self):
        res = get_area(5, 12)
        self.assertEqual(res, 30)
    def test_case_3(self):
        res = get_area(8, 15)
        self.assertEqual(res, 60)
Для того, чтобы наше приложение можно было запускать не только на локальном компьютере, необходимо указать перечень пакетов, который используется в проекте. Это можно сделать с помощью файлов requirements.txt.
Что такое
requirements.txtи как с ним работать смотрите в статье Что такое requirements.txt и как с ним работать? | Pythonist.
Содержимое requirements.txt:
altgraph==0.17.3
astroid==2.12.12
autopep8==1.7.0
dill==0.3.5.1
isort==5.10.1
lazy-object-proxy==1.7.1
macholib==1.16.2
mccabe==0.7.0
platformdirs==2.5.2
pycodestyle==2.9.1
pyinstaller==5.5
pyinstaller-hooks-contrib==2022.10
pylint==2.15.4
toml==0.10.2
tomli==2.0.1
tomlkit==0.11.5
wrapt==1.14.1
Вот такие файлы должны получиться в вашем репозитории. Чтобы наполнить ваш проект сод ержимым, вы можете воспользоваться Web IDE, либо работать через локальный репозиторий с отправкой в удаленный репозиторий.
Подготовка к описанию конвейера
Кратко напомним процесс, который обычно реализуется конвейер в GitLab CI:
- разработчик отправляет коммит в репозиторий, создаёт merge request через сайт, или ещё каким-либо образом явно или неявно запускает конвейер;
- из конфигурации выбираются все задачи, условия которых позволяют их запустить в данном контексте;
- задачи организуются в соответствии со своими этапами;
- этапы по очереди выполняются - т.е. параллельно выполняются все задачи этого этапа:
- если этап завершается неудачей (т.е. завершается неудачей хотя бы одна из задач этапа) - конвейер останавливается (почти всегда);
- если все этапы завершены успешно, конвейер считается успешно прошедшим.
 
Таким образом, имеем:
- конвейер (pipeline) - набор задач, организованных в этапы, в котором можно собрать, протестировать, упаковать код, развернуть готовую сборку в облачный сервис, и пр.;
- этап (stage) - единица организации конвейера, содержит 1+ задачу;
- задача (job) — единица работы в конвейера. Состоит из скрипта (обязательно), условий запуска, настроек публикации/кеширования артефактов и много другого.
Соответственно, задача при настройке CI/CD сводится к тому, чтобы создать набор задач, реализующих все необходимые действия для сборки, тестирования и публикации кода и артефактов.
Исходная позиция
Имеем:
- репозиторий в GitLab.
Хотим:
- Автоматическую сборку и тестирование для каждого merge request;
- Помимо тестирования провести статический анализ кода;
- В случае прохождения всех тестов, разрешить слияние. В противном случае заблокировать слияние.
- В случае усп ешного мерджа в ветку по умолчанию, собрать бинарники программы и публиковать их в релизах.
Описанные требования органично ложатся на следующую модель конвейера:
- 
Этап 1 — тестирование Проводим статический анализ кода и тестируем его. 
- 
Этап 2 - сборка бинарников В случае успешного мерджа в ветку соберем бинарники и опубликуем их в артефактах. 
- 
Этап 3 - подготовка релиза Подготавливаем красивый релиз с прикрепленными бинарниками. 
Настройка Gitlab CI для приложения Python
Основано на статье "Setting Gitlab CI/CD for Python application" и "Python Unit Test And Some CI via GitLab (Python)".
В этой части работы предстоит настроить процесс GitLab CI для заданий:
Создание .gitlab-ci.yml
Первым шагом является добавление в репозиторий .gitlab-ci.yml yml определяет структуру и порядок конвейеров и определяет, как выполнять Gitlab Runner:
# This file is a template, and might need editing before it works on your project.
# Official language image. Look for the different tagged releases at:
# https://hub.docker.com/r/library/python/tags/
image: "python:3.10.3" 
# команды для запуска в контейнере Docker перед запуском каждого задания.
before_script:
 - python --version
 - pip install -r requirements.txt
# различные этапы в конвейере
stages:
 - Static Analysis
 - Test
# определяет задание в статическом анализе
pylint:
 stage: Static Analysis
 script:
 - pylint -d C0301 calculator.py
Напомним, что перед этим заданием мы специально добавляли requirements.txt в репозиторий.
Мониторинг выполнения можно найти в левой вкладке Build > Pipelines в нашем проекте:

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

Во вкладке "Неудачные задания" показывает причину, по которой задача с pylint завершилась с ошибкой:
