I recently made the move, for a variety of reasons, from a public Github profile to private git infrastructure. One of the solutions I tried was Gitea, an opensource, self-hosted solution with a Github-like UI and a very accessible API.
Gitea has facilities in the UI to import repositories, but I had a lot of repos to recreate, and wanted to migrate quickly, so I wrote a script to consume both ends’ APIs:
Import the Github python client, and the os
, re uests
, and json
packages into your script, and plugin your Github and Gitea credentials and endpoint (the server address) information:
from github import Github
import os
import json
import requests
#Github GH_ACCESS_TOKEN = os.environ['GH_ACCESS_TOKEN']
#Gitea GITEA_ACCESS_TOKEN = os.environ['GITEA_ACCESS_TOKEN']
GITEA_USER = ""
GITEA_PASS = ""
TARGET_HOST = "https://git.yourserver.co"
MIGRATE_URI = "/api/v1/repos/migrate"
ENDPOINT = "%s%s" % (TARGET_HOST, MIGRATE_URI)
g = Github(GH_ACCESS_TOKEN)
EXCLUDE = []
and in EXCLUDE
, put in a comma-delimited list of repo names from Github you don’t want to migrate, i.e.:
EXCLUDE = ["repo1", "repo2"...]
Our first function will just build a list of your repos, and some pertinent information relevant to Gitea required for create a new repo on that end, mostly just the name, description, whether or not it’s private, and the URL to clone from:
def getRepos(g):
repos = []
for repo in g.get_user().get_repos():
r = {}
r['name'] = str(repo.name)
r['url'] = str(repo.url)
r['description'] = str(repo.description)
r['private'] = str(repo.private)
repos.append(r)
return repos
This returns a list of dictionaries structured like:
{"name": "repo_name", "url": "https://github.com/...", ... }
The next function we’ll start will ingest an object like the one above to create a new respository:
def createRepo(source_url,name,description,private):
headers = { "accept": "application/json", "content-type": "application/json" }
headers["Authorization"] = "token %s" % (GITEA_ACCESS_TOKEN)
migrate_data = { "mirror": "false", "uid": 1 }
migrate_data["auth_password"] = "%s" % (GITEA_PASS)
migrate_data["auth_username"] = "%s" % (GITEA_USER)
migrate_data["description"] = "%s" % (description)
migrate_data["repo_name"] = "%s" % (name)
migrate_data["private"] = "%s" % (private)
migrate_data["clone_url"] = "%s" % (source_url)
...
The above is creating the required authentication headers, and then the request body with the repo data we specified in the getRepos
function. We’ll finish this function by sending this request:
...
try:
r = requests.post(url=ENDPOINT, data=json.dumps(migrate_data), headers=json.dumps(headers))
if r.status_code != 200:
return "Non-OK Response: %s" % (r.status_code)
else:
return "Done: %s" % (source_url)
except Exception as e:
return e
Now, to connect these two tasks together, we’re going to create a handler to create the repository list, and then instantiate our second function to create the new repo from it:
def runMigration(r,x):
exclude_repos = x
for repo in r:
if repo not in exclude_repos:
print "Working on %s" % (repo['name'])
print createRepo(repo['url'],repo['name'],repo['description'],repo['private'])
else:
print "Excluding %s" % (repo['name'])
return "Done"
You’ll see this iterates the repo list, checks that you have not excluded it, and then creates the new repo.
Putting it all together, it will look like this, and be ready to run:
For whatever your given git solution, a script like this can similarly process data from Github, and create new repos on the new host (if it has an API, a similar flow for your createRepo
function will likely suffice! However, you can use that fed data, and use a library like GitPython to create the new clone locally, etc.)–this can help make such a move to a decentralized platform just that much more painless!
暂无评论内容