-
-
Save benoitzohar/57a93f8edc2a679e360e to your computer and use it in GitHub Desktop.
| #!/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 |
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 !
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'
)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?
Figured out my issues... it was a firewall issues with the gitlab and gitolite... working now. Great Script!!
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