Skip to content

Instantly share code, notes, and snippets.

@benoitzohar
Last active September 3, 2017 09:29
Show Gist options
  • Select an option

  • Save benoitzohar/57a93f8edc2a679e360e to your computer and use it in GitHub Desktop.

Select an option

Save benoitzohar/57a93f8edc2a679e360e to your computer and use it in GitHub Desktop.
Migrate repositories from Gitolite to GitLab.
#!/usr/bin/php -qC
<?php
/******************************************************************************
*
* @file gitolab.php
* @author Benoit Zohar
* @link http://benoitzohar.fr/
* @last-edited 2015-01-09
* @description Migrate projects from Gitolite to GitLab
* @requisite cURL library for PHP
* @usage 1. Change the value of the private variables of the GitoLab class
* 2. Launch "php gitolab.php" to start the process
* 3. Enter Y or N to import each pre-specified project
*
******************************************************************************/
error_reporting(E_ALL ^ E_NOTICE);
class GitoLab {
//Gitolite prefix url (you'll need to have you ssh key configured to make this work)
private $gitolite_url = 'ssh://gitolite@gexample.com/';
//Gitlab API url prefix
private $gitlab_url = 'https://gitlab.example.com/';
//Gitlab ssh access prefoex
private $gitlab_ssh = 'git@gitlab.example.com';
//Gitlab private token (see Gitlab documentation)
private $gitlab_private_token = '1234567890AZERTY';
private $projects = array(
//there are two ways of defining the repositories you want to import:
//first: use the very nice long keys of an associative array:
array(
//Name of the project in gitolite (name of the repository)
'liteProjectName' => 'example',
//Complete name of the project in GitLab
'labProjectName' => 'ExampleLab',
//Repository name of the project in GitLab
'labProjectPath' => 'exampleLab',
//Namespace in GitLab (must already exist !)
'labNamespace' => 'NameSpaceEx',
//Namespace ID in GitLab (must already exist !) use the _ID_ (check GET http://example.com/api/v3/groups to get it)
'labNamespaceId' => '10',
//[Optionnal] : description of the project in gitlab
'labDescription' => 'DescriptionExample'
),
//second: use the quick'n'dirty "no-key" of a standard array: (the keys are in the same order.)
array(
'example','ExampleLab','exampleLab','NameSpaceEx','DescriptionExample'
)
);
//Root of temporary directory used to clone repositories
private $root_dir = '';
public function __construct() {
//init variables
if (empty($this->root_dir)) {
//if the temporary directory is not set: use the current directory of the script
$this->root_dir = getcwd();
}
//start Migration process
try {
$this->checkRights();
$this->startMigration();
}
catch(Exception $e) {
$this->cleanTemporaryDirectory();
die("An error occured : ".$e->getMessage()."\n\n");
}
$this->cleanTemporaryDirectory();
echo "\n\n";
}
private function checkRights() {
echo "Checking rights for directory ".$this->root_dir." ...\n";
if (!is_dir($this->root_dir)) throw new Exception("'".$this->root_dir."' is not a directory");
if (!is_writable($this->root_dir)) throw new Exception("'".$this->root_dir."' is not a writable");
}
private function startMigration() {
echo "Starting migration ... \n";
$autoyes = false; //set to true to automatically accept every repository
foreach($this->projects as $project) {
if (!$autoyes) $r = readline("Migrate project ".($project['liteProjectName'] ? $project['liteProjectName'] : $project[0])." (Y/N) ? ");
//set to auto true if the user uses YYY once.
if ($r === 'YYY') $autoyes = true;
if ($autoyes || empty($r) || strtolower($r) == 'y') {
if (array_key_exists('liteProjectName', $project)) {
$this->migrateProject(
$project['liteProjectName'],
$project['labProjectName'],
$project['labProjectPath'],
$project['labNamespace'],
$project['labNamespaceId'],
$project['labDescription']
);
} else if (!empty($project[0])) {
$this->migrateProject(
$project[0],
$project[1],
$project[2],
$project[3],
$project[4],
$project[5]
);
}
}
}
}
private function migrateProject($liteProjectName,$labProjectName,$labProjectPath,$labNamespace,$labNamespaceId,$labDescription = '') {
echo "Migrating project ".$liteProjectName." ...\n";
//create the projet on gitlab
$url = $this->gitlab_url.'api/v3/projects';
$data = array(
'name' => $labProjectName,
'path' => $labProjectPath,
'namespace_id' => $labNamespaceId
);
if (!empty($labDescription)) {
$data['description'] = $labDescription;
}
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("PRIVATE-TOKEN: ".$this->gitlab_private_token));
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$head = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if(!$head) {
throw new Exception("Could not curl ".$url);
}
if($httpCode != 201) { //201 for "created" for GitLab API
throw new Exception("Could not curl ".$url." httpcode=".$httpCode);
}
$path = 'gitolab-tmp/'.$labProjectPath;
//clone the project from gitolite
echo "> 'git clone --mirror ".$this->gitolite_url.$liteProjectName.".git \"".$path."\"'\n";
exec('git clone --mirror '.$this->gitolite_url.$liteProjectName.'.git "'.$path.'"');
//move inside temporary path
chdir($path);
//clean gitolite remote
echo "> 'git remote rm origin'\n";
exec('git remote rm origin');
//add gitlab remote
echo "> 'git remote add origin ".$this->gitlab_ssh.":".$labNamespace."/".$labProjectPath.".git'\n";
exec('git remote add origin '.$this->gitlab_ssh.':'.$labNamespace.'/'.$labProjectPath.'.git');
//push all branches to the new remote
echo "> 'git push --all'\n";
exec("git push --all");
//push all tags to the new remote
echo "> 'git push --tags'\n";
exec("git push --tags");
//go back to original dir
chdir($this->root_dir);
}
private function cleanTemporaryDirectory() {
echo "Cleaning temporary directory ...\n";
$this->rrmdir($this->root_dir."/gitolab-tmp");
}
//recursively remove directory
private function rrmdir($dir) {
if (is_dir($dir)) {
$objects = scandir($dir);
foreach ($objects as $object) {
if ($object != "." && $object != "..") {
if (filetype($dir."/".$object) == "dir") $this->rrmdir($dir."/".$object); else unlink($dir."/".$object);
}
}
reset($objects);
rmdir($dir);
}
}
}
new GitoLab(); // launch migration
@Ulrar
Copy link
Copy Markdown

Ulrar commented May 15, 2015

Hi,

I'm trying to use that to migrate but I get a "An error occured : Could not curl https://git.local/api/v3/projects httpcode=400"
Do you have any idea why ? May be the API changed since you did that script ?

Thanks a lot

@Ulrar
Copy link
Copy Markdown

Ulrar commented May 15, 2015

Okay my bad, the repository is created by the script, if it exists it does an error 400. Works fine now ! Thanks a lot for that script !

@tleish
Copy link
Copy Markdown

tleish commented May 21, 2015

Note: The quick'n'dirty "no-key" example has 5 elements in the array, but should have 6. It is missing the Gitlab Namespace ID ('labNamespaceId' => '10' in the associative array example).

Should look like:

//second: use the quick'n'dirty "no-key" of a standard array: (the keys are in the same order.)
array(
    'example','ExampleLab','exampleLab','NameSpaceEx','10','DescriptionExample'
)

@grobm
Copy link
Copy Markdown

grobm commented Dec 15, 2016

trying to use this script and I keep getting:

fatal: The remote end hung up unexpectedly
error: failed to push some refs to 'git@mygitlaburl:adminID/testing.git

Any ideas? cloning works fine... via commandline but "--clone" does not work inside the script.

CentOS 7 is the platform I have it running on?

@grobm
Copy link
Copy Markdown

grobm commented Dec 15, 2016

Figured out my issues... it was a firewall issues with the gitlab and gitolite... working now. Great Script!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment