← Назад к вопросам

Как проверять merge-реквизиты в бесплатной версии GitLab

2.0 Middle🔥 241 комментариев
#CI/CD и автоматизация#Git и системы контроля версий

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Отличный вопрос, который затрагивает один из ключевых аспектов поддержания чистоты и управляемости кодовой базы в CI/CD. В бесплатной версии GitLab (раньше Core, теперь Free) нет встроенной, готовой к использованию функции Merge Request Approvals в её расширенном виде (правила, обязательные апруверы, контроль по числу апрувов). Однако есть мощный и гибкий механизм, который полностью позволяет решать эту задачу — GitLab CI/CD в связке с Merge Request Pipelines и проверками через .gitlab-ci.yml.

Основная идея: мы создаем CI/CD пайплайн, который запускается для каждого Merge Request (MR). Этот пайплайн выполняет скрипты (на bash, Python и т.д.), которые анализируют содержимое MR и "ломаются" (возвращают ненулевой код выхода), если условия не выполнены. Сломанный пайплайн блокирует возможность слияния (merge), пока ошибки не будут исправлены.

Вот основные подходы и примеры реализации.

1. Проверка через CI/CD Job с использованием Bash и Git

Создаем джобу в .gitlab-ci.yml, которая будет запускаться только для MR. Она использует команды git diff для анализа изменений.

stages:
  - validation

check_commit_messages:
  stage: validation
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event" # Ключевое правило: только для MR
  script:
    # Получаем список коммитов в MR (от целевой ветки до последнего коммита MR)
    - |
      # Проверка формата сообщений коммитов (например, Convential Commits)
      for commit in $(git log --oneline --no-merges $CI_MERGE_REQUEST_TARGET_BRANCH_NAME..$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME | awk '{print $1}'); do
        commit_msg=$(git log --format=%B -n 1 $commit)
        if ! echo "$commit_msg" | grep -qE "^(feat|fix|docs|style|refactor|test|chore)\(?(\w+)?\)?:\s.+"; then
          echo "❌ Коммит $commit имеет неверный формат сообщения: '$commit_msg'"
          echo "   Ожидается формат: type(scope): description (например, feat(auth): add login button)"
          exit 1
        fi
      done
    echo "✅ Все сообщения коммитов соответствуют формату."

2. Проверка наличия ссылки на задачу (Issue) или Jira-тикета

Часто требуется, чтобы в описании MR или в названии ветки была ссылка на задачу из трекера.

check_mr_description:
  stage: validation
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  script:
    # Проверяем, что в описании MR есть ссылка на Issue (например, #123 или JIRA-123)
    - |
      if ! echo "$CI_MERGE_REQUEST_DESCRIPTION" | grep -qE "((#|!)\d+|([A-Z]+-\d+))"; then
        echo "❌ В описании Merge Request отсутствует ссылка на Issue или тикет (например, #123 или PROJECT-456)."
        echo "   Описание MR: $CI_MERGE_REQUEST_DESCRIPTION"
        exit 1
      fi
    echo "✅ Ссылка на задачу найдена в описании MR."

3. Проверка изменений в критических файлах (например, миграций БД)

Можно требовать дополнительных проверок, если затронуты определенные файлы.

check_database_migrations:
  stage: validation
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      changes: # Запускаем джобу только если изменились файлы в db/migrate/
        - db/migrate/*.rb
  script:
    - |
      # Пример: проверяем, что к миграции приложен SQL-скрипт отката (rollback)
      for file in $(git diff --name-only $CI_MERGE_REQUEST_TARGET_BRANCH_NAME..$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME -- db/migrate/); do
        if [[ ! -f "${file%.rb}_rollback.sql" ]]; then
          echo "❌ Для миграции $file не найден файл отката (${file%.rb}_rollback.sql)."
          exit 1
        fi
      done
    echo "✅ Для всех миграций есть скрипты отката."

4. Использование внешних инструментов и скриптов

Для сложных проверок можно использовать отдельные скрипты на Python, Node.js и т.д.

validate_mr_with_python:
  stage: validation
  image: python:3.11-slim # Используем специфичный образ
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  before_script:
    - pip install requests # Устанавливаем зависимости, если нужны
  script:
    - python .gitlab/scripts/validate_mr.py # Выносим логику в отдельный файл

А содержимое .gitlab/scripts/validate_mr.py может быть таким:

#!/usr/bin/env python3
import os
import sys
import re

mr_description = os.environ.get('CI_MERGE_REQUEST_DESCRIPTION', '')
target_branch = os.environ.get('CI_MERGE_REQUEST_TARGET_BRANCH_NAME', '')

# Пример: проверка, что в main/master нельзя мержить без тега [PROD-READY]
if target_branch in ['main', 'master']:
    if '[PROD-READY]' not in mr_description:
        print("[ERROR] Мерж в main/master требует тега [PROD-READY] в описании MR.")
        sys.exit(1)

print("Все проверки пройдены.")
sys.exit(0)

5. Комплексный пример: требуем label и апрув от определенного пользователя (эмулируем Approvals)

Так как в Free нет обязательных апруверов, мы можем эмулировать это через проверку labels и упоминаний в комментариях.

check_approval_emulation:
  stage: validation
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  script:
    # Используем GitLab API для проверки лейблов и комментариев
    # Требуем наличие лейбла 'tech-lead-review'
    - |
      MR_URL="${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests/${CI_MERGE_REQUEST_IID}"
      MR_DATA=$(curl --silent --header "PRIVATE-TOKEN: $GITLAB_CI_TOKEN" "$MR_URL")
      LABELS=$(echo "$MR_DATA" | jq -r '.labels[]')

      if ! echo "$LABELS" | grep -q "tech-lead-review"; then
        echo "❌ MR должен иметь лейбл 'tech-lead-review'."
        exit 1
      fi

      # Проверяем, что есть комментарий от определенного пользователя с :+1:
      NOTES_URL="${MR_URL}/notes"
      NOTES_DATA=$(curl --silent --header "PRIVATE-TOKEN: $GITLAB_CI_TOKEN" "$NOTES_URL")
      if ! echo "$NOTES_DATA" | jq -r '.[] | select(.author.username == "senior_dev") | .body' | grep -q ":\+1:"; then
        echo "❌ Не найден апрув (комментарий с :+1:) от пользователя senior_dev."
        exit 1
      fi
    echo "✅ Все условия эмулированного апрува выполнены."

Важные моменты и лучшие практики:

  • Токен доступа: Для работы с GitLab API в скриптах нужно создать Project Access Token или использовать CI_JOB_TOKEN (но у него могут быть ограничения на чтение). Безопаснее хранить его в CI/CD Variables (Settings > CI/CD > Variables) как GITLAB_CI_TOKEN с маской.
  • Переменные GitLab CI: Используйте богатый набор предопределенных переменных, таких как CI_MERGE_REQUEST_*, CI_COMMIT_*, CI_PROJECT_* — они невероятно полезны.
  • Правила (rules): Тщательно настраивайте rules для джоб, используя changes, if, variables чтобы пайплайны были эффективными и запускались только когда нужно.
  • Визуальная проверка: Размещайте такие валидационные джобы в начале пайплайна (например, в stage validation). Их failure будет четко виден в интерфейсе MR и заблокирует кнопку merge.

Заключение: Несмотря на отсутствие графического интерфейса для правил апрува, бесплатная версия GitLab предоставляет через CI/CD более мощный и программируемый инструмент для проверки merge-реквизитов. Вы можете создать любые, даже самые сложные правила, адаптированные под процессы вашей команды. Главное — правильно структурировать .gitlab-ci.yml и использовать возможности GitLab API для анализа MR. Это требует некоторой настройки, но в результате дает полный контроль над качеством вливаемого кода.

Как проверять merge-реквизиты в бесплатной версии GitLab | PrepBro