
Uma das funções mais necessárias, que não está na versão gratuita do GitLab, é a possibilidade de votar contra o reset do repositório, controlando a Merge request (MR) com uma revisão de código obrigatória.
Vamos implementar um funcionalidade mínima sozinhos — proibiremos a Merge até que vários desenvolvedores deem um "joinha" na MR.
Por que isso é importante?
Nossa organização pode arcar com a compra de uma licença do GitLab. No entanto, como o desenvolvimento ocorre em um ambiente fechado sem acesso à internet e há um planejamento orçamentário rígido, a aquisição de licenças self-managed com a funcionalidade necessária pode atrasar por meses, mas precisamos trabalhar agora.
No final, temos que:
- ou proibir totalmente a Merge em branches protegidas para alguns desenvolvedores, mas isso resulta em conflitos para os desenvolvedores que têm permissão para Merge ao tentarem mesclar MR de outros como um bônus;
- ou permitir mesclagens descontroladas com sua branch master sem revisão de código, mesmo que seja um júnior que começou ontem.
A primeira coisa que fiz foi pesquisar, assumindo que com certeza alguém já havia feito algo semelhante (sem modificação de código), mas descobri que tal implementação ainda não existia na versão community.
O esquema geral de funcionamento
Como exemplo, vamos configurar aprovações de Merge request em um repositório de teste. :
- Vamos criar um token para acessar a API do GitLab (por meio do qual obteremos informações sobre o número de votos "a favor" e "contra").
- Adicionaremos o token às variáveis do GitLab.
- Proibiremos a Merge em caso de erros no pipeline (se os votos "a favor" forem insuficientes).
- Vamos configurar a verificação de votos como parte do pipeline CI/CD.
- Proibiremos commits em branches protegidas, realizando todas as mudanças apenas por meio de MR.
- Vamos verificar o que conseguimos no final.
1. Criamos um token para acessar a API.
Acesse Configurações do usuário → Tokens de acesso e anote o token:

Conta para obter o token.
O acesso à API permite fazer quase tudo com seus repositórios, portanto, recomendo criar uma conta GitLab separada, conceder a ela permissões mínimas em seus repositórios (por exemplo, Reporter) e obter um token para essa conta.
2. Adicionar o token às variáveis do GitLab.
Por exemplo, no passo anterior obtivemos o token QmN2Y0NOUFlfeXhvd21ZS01aQzgK
Abra Configurações → CI/CD → Variáveis → Adicionar variável → GITLAB_TOKEN_FOR_CI

No final, teremos:

Isso pode ser feito tanto em um único repositório quanto em um grupo de repositórios.
3. Impomos uma proibição de Merge se não tivermos aprovações de colegas após a revisão de código.
No nosso caso, a proibição de Merge será que o pipeline retornará um erro se o número de votos for insuficiente.
Acesse Configurações → Gerais → Pedidos de Mesclagem → Verificações de Mesclagem e ative a opção As linhas de compilação devem ser executadas com sucesso.

4. Configurando o pipeline
Se você ainda não criou um pipeline de CI/CD para seu aplicativo
Crie um arquivo na raiz do repositório .gitlab-ci.yml com o conteúdo mais simples:
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"
Repositório separado para configuração de CI/CD
Eu recomendaria fazer um repositório separado onde você deve criar o arquivo myapp.gitlab-ci.yml para configurar o pipeline. Assim, você poderá controlar melhor o acesso dos participantes que podem alterar o pipeline de build e obter o token de acesso.
A localização do novo arquivo do pipeline precisará ser indicada entrando no repositório myapp — Configurações — CI/CD — Linhas de Build — Caminho de Configuração de CI — indicar o novo arquivo, por exemplo myapp.gitlab-ci.yml@gitlab-ce-mr-approvals/Ci
Dica: use um linter para fazer alterações em arquivos do GitLab CI
Mesmo que você esteja trabalhando sozinho, é bom usar MR, passando todas as suas alterações nos arquivos do pipeline por meio de um linter. Se você cometer um erro na sintaxe do arquivo YAML, isso não quebrará seu pipeline em funcionamento, apenas bloqueará o Merge.
Exemplo de contêineres com linters que você pode integrar ao seu pipeline:
E um exemplo de estágio de verificação:
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;
Agora, você precisa adicionar alguns parâmetros ao seu pipeline para que tudo funcione:
etapas:
- teste
variables:
NEED_VOTES: 1
include:
- remote: "https://gitlab.com/gitlab-ce-mr-approvals/ci/-/raw/master/check-approve.gitlab-ci.yml"
A variável NEED_VOTES determina quantos "votos positivos" são necessários para que o Merge esteja disponível. Um valor igual a um significa que você pode aprovar seu próprio MR "curtindo-o."
include conecta a etapa de teste, que verifica a quantidade de "curtidas."
Pipeline simples usando myapp.gitlab-ci.yml
etapas:
- construir
- teste
variables:
NEED_VOTES: 0
include:
- remote: "https://gitlab.com/gitlab-ce-mr-approvals/ci/-/raw/master/check-approve.gitlab-ci.yml"
run-myapp:
estágio: build
imagem: openjdk
script:
- echo CI_MERGE_REQUEST_TARGET_BRANCH_NAME $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
- java HelloWorld.java
Conteúdo do check-approve.gitlab-ci.yml
ci-mr:
etapa: teste
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 positivo = 1, voto negativo = -1, MR OK se votos >=${NEED_VOTES_REAL}"
- if [ "${MR_VOTES}" -ge "$(expr ${NEED_VOTES_REAL})" ];
then
echo "MR OK";
else
echo "MR ERRO Necessita de mais votos";
exit 1;
fi
imagem: laptevss\/gitlab-api-util
regras:
- se: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ \/^release\/.*$\/'
Mais detalhes sobre o que acontece durante a verificação:
- foi estabelecido um limite de que a verificação ocorrerá apenas na criação de MR nas ramas master ou release/*
- usando a API GitLab, obtemos a quantidade de 'likes' e 'dislikes'
- calculamos a diferença entre os feedbacks positivos e negativos
- se a diferença for menor do que o valor definido em NEED_VOTES, bloqueamos a possibilidade de mesclar
5. Proibimos commits em ramas protegidas
Definimos as ramas para as quais devemos realizar a revisão de código e indicamos que o trabalho nelas só pode ser feito através de MR.
Para isso, vá em Configurações → Repositório → Ramas Protegidas:

6. Verificamos
Definimos NEED_VOTES: 0
Fazemos MR e colocamos 'dislike'.

Nos logs da construção:

Agora colocamos 'like' e iniciamos uma nova verificação:

Fonte: habr.com
