вторник, 27 марта 2018 г.

04 - Gitlab pages

Идея

Наш проект занимается тестированием сайта. Результаты тестов выкладываются как артефакт. Очень "удобно".
Можно
1. Посмотреть содержимое папки

Тыкать на reports.html бесполезно, не откроется

2. Скачать артефакты в zip-архиве, распаковать, посмотреть.


Впечатляет?  И меня.
...нет
Хотелось бы смотреть отчеты без дополнительных телодвижений.
И такой способ есть!

Gitlab Pages

Каждый проект может хостить статику по определенному адресу, нужно только по хитрому это описать в CI файле.
Описательство этого механизма на сайте Гитлаб.
Степ бай степ.
Самый простой пример того, что нужно написать в .gitlab-ci.yml

Реализация

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

Куски .gitlab-ci.yml

stages:
  - build
  - pages

pages:
  stage: pages
  script:
  - pwd
  - mv Reports public
  dependencies:
  - build 
  artifacts:
    expire_in: 1 week
    paths:
    - public
  environment: DEV
  only:
  - master
  when: always

Ключевые моменты

Отчеты нужны даже если все тесты попадали (тем более, если все тесты попадали), говоря терминами CI, "если предыдущий stage сфейлился", так что прописываем
  when: always

Второе
Артефакты с результатами запуска генерируются в предыдущем stage и нам нужно их передать "по цепочке". Для этого используется
  dependencies:
  - build  

Третье
Система отчетности рождает несколько папок (по кол-ву браузеров, в которых были запущены тесты) и не создаёт никакого index.html, что, в свою очередь приводит к тому, что Gitlab Pages ничего не показывают.
Как это выглядит:
Нужно самому сгенерить index.html и подсунуть его в артефакты.
Пришлось вспомнить немного шелла и awk:
Результат:
- find . -name report.html | awk 'BEGIN {print "<!DOCTYPE html>\n<html>\n<head></head>\n<body>"}{print "<a href=\"" $1 "\">Report "NR"</a><br>"} END {print "</body>\n</html>"}' > index.html
Продолжение следует...

03 - Дёрнуть другой пайплайн и покраснеть

Итак, пытаюсь добить задачу:
В разрабовском проекте на определенном этапе прохождения пайплайна вызвать через хуки/триггер/магию другой пайплайн с тестами и дождаться их работы. После этого нужно покраснеть, если тесты упали или позеленеть, если они прошли.
Понятное дело, мы можем покраснеть ещё раньше.
Моя предыдущая история закончилась  на том, что я создал дополнительный stage, в котором курлом дёргается тригер, навешенный на тестирующий проект.
При этом текущий пайплайн считает свою задачу выполненной и заканчивает работу, зеленея. Как там отработали тесты, ему пофиг.
После недолгого изучения документации на гитлабе, я нашел почти решение проблемы.
Мой прошлый скрипт выглядел вот так:

script:
    - apk --no-cache add curl
    - curl -X POST -F token="$TEST_TOKEN" -F ref=master https://gitlab.com/api/v4/projects/NNNNNN/trigger/pipeline

Для того, чтобы "связать" два пайплайна используется магия в виде $CI_JOB_TOKEN
Почитать об этом можно здесь.

Текущий вариант куска CI:
trigger_tests:
  stage: test
  script:
    - apk --no-cache add curl
    - curl -X POST -F token="$CI_JOB_TOKEN" -F ref=master https://gitlab.com/api/v4/projects/NNNNNN/trigger/pipeline
  environment: staging
  only:
    - master

И что это дало?
На первый взгляд - ничего. Всё тот же зеленый passed, но при тычке на него появляется красивый пайплайн граф, на котором появился столбец Downstream. В нём-то и отображается результат работы "дёрнутого" пайплайна.

Суммаризируя
Результат как бы получен, но он стрёмный. В списке выполненных пайплайнов результат залёный. Чтобы увидеть результат тестов нужно ткнуть на него у посмотреть результат в столбце Downstream - он может быть красным.

Как лечить?
Навскидку, на той же странице, где описан CI_JOB_TOKEN, есть опция - скачать по апи артефакты с downstream пайплайна. Можно скачать, добавить этап, проверяющий наличие файла. Если файл будет найден - всё гуд, если нет - падать.

Решение какое-то напряжное. Отложу его реализацию, вдруг найду что-то другое.

пятница, 23 марта 2018 г.

02 - Запуск билда другого проекта

Задача такая:
Разрабы пушат в свой репозиторий. В результате пуша делается диплой на тестовый стенд.
Да, знаю, в идеале нужно собрать контейнер и натравить свои тесты на него, а я пока так не умею, я заливаю по ssh на стенд и хочу вызвать процесс тестирования (вызвать pipeline тестирующего репозитория).
Для такого извращения есть механизм webhooks.
В тестирующем репо создаю триггер: Settings->CI / CD -> Pipeline Triggers

Называю этот триггер как-то и тычу "создать". Триггер создан. Ему присвоили ТОКЕН, который я должен вписать в url, чтобы "дёрнуть" его снаружи.
На странице прилагаются примеры скриптов, "как можно дёрнуть триггер".
Вариант 1
Первое, что я попробовал - это webhook со стороны репозитория разрабов.
  • В репозитории разрабов Settings->Integrations
  • Вписал на push ивент url, который мне сгенерировал gitlab.
  • Запустил разрабовский pipeline (диплой проекта на сервер)

Заработало!
Из минусов: не учел, что вебхук срабатывает сразу же после пуша, ещё до того, как разрабовский проект задиплоился на сервер.
Нужно как-то дождаться окончания диплоя и только потом "дёргать триггер"
Удалил вебхук.
Вариант 2
На странице с тестовым репо зашёл опять в  Settings->CI / CD -> Pipeline Triggers и скопировал
кусок скрипта
trigger_build:
  stage: deploy
  script:
    - "curl -X POST -F token=TOKEN -F ref=REF_NAME https://gitlab.com/api/v4/projects/NNNNNN/trigger/pipeline"
который вставил в .gitlab-ci.yml разрабовского репозитория. Ну, поменял stage, естественно.
Не заработало.
В контейнере, который я использовал для диплоя (image: ubuntu) не оказалось curl.
Рецепты гуглятся за 5 сек

  • Использовать контейнер с предустановленным curl (ну, нафиг, они все частные, я окую)
  • Сделать ap-tget update; apt-get install curl

Пока искал, нашёл, что image с бубунтой весит 186Мб (и они не включили в него curl!), а есть alpine linux, который весит 5Мб!!!
Нафиг убунту, вписал image: alpine
Переделал apt-get на apk
script:
    - apk --no-cache add curl
    - curl -X POST -F token="$TEST_TOKEN" -F ref=master https://gitlab.com/api/v4/projects/NNNNNN/trigger/pipeline
Заработало!
Из минусов: разрабовский диплой отрабатывает, "дёргает триггер" и зеленеет. А потом запускаются тесты. Некрасиво :(

01 - Холодный старт

Gitlab и его CI

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

Задача

Организовать процесс тестирование проекта.
Проект состоит из нескольких частей: web, android, ios. В приоритете web, который на данный момент выглядит очень статически, а в перспективе к нему будет прикручен backend.

От текущего состояния к требуемому

Есть проект на nodejs, который разрабы как-то "компиляют" у себя и получают статический сайт, который по ftp выкатывают ручками на тестовый сервер.

Требуемый flow

  • Разрабы пушат в git в ветку master
  • Запускается сборка проекта (node install, кажется)
  • Получается статический сайт - директория с файлами
  • Директория заливается на стенд
  • Вызываются автотесты.
  • Результаты автотестов видны где-то в красивом виде.

С чего начать?

Начинать нужно с Ивана Немытченко, он даёт хорошее представление, что такое вообще gitlab CI. Как только придёт осознание, что "я всё понял", нужно принять холодный душ от Дмитрия Столярова - вот кто взрывает мозг и давит интеллектом!


После вкуривания видосов я пошёл на gitlab и попытался написать свой маленький ci-скрипт. Для этого в корне репозитория нужно создать файл .gitlab-ci.yml
Кстати, при создании этого файла из web-интерфейса, будет предоставлена возможность выбрать из набора готовых темплейтов:

Откровение первое

Об этом было в видео, но всё равно:
Все скрипты выполняются с помощью докер-контейнеров! Т.е. если вы напишете простое
script:
    - echo "Test"

то для выполнения этого скрипта будет спулен docker-контейнер (по умолчанию ruby, если вы не указали какой-нибудь другой image). Спулен, запущен и в нём уже выполнено echo.

Откровение второе

А как же наши исходники попадут в контейнер-то? Оказывается, кроме git pull будет вызвано
Cloning repository...
Cloning into '/builds/...

Я не нашёл где описано, что ваш репо будет скопирован в /builds, но уверен, что это где-то описано.