Как заставить не забывать создавать merge request’ы

История о том, как простая проблема в команде привела к интересному техническому решению

Проблема, которая достала

Работаю DevOps’ом aka восьмийух-fullstack в стартапе, где делаем платформу для психологов. У нас классический workflow: ветка master для продакшена,  основнаяdev для разработки и отдельная layout-branch для верстальщика.

Вроде бы всё логично — верстка работает в своей песочнице, пушит изменения, они автоматически собираются и деплоятся в dev-окружение для моментального просмотра. А потом он должен создать merge request в dev, чтобы изменения попали в общую ветку разработки.

Но вот незадача — парень постоянно забывал создавать эти MR’ы. И я вынужден регулярно отслеживать прогресс вручную, чтобы вёрстка не оказывалась в изоляции. Уже третий-пятый раз, просил, напоминал — толку ноль. Человеческий фактор, что сказать.

Тогда я решил: хватит полагаться на память! Нужно автоматизировать этот процесс на уровне CI/CD.

Техническая реализация

Сборка npm билда происходит минимум 2 минуты, это достаточное время, чтобы не забыть нажать на кнопку — создать MR, а затем идея простая — не позволять запускаться deploy для layout-branch до тех пор, пока не создан открытый merge request в dev. GitLab API в помощь!

Вот что получилось в .gitlab-ci.yml:

deploy-layout-dev:
  stage: deploy
  environment: development
  before_script:
    - apk add --no-cache curl jq
  script:
    - set -e
    - |
      HTTP_STATUS=$(curl --globoff -s -o response.json -w "%{http_code}" \
        --header "PRIVATE-TOKEN: ${GITLAB_API_TOKEN}" \
        "$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests?state=opened&source_branch=$CI_COMMIT_BRANCH&target_branch=dev")
      
      MERGE_REQUEST_BODY=$(cat response.json)

      if [ "$HTTP_STATUS" -ne 200 ]; then
        echo "Ошибка: Не удалось получить данные от GitLab API. HTTP статус: $HTTP_STATUS"
        echo "Ответ API: $MERGE_REQUEST_BODY" 
        exit 1
      fi

      if [ "$(echo "$MERGE_REQUEST_BODY" | jq 'length')" -eq 0 ]; then
        echo "Ошибка: Merge Request из ветки '$CI_COMMIT_BRANCH' в 'dev' не найден."
        echo "Пожалуйста, создайте Merge Request перед запуском deploy."
        exit 1
      fi
    - apk add --no-cache bash rsync git
    - bash ./.ci-cd/deploy-layout-dev.sh
  only:
    - layout-branch
  interruptible: true

Логика такая:

  1. Делаем запрос к GitLab API для получения списка открытых MR из текущей ветки в dev
  2. Если API вернул ошибку — останавливаем пайплайн с диагностикой
  3. Если список пустой (нет MR) — тоже останавливаем с понятным сообщением
  4. Только если всё ОК — продолжаем с обычным деплоем

Подводные камни при реализации

Конечно же, с первого раза ничего не заработало. Столкнулся с несколькими проблемами:

Проблема #1: Ошибка 404 при корректном URL
Это было самое загадочное. URL формировался правильно, переменные CI подставлялись корректно, но GitLab упорно отвечал «404 Project Not Found».

Добавил отладочный вывод:

echo "CI_PROJECT_ID: $CI_PROJECT_ID"
echo "CI_API_V4_URL: $CI_API_V4_URL" 
echo "Request URL: $REQUEST_URL"

Всё выглядело корректно, но 404 не исчезал. В итоге оказалось банально — переменная GITLAB_API_TOKEN была пустая! GitLab из соображений безопасности маскирует 403 Forbidden под 404 Not Found для приватных проектов.

Проблема #2: Обработка ошибок API Изначально проверял только количество найденных MR через jq 'length'. Но если API возвращает ошибку (например, JSON с полем «message»), то jq может вернуть неожиданный результат. Пришлось сначала проверять HTTP-статус ответа.

Дополнительные улучшения

В процессе отладки добавил несколько полезных деталей:

  1. Директива environment: Добавил environment: development для корректного отображения в разделе Deployments GitLab’а
  2. Флаг —globoff для curl: На всякий случай отключил glob-интерпретацию в URL’ах
  3. Закомментированная отладка: Оставил в коде, но закомментировал — на случай будущих проблем

Результат

Теперь когда верстка пушит в layout-branch, но забывает создать MR, он получает чёткое сообщение:

Ошибка: Merge Request из ветки 'layout-branch' в 'dev' не найден.
Пожалуйста, создайте Merge Request перед запуском deploy.

Сборка останавливается, deploy не происходит. Через пару таких «напоминаний» привычка создавать MR выработалась сама собой.

Что можно улучшить

Если развивать идею дальше, можно добавить:

  • Автоматическое создание draft MR через API (но тогда теряется осознанность процесса)
  • Уведомления в Slack при блокировке deploy’я
  • Проверку не только наличия MR, но и его статуса (например, что он не в draft)

Простая проблема с человеческим фактором решилась довольно элегантно через автоматизацию. GitLab API оказался достаточно мощным для таких сценариев, а CI/CD пайплайн — гибким.

Главное — не переусердствовать с автоматизацией. Цель была не наказать разработчика, а программно создать полезное напоминание, которое улучшит workflow всей команды. Да и нет смысла гавкать в 5-й и 10-й раз, повторяя одно и то же, будь у меня материальные способы воздействия на память, то после 2-го напоминания, всё идеально бы усвоилось наверняка. Но поскольку таковых нет, используем программные.


P.S. Переменную GITLAB_API_TOKEN не забудьте пометить как Protected и Masked в настройках проекта. Безопасность прежде всего!

Оставить ответ

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