
Една от най-необходимите функции, която липсва в безплатната версия на GitLab, е възможността за гласуване срещу нулиране на репозитория, контролирайки Merge request (MR) чрез задължителен code review.
Нека създадем минималния функционал сами - ще забраним Merge, докато няколко разработчици не поставят «палец нагоре» на MR.
Защо изобщо?
Нашата организация напълно може да си позволи да закупи лиценз за GitLab. Но, тъй като разработката се извършва в затворен контур без достъп до интернет и имаме строги бюджетни планове, закупуването на лицензи self-managed с нужната функционалност може да отнеме много месеци, а работата трябва да започне веднага.
В крайна сметка ни се налага:
- или напълно да забраним Merge в защитените клонове за част от разработчиците, но тогава разработчиците, които имат право на Merge, получават конфликти при сливане на чужди MR като бонус;
- или да предоставим възможност за неконтролирани слиwania с вашата основна клон без code review, дори ако това е Junior, който току-що е започнал.
Първото нещо, което направих, беше да гугля, вярвайки, че със сигурност някой вече е направил нещо подобно (без модификация на кода), но се оказа, че такава реализация в community версията все още не е имало.
Обща схема на работа
Като пример ще настроим одобрения за Merge request на тестово хранилище :
- Създаваме токен за достъп до API на GitLab (чрез него ще получаваме информация за броя на гласовете «за» и «против»)
- Добавяме токена в променливите на GitLab
- Забраняваме Merge при грешки в пайплайна (ако гласовете «за» са недостатъчни)
- Настройваме проверка на гласовете като част от пайплайна CI/CD
- Забраняваме извършването на комити в защитените клонове, всички промени се извършват само чрез MR
- Ще проверим какво сме постигнали в крайна сметка
1. Създаваме токен за достъп до API
Влизаме в Настройки на потребителя → Токени за достъп и записваме токена:

Профил за получаване на токен
Достъпът до API позволява да правите практически всичко с вашите репозитории, затова препоръчвам да създадете отделен профил за GitLab, да му предоставите минимални права върху вашите репозитории (например, Reporter) и да получите токен за този профил.
2. Добавяме токена в променливите на GitLab
Например, на предишната стъпка получихме токена QmN2Y0NOUFlfeXhvd21ZS01aQzgK
Отваряме Настройки → CI/CD → Променливи → Добавяне на променлива → GITLAB_TOKEN_FOR_CI

В крайна сметка ще получим:

Можете да направите това както на едно хранилище, така и на група хранилища.
3. Налагаме забрана за Merge, ако не получим одобрение от колеги след проведен код преглед.
В нашия случай забраната за Merge ще бъде, че сборният конвейер ще върне грешка при недостатъчен брой гласове.
Влизаме в Настройки → Основни → Запитвания за сливане → Проверки при сливане и активираме опцията Сборните линии трябва да завършват успешно.

4. Настройваме пайплайна
Ако все още не сте направили CI/CD конвейер за вашето приложение
Създайте в корена на хранилището файл .gitlab-ci.yml с най-простото съдържание:
stages:
- build
- test
variables:
NEED_VOTES: 1
include:
- remote: "https://gitlab.com/gitlab-ce-mr-approvals/ci/-/raw/master/check-approve.gitlab-ci.yml"
run-myapp:
stage: build
script: echo "Hello world"
Отделно хранилище за конфигурация на CI/CD
Препоръчвам да направите отделно хранилище, в което трябва да създадете файл myapp.gitlab-ci.yml за настройка на конвейера. По този начин ще можете по-добре да контролирате достъпа на участниците, които могат да променят сборния конвейер и да получат токен за достъп.
Местоположението на новия файлов конвейер трябва да бъде указано, като влезете в хранилището myapp — Настройки — CI/CD — Сборни линии — Потребителски маршрут за конфигурация на CI — указвате новия файл, например myapp.gitlab-ci.yml@gitlab-ce-mr-approvals/Ci
Съвет: използвайте линтер за въвеждане на промени в файловете на GitLab CI
Дори ако работите сами, добър помощник е работата чрез MR, проверявайки всички ваши промени в файловете на пайплайна през линтер. Ако допуснете грешка в синтаксиса на YAML файла, това няма да ви позволи да счупите работния конвейер, а просто ще блокира Merge.
Пример за контейнери с линтери, които можете да вградите в вашия пайплайн:
И пример за етапа на проверка:
stages:
- lint
lint:
stage: lint
image: sebiwi/gitlab-ci-validate:1.3.0
variables:
GITLAB_HOST: https://gitlab.com
script:
- CI_FILES=(./*.yml)
- for f in "${CI_FILES[@]}"; do
gitlab-ci-validate $f;
done;
Остава да добавите няколко параметъра в вашия пайплайн, за да заработи всичко:
етапи:
- тест
variables:
NEED_VOTES: 1
include:
- remote: "https://gitlab.com/gitlab-ce-mr-approvals/ci/-/raw/master/check-approve.gitlab-ci.yml"
Променливата NEED_VOTES определя колко "палци нагоре" трябва да има MR, за да бъде разрешен Merge. Стойността, равна на един, означава, че самият вие можете да одобрите своя MR, като му дадете "лайк".
include вклучва етапа test, който проверява броя "лайкове".
Най-простият пайплайн на примера myapp.gitlab-ci.yml
етапи:
- изграждане
- тест
variables:
NEED_VOTES: 0
include:
- remote: "https://gitlab.com/gitlab-ce-mr-approvals/ci/-/raw/master/check-approve.gitlab-ci.yml"
run-myapp:
stage: build
image: openjdk
скрипт:
- echo CI_MERGE_REQUEST_TARGET_BRANCH_NAME $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
- java HelloWorld.java
Съдържание check-approve.gitlab-ci.yml
ci-mr:
етап: тест
скрипт:
- echo ${CI_API_V4_URL}
- echo "CI_PROJECT_ID ${CI_PROJECT_ID}"
- echo "CI_COMMIT_SHA ${CI_COMMIT_SHA}"
- "export MR_ID=$(curl --silent --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN_FOR_CI" ${CI_API_V4_URL}\/projects\/${CI_PROJECT_ID}\/merge_requests | jq ".[] | if .sha == \"${CI_COMMIT_SHA}\" then .id else {} end" | grep --invert-match {})"
- "export MR_TITLE=$(curl --silent --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN_FOR_CI" ${CI_API_V4_URL}\/projects\/${CI_PROJECT_ID}\/merge_requests | jq ".[] | if .sha == \"${CI_COMMIT_SHA}\" then .title else {} end" | grep --invert-match {})"
- "export MR_WIP=$(curl --silent --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN_FOR_CI" ${CI_API_V4_URL}\/projects\/${CI_PROJECT_ID}\/merge_requests | jq ".[] | if .sha == \"${CI_COMMIT_SHA}\" then .work_in_progress else {} end" | grep --invert-match {})"
- "export MR_UPVOTES=$(curl --silent --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN_FOR_CI" ${CI_API_V4_URL}\/projects\/${CI_PROJECT_ID}\/merge_requests | jq ".[] | if .sha == \"${CI_COMMIT_SHA}\" then .upvotes else {} end" | grep --invert-match {})"
- "export MR_DOWNVOTES=$(curl --silent --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN_FOR_CI" ${CI_API_V4_URL}\/projects\/${CI_PROJECT_ID}\/merge_requests | jq ".[] | if .sha == \"${CI_COMMIT_SHA}\" then .downvotes else {} end" | grep --invert-match {})"
- MR_VOTES=$(expr ${MR_UPVOTES} - ${MR_DOWNVOTES})
- NEED_VOTES_REAL=${NEED_VOTES:-1}
- echo "MR_ID ${MR_ID} MR_TITLE ${MR_TITLE} MR_WIP ${MR_WIP} MR_UPVOTES ${MR_UPVOTES} MR_DOWNVOTES ${MR_DOWNVOTES}"
- echo "MR_VOTES ${MR_VOTES} Up vote = 1, down vote = -1, MR OK if votes >=${NEED_VOTES_REAL}"
- if [ "${MR_VOTES}" -ge "$(expr ${NEED_VOTES_REAL})" ];
тогава
echo "MR OK";
иначе
echo "MR ERROR Need more votes";
exit 1;
fi
image: laptevss\/gitlab-api-util
правила:
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ \/^release\/.*$\/'
Повече информация за това, което се случва при проверка:
- наложено е ограничение, че проверката ще стане само при създаване на MR в клонове master или release/*
- използвайки GitLab API, получаваме броя на «лайковете» и «дизлайковете»
- изчисляваме разликата между положителните и отрицателните отзиви
- ако разликата е по-малка от зададената от нас стойност в NEED_VOTES, блокираме възможността за извършване на сливане
5. Забраняваме комитите в защитени клони
Определяме клоновете, за които трябва да проведем code review и посочваме, че работата с тях е възможна само чрез MR.
За целта отиваме в Настройки → Репозиторий → Защитени клони:

6. Проверяваме
Задаваме NEED_VOTES: 0
Правим MR и поставяме «дизлайк».

В логовете на сборката:

Сега поставяме «лайк» и стартираме повторна проверка:

Източник: habr.com
