Процесс миграции нередко представляет собой трудную задачу, особенно, когда объем информации, который необходимо перенести, настолько велик, что выгоднее становится его автоматизировать. Именно необходимость миграции с Gitolite на GitLab и побудила меня написать статью о моем опыте в данном вопросе.

Для миграции репозиториев я буду использовать компьютер с установленной операционной системой CentOS 7. На ней необходимо установить следующий набор приложений: git, ssh-agent, curl, jq, xargs.
Для начала работы нам необходимо получить ключ доступа к API GitLab. В веб-интерфейсе заходим в раздел настройки пользователя. Далее выбираем пункт меню «Access Tokens». В открывшейся форме необходимо указать наименование получаемого ключа, а также можно указать срок, до которого ключ будет активен. Ниже ставим галочку напротив пункта api и нажимаем кнопку «Create personal access token». Этот ключ будет применяться при отправке запросов в API GitLab.
-
Подготовка рабочей среды
Для того чтобы мы могли загружать код в репозиторий GitLab по SSH, необходимо сгенерировать пару приватного и публичного ключей, выполнить регистрацию публичного ключа в GitLab. Для регистрации публичного ключа в панели администратора GitLab «Admin area» заходим в раздел «Deploy keys» и нажимаем кнопку «New deploy key». В открывшейся форме необходимо указать наименование загружаемого ключа, а также сам публичный ключ. После добавления ключа, нам необходимо определить идентификатор данного ключа в системе GitLab. Чтобы определить его мы можем выполнить следующий команду в bash:
curl -k -X GET --header "PRIVATE-TOKEN: <your private token>" <gitlab url>/api/v4/deploy_keysПримечание: Чтобы не вводить пароль от приватного SSH ключа при выполнении действий git с сервером, необходимо добавить данный ключ в ssh-agent. Для этого выполним следующие команды:
eval `ssh-agent`ssh-add ~/.ssh/id_rsa -
Создание репозитория в GitLab с использованием API
Чтобы создать репозиторий в GitLab, необходимо отправить POST запрос в API GitLab, передав параметры, согласно документации. Подробнее о Projects API GitLab читайте в документации на сайте GitLab.
# $1 - gitlab remote url # $2 - api access token # $3 - remote repository name # $4 - remote repository namespace identifier initRemoteRepository() { local response=`curl -s -k -X POST --header "Private-Token: $2" --data "name=$3&namespace_id=$4&visibility=private&description=$3" $1/api/v4/projects` local id=`echo $response | jq -r ".id"` echo "$id" }Функция initRemoteRepository возвращает идентификатор созданного репозитория. В дальнейшем идентификатор репозитория будет использоваться для установки прав доступа.
Примечание: ключ –k необходим, если серверный сертификат GitLab является самозаверенным. -
Предоставление доступа на запись и чтение репозитория с использованием API
Для того, чтобы выполнить запись в созданный репозиторий, необходимо выдать соответствующее право. Подробнее о Deploy Keys API GitLab читайте в документации на сайте GitLab.
# $1 - remote url # $2 - api token # $3 - repository identifier # $4 - deploy key identifier setRepositoryWriteAccess() { local response=`curl -s -k -X PUT --header "PRIVATE-TOKEN: $2" --header "Content-Type: application/json" --data '{"can_push": true}' $1/api/v4/projects/$3/deploy_keys/$4` echo "$response" }Функция enableRepositoryDeployKey позволяет добавить публичный ключ с соответствующим идентификатором в список ключей соответствующего рапозитория.
# $1 - remote url # $2 - api token # $3 - repository identifier # $4 - deploy key identifier enableRepositoryDeployKey() { local response=`curl -s -k -X POST --header "Private-Token: $2" $1/api/v4/projects/$3/deploy_keys/$4/enable` echo "$response" }Функция setRepositoryWriteAccess позволяет установить доступ на запись в конкретный репозиторий.
-
Мигрирация репозиториев включая все ветки
Основной скрипт перебирает список репозиториев, указанных в заранее заданном файле. Создается соответствующий репозиторий в GitLab, а также выдаются привелегии для чтения и записи. После подготовительных действий выполняется запрос веток данного репозитория. Далее выполняется переключение на очередную ветку репозитория и отправка в GitLab.
# $1 - branch # $2 – separator getCanonicalBranchName() { local branch="" IFS=$2 read -r -a array <<< "$1" length=${#array[@]} for index in "${!array[@]}" do if [ $index -gt 0 ]; then if [ $index -eq 1 ]; then local branch="${array[index]}" else local branch="$branch/${array[index]}" fi fi done echo "$branch" } PSWD="$(dirname "$0")" cd $PSWD while IFS= read -r REPOSITORY do echo "==================== <$REPOSITORY> ====================" GITOLITE_REPO=$GITOLITE$REPOSITORY echo "Run cloning remote repository $GITOLITE_REPO" git clone $GITOLITE_REPO cd $REPOSITORY GITLAB_REPO=$GITLAB$REPOSITORY.git echo "Initialize remote gitgab repository $GITLAB_REPO" PROJECT=$(initRemoteRepository $GITLAB_URL $API_TOKEN $REPOSITORY) echo "Remote repository initialized identifier $PROJECT" echo "Add deploy key and enable write access to remote repository $REPOSITORY ($PROJECT)" response=$(enableRepositoryDeployKey $GITLAB_URL $API_TOKEN $PROJECT $DEPLOY_KEY_ID) response =$(setRepositoryWriteAccess $GITLAB_URL $API_TOKEN $PROJECT $DEPLOY_KEY_ID) echo "Add new remote url for repository $GITLAB_REPO" git remote add gitlab $GITLAB_REPO # push all branches IFS_BACK=$IFS IFS=$'\n' branches=$(git branch -r) for branchName in $branches; do trimBranchName=`echo $branchName | xargs` canonicalBranchName=$(getCanonicalBranchName $trimBranchName '/') echo "$trimBranchName ($canonicalBranchName) init push" git checkout -b $canonicalBranchName remotes/origin/$canonicalBranchName git push -f gitlab $canonicalBranchName done IFS=$IFS_BACK cd .. rm -r -f $REPOSITORY echo "==================== <$REPOSITORY> ====================" echo "" done < "$REPOSITORIES"Сохраняем файл скрипта и запускаем, при необходимости изменив права доступа. Пример вывода работы данного скрипта можно посмотреть ниже.
REPOSITORIES="<repositories_file>" GITOLITE="<gitolite_ssh_url>" GITLAB_URL="<gitlab_api_url>" GITLAB="<gitolite_ssh_url>" API_TOKEN="<api_access_token>" DEPLOY_KEY_ID="<deploy_key_identifier>" # $1 - gitlab remote url # $2 - api access token # $3 - remote repository name # $4 - remote repository namespace identifier initRemoteRepository() { local response=`curl -s -k -X POST --header "Private-Token: $2" --data "name=$3&namespace_id=$4&visibility=private&description=$3" $1/api/v4/projects` local id=`echo $response | jq -r ".id"` echo "$id" } # $1 - remote url # $2 - api token # $3 - repository identifier # $4 - deploy key identifier setRepositoryWriteAccess() { local response=`curl -s -k -X PUT --header "PRIVATE-TOKEN: $2" --header "Content-Type: application/json" --data '{"can_push": true}' $1/api/v4/projects/$3/deploy_keys/$4` echo "$response" } # $1 - remote url # $2 - api token # $3 - repository identifier # $4 - deploy key identifier enableRepositoryDeployKey() { local response=`curl -s -k -X POST --header "Private-Token: $2" $1/api/v4/projects/$3/deploy_keys/$4/enable` echo "$response" } # $1 - branch # $2 – separator getCanonicalBranchName() { local branch="" IFS=$2 read -r -a array <<< "$1" length=${#array[@]} for index in "${!array[@]}" do if [ $index -gt 0 ]; then if [ $index -eq 1 ]; then local branch="${array[index]}" else local branch="$branch/${array[index]}" fi fi done echo "$branch" } PSWD="$(dirname "$0")" cd $PSWD while IFS= read -r REPOSITORY do echo "==================== <$REPOSITORY> ====================" GITOLITE_REPO=$GITOLITE$REPOSITORY echo "Run cloning remote repository $GITOLITE_REPO" git clone $GITOLITE_REPO cd $REPOSITORY GITLAB_REPO=$GITLAB$REPOSITORY.git echo "Initialize remote gitgab repository $GITLAB_REPO" PROJECT=$(initRemoteRepository $GITLAB_URL $API_TOKEN $REPOSITORY) echo "Remote repository initialized identifier $PROJECT" echo "Add deploy key and enable write access to remote repository $REPOSITORY ($PROJECT)" response=$(enableRepositoryDeployKey $GITLAB_URL $API_TOKEN $PROJECT $DEPLOY_KEY_ID) response=$(setRepositoryWriteAccess $GITLAB_URL $API_TOKEN $PROJECT $DEPLOY_KEY_ID) echo "Add new remote url for repository $GITLAB_REPO" git remote add gitlab $GITLAB_REPO # push all branches IFS_BACK=$IFS IFS=$'\n' branches=$(git branch -r) for branchName in $branches; do trimBranchName=`echo $branchName | xargs` canonicalBranchName=$(getCanonicalBranchName $trimBranchName '/') echo "$trimBranchName ($canonicalBranchName) init push" git checkout -b $canonicalBranchName remotes/origin/$canonicalBranchName git push -f gitlab $canonicalBranchName done IFS=$IFS_BACK cd .. rm -r -f $REPOSITORY echo "==================== <$REPOSITORY> ====================" echo "" done < "$REPOSITORIES"
==================== <project> ==================== Run cloning remote repository git@skynet-uro.bank.srv:project Cloning into 'project'... remote: Counting objects: 62, done. remote: Compressing objects: 100% (61/61), done. remote: Total 62 (delta 21), reused 0 (delta 0) Receiving objects: 100% (62/62), 15.57 KiB | 0 bytes/s, done. Resolving deltas: 100% (21/21), done. Current folder path: /app/migration/project Initialize remote gitgab repository git@127.0.0.1:project.git Remote repository initialized identifier 222 Enable deploy key write access to remote repository project (222) Set write access to remote repository project (222) Add new remote url for repository git@127.0.0.1:project.git Push to new remote gitlab repository git@127.0.0.1:project.git Counting objects: 55, done. Delta compression using up to 2 threads. Compressing objects: 100% (38/38), done. Writing objects: 100% (55/55), 14.65 KiB | 0 bytes/s, done. Total 55 (delta 18), reused 50 (delta 16) To git@127.0.0.1:project.git * [new branch] master -> master <--- gitlab/master (master) init push fatal: A branch named 'master' already exists. Everything up-to-date ---> gitlab/master (master) success pushed <--- origin/v0.0.0 (v0.0.0) init push Branch v0.0.0 set up to track remote branch v0.0.0 from origin. Switched to a new branch 'v0.0.0' Total 0 (delta 0), reused 0 (delta 0) remote: remote: To create a merge request for v0.0.0, visit: remote: https://127.0.0.1:8082/project/merge_requests/new?merge_request%5Bsource_branch%5D=v0.0.0 remote: To git@127.0.0.1:project.git * [new branch] v0.0.0 -> v0.0.0 ---> origin/v0.0.0 (v0.0.0) success pushed <--- origin/v0.0.0-13 (v0.0.0-13) init push Branch v0.0.0-13 set up to track remote branch v0.0.0-13 from origin. Switched to a new branch 'v0.0.0-13' Total 0 (delta 0), reused 0 (delta 0) remote: remote: To create a merge request for v0.0.0-13, visit: remote: https://127.0.0.1:8082/project/merge_requests/new?merge_request%5Bsource_branch%5D=v0.0.0-13 remote: To git@127.0.0.1:project.git * [new branch] v0.0.0-13 -> v0.0.0-13 ---> origin/v0.0.0-13 (v0.0.0-13) success pushed <--- origin/v0.0.0-15 (v0.0.0-15) init push Branch v0.0.0-15 set up to track remote branch v0.0.0-15 from origin. Switched to a new branch 'v0.0.0-15' Total 0 (delta 0), reused 0 (delta 0) remote: remote: To create a merge request for v0.0.0-15, visit: remote: https://127.0.0.1:8082/project/merge_requests/new?merge_request%5Bsource_branch%5D=v0.0.0-15 remote: To git@127.0.0.1:project.git * [new branch] v0.0.0-15 -> v0.0.0-15 ---> origin/v0.0.0-15 (v0.0.0-15) success pushed <--- origin/v0.0.1 (v0.0.1) init push Branch v0.0.1 set up to track remote branch v0.0.1 from origin. Switched to a new branch 'v0.0.1' Total 0 (delta 0), reused 0 (delta 0) remote: remote: To create a merge request for v0.0.1, visit: remote: https://127.0.0.1:8082/project/merge_requests/new?merge_request%5Bsource_branch%5D=v0.0.1 remote: To git@127.0.0.1:project.git * [new branch] v0.0.1 -> v0.0.1 ---> origin/v0.0.1 (v0.0.1) success pushed <--- origin/v0.0.1-11 (v0.0.1-11) init push Branch v0.0.1-11 set up to track remote branch v0.0.1-11 from origin. Switched to a new branch 'v0.0.1-11' Total 0 (delta 0), reused 0 (delta 0) remote: remote: To create a merge request for v0.0.1-11, visit: remote: https://127.0.0.1:8082/project/merge_requests/new?merge_request%5Bsource_branch%5D=v0.0.1-11 remote: To git@127.0.0.1:project.git * [new branch] v0.0.1-11 -> v0.0.1-11 ---> origin/v0.0.1-11 (v0.0.1-11) success pushed <--- origin/v0.0.2 (v0.0.2) init push Branch v0.0.2 set up to track remote branch v0.0.2 from origin. Switched to a new branch 'v0.0.2' Total 0 (delta 0), reused 0 (delta 0) remote: remote: To create a merge request for v0.0.2, visit: remote: https://127.0.0.1:8082/project/merge_requests/new?merge_request%5Bsource_branch%5D=v0.0.2 remote: To git@127.0.0.1:project.git * [new branch] v0.0.2 -> v0.0.2 ---> origin/v0.0.2 (v0.0.2) success pushed <--- origin/v0.0.3 (v0.0.3) init push Branch v0.0.3 set up to track remote branch v0.0.3 from origin. Switched to a new branch 'v0.0.3' Counting objects: 7, done. Delta compression using up to 2 threads. Compressing objects: 100% (4/4), done. Writing objects: 100% (4/4), 592 bytes | 0 bytes/s, done. Total 4 (delta 3), reused 1 (delta 0) remote: remote: To create a merge request for v0.0.3, visit: remote: https://127.0.0.1:8082/project/merge_requests/new?merge_request%5Bsource_branch%5D=v0.0.3 remote: To git@127.0.0.1:project.git * [new branch] v0.0.3 -> v0.0.3 ---> origin/v0.0.3 (v0.0.3) success pushed ==================== <project> ====================
ссылка на оригинал статьи https://habr.com/ru/post/492122/
Добавить комментарий