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 <sgallagh@redhat.com>
This commit is contained in:
Stephen Gallagher 2022-11-18 15:25:21 -05:00
parent 5cc23ef01e
commit 5a7f92eab3
No known key found for this signature in database
GPG key ID: 45DB85A568286D11
2 changed files with 57 additions and 2 deletions

View file

@ -19,6 +19,7 @@ import argparse
import textwrap import textwrap
from centpkg.utils import config_get_safely, do_add_remote, do_fork from centpkg.utils import config_get_safely, do_add_remote, do_fork
import centpkg.utils
from pyrpkg.cli import cliClient from pyrpkg.cli import cliClient
from pyrpkg import rpkgError from pyrpkg import rpkgError
from six.moves.urllib_parse import urlparse from six.moves.urllib_parse import urlparse
@ -31,6 +32,11 @@ class centpkgClient(cliClient):
def __init__(self, config, name='centpkg'): def __init__(self, config, name='centpkg'):
self.DEFAULT_CLI_NAME = name 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) super(centpkgClient, self).__init__(config, name)
self.setup_centos_subparsers() self.setup_centos_subparsers()

View file

@ -20,6 +20,7 @@ from requests.exceptions import ConnectionError
from six.moves.configparser import NoOptionError, NoSectionError from six.moves.configparser import NoOptionError, NoSectionError
from six.moves.urllib.parse import quote_plus, urlparse 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): def do_fork(logger, base_url, token, repo_name, namespace, cli_name):
""" """
@ -180,6 +181,54 @@ def config_get_safely(config, section, option):
raise 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'): def get_repo_name(name, org='rpms'):
""" """
Try to parse the repository name in case it is a git url. 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): if name.startswith(org):
return name return name
parsed = '/'.join(name.split('/')[1:]) # This is probably a renamed fork, so try to find the fork's parent
repo_name = parsed.split('_')[-1:][0] repo_name = get_canonical_repo_name(dist_git_config, name)
return '%s/%s' % (org, repo_name) return '%s/%s' % (org, repo_name)