Адной з самых патрэбных функцый, якой няма ў бясплатнай версіі GitLab, з'яўляецца магчымасць галасавання супраць абнулення рэпазітара кантраляваць Merge request (MR), выкарыстоўваючы абавязковы code review.
Зробім мінімальны функцыянал самі - забаронім Merge, пакуль некалькі распрацоўшчыкаў не паставяць «палец уверх» на MR.
Навошта гэта ўвогуле?
Наша арганізацыя цалкам можа дазволіць сабе купіць ліцэнзію GitLab. Але, бо распрацоўка вядзецца ў зачыненым контуры без доступу ў інтэрнэт, і ёсць цвёрдае планаванне бюджэту, закуп ліцэнзій self-managed з патрэбным функцыяналам можа зацягнуцца на шматлікія месяцы, а працаваць трэба ўжо цяпер.
У выніку даводзіцца:
- альбо зусім забараняць Merge у абароненыя галінкі для часткі распрацоўшчыкаў, але тады распрацоўшчыкі, якія маюць права на Merge, атрымліваюць канфлікты пры зліцці чужых MR як бонус;
- альбо даваць магчымасць рабіць бескантрольныя зліцці з вашай майстар-галінкай без code review, нават калі гэта Junior, які ўладкаваўся толькі ўчора.
Перш за ўсё адправіўся гугліць, мяркуючы, што ўжо сапраўды хтосьці нешта падобнае ўжо зрабіў (без дапрацоўкі кода), але аказалася, што падобнай рэалізацыі ў community версіі яшчэ не было.
Агульная схема працы
У якасці прыкладу наладзім Merge request approvals на тэставым рэпазітары
- Створым токен для доступу да API GitLab (праз яго будзем атрымліваць інфармацыю аб колькасці галасоў "за" і "супраць")
- Дадамо токен у зменныя GitLab
- Забаранім Merge пры памылках у пайплайне (калі галасоў "за" недастаткова)
- Наладзім праверку галасоў як частка пайплайну CI/CD
- Забаранім рабіць коміты ў абароненыя галінкі, усе змены праводзім толькі праз MR
- Праверым, што атрымалася ў выніку
1. Ствараем токен для доступу да API
Заходзім у Налады карыстальніка → Такены доступу і запісваем токен:
Уліковы запіс для атрымання токена
Доступ да API дазваляе рабіць практычна ўсё з вашымі рэпазітарамі, таму раю стварыць асобны ўліковы запіс Gitlab, даць ёй мінімальныя правы на вашыя рэпазаторыі (напрыклад, Reporter) і атрымаць токен для гэтага ўліковага запісу.
2. Дадаем токен у зменныя Gitlab
Напрыклад, на папярэднім кроку мы атрымалі токен QmN2Y0NOUFlfeXhvd21ZS01aQzgK
Адкрываем паводле → CI/CD → Пераменныя → Дадаць зменную → GITLAB_TOKEN_FOR_CI
У выніку атрымаем:
Гэта можна зрабіць як на адным рэпазітары, так і на групе рэпазітароў.
3. Ставім забарону на Merge, калі не атрыманы адабрэнні калег пасля праведзенага code review
У нашым выпадку забаронай на 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;
Засталося дадаць у ваш пайплайн некалькі параметраў, каб усё зарабіла:
stages:
- test
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
stages:
- build
- test
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
script:
- echo CI_MERGE_REQUEST_TARGET_BRANCH_NAME $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
- java HelloWorld.java
Змест check-approve.gitlab-ci.yml
ci-mr:
stage: test
script:
- 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})" ];
then
echo "MR OK";
else
echo "MR ERROR Need more votes";
exit 1;
fi
image: laptevss/gitlab-api-util
rules:
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /^release/.*$/'
Падрабязней аб тым, што адбываецца пры праверцы:
- устаноўлена абмежаванне, што праверка будзе толькі пры стварэнні MR у галінкі master ці release/*
- выкарыстоўваючы API GitLab, атрымліваем колькасць "лайкаў" і "дызлайкаў"
- вылічаем рознасць паміж станоўчымі і адмоўнымі водгукамі
- калі рознасць менш зададзенага намі значэння ў NEED_VOTES, то блакуем магчымасць зрабіць зліццё
5. Забараняем коміты ў абароненыя галінкі
Вызначаем галінкі, для якіх мы павінны праводзіць code review і паказваем, што працаваць з імі можна толькі праз MR.
Для гэтага заходзім у паводле → Рэпазітар → Protected Branches:
6. Правяраем
Зададзім NEED_VOTES: 0
Які робіцца MR і ставім «дызлайк».
У логах зборкі:
Цяпер ставім «лайк» і запускаем паўторную праверку:
Крыніца: habr.com