Задача: проработать простую пошаговую настройку Git-репозитория на сервере хранения "GitLab", ориентированную на следующие основные положения методики управления данными ("workflow"):
1. Репозиторий используется для хранения любого дерева веток, но подразумевается наличие как минимум трёх: "master", "testing" и "develop";
2. В "develop" и ответвлениях "feature" ведётся разработка - с ними можно делать что угодно;
3. Ветка "testing" по правам доступа аналогична "develop" - но выгрузка в неё запускает автоматизацию процедур тестирования;
4. Выгрузка в "master" напрямую запрещена - только вливание из "testing" с предварительным "pull request"-ом, который должен быть одобрен руководителем - после чего запускаются автоматизированные процедуры публикации.
2. В "develop" и ответвлениях "feature" ведётся разработка - с ними можно делать что угодно;
3. Ветка "testing" по правам доступа аналогична "develop" - но выгрузка в неё запускает автоматизацию процедур тестирования;
4. Выгрузка в "master" напрямую запрещена - только вливание из "testing" с предварительным "pull request"-ом, который должен быть одобрен руководителем - после чего запускаются автоматизированные процедуры публикации.
Создание группы и Git-репозитория в таковой.
В современных web-сервисах, в частности "GitLab CE Server", создание группы репозиториев и Git-репозитория в таковой не представляет сложности и не требует особого описания - пара нажатий на кнопки, заполнение полей именований и описаний, и вот у нас есть место на сервере хранения, куда уже можно загружать данные.
Обращу внимание на неочевидную особенность именований сущностей группы репозиториев:
"group name" - это отображаемое условное наименование (например "Our first group") и его можно безвредно изменить в любой момент;
(элемент) "group path" - это уникальный идентификатор группы (например "group-01") и его крайне нежелательно изменять в последствии, так как только через него возможна идентификация группы репозиториев в процедурах автоматизации.
(элемент) "group path" - это уникальный идентификатор группы (например "group-01") и его крайне нежелательно изменять в последствии, так как только через него возможна идентификация группы репозиториев в процедурах автоматизации.
В дальнейшем URI для доступа к созданному репозиторию в группе таковых будет выглядеть так:
https://gitlab.example.net/group_path/repo.git
Настройки группы репозиториев.
Ограничиваем видимость группы репозиториев, разрешая это только явно заданным далее пользователям, а также отключаем поддержку хранения больших файлов (LFS) отдельно от репозитория (эта функциональность требует отдельного навыка, не всегда имеющегося у разработчиков):
Group -> Group settings:
Visibility Level: Private
Large File Storage: false
Visibility Level: Private
Large File Storage: false
Задаём разрешения доступа к группе репозиториев (эта политика распространяется на все репозитории группы, но может быть переопределена):
Group -> Members:
Member: user-one
Role: Developer
Expiration date: none
Member: user-one
Role: Developer
Expiration date: none
Установка ограничений на запись в "master".
К сожалению, насколько я уловил, в "GitLab Community Edition (Standalone) Server" (в отличие от "BitBucket (Standalone) Server") групповые политики ограничений доступа к веткам наследуемого типа не поддерживаются - приходится устанавливать их точечно.
В настройках репозитория применим ограничивающие правила записи в ветку "master", запретив прямую загрузку (push) в неё кому бы то ни было, и разрешив вливание (merge) из других ветвей только руководителям проекта (по умолчанию "masters" - в терминологии "GitLab"):
Group -> Repository -> Repository Settings -> Protected Branches:
Branch: master
Allowed to merge: Masters
Allowed to push: No one
Branch: master
Allowed to merge: Masters
Allowed to push: No one
Если используется платный продукт "GitLab Enterprise Edition (EE)" (documentation, documentation), то в настройках репозитория укажем пользователей, которые в обязательном порядке должны будут проводить "review" кода и одобрение такового для всех поступающих "merge request":
Group -> Repository -> Repository Settings -> General -> Merge request approvals:
No. approvals required: 2 - минимум два пользователя должны одобрить загрузку,
Members: teamlead, manager - пользователи, проводящие проверку.
No. approvals required: 2 - минимум два пользователя должны одобрить загрузку,
Members: teamlead, manager - пользователи, проводящие проверку.
У бесплатного варианта "GitLab Community Edition (CE)" возможности организации процесса разработки существенно скромнее - можно лишь задать в настройках репозитория пользователя (или несколько таковых), исполняющего роль руководителя процесса разработки и обладающего правом вливания (merge) в ветку "master" (обычно по завершению процедуры одобрения поступившего "pull request"):
Group -> Repository -> Members:
Member: user-one
Role: Master
Expiration date: none
Member: user-one
Role: Master
Expiration date: none
В дополнение к вышеуказанным настройкам разрешения на вливание в защищённые ветви потребуем предварительного одобрения вносимых изменений всеми пользователями, проводящими "review" поступающих "pull request" - это снизит вероятность внесения несогласованных изменений:
Group -> Repository -> General Settings -> Merge request settings:
Merge method:
Merge commit.
....
Only allow merge requests to be merged if all discussions are resolved: true
Merge method:
Merge commit.
....
Only allow merge requests to be merged if all discussions are resolved: true
Теперь, при попытке сделать выгрузку (push) напрямую в "master" мы получим отказ:
$ git clone --branch master https://gitlab.example.net/group/repo.git
$ cd ./test && vi ./probe.txt && $ git add --all && $ git commit -m "Probe push to master"
$ git push -u origin master
$ cd ./test && vi ./probe.txt && $ git add --all && $ git commit -m "Probe push to master"
$ git push -u origin master
....
remote: GitLab: You are not allowed to push code to protected branches on this project.
To https://gitlab.example.net/group/repo.git
! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://gitlab.example.net/group/repo.git'
remote: GitLab: You are not allowed to push code to protected branches on this project.
To https://gitlab.example.net/group/repo.git
! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://gitlab.example.net/group/repo.git'
Индивидуальные настройки репозитория хранения.
Сразу после загрузки данных в свежий репозиторий есть смысл произвести некоторые настройки для удобства его дальнейшей эксплуатации.
Заранее создаём ветви "testing" и "develop" (предполагая, что первичная загрузка была в "master"):
Group -> Repository -> Branches -> New branch:
Branch name: testing
Create from: master
Branch name: testing
Create from: master
Задаём ветку, в которую пользователь попадает по умолчанию, при обращении к функционалу просмотра содержимого репозитория:
Group -> Repository -> General Settings:
Default Branch: develop
Default Branch: develop
В настройках репозитория задаём уровень видимости репозитория, деактивируем дополнительный функционал справочной (Wiki), разделения блоков кода (Snippets) и отключаем поддержку хранения больших файлов (LFS) отдельно от репозитория:
Group -> Repository -> Permissions:
Project visibility: Private
Wiki: false
Snippets: false
Repository -> Git Large File Storage: false
Project visibility: Private
Wiki: false
Snippets: false
Repository -> Git Large File Storage: false
Задаём разрешения доступа к репозиторию или проверяем и переопределяем их при необходимости, если они заданы на уровне группы:
Group -> Repository -> Members:
Member: user-one
Role: Developer
Expiration date: none
Member: user-one
Role: Developer
Expiration date: none
Пример очерёдности процедур работы с репозиториями "GitLab".
Запрашиваем из репозитория хранения актуальное содержимое ветви разработки и явно переключаемся в таковую:
$ git clone https://gitlab.example.net/group/repo.git
$ cd ./test
$ git branch
$ git checkout develop
$ cd ./test
$ git branch
$ git checkout develop
Вносим изменения в файлы, сверяем и фиксируем их в ветви "develop":
$ vi ./probe.txt
$ git status
$ git add --all
$ git commit -m "Probe Commit"
$ git log
$ git status
$ git add --all
$ git commit -m "Probe Commit"
$ git log
Выгружаем в репозиторий хранения наработки ветви "develop", воспользовавшись тем же адресом (web-интерфейс) и протоколом (HTTPS), что и при предыдущей загрузке (обычно эти параметры автоматически фиксируются Git-клиентом в конфигурационном файле ".git/config" локального репозитория):
$ git push -u origin develop
Username for 'https://gitlab.example.net': user-one
Password for 'https://user-one@gitlab.example.net':
....
To https://gitlab.example.net/group/repo.git
e1f0938..5cf06ed develop -> develop
Branch 'develop' set up to track remote branch 'develop' from 'origin'.
Password for 'https://user-one@gitlab.example.net':
....
To https://gitlab.example.net/group/repo.git
e1f0938..5cf06ed develop -> develop
Branch 'develop' set up to track remote branch 'develop' from 'origin'.
После успешной фиксации изменений в ветке разработке переходим в ветку "testing" локального репозитория:
$ git fetch https://gitlab.example.net/group/repo.git testing
$ git checkout testing
$ git checkout testing
Вливаем в ветку "testing" отличия, накопившиеся в ветке "develop":
$ git merge develop
Fast-forward
./probe.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
./probe.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
$ git status
$ git diff
$ git log
$ git diff
$ git log
При желании можно указать явно указать адрес репозитория хранения и протокол (SSH) выгрузки туда данных (учтите, что это работает только с аутентификацией посредством SSH-ключей):
$ git push ssh://git@gitlab.example.net/group/repo.git testing
В соответствии с логикой построения нашей схемы на событие выгрузки в "testing" должны сработать предусмотренные процедуры автоматизированного тестирования (разберём их в отдельной заметке).
Теперь идём в web-интерфейс "GitLab" и создаём запрос "(New) Merge Request" на вливание изменений из ветки "testing" в "master":
Group -> Repository -> Merge Requests -> New merge request:
Source branch: testing
Target branch: master
Source branch: testing
Target branch: master
Далее всё просто и очевидно - в версии "GitLab EE" назначенные или произвольно добавленные "Approvers" проверяют и одобряют, в версии "GitLab CE" кто-то из уполномоченных "Masters" проверяет и одобряет, после чего отдаёт команду влить изменения.
В соответствие с логикой построения нашей схемы на событие выгрузки в "master" должна сработать автоматизация публикации, которая будет рассмотрена в отдельной публикации.