НОВОСТИ [Из песочницы] Миграция с Gitolite на GitLab с помощью Shell скрипта

BDFINFO2.0
Оффлайн
Регистрация
14.05.16
Сообщения
11.398
Реакции
501
Репутация
0
Процесс миграции нередко представляет собой трудную задачу, особенно, когда объем информации, который необходимо перенести, настолько велик, что выгоднее становится его автоматизировать. Именно необходимость миграции с Gitolite на GitLab и побудила меня написать статью о моем опыте в данном вопросе.
6smhkn4gi8_7ngzatgsoijdvyti.png




Для миграции репозиториев я буду использовать компьютер с установленной операционной системой CentOS 7. На ней необходимо установить следующий набор приложений: git, ssh-agent, curl, jq, xargs.


Для начала работы нам необходимо получить ключ доступа к API GitLab. В веб-интерфейсе заходим в раздел настройки пользователя. Далее выбираем пункт меню «Access Tokens». В открывшейся форме необходимо указать наименование получаемого ключа, а также можно указать срок, до которого ключ будет активен. Ниже ставим галочку напротив пункта api и нажимаем кнопку «Create personal access token». Этот ключ будет применяться при отправке запросов в API GitLab.

  1. Подготовка рабочей среды



    Для того чтобы мы могли загружать код в репозиторий GitLab по SSH, необходимо сгенерировать пару приватного и публичного ключей, выполнить регистрацию публичного ключа в GitLab. Для регистрации публичного ключа в панели администратора GitLab «Admin area» заходим в раздел «Deploy keys» и нажимаем кнопку «New deploy key». В открывшейся форме необходимо указать наименование загружаемого ключа, а также сам публичный ключ. После добавления ключа, нам необходимо определить идентификатор данного ключа в системе GitLab. Чтобы определить его мы можем выполнить следующий команду в bash:


    curl -k -X GET --header "PRIVATE-TOKEN: " /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 ===================="
      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 "==================== ===================="
      echo ""
      done < "$REPOSITORIES"


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

Полный текст скрипта

REPOSITORIES=""
GITOLITE=""
GITLAB_URL=""
GITLAB=""
API_TOKEN=""
DEPLOY_KEY_ID=""
# $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 ===================="
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 "==================== ===================="
echo ""
done < "$REPOSITORIES"

Пример вывода в консоль

====================
====================
Run cloning remote repository [email protected]: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 [email protected]: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 [email protected]:project.git
Push to new remote gitlab repository [email protected]: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 [email protected]:project.git
* [new branch] master -> master
master (master) init push
fatal: A branch named 'master' already exists.
Everything up-to-date
---> gitlab/master (master) success pushed
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:
remote:
To [email protected]:project.git
* [new branch] v0.0.0 -> v0.0.0
---> origin/v0.0.0 (v0.0.0) success pushed
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:
remote:
To [email protected]:project.git
* [new branch] v0.0.0-13 -> v0.0.0-13
---> origin/v0.0.0-13 (v0.0.0-13) success pushed
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:
remote:
To [email protected]:project.git
* [new branch] v0.0.0-15 -> v0.0.0-15
---> origin/v0.0.0-15 (v0.0.0-15) success pushed
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:
remote:
To [email protected]:project.git
* [new branch] v0.0.1 -> v0.0.1
---> origin/v0.0.1 (v0.0.1) success pushed
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:
remote:
To [email protected]:project.git
* [new branch] v0.0.1-11 -> v0.0.1-11
---> origin/v0.0.1-11 (v0.0.1-11) success pushed
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:
remote:
To [email protected]:project.git
* [new branch] v0.0.2 -> v0.0.2
---> origin/v0.0.2 (v0.0.2) success pushed
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:
remote:
To [email protected]:project.git
* [new branch] v0.0.3 -> v0.0.3
---> origin/v0.0.3 (v0.0.3) success pushed
====================
====================
 
Сверху Снизу