Как стать автором
Обновить

Комментарии 18

Зачем вообще использовать approve rules?

Или компании нужно получить сертификат по безопасности и эти правила нужны для прохождения аудита. Может быть следствием SOX(Sarbanes–Oxley Act).

Привет, кстати да, спасибо

Апи гитлаба это просто сундук с сокровищами:) Вытащить много что можно.

Прикольная идея, но я бы завернул эту реализацию в python скрипт(я про часть с блоком script).

Привет, спасибо) простора для улучшения много, как ты и написал, статья больше про идею

Что именно в этом конкретном случае позволит вам реализовать скрипт на python из того, что нельзя реализовать на bash?

Вкусовщина:)
я больше про то, что лично мне не нравится, когда ты создаешь еще один файл с ci и складываешь туда целые блоки bash "техник" :) Поэтому ответил, что реализацию яб написал через python(тут на самом деле не важно на чем писать, можно и bash оставить) и только добавил доп стадию в основной gitlab-ci.yml

создаешь еще один файл с ci и складываешь туда целые блоки bash

Но вы хотите создать ещё один файл и положить туда целые блоки python. Не вижу логики.

К тому же используя нативный для Gitlab include, почти что так, как сделал автор, можно переиспользовать ci templates без необходимости делать clone какого-то tool репозитория (куда бы вы положили ваш python скрипт, если бы вы использовали его в более чем одном репозитории). И bash также нативен для Gitlab pipelines + нет необходимости ставить какие-то python requirements и т.п. не нужное здесь.

Пример с нехватающим у автора версионированием:

include:
  - project: 'test/pipelines'
    file: '.gitlab-ci-check-approve.yml'
    ref: v1.0.0

Вы явно не поняли реализацию. Сейчас опишу, так, как я ее вижу и как я ее благополучно реализовал на своем проекте рабочем.
Я взял тот блок кода на bash из .gitlab-ci-check-approve.yml и переписал "на коленках" его на python(код не жалко, можно спокойно использовать):

import os
import requests
import sys

def main():
    gitlab_token = os.getenv("CI_GITLAB_API_TOKEN")
    api_url = os.getenv("CI_API_V4_URL")
    project_id = os.getenv("CI_PROJECT_ID")
    commit_sha = os.getenv("CI_COMMIT_SHA")
    target_branch = os.getenv("CI_MERGE_REQUEST_TARGET_BRANCH_NAME")
    approval_authors = os.getenv("APPROVAL_AUTHORS", "").split(',')

    # Получаем информацию о merge request
    response = requests.get(
        f"{api_url}/projects/{project_id}/merge_requests",
        headers={"PRIVATE-TOKEN": gitlab_token}
    )
   
    merge_requests = response.json()
    #print(merge_requests)

    mr_info = [mr for mr in merge_requests if mr['sha'] == commit_sha and mr['state'] == "opened" and mr['target_branch'] == target_branch]

    if not mr_info:
       print("Merge request not found.")
       sys.exit(1)

    mr_id = mr_info[0]["iid"]

    # Получаем approval
    response = requests.get(
        f"{api_url}/projects/{project_id}/merge_requests/{mr_id}/approvals",
        headers={"PRIVATE-TOKEN": gitlab_token}
    )
    approvals = response.json()

    approved = False
    for author in approval_authors:
        if any(user['user']['username'] == author for user in approvals['approved_by']):
            approved = True
        break

    if approved:
        print("Great job! Your merge request has been approved!")
    else:
        print(f"Almost there! Please get approval from one of the following users: {', '.join(approval_authors)} to proceed.")
        sys.exit(1)

if __name__ == "__main__":
    main()

Дальше мы его компилируем и получаем бинарный файл:
pyinstaller --onefile approved.py

А дальше все еще проще:)
Мы кладем бинарь на сервер в /usr/local/bin, где у нас обитает gitlab-runner и дописываем основной gitlab-ci.yml у нужного проекта, где мы просто указываем доп стадию:

stages:
  - check_ap
  - Build
  - test
  - deploy

check_approv:
  stage: check_ap
  script:
    - approved
  variables:
    CI_GITLAB_API_TOKEN: ${CI_GITLAB_API_TOKEN}
    APPROVAL_AUTHORS: "i.ivanov"
  rules:
    - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "stage"'
  tags:
    - docker

Перед этим обязательно нужно выполнить Шаг 1-4, которые описал автор этой статьи.
И все, апрув чек благополучно работает, так как задумал автор:

Almost there! Please get approval from one of the following users: i.ivanov to proceed.
Cleaning up project directory and file based variables00:00
ERROR: Job failed: exit status 1
Great job! Your merge request has been approved!
Cleaning up project directory and file based variables
Job succeeded

Итого мы имеем:
1) Завернули реализацию как отдельный мини сервис. Для его компиляции мучится не нужно, одна команда на сбор бинарника и в путь.
2) Если нужны доработки(например отправлять пуши ответственным, если кинули мерж), то завел отдельный проект, дорабатывай спокойно скрипт, собирай и скидывай на сервер с раннером. Все, если в ci не нужно будет дописывать переменные, то проекты вообще трогать не нужно для изменения.
3) Удобно подключать проекты, где такая проверка нужна. У меня 100+ реп в gitlab и намного проще и удобнее добавить одну стадию в уже готовый gitlab-ci.yaml и все.
Не нужно создавать доп ci манифесты на каждом проекте (-1-2 действия в экономии времени)
Переменные вообще можно сделать глобальные для групп в гитлабе.
4) Простой и читаемый код(который 100% можно еще лучше сделать. Повторюсь написал пример на коленках). Да можно с таким же методом использовать bash, но bash скрипты очень плохо читаются. Смотришь на эту "кашу" и хочется закрыть сразу :)

Я же правильно понимаю что ничего автоматом при простановке аппрувов происходить не будет, и надо руками перезапускать пайплайн, чтобы он осознал изменившееся количество голосов?

Привет, ага, пайплайн придется перезапускать, в рамках задачи это удовлетворило заказчика

Пишут что можно ранить на аппруве. https://stackoverflow.com/a/63893810

rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"'

При аппруве не возникает никакого события, пайплайн все равно нужно перезапускать руками. Или вы нашли конкретное решение?

Поискал в доках и нечего не нашёл, что именно этот event значит. Видимо да никакого события на апруве не выкидывается.

Выяснил, что можно провернуть это через веб-хуки. При нажатии на аппрув гитлаб дёргает хук, отправляет инфу в мерж-эвенте, а наш сервис после получения такого запроса перезапускает пайп через гитлаб апи.

- echo "${GITLAB_TOKEN_FOR_CI}"


Гитлаб заменяет это звёздачками в выводе?

Да, если прожать у переменной галочку соответствующую, я это вставил для тестирования больше)

Не кидайте тапками за неоптимальность скрипта, да, можно написать более элегантно, не забирая лишнюю информацию, сократив сам код и т.д. Суть не в этом.

Выкладывать от лица компании которая предоставляет услуги DevOps в публичное пространство такой код не стоит. Это в том числе говорит о качестве предоставляемых услуг.

Привет, от чего же? Вы же сами процитировали фразу - суть не в этом.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий