This commit is contained in:
mike 2024-06-18 00:57:09 -07:00
parent 17a6422b1b
commit 27a8f73390
3 changed files with 110 additions and 60 deletions

View File

@ -7,9 +7,10 @@ class API:
__DEFAULT_API_PATH = "/api/v1" __DEFAULT_API_PATH = "/api/v1"
def __init__(self): def __init__(self, verify_ssl, ca_bundle):
pass self.__verify_ssl = verify_ssl
self.__ca_bundle = ca_bundle
@staticmethod @staticmethod
def _make_api_base_url(hostname, port): def _make_api_base_url(hostname, port):
@ -20,17 +21,23 @@ class API:
return base return base
@staticmethod def get(self, hostname, port, token) -> gitea.Gitea:
def factory(hostname, port, token) -> gitea.Gitea:
url = API._make_api_base_url( url = API._make_api_base_url(
hostname=hostname, hostname=hostname,
port=port port=port
) )
ssl_verify_arg = True
if self.__verify_ssl is not None:
ssl_verify_arg = self.__verify_ssl
if self.__ca_bundle is not None:
ssl_verify_arg = self.__ca_bundle
g = gitea.Gitea( g = gitea.Gitea(
gitea_url=url, gitea_url=url,
token_text=token token_text=token,
verify=ssl_verify_arg
) )
return g return g

View File

