Last active
October 26, 2020 22:38
-
-
Save bjeanes/c8610fe1842cb401d8e34ba7159adae1 to your computer and use it in GitHub Desktop.
scrappy script to migrate Gitlab->Gitea
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
## NOTE: sometimes (probably because GL can't handle load) the repo is created but the import/migrate fails. | |
## go to <gitea>/admin/repos?sort=size to find 0-byte repos, delete them, and try again. Unfortunately, | |
## deleting these repos (either because of that page or because the repo isn't fully initialised) doesn't | |
## clean up on disk, so I had to manually `rm -rf` them too. | |
require 'json' | |
require 'uri' | |
require 'net/https' | |
require 'pry-byebug' | |
GITLAB_TOKEN = 'REPLACE ME WITH ADMIN + READ_REPO TOKEN' | |
GITEA_TOKEN = 'REPLACE ME' | |
GITLAB_HEADER = {'Authorization' => "Bearer #{GITLAB_TOKEN}"} | |
GITEA_HEADER = { | |
'Accept' => 'application/json', | |
'Authorization' => "token #{GITEA_TOKEN}", | |
'Content-Type' => 'application/json', | |
} | |
$gitea = Net::HTTP.new('git.bjeanes.com', 443) | |
$gitea.use_ssl = true | |
$gitlab = Net::HTTP.new('gitlab.bjeanes.com', 443) | |
$gitlab.use_ssl = true | |
# hacky "cache" to skip migrated ones when re-runnign script, due to GitLab's incredibly slow API | |
$migrated_file = File.open('./migrated.txt', 'a+') | |
$migrated = File.readlines('./migrated.txt').map(&:chomp) | |
def each_gitlab_repo(&block) | |
path = '/api/v4/projects?pagination=keyset&per_page=10&order_by=id&sort=asc' | |
loop do | |
resp = $gitlab.get(path, GITLAB_HEADER) | |
data = JSON.parse(resp.body) | |
data.each(&block) | |
next_path = Array(resp.to_hash['link']).grep(/rel="next"/)[0].to_s.scan(/<(.*?)>/).flatten.first | |
return unless next_path | |
path = URI.parse(next_path).request_uri | |
end | |
end | |
def create_gitea_org(name) | |
$created_orgs ||= [] | |
return true if $created_orgs.include?(name) | |
resp = $gitea.post("/api/v1/orgs", JSON.generate({visibility: :private, username: name}), GITEA_HEADER) | |
if resp.code == "201" || resp.body.match("user already exists") | |
puts "Created org #{name}" if resp.code == 201 | |
$created_orgs << name | |
else | |
$migrated_file.close | |
raise resp.body | |
end | |
end | |
def migrate(repo) | |
return if $migrated.include?(repo["path_with_namespace"]) | |
owner, repo_name = repo["path_with_namespace"].split('/', 2) | |
# Everything under this account on my GL is a stale mirror of GH account. | |
# I will pull these into Gitea separately so they stay as up-to-date mirrors | |
if owner == "bjeanes" | |
return | |
else | |
create_gitea_org(owner) | |
end | |
# Gitea doesn't support nested namespaces, unlike GitLab :( | |
# See https://github.com/go-gitea/gitea/issues/1872 | |
repo_name = repo_name.gsub('/','__') | |
is_private = repo["visibility"] == "private" | |
resp = $gitea.post("/api/v1/repos/migrate", JSON.generate({ | |
service: "gitlab", | |
private: is_private, | |
clone_addr: repo["http_url_to_repo"], | |
repo_owner: owner, | |
repo_name: repo_name, | |
auth_token: GITLAB_TOKEN, | |
mirror: false, | |
issues: false, | |
labels: false, | |
milestones: false, | |
releases: false, | |
pull_requests: false, | |
wiki: false, | |
}), GITEA_HEADER) | |
if resp.code == "201" | |
puts "Repo #{owner}/#{repo_name} created and queued for import :)" | |
elsif resp.code == "409" && resp.body.match("Files already exist for this repository") | |
# I had to fix these manually by `rm -rf` the files under Gitea | |
puts "Gitea bug? Repo doesn't exist but can't be created" | |
return | |
elsif resp.code == "409" && resp.body.match("repository with the same name already exists.") | |
# Assume we already imported this so just skip | |
puts "Repo #{owner}/#{repo_name} already exists" | |
else | |
$migrated_file.close | |
raise resp.body | |
end | |
$migrated_file.puts repo["path_with_namespace"] | |
$migrated_file.flush | |
# Un-watch repo | |
$gitea.delete("/api/v1/repos/#{owner}/#{repo_name}/subscription", GITEA_HEADER) | |
end | |
each_gitlab_repo { |r| | |
next if r['path'] =~ /gitlab/ | |
migrate(r) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment