
Una delle funzioni più necessarie non disponibili nella versione gratuita di GitLab è la possibilità di votare contro il reset del repository per controllare le Merge request (MR) utilizzando un code review obbligatorio.
Creeremo noi stessi una funzionalità minima: vietiamo il Merge fino a quando diversi sviluppatori non metteranno "mi piace" sulla MR.
Perché tutto ciò?
La nostra organizzazione può tranquillamente permettersi di acquistare una licenza GitLab. Tuttavia, poiché lo sviluppo avviene in un ambiente chiuso senza accesso a Internet e c'è una pianificazione rigorosa del budget, l'acquisto di licenze self-managed con le funzionalità necessarie potrebbe richiedere molti mesi e bisogna già lavorare ora.
Di conseguenza, ci si trova a dover:
- o vietare completamente il Merge in rami protetti per alcuni sviluppatori, ma in tal caso gli sviluppatori autorizzati al Merge ricevono conflitti durante la fusione di MR altrui come bonus;
- oppure consentire fusioni incontrollate con il tuo ramo master senza code review, anche se si tratta di un Junior assunto solo ieri.
La prima cosa da fare è andare a cercare su Google, pensando che sicuramente qualcuno abbia già fatto qualcosa di simile (senza dover rivedere il codice), ma è emerso che una simile implementazione non esisteva ancora nella versione community.
Schema generale di lavoro
Come esempio, configureremo approvazioni per Merge request in un repository di test :
- Creeremo un token per accedere all'API di GitLab (attraverso cui otterremo informazioni sul numero di voti "sì" e "no")
- Aggiungeremo il token alle variabili di GitLab
- Vieteremo il Merge in caso di errori nel pipeline (se i voti "sì" non sono sufficienti)
- Configureremo il controllo dei voti come parte del pipeline CI/CD
- Vieteremo di effettuare commit in rami protetti, tutte le modifiche saranno effettuate solo tramite MR
- Controlliamo il risultato finale
1. Creiamo un token per accedere all'API
Accediamo a Impostazioni utente → Token di accesso e annotiamo il token:

Account per ottenere il token
L'accesso all'API consente di fare praticamente tutto con i tuoi repository, quindi ti consiglio di creare un account Gitlab separato, darle i diritti minimi sui tuoi repository (ad esempio, Reporter) e ottenere un token per questo account.
2. Aggiungiamo il token alle variabili di Gitlab
Ad esempio, nel passo precedente abbiamo ottenuto il token QmN2Y0NOUFlfeXhvd21ZS01aQzgK
Apriamo Impostazioni → CI/CD → Variabili → Aggiungi variabile → GITLAB_TOKEN_FOR_CI

Alla fine otterremo:

Questo può essere fatto sia su un singolo repository che su un gruppo di repository.
3. Impediamo il Merge se non si ricevono approvazioni dai colleghi dopo il code review effettuato.
Nel nostro caso, impedire il Merge significa che la pipeline di build restituirà un errore se non ci sono abbastanza voti.
Andiamo su Impostazioni → Generali → Richieste di unione → Controlli delle unioni e abilitiamo l'opzione Le linee di build devono essere completate con successo.

4. Configuriamo il pipeline
Se non hai ancora creato una pipeline CI/CD per la tua applicazione
Creiamo nella radice del repository un file .gitlab-ci.yml con un contenuto molto semplice:
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 separato per la configurazione CI/CD
Ti consiglio di creare un repository separato in cui dovrai creare il file myapp.gitlab-ci.yml per configurare la pipeline. In questo modo potrai controllare meglio l'accesso dei partecipanti che possono modificare la pipeline di build e ottenere un token di accesso.
Dovrai specificare la posizione del nuovo file della pipeline accedendo al repository myapp — Impostazioni — CI/CD — Linee di build — Percorso personalizzato di configurazione CI — specificare il nuovo file, ad esempio myapp.gitlab-ci.yml@gitlab-ce-mr-approvals/Ci
Consiglio: utilizza un linter per apportare modifiche ai file GitLab CI
Anche se lavori da solo, utilizzare MR sarà utile, eseguendo tutte le tue modifiche ai file della pipeline attraverso il linter. Se commetti un errore nella sintassi del file YAML, non romperai la pipeline funzionante, ma semplicemente bloccherai il Merge.
Esempio di container con linter che puoi integrare nella tua pipeline:
E un esempio di fase di controllo:
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;
Restano da aggiungere alla tua pipeline alcuni parametri affinché tutto funzioni:
fasi:
- test
variables:
NEED_VOTES: 1
include:
- remote: "https://gitlab.com/gitlab-ce-mr-approvals/ci/-/raw/master/check-approve.gitlab-ci.yml"
La variabile NEED_VOTES definisce quanti "pollici alzati" devono esserci per il MR affinché il Merge sia disponibile. Un valore pari a uno significa che puoi approvare il tuo stesso MR esprimendo un "like".
L'include integra la fase di test, che verifica il numero di "like".
Pipeline più semplice con l'esempio myapp.gitlab-ci.yml
fasi:
- costruire
- 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
Contenuto check-approve.gitlab-ci.yml
ci-mr:
fase: 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} Voto favorevole = 1, voto contrario = -1, MR OK se i voti >=${NEED_VOTES_REAL}"
- if [ "${MR_VOTES}" -ge "$(expr ${NEED_VOTES_REAL})" ];
allora
echo "MR OK";
else
echo "MR ERRORE Necessita di più voti";
exit 1;
fi
immagine: laptevss\/gitlab-api-util
regole:
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ \/^release\/.*$\/'
Ulteriori informazioni su cosa accade durante la verifica:
- è stato impostato un limite affinché la verifica avvenga solo durante la creazione di MR nei rami master o release/*
- utilizzando l'API di GitLab, otteniamo il numero di 'mi piace' e 'non mi piace'
- calcoliamo la differenza tra i feedback positivi e negativi
- se la differenza è inferiore al valore impostato in NEED_VOTES, blocchiamo la possibilità di effettuare il merge
5. Vietiamo i commit nei rami protetti
Definiamo i rami per i quali dobbiamo effettuare una revisione del codice e indichiamo che è possibile lavorarci solo tramite MR.
A tal fine, andiamo su Impostazioni → Repository → Rami protetti:

6. Controlliamo
Impostiamo NEED_VOTES: 0
Facciamo un MR e mettiamo un 'non mi piace'.

Nei log di build:

Ora mettiamo un 'mi piace' e avviamo una nuova verifica:

Fonte: habr.com