@ -18,14 +18,13 @@ class Migrator:
self, self,
source_host, source_port, source_token, source_host, source_port, source_token,
destination_host, destination_port, destination_token, destination_host, destination_port, destination_token,
verify_ssl: bool = True, ca_bundle: str = None
): ):
# noinspection PyTypeChecker # noinspection PyTypeChecker
self.__logger: logging.Logger = None self.__logger: logging.Logger = None
self._init_logger() self._init_logger()
self.__verify_ssl = True
self.__source_host = source_host self.__source_host = source_host
self.__source_port = source_port self.__source_port = source_port
self.__source_token = source_token self.__source_token = source_token
@ -34,15 +33,24 @@ class Migrator:
self.__destination_port = destination_port self.__destination_port = destination_port
self.__destination_token = destination_token self.__destination_token = destination_token
self.__source_api = API.factory( self.__verify_ssl = verify_ssl
self.__ca_bundle = ca_bundle
api = API(
verify_ssl=self.__verify_ssl,
ca_bundle=self.__ca_bundle,
)
self.__source_api = api.get(
hostname=self.__source_host, hostname=self.__source_host,
port=self.__source_port, port=self.__source_port,
token=self.__source_token token=self.__source_token,
) )
self.__destination_api = API.factory( self.__destination_api = api.get(
hostname=self.__destination_host, hostname=self.__destination_host,
port=self.__destination_port, port=self.__destination_port,
token=self.__destination_token token=self.__destination_token,
) )
def _init_logger(self): def _init_logger(self):
@ -111,10 +119,7 @@ class Migrator:
return repo_name return repo_name
def set_verify_ssl(self, b: bool): """
self.__verify_ssl = b
def set_ca_bundle(self, bundle_path: str): def set_ca_bundle(self, bundle_path: str):
self.__logger.info("Setting certificate bundle path") self.__logger.info("Setting certificate bundle path")
@ -123,6 +128,10 @@ class Migrator:
self.__logger.info(f"Old path: {certifi.where()}") self.__logger.info(f"Old path: {certifi.where()}")
certifi.core._CACERT_PATH = bundle_path certifi.core._CACERT_PATH = bundle_path
self.__logger.info(f"New path: {certifi.where()}") self.__logger.info(f"New path: {certifi.where()}")
# TODO: JUST TESTING
self.__verify_ssl = bundle_path
"""
def migrate_entire_org( def migrate_entire_org(
self, self,
@ -165,19 +174,21 @@ class Migrator:
for repo in source_repos: for repo in source_repos:
repo: gitea.Repository repo: gitea.Repository
self.__logger.info(f"- {repo.get_full_name()}") self.__logger.info(f"- {repo.get_full_name()}")
assert False, "Poop"
repos_migrate = [] repos_migrate = []
repos_ignore = [] repos_ignore = []
go_right_now = False go_right_now = False
for repo in source_repos: for repo in source_repos:
repo: giteapy.Repository repo: gitea.Repository
while True: while True:
if interactive: if interactive:
response = input(f"Migrate repo #{repo.id} \"{repo.full_name}\" ? (Y)es, (N)o, (G)o right now, (Q)uit ==> ") response = input(
f"Migrate repo #{repo.id} \"{repo.full_name}\" ?"
" (Y)es, (N)o, (G)o right now, (Q)uit ==> "
)
response = response.lower() response = response.lower()
else: else:
response = "y" response = "y"
@ -205,28 +216,32 @@ class Migrator:
if go_right_now: if go_right_now:
break break
# # Announce repo destination names
self.__logger.info("") self.__logger.info("")
if len(repos_migrate): if len(repos_migrate):
self.__logger.info("Repos to migrate:") self.__logger.info("Repos to migrate:")
for repo in repos_migrate: for repo in repos_migrate:
repo: giteapy.Repository repo: gitea.Repository
destination_name = self._make_destination_repo_name(pattern=destination_repo_name, repo=repo) destination_name = self._make_destination_repo_name(
pattern=destination_repo_name, repo=repo
)
self.__logger.info( self.__logger.info(
f"#{repo.id} \"{repo.name}\"\n> \"{destination_name}\"" f"#{repo.id} \"{repo.name}\"\n> \"{destination_name}\""
) )
else: else:
self.__logger.info("No repos marked to migrate") self.__logger.info("No repos marked to migrate")
# Announce manually ignored repos
self.__logger.info("") self.__logger.info("")
if len(repos_ignore): if len(repos_ignore):
self.__logger.info("Repos to ignore:") self.__logger.info("Repos to ignore:")
for repo in repos_ignore: for repo in repos_ignore:
repo: giteapy.Repository repo: gitea.Repository
self.__logger.info(f"#{repo.id} \"{repo.name}\"") self.__logger.info(f"#{repo.id} \"{repo.get_full_name()}\"")
else: else:
self.__logger.info("No repos marked to ignore") self.__logger.info("No repos marked to ignore")
# Migrate
if len(repos_migrate): if len(repos_migrate):
confirmation = input("Do you confirm the above selections? Enter MIGRATE ==> ") confirmation = input("Do you confirm the above selections? Enter MIGRATE ==> ")
@ -242,7 +257,8 @@ class Migrator:
repos=repos_migrate repos=repos_migrate
) )
self.__logger.info( self.__logger.info(
f"{len(source_repos_successful)} of {len(repos_migrate)} repos successfully migrated." f"{len(source_repos_successful)} of {len(repos_migrate)}"
" repos successfully migrated."
) )
if len(source_repos_failed) > 0: if len(source_repos_failed) > 0:
self.__logger.error(f"Failed to migrate {len(source_repos_failed)} repos:") self.__logger.error(f"Failed to migrate {len(source_repos_failed)} repos:")
@ -256,7 +272,10 @@ class Migrator:
f"Failed to migrate repo: {repo.name}\n> {exception}" f"Failed to migrate repo: {repo.name}\n> {exception}"
) )
self._delete_migrated_repos(source_org_name=source_org, repos=source_repos_successful) self._delete_migrated_repos(
source_org_name=source_org,
repos=source_repos_successful
)
else: else:
self.__logger.info("Confirmation not received; Won't do anything.") self.__logger.info("Confirmation not received; Won't do anything.")
@ -296,9 +315,7 @@ class Migrator:
repo_key = repo.get_full_name() repo_key = repo.get_full_name()
topics_present = repo.get_topics() topics_present = repo.get_topics()
print(topics_present) repo_topics[repo_key] = topics_present
repo_topics[repo_key] = topics_present["topics"]
print(repo_topics[repo_key])
if self._check_required_topics( if self._check_required_topics(
topics_present=repo_topics[repo_key], topics_present=repo_topics[repo_key],
@ -334,9 +351,6 @@ class Migrator:
@staticmethod @staticmethod
def _check_required_topics(topics_present: list[str], topics_required: list[str]) -> bool: def _check_required_topics(topics_present: list[str], topics_required: list[str]) -> bool:
print("Required topics:", topics_required)
print("Present topics:", topics_present)
for topic in topics_required: for topic in topics_required:
if topic not in topics_present: if topic not in topics_present:
return False return False
@ -352,44 +366,75 @@ class Migrator:
repos: list repos: list
): ):
api_source, api_destination = self._get_org_apis() # api_source, api_destination = self._get_org_apis()
# destination_org = api_destination.org_get(org=destination_org_name)
# destination_org: giteapy.Organization
destination_org = api_destination.org_get(org=destination_org_name) api_dest_org = gitea.Organization.request(
destination_org: giteapy.Organization gitea=self.__destination_api,
self.__logger.info(f"Destination organization: {destination_org.full_name}") name=destination_org_name
api_source_repos = self._get_repo_api(
hostname=self.__source_host, port=self.__source_port,
token=self.__source_token
) )
self.__logger.info(f"Destination organization: {api_dest_org.full_name}")
source_repos_successful = [] source_repos_successful = []
source_repos_failed = [] source_repos_failed = []
for source_repo in repos: for source_repo in repos:
source_repo: giteapy.Repository source_repo: gitea.Repository
this_destination_repo_name = destination_repo_name.replace("%N%", source_repo.name) this_destination_repo_name = destination_repo_name.replace(
"%N%",
self.__logger.info(f"Migrating: {source_repo.name} ==> {this_destination_repo_name}") source_repo.name
source_repo_topics = api_source_repos.repo_list_topics(owner=source_repo.owner.login, repo=source_repo.name)
source_repo_topics = source_repo_topics.topics
migrate_body = giteapy.MigrateRepoForm(
mirror=False,
clone_addr=source_repo.clone_url,
uid=destination_org.id,
private=source_repo.private,
repo_name=this_destination_repo_name,
description=source_repo.description,
labels=True, issues=True, pull_requests=True, releases=True, milestones=True, wiki=True
) )
self.__logger.info(
f"Migrating: {source_repo.name} ==> {this_destination_repo_name}"
)
# source_repo_topics = api_source_repos.repo_list_topics(
# owner=source_repo.owner.login, repo=source_repo.name
# )
# source_repo_topics = source_repo_topics.topics
topics = source_repo.get_topics()
# migrate_body = giteapy.MigrateRepoForm(
# mirror=False,
# clone_addr=source_repo.clone_url,
# uid=destination_org.id,
# private=source_repo.private,
# repo_name=this_destination_repo_name,
# description=source_repo.description,
# labels=True, issues=True, pull_requests=True, releases=True, milestones=True, wiki=True
# )
# TODO: These three lines represent feature request to giteapy authors # TODO: These three lines represent feature request to giteapy authors
#migrate_body.auth_token = self.__source_token #migrate_body.auth_token = self.__source_token
#migrate_body.swagger_types["auth_token"] = "str" #migrate_body.swagger_types["auth_token"] = "str"
#migrate_body.attribute_map["auth_token"] = "auth_token" #migrate_body.attribute_map["auth_token"] = "auth_token"
destination_repo = gitea.Repository.migrate_repo(
gitea=self.__destination_api,
service: str,
clone_addr: str,
repo_name: str,
description: str = "",
private: bool = False,
auth_token: str = None,
auth_username: str = None,
auth_password: str = None,
mirror: bool = False,
mirror_interval: str = None,
lfs: bool = False,
lfs_endpoint: str = "",
wiki: bool = False,
labels: bool = False,
issues: bool = False,
pull_requests: bool = False,
releases: bool = False,
milestones: bool = False,
repo_owner: str = None,
)
self.__logger.debug("Migrate body:") self.__logger.debug("Migrate body:")
self.__logger.debug(migrate_body) self.__logger.debug(migrate_body)

View File

@ -138,13 +138,11 @@ def main():
source_token=args.source_token, source_token=args.source_token,
destination_host=args.destination_hostname, destination_host=args.destination_hostname,
destination_port=args.destination_port, destination_port=args.destination_port,
destination_token=args.destination_token destination_token=args.destination_token,
verify_ssl=args.verify_ssl,
ca_bundle=args.ca_bundle
) )
mig.set_verify_ssl(args.verify_ssl)
if args.ca_bundle:
mig.set_ca_bundle(args.ca_bundle)
mig.migrate_entire_org( mig.migrate_entire_org(
interactive=args.interactive, interactive=args.interactive,
source_org=args.source_org, source_org=args.source_org,