
Una dintre cele mai necesare funcții care lipsesc în versiunea gratuită a GitLab este posibilitatea de a vota împotriva resettării unui repository pentru a controla Merge request (MR) folosind o revizuire de cod obligatorie.
Vom implementa un minim de funcționalitate noi – vom interzice Merge-ul, până când câțiva dezvoltatori nu vor da «thumbs up» pentru MR.
De ce este necesar acest lucru?
Organizația noastră își poate permite să achiziționeze o licență GitLab. Totuși, deoarece dezvoltarea se desfășoară într-un mediu închis, fără acces la internet, și există o planificare strictă a bugetului, achiziția licențelor self-managed cu funcționalitatea necesară poate dura multe luni, iar munca trebuie să înceapă deja acum.
În consecință, se ajunge la:
- fie să interzicem complet Merge-ul în ramurile protejate pentru o parte dintre dezvoltatori, dar atunci dezvoltatorii care au dreptul de a face Merge vor obține conflicte la fuzionarea MR-urilor altora, ca bonus;
- fie să oferim posibilitatea de a face fuzionări necontrolate cu ramura principală, fără revizuire de cod, chiar dacă este vorba de un Junior care abia a fost angajat ieri.
Primul lucru pe care l-am făcut a fost să caut pe Google, presupunând că cu siguranță cineva a realizat deja ceva similar (fără modificarea codului), dar s-a dovedit că o astfel de implementare în versiunea community nu existase încă.
Schema generală de lucru
Ca exemplu, vom configura aprobările pentru Merge request-uri pe un repository de test. :
- Vom crea un token pentru accesul la API-ul GitLab (prin care vom obține informații despre numărul de voturi «pentru» și «împotrivă»)
- Vom adăuga tokenul în variabilele GitLab
- Vom interzice Merge-ul în cazul unor erori în pipeline (dacă nu sunt suficiente voturi «pentru»)
- Vom configura verificarea voturilor ca parte a pipeline-ului CI/CD
- Vom interzice realizarea commit-urilor în ramurile protejate, toate modificările fiind efectuate numai prin MR.
- Vom verifica ce am obținut în final
1. Creăm un token pentru accesul la API
Accesăm Setările utilizatorului → Tokenuri de acces și notăm tokenul:

Contul pentru obținerea tokenului
Accesul la API permite practic orice acțiune cu repositoarele dvs., așa că recomand să creați un cont GitLab separat, să-i oferiți drepturi minime asupra repositoarelor dvs. (de exemplu, Reporter) și să obțineți un token pentru acest cont.
2. Adăugăm tokenul în variabilele GitLab
De exemplu, în pasul anterior am obținut tokenul QmN2Y0NOUFlfeXhvd21ZS01aQzgK
Accesăm Setări → CI/CD → Variabile → Adăugați variabilă → GITLAB_TOKEN_FOR_CI

În rezultatul final vom obține:

Acest lucru se poate face atât pe un singur repository, cât și pe un grup de repositoare.
3. Interzicem fuzionarea dacă nu primim aprobările colegilor după revizuirea codului
În cazul nostru, interzicerea fuzionării va fi că linia de construcție va returna o eroare în cazul unui număr insuficient de voturi.
Accesăm Setări → Generale → Cereri de fuzionare → Verificări de fuzionare și activăm opțiunea Linile de construcție trebuie să fie finalizate cu succes.

4. Configurăm pipeline-ul
Dacă nu ați creat încă un pipeline CI/CD pentru aplicația dvs.
Creăm în rădăcina repository-ului un fișier .gitlab-ci.yml cu conținut simplu:
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"
Repository separat pentru configurația CI/CD
V-aș recomanda să creați un repository separat în care să creați fișierul myapp.gitlab-ci.yml pentru configurarea pipeline-ului. Așa veți putea controla mai bine accesul participanților care pot schimba pipeline-ul de construcție și obține un token de acces.
Locația noului fișier pipeline va trebui specificată, intrând în repository-ul myapp — Setări — CI/CD — Linii de construcție — Calea de configurare CI personalizată — specificați noul fișier, de exemplu myapp.gitlab-ci.yml@gitlab-ce-mr-approvals/Ci
Sfaturi: folosiți un linter pentru a face modificări în fișierele GitLab CI
Chiar dacă lucrați singur, o idee bună este să lucrați prin MR, rulat toate modificările fișierelor pipeline-ului prin linter. Dacă greșiți în sintaxa fișierului YAML, acest lucru nu vă va strica pipeline-ul funcțional, ci va bloca pur și simplu fuzionarea.
Exemplu de containere cu lintere pe care le puteți integra în pipeline-ul dvs.:
Și un exemplu de etapă de verificare:
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;
Rămâne să adăugați în pipeline-ul dvs. câteva variabile pentru ca totul să funcționeze:
etape:
- test
variables:
NEED_VOTES: 1
include:
- remote: "https://gitlab.com/gitlab-ce-mr-approvals/ci/-/raw/master/check-approve.gitlab-ci.yml"
Variabila NEED_VOTES determină câte "like-uri" trebuie să aibă MR pentru a permite fuzionarea. O valoare de unu înseamnă că puteți aproba singur MR-ul dvs., "apreciindu-l".
include includează etapa test care verifică numărul de "like-uri".
Pipeline-ul cel mai simplu pe exemplul myapp.gitlab-ci.yml
etape:
- construiește
- 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
Conținutul check-approve.gitlab-ci.yml
ci-mr:
stadiu: 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} Vot A = 1, vot Ă = -1, MR OK dacă voturile >=${NEED_VOTES_REAL}"
- if [ "${MR_VOTES}" -ge "$(expr ${NEED_VOTES_REAL})" ];
atunci
echo "MR OK";
altfel
echo "MR ERROR Necesită mai multe voturi";
exit 1;
fi
imagine: laptevss\/gitlab-api-util
reguli:
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ \/^release\/.*$\/'
Mai multe informații despre ce se întâmplă în timpul verificării:
- s-a stabilit o restricție astfel încât verificarea să se facă numai la crearea MR în ramurile master sau release/*
- folosind API-ul GitLab, obținem numărul de «like-uri» și «dislike-uri»
- calculăm diferența dintre răspunsurile pozitive și negative
- dacă diferența este mai mică decât valoarea stabilită de noi în NEED_VOTES, blocăm posibilitatea de a face un merge
5. Interzicerea commit-urilor în ramuri protejate
Definim ramurile pentru care trebuie să efectuăm code review și specificăm că lucrul cu acestea se poate face doar prin MR.
Pentru aceasta, mergem la Setări → Repositoriu → Ramuri Protejate:

6. Verificăm
Să stabilim NEED_VOTES: 0
Facem MR și punem «dislike».

În log-urile de construire:

Acum punem «like» și reluăm verificarea:

Sursa: habr.com
