Skip to content

Instantly share code, notes, and snippets.

@endquote
Last active March 2, 2017 15:29
Show Gist options
  • Save endquote/ead21f78b83901563ff3 to your computer and use it in GitHub Desktop.
Save endquote/ead21f78b83901563ff3 to your computer and use it in GitHub Desktop.
Migrate private repositories from your GitHub organization to your Bitbucket team.
/*
To use:
* save this script as migrate.js
* fill in the user/pass variables at the top
* save the block of json below as package.json right next to it
* install node.js from nodejs.org
* run 'npm install' from the directory where you saved the files
* run 'node migrate.js'
* profit
{
"dependencies": {
"async": "^0.9.0",
"fs.extra": "^1.3.2",
"github": "^0.2.4",
"request": "^2.55.0",
"underscore": "^1.8.3"
}
}
*/
var GitHubApi = require('github');
var request = require('request');
var child_process = require('child_process');
var async = require('async');
var fs = require('fs.extra');
var path = require('path');
var _ = require('underscore');
// fill in this stuff
var githubUser = '';
var githubPass = '';
var githubOrg = '';
var bitbucketUser = '';
var bitbucketPass = '';
var bitbucketTeam = '';
var checkoutDir = 'git';
var threads = 10;
var github = new GitHubApi({
version: '3.0.0'
});
async.waterfall([
// Wipe out previous checkouts
function(callback) {
fs.rmrf(checkoutDir, callback);
},
// Make a directory to check out to
function(callback) {
fs.mkdir(checkoutDir, 0777, callback);
},
// Auth to GitHub
function(callback) {
github.authenticate({
type: 'basic',
username: githubUser,
password: githubPass
});
callback();
},
// Get the list of repositories
function(callback) {
github.repos.getFromOrg({
org: githubOrg,
type: 'all',
per_page: 100
}, callback);
},
], function(error, data) {
// Ignore public repos, they can stay on GitHub.
var repos = _.filter(data, function(repo) {
return repo.private;
});
console.log(repos.length + ' repositories found.');
async.eachLimit(repos, threads, function(item, callback) {
var index = repos.indexOf(item) + 1;
var prompt = index + '/' + repos.length + ' - ' + item.name + ' - ';
async.waterfall([
// Clone the repo from GitHub
function(callback) {
console.info(prompt + 'cloning from GitHub');
child_process.exec('git clone --mirror ' + item.clone_url, {
cwd: path.join(__dirname, checkoutDir)
}, function(error, stdout, stderr) {
callback(error);
});
},
// Set the new remote
function(callback) {
console.info(prompt + 'setting remote ');
var remote = 'https://' + bitbucketUser + '@bitbucket.org/' + bitbucketTeam + '/' + item.name + '.git';
child_process.exec('git remote set-url --push origin ' + remote, {
cwd: path.join(__dirname, checkoutDir, item.name + '.git')
}, function(error, stdout, stderr) {
callback(error);
});
},
// Delete the Bitbucket repo if it exists.
function(callback) {
console.info(prompt + 'deleting Bitbucket repo');
request
.del('https://bitbucket.org/api/2.0/repositories/' + bitbucketTeam + '/' + item.name.toLowerCase(), function(error, response, body) {
callback();
})
.auth(bitbucketUser, bitbucketPass);
},
// Create the new Bitbucket repo.
function(callback) {
console.info(prompt + 'creating Bitbucket repo');
request
.post('https://bitbucket.org/api/2.0/repositories/' + bitbucketTeam + '/' + item.name.toLowerCase(), function(error, response, body) {
body = JSON.parse(body);
error = body.error;
callback(error);
})
.form({
name: item.name,
description: item.description,
is_private: true,
scm: 'git',
has_issues: false,
has_wiki: false
})
.auth(bitbucketUser, bitbucketPass);
},
// Push the repo to Bitbucket
function(callback) {
console.info(prompt + 'pushing to Bitbucket');
child_process.exec('git push --mirror', {
cwd: path.join(__dirname, checkoutDir, item.name + '.git')
}, function(error, stdout, stderr) {
callback(error);
});
},
// Delete the checkout
function(callback) {
console.info(prompt + 'deleting clone');
fs.rmrf(path.join(__dirname, checkoutDir, item.name + '.git'), function(error) {
callback(error)
});
}
], function(error, result) {
// Go on to the next one
if (error) {
console.error(prompt + error);
} else {
callback();
}
});
});
});
@fro
Copy link

fro commented Apr 30, 2015

Great job, useful stuff.

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