Как я собрал рабочий пайплайн в GitLab: от версии до красивого отчёта

в 18:46, , рубрики: autotest, autotesting, autotests, gitlab, jobs, pipeline

С чего начать разбираться в этом всём

Когда я впервые увидел .gitlab-ci.yml, мне показалось, что это какой-то древний магический свиток. Сплошные stages, artifacts, непонятные правила... Но на самом деле всё гораздо проще — это просто рецепт: что, в каком порядке и как делать с твоим кодом.

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

Что такое workflow и зачем он нужен

Это как швейцар у подъезда — решает, пускать ли пайплайн на работу. У меня настроено строго:

workflow:
  rules:
    - if: $CI_PIPELINE_SOURCE == "web"
      when: always
    - if: $CI_PIPELINE_SOURCE == "pipeline"
      when: always
    - when: never
Как я собрал рабочий пайплайн в GitLab: от версии до красивого отчёта - 1

Перевод на человеческий: запускайся только если я сам нажал кнопку «Run pipeline» в интерфейсе, или если тебя вызвал другой пайплайн. Всё остальное — от ворот поворот.

Зачем так? Чтобы случайно не запустить тяжёлые тесты при каждом пуше в ветку. Представьте: приходит джуниор, делает коммит — и бац, у вас 20 минут грузятся раннеры. Такой подход экономит и время, и нервы.

Этапы (stages) — конвейер из жизни

Пайплайн у меня разбит на пять этапов:

stages:
  - get_version
  - testing
  - history_copy
  - reports
  - deploy
Как я собрал рабочий пайплайн в GitLab: от версии до красивого отчёта - 2

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

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

Переменные — чтобы не мучиться с сертификатами

В корпоративных сетях постоянно проблемы с сертификатами. У меня в пайплайне стоят две «костыльные» переменные:

variables:
  GIT_SSL_NO_VERIFY: "1"
  DOCKER_TLS_VERIFY: ""
Как я собрал рабочий пайплайн в GitLab: от версии до красивого отчёта - 3

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

И ещё один важный момент: все секреты (ключи, токены) хранятся не в файле, а в настройках проекта (Settings → CI/CD → Variables). Там же ставим галочку «Маскировать переменную» — тогда в логах они покажутся как ***.


Как достать версию с удалённого сервера

Первая задача — get_soft_version. Её цель простая: узнать, с какой версией ПО мы сейчас работаем.

get_soft_version:
  stage: get_version
  tags:
    - docker
  image: docker:25.0.4-alpine3.19
  script:
    - mkdir -p ~/.ssh && chmod 0700 ~/.ssh
    - echo "$SSH_KEY_DEV" > ~/.ssh/id_rsa
    - echo "$known_hosts" > ~/.ssh/known_hosts
    - chmod 0600 ~/.ssh/id_rsa
    - apk add bash postgresql-client
    - ssh dev-docker@$SERVER_IP_KPPO1 date
    - docker context create remote --docker "host=ssh://dev-docker@$SERVER_IP_KPPO1"
    - mkdir ./VER
    - chmod +x ./version.sh 
    - ./version.sh 
    - cp ./.properties ./VER/.properties
  artifacts:
    paths:
      - ./VER
Как я собрал рабочий пайплайн в GitLab: от версии до красивого отчёта - 4

Что здесь происходит:

  1. Настраиваем SSH — создаём папку, копируем ключ из переменной окружения, ставим правильные права (chmod 0600 — без этого SSH откажется работать).

  2. Проверяем соединение простой командой date — если сработало, значит ключ живой.

  3. Создаём удалённый докер-контекст. Это хитрый трюк: теперь все команды docker будут лететь не на локальный раннер, а на удалённый сервер.

  4. Запускаем скрипт version.sh, который определяет версию и пишет её в файл .properties.

  5. Копируем результат в папку VER и сохраняем как артефакт.

Последний пункт критически важен. Без artifacts следующие задачи ничего не увидят — каждая задача живёт в своём изолированном контейнере. expire_in: 1 day ставлю, чтобы не засорять хранилище старыми версиями.


Тесты: не бойтесь упавших проверок

Вот тут начинается самое интересное — запуск тестов через Playwright:

docker_job:
  stage: testing
  tags:
    - docker
  image: registry.pdc.local.rielta/.../playwright:v1.50.0-noble-py3.12
  before_script:
    - source /venv/bin/activate
  script:
    - update-ca-certificates
    - mkdir ./allure-current-results
    - pytest -v --maxfail=100 --alluredir=./allure-current-results --browser firefox
  allow_failure: true
  artifacts:
    when: always
    paths:
      - ./allure-current-results
    expire_in: 1 day
Как я собрал рабочий пайплайн в GitLab: от версии до красивого отчёта - 5

Несколько моментов, на которые стоит обратить внимание:

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

allow_failure: true — мой любимый трюк. Многие думают, что пайплайн должен быть всегда зелёным. Но на практике важнее получить отчёт, даже если тесты упали. С этой директивой пайплайн продолжит работу: соберёт историю, сгенерирует отчёт и опубликует его. Разработчик увидит не просто «упало», а конкретные скриншоты, логи и шаги воспроизведения. Это экономит кучу времени на отладку.

Артефакты сохраняются всегда (when: always). Даже проваленные тесты дают полезные данные — их тоже нужно сохранить.


История и отчёты: как не потерять контекст

Подтягиваем историю прошлых запусков

history_job:
  stage: history_copy
  tags:
    - docker
  image: storytel/alpine-bash-curl
  script:
    - curl -k --output ./artifacts.zip --header "PRIVATE-TOKEN:$TOKEN_ISSUE" 
        "https://gitlab.pdc.local.rielta/api/v4/projects/439/jobs/artifacts/master/download?job=pages"
    - apk add unzip
    - unzip ./artifacts.zip
    - cp -r ./public/history/* ./allure-previous-results
  allow_failure: true
  artifacts:
    paths:
      - ./allure-previous-results
    expire_in: 1 day
  needs:
    - docker_job
Как я собрал рабочий пайплайн в GitLab: от версии до красивого отчёта - 6

Зачем это нужно? Чтобы в отчёте видеть тренды: улучшается качество или, наоборот, появляются регрессии. Без истории ты видишь только текущий срез — а это как лечить пациента без истории болезни.

Команда curl качает артефакты из последнего успешного пайплайна на ветке master. Обрати внимание на параметр ?job=pages — он указывает, из какой именно задачи брать артефакты.

allow_failure: true здесь тоже критичен: при первом запуске истории ещё нет, и пайплайн не должен падать из-за этого.

Генерируем красивый отчёт в Allure

allure_job:
  stage: reports
  tags:
    - docker
  image: frankescobar/allure-docker-service:2.21.0-amd64
  script:
    - mkdir ./allure-results
    - mkdir ./allure-results/history
    - cp -r ./allure-previous-results/* ./allure-results/history || true
    - cp -r ./allure-current-results/* ./allure-results
    - cp ./VER/.properties ./allure-results/environment.properties
    - allure generate -c ./allure-results -o ./allure-report
  artifacts:
    paths:
      - ./allure-report
    expire_in: 1 day
  needs:
    - job: docker_job
      artifacts: true
    - job: history_job
      artifacts: true
    - job: get_soft_version
      artifacts: true
Как я собрал рабочий пайплайн в GitLab: от версии до красивого отчёта - 7

Самый вкусный момент — копирование .properties в environment.properties:

cp ./VER/.properties ./allure-results/environment.properties
Как я собрал рабочий пайплайн в GitLab: от версии до красивого отчёта - 8

Allure автоматически подхватывает этот файл и показывает информацию об окружении прямо в интерфейсе отчёта. Теперь любой разработчик сразу видит: «Ага, эти тесты прогонялись на версии 2.3.1 от 15 февраля».

Флаг artifacts: true в секции needs гарантирует, что все необходимые файлы подтянутся из предыдущих задач. Без него пайплайн сломается — он не будет знать, откуда брать данные.


Финальный аккорд: публикация и уведомления

Последняя задача — pages — делает две вещи одновременно.

Публикуем отчёт на GitLab Pages

GitLab Pages ищет контент только в папке public. Поэтому просто переносим туда сгенерированный отчёт:

mkdir public
mv ./allure-report/* public
Как я собрал рабочий пайплайн в GitLab: от версии до красивого отчёта - 9

Готово — отчёт доступен по адресу вида https://ваш-проект.pages.gitlab.io.

Создаём задачу с результатами

А ещё автоматически создаём задачу в трекере:

curl -k -X POST 
  -H "PRIVATE-TOKEN:$TOKEN_ISSUE" 
  -H "Content-Type: application/json" 
  --data '{
    "title": "Тестирование сервиса '"$SERVICE_NAME"' (версия '"$VERSION"')",
    "description": "'"$(tr 'n' ' ' < ./VER/.properties)"'",
    "labels": ["test"]
  }' 
  "https://gitlab.***.local.rielta/api/v4/projects/439/issues"
Как я собрал рабочий пайплайн в GitLab: от версии до красивого отчёта - 10

После каждого запуска пайплайна команда получает уведомление с:

  • Ссылкой на подробный отчёт

  • Версией протестированного сервиса

  • Статистикой по тестам

Это сильно повышает прозрачность процесса — теперь все видят, что тесты вообще запускались, и могут быстро оценить результат.


Что я вынес из этого опыта

Артефакты — не опция, а основа

Без правильной работы с артефактами пайплайн превращается в набор изолированных островков. Каждая задача должна чётко понимать: что она получает от предыдущих этапов и что передаёт следующим.

Не бойтесь allow_failure

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

Версионируйте образы

Мой образ playwright:v1.50.0-noble-py3.12 — это не прихоть. Когда образ версионирован, ты точно знаешь, в какой среде бегут тесты. Никаких сюрпризов вроде «вчера работало, сегодня сломалось» из-за обновления базового образа.

Держите секреты в секрете

Никогда не храните ключи и токены в коде. Даже если репозиторий приватный — рано или поздно кто-то скопирует код, сделает форк или случайно зальёт в публичный гит. Переменные в настройках проекта — единственный правильный путь.


Итог

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

И помните: даже самый сложный пайплайн начинался с одной простой задачи — «а давайте автоматизируем запуск тестов». Остальное пришло со временем.

Автор: Verstuk

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js