From 5a7f92eab3700727f53ecd3dc26bb14cbeb02d5f Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Nov 18 2022 20:27:07 +0000 Subject: Improve package name detection Look up the parent repo of forks for the package name. This requires the user to have a valid Gitlab API token in their configuration. It will raise an error if it takes this path and does not have permission. Note that when https://gitlab.com/gitlab-org/gitlab/-/issues/361952 is fixed in Gitlab, the token will not be required in this case. Signed-off-by: Stephen Gallagher --- diff --git a/src/centpkg/cli.py b/src/centpkg/cli.py index 61202fb..0d5a58e 100755 --- a/src/centpkg/cli.py +++ b/src/centpkg/cli.py @@ -19,6 +19,7 @@ import argparse import textwrap from centpkg.utils import config_get_safely, do_add_remote, do_fork +import centpkg.utils from pyrpkg.cli import cliClient from pyrpkg import rpkgError from six.moves.urllib_parse import urlparse @@ -31,6 +32,11 @@ class centpkgClient(cliClient): def __init__(self, config, name='centpkg'): self.DEFAULT_CLI_NAME = name + # Save the config for utilities such as get_repo_name() + centpkg.utils.dist_git_config = config + centpkg.utils.dist_git_config.add_section('__default') + centpkg.utils.dist_git_config.set('__default', 'cli_name', name) + super(centpkgClient, self).__init__(config, name) self.setup_centos_subparsers() diff --git a/src/centpkg/utils.py b/src/centpkg/utils.py index 8bc3b4c..1f9524d 100644 --- a/src/centpkg/utils.py +++ b/src/centpkg/utils.py @@ -20,6 +20,7 @@ from requests.exceptions import ConnectionError from six.moves.configparser import NoOptionError, NoSectionError from six.moves.urllib.parse import quote_plus, urlparse +dist_git_config = None def do_fork(logger, base_url, token, repo_name, namespace, cli_name): """ @@ -180,6 +181,54 @@ def config_get_safely(config, section, option): raise +def get_canonical_repo_name(config, repo_url): + """ + Check whether the current repo is a fork and if so, retrieve the parent + fork to get the proper name. + """ + + # Look up the repo and query for forked_from_project + cli_name = config_get_safely(dist_git_config, '__default', 'cli_name') + distgit_section = '{0}.distgit'.format(cli_name) + distgit_api_base_url = config_get_safely(dist_git_config, distgit_section, "apibaseurl") + + # Make sure the fork comes from the same Gitlab instance + parsed_repo_url = urlparse(repo_url) + parsed_base_url = urlparse(distgit_api_base_url) + + try: + distgit_token = config_get_safely(dist_git_config, distgit_section, 'token') + + api_url = '{0}/api/v4'.format(distgit_api_base_url.rstrip('/')) + project_url = '{0}/projects/{1}'.format(api_url, quote_plus(parsed_repo_url.path.lstrip('/'))) + + headers = { + 'PRIVATE-TOKEN': distgit_token, + 'Accept': 'application/json', + 'Content-Type': 'application/json' + } + + rv = requests.get(project_url, headers=headers) + rv.raise_for_status() + + # Extract response json for debugging + rv_json = rv.json() + + canonical_repo_name = rv_json['forked_from_project']['name'] + except KeyError as e: + # There was no 'forked_from_project' key, likely meaning the + # user lacked permissions to read the API. Usually this means + # they haven't supplied a token or it is expired. + raise rpkgError("Insufficient Gitlab API permissions. Missing token?") + + except Exception as e: + # For any other exception, just fall back to using the last segment + # of the URL path. + canonical_repo_name = parsed_repo_url.path.split('/')[-1] + + # Chop off a trailing .git if any + return canonical_repo_name.rsplit('.git', 1)[0] + def get_repo_name(name, org='rpms'): """ Try to parse the repository name in case it is a git url. @@ -202,7 +251,7 @@ def get_repo_name(name, org='rpms'): if name.startswith(org): return name - parsed = '/'.join(name.split('/')[1:]) - repo_name = parsed.split('_')[-1:][0] + # This is probably a renamed fork, so try to find the fork's parent + repo_name = get_canonical_repo_name(dist_git_config, name) return '%s/%s' % (org, repo_name)