Skip to content

Instantly share code, notes, and snippets.

@SimeonC
Last active December 20, 2021 02:34
Show Gist options
  • Save SimeonC/6fb3fb3688b58931fadf75f179804eb3 to your computer and use it in GitHub Desktop.
Save SimeonC/6fb3fb3688b58931fadf75f179804eb3 to your computer and use it in GitHub Desktop.
Scripts for migrating Gitlab content to Github

The above scripts require the following environment variables defined to use.

  • GITLAB_TOKEN a personal access token for gitlab
  • GITHUB_TOKEN a personal access token for github with all repo scopes
  • GITLAB_REPO the id of the Gitlab project as in the Settings > General page of the Gitlab project
  • GITHUB_REPO the 'owner/repository' string of the GitHub repository as in the url; https://github.com/owner/repository
#!/usr/bin/env /usr/local/bin/node
// jshint asi:true
// jshint esversion: 11
// jshint module:true
// jshint node:true
/**
Before running this script make sure all the tags for the releases are pushed to the GitHub repository as they were in Gitlab
*/
import childProcess from "child_process";
import fs from "fs";
import path from "path";
const { Octokit } = await installAndRequire("octokit");
const { Gitlab } = await installAndRequire("@gitbeaker/node");
const octokit = new Octokit({
userAgent: "node " + process.version,
auth: process.env.GITHUB_TOKEN,
});
const gitbeaker = new Gitlab({ token: process.env.GITLAB_TOKEN });
const gitlabRepositoryId = process.env.GITLAB_REPO;
if (!gitlabRepositoryId) {
throw new Error(
`"GITLAB_REPO" env var is required and set to the id as retrieved from gitlab settings page`
);
}
const githubOwnerRepo = process.env.GITHUB_REPO || "";
const [githubOwner, githubRepo] = githubOwnerRepo.split("/");
if (!githubOwner || !githubRepo) {
throw new Error(
`Valid "GITHUB_REPO" env var is required of the format "owner/project", '${githubOwnerRepo}' was passed`
);
}
const gitlabProject = await gitbeaker.Projects.show(gitlabRepositoryId);
const existingReleases = await gitbeaker.Releases.all(gitlabRepositoryId);
existingReleases.forEach(async ({ name, tag_name, description }) => {
console.log("uploading", name);
await octokit.request("POST /repos/{owner}/{repo}/releases", {
owner: githubOwner,
repo: githubRepo,
tag_name: tag_name,
name: name,
body: mapLinks(description),
});
});
function mapLinks(gitlabMarkdown) {
const linkRegexp = new RegExp(
`(\\[[^\\]]+\\])(?:\\(${gitlabProject.web_url
.replace("/", "\\/")
.replace(".", "\\.")}(?:\\/-\\/)?)([^\\)]*)\\)`,
"ig"
);
return gitlabMarkdown.replace(
linkRegexp,
(match, displayText, commitSlug) =>
`${displayText}(https://github.com/${githubOwnerRepo}${commitSlug})`
);
}
/**
* Sets up the ability to require global node packages.
*
* @return {object} Returns the required node package object
*/
async function globalRequire(packageName) {
const env = Object.assign({}, process.env);
env.PATH = path.resolve("/usr/local/bin") + ":" + env.PATH;
const globalNodeModulesDir =
childProcess
.execSync(npmBin() + " root -g", { env: env })
.toString()
.trim() + "/";
let packageDir = path.join(globalNodeModulesDir, packageName, "/");
//find package required by older versions of npm
if (!fs.existsSync(packageDir)) {
packageDir = path.join(
globalNodeModulesDir,
"npm/node_modules/",
packageName
);
}
// Package not found
if (!fs.existsSync(packageDir)) {
throw new Error("Cannot find global module '" + packageName + "'");
}
const packageMeta = JSON.parse(
fs.readFileSync(path.join(packageDir, "package.json")).toString()
);
const main = path.join(packageDir, packageMeta.main || packageMeta.files[0]);
return await import(main);
}
async function installAndRequire(module) {
try {
return await import(module);
} catch (e) {
try {
return await globalRequire(module);
} catch (e) {
installModule(module);
// Not catching error if one is thrown.
return await globalRequire(module);
}
}
}
/**
* Installs node module if it doesn't exit.)
*/
function installModule(module) {
// Allows one to run the npm command as if on the command line.
const execSync = childProcess.execSync;
const env = Object.assign({}, process.env);
env.PATH = path.resolve("/usr/local/bin") + ":" + env.PATH;
// Get the path to npm bin
const npm = npmBin();
// The install command
const cmd = npm + " install -g " + module;
console.log("Installing the " + module + " Node module...");
execSync(cmd, {
cwd: process.cwd(),
env: env,
})
.toString("utf8")
.trim();
console.log("Installation complete.");
}
/**
* Gets the path to your npm executable.
*
* @return {string} The full path to your npm executable
*/
function npmBin() {
const execSync = childProcess.execSync;
const env = Object.assign({}, process.env);
env.PATH = path.resolve("/usr/local/bin") + ":" + env.PATH;
// Get the path to npm bin
return execSync("which npm", { env: env }).toString("utf8").trim();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment