
Jednou z nejpotřebnějších funkcí, které ve volné verzi GitLab chybí, je možnost hlasovat proti resetování repozitáře v rámci kontrolování Merge requestu (MR) pomocí povinného code review.
Vytvoříme minimální funkčnost sami – zakážeme Merge, dokud několik vývojářů nedá "palec nahoru" na MR.
Proč to vlastně?
Naše organizace si klidně může dovolit zakoupit licenci GitLab. Ale protože se vývoj provádí v uzavřeném prostředí bez přístupu na internet a rozpočet je přísně naplánován, může trvat měsíce, než se zakoupí licence self-managed s potřebnou funkčností, a pracovat je třeba už nyní.
Nakonec se musíme:
- buď zcela zakázat Merge do chráněných větví pro některé vývojáře, ale pak vývojáři, kteří mají právo na Merge, získávají konflikty při sloučení cizích MR jako bonus;
- nebo umožnit nekontrolované sloučení s vaší hlavní větví bez code review, i když je to začátečník, který nastoupil teprve včera.
Hned jsem začal googlit, protože jsem si myslel, že už určitě někdo něco podobného udělal (bez úprav kódu), ale ukázalo se, že taková implementace ve komunitní verzi ještě nebyla.
Obecný pracovní diagram
Jako příklad nastavíme schválení Merge requestu na testovacím repozitáři :
- Vytvoříme token pro přístup k API GitLab (skrz něj budeme získávat informace o počtu hlasů "pro" a "proti")
- Přidáme token do proměnných GitLab
- Zakážeme Merge při chybách v pipeline (pokud není dostatek hlasů "pro")
- Nastavíme kontrolu hlasů jako součást CI/CD pipeline
- Zakážeme provádět commity do chráněných větví, všechny změny provádíme pouze přes MR
- Zkontrolujeme, co jsme nakonec vytvořili
1. Vytváříme token pro přístup k API
Přejdeme do Nastavení uživatele → Přístupové tokeny a zapíšeme si token:

Účet pro získání tokenu
Přístup k API umožňuje dělat prakticky cokoliv s vašimi repozitáři, proto doporučuji vytvořit samostatný účet GitLab, dát mu minimální práva na vaše repozitáře (například Reporter) a získat token pro tento účet.
2. Přidáváme token do proměnných GitLab
Například na předchozím kroku jsme získali token QmN2Y0NOUFlfeXhvd21ZS01aQzgK
Otevřeme Nastavení → CI/CD → Proměnné → Přidat proměnnou → GITLAB_TOKEN_FOR_CI

$$display$$F(phi)=|y|^2=frac{sin^2(pi frac{Nd}{lambda}sinphi)}{sin^2(pi frac{d}{lambda}sinphi)} $$display$$

To do this, you can use either a single repository or a group of repositories.
3. Set a Merge prohibition unless approvals are received from colleagues after the code review.
In our case, the Merge prohibition will occur if the build pipeline returns an error due to insufficient votes.
Go to Settings → General → Merge Requests → Merge Checks and enable the option The build pipeline must successfully pass.

4. Set up the pipeline.
If you haven't created a CI/CD pipeline for your application yet,
create a file in the root of the repository .gitlab-ci.yml with the following simple content:
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"
A separate repository for CI/CD configuration.
I would recommend creating a separate repository where you need to create the file myapp.gitlab-ci.yml to configure the pipeline. This way, you can better control the access of participants who can change the build pipeline and obtain an access token.
The location of the new pipeline file will need to be specified by going to the myapp repository — Settings — CI/CD — Build Environments — Custom CI Configuration Path — specify the new file, for example, myapp.gitlab-ci.yml@gitlab-ce-mr-approvals/Ci
Tip: use a linter to make changes to GitLab CI files.
Even if you are working alone, using MR can be a helpful approach, running all your changes to the pipeline files through the linter. If you make a mistake in the YAML file syntax, it won't break your operational pipeline, but will simply block the Merge.
Example containers with linters that you can integrate into your pipeline:
And an example check stage:
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;
You just need to add a few parameters to your pipeline to make everything work:
stádia:
- test
variables:
NEED_VOTES: 1
include:
- remote: "https://gitlab.com/gitlab-ce-mr-approvals/ci/-/raw/master/check-approve.gitlab-ci.yml"
The NEED_VOTES variable determines how many 'thumbs up' the MR must have for the Merge to be enabled. A value of one means you can approve your own MR by 'liking' it.
include connects the test stage that checks the number of 'likes'.
Nejjednodušší pipeline na příkladu myapp.gitlab-ci.yml
stádia:
- sestavit
- 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
Obsah 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\/.*)$/ '
Více o tom, co se děje během kontroly:
- bylo nastavenu omezení, že kontrola bude probíhat pouze při vytvoření MR do větví master nebo release/*
- pomocí API GitLab získáváme počet 'lajků' a 'disklajků'
- vypočítáváme rozdíl mezi pozitivními a negativními ohlasy
- pokud je rozdíl menší než námi nastavená hodnota v NEED_VOTES, zablokujeme možnost provést sloučení
5. Zakazujeme commity do chráněných větví
Určujeme větve, pro které musíme provádět code review, a uvádíme, že je možné s nimi pracovat pouze prostřednictvím MR.
K tomu přejdeme do Nastavení → Repozitář → Chráněné větve:

6. Kontrolujeme
Nastavíme NEED_VOTES: 0
Vytvoříme MR a dáme 'disklajk'.

V loggingu sestavení:

Nyní dáme 'lajk' a spustíme opětovnou kontrolu:

Zdroj: habr.com
