Code review in Gitlab CE: if there is no Merge request approvals, but I really want to

Code review in Gitlab CE: if there is no Merge request approvals, but I really want to

One of the most needed features that is not in the free version of GitLab is the ability to vote against zeroing the repository to control the Merge request (MR) using the mandatory code review.

We will do the minimum functionality ourselves - we will disable Merge until several developers give a “thumbs up” to MR.

Why is this at all?

Our organization can afford to buy a GitLab license. But, since the development is carried out in a closed loop without access to the Internet, and there is a strict budget planning, the purchase of self-managed licenses with the necessary functionality can take many months, and you need to work now.

As a result, you have to:

  • or completely prohibit Merge into protected branches for some developers, but then developers who have the right to Merge receive conflicts when merging other people's MRs as a bonus;
  • or allow you to do uncontrolled merges with your master branch without code review, even if it's a Junior who just settled in yesterday.

The first thing I did was go google, believing that someone had already done something similar (without refining the code), but it turned out that there was no such implementation in the community version yet.

General scheme of work

As an example, let's set up Merge request approvals on a test repository myapp:

  1. Let's create a token for accessing the GitLab API (through it we will receive information about the number of votes for and against)
  2. Add a token to GitLab variables
  3. Disable Merge if there are errors in the pipeline (if there are not enough “for” votes)
  4. Set up vote validation as part of the CI/CD pipeline
  5. We will prohibit making commits to protected branches, we make all changes only through MR
  6. Let's check what happened in the end

1. Create a token to access the API

Go to User Settings → Access Tokens and write down the token:

Code review in Gitlab CE: if there is no Merge request approvals, but I really want to

Account to receive the token
API access allows you to do almost anything with your repositories, so I suggest you create a separate Gitlab account, give it minimal rights to your repositories (like Reporter) and get a token for that account.

2. Add the token to Gitlab variables

For example, in the previous step, we received a token QmN2Y0NOUFlfeXhvd21ZS01aQzgK

Open Settings → CI/CD → Variables → Add Variable → GITLAB_TOKEN_FOR_CI

Code review in Gitlab CE: if there is no Merge request approvals, but I really want to

As a result, we get:

Code review in Gitlab CE: if there is no Merge request approvals, but I really want to

This can be done both on one repository and on a group of repositories.

3. We put a ban on Merge if the approval of colleagues is not received after the code review

In our case, the ban on Merge will be that the assembly pipeline will return an error if there are not enough votes.

Go to Settings → General → Merge Requests → Merge Checks and enable the option Assembly lines must run successfully.

Code review in Gitlab CE: if there is no Merge request approvals, but I really want to

4. Set up the pipeline

If you haven't made a CI/CD pipeline for your application yet
Create a file in the root of the repository .gitlab-ci.yml with 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"

Separate repository for CI/CD configuration
I would recommend making a separate repository where you need to create a myapp.gitlab-ci.yml file to set up the pipeline. This way you can better control the access of contributors who can change the build pipeline and get an access token.

The location of the new pipeline file will need to be specified by going to the myapp repository - Settings - CI / CD - Assembly lines - Custom CI configuration path - specify a 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 work alone, working through MR will be a good helper, running all your changes to the pipeline files through the linter. If you make a mistake in the syntax of the YAML file, this will not allow you to break the working pipeline, but will simply block Merge.

An example of containers with linters that you can embed in your pipeline:

hub.docker.com/r/gableroux/gitlab-ci-lint
hub.docker.com/r/sebiwi/gitlab-ci-validate

And an example of the validation 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;

It remains to add a few parameters to your pipeline to make it work:

stages:
- 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" MR must have in order for Merge to be available. A value of one means that you yourself can approve your MR by "liking" it.

include includes the test stage, which checks the number of "likes".

The simplest pipeline using myapp.gitlab-ci.yml as an example
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

Contents of 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/.*$/'

Learn more about what happens when checking:

  • the restriction is set that the check will be only when creating an MR in the master or release /* branches
  • using the GitLab API, get the number of "likes" and "dislikes"
  • calculate the difference between positive and negative responses
  • if the difference is less than the value we set in NEED_VOTES, then we block the ability to merge

5. Disable commits to protected branches

We determine the branches for which we should conduct code review and indicate that they can only be worked with through MR.

To do this, go to Settings → Repository → Protected Branches:

Code review in Gitlab CE: if there is no Merge request approvals, but I really want to

6. Checking

Set NEED_VOTES: 0

We do MR and put a "dislike".

Code review in Gitlab CE: if there is no Merge request approvals, but I really want to

In the build logs:

Code review in Gitlab CE: if there is no Merge request approvals, but I really want to

Now put "like" and run a re-check:

Code review in Gitlab CE: if there is no Merge request approvals, but I really want to

Source: habr.com

Add a comment