# -*- coding: utf-8 -*-
# utils.py - a module with support methods for centpkg
#
# Copyright (C) 2021 Red Hat Inc.
# Author(s): Ondrej Nosek <onosek@redhat.com>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version. See http://www.gnu.org/copyleft/gpl.html for
# the full text of the license.
import json
import git
import requests
from pyrpkg import rpkgError
from requests.exceptions import ConnectionError
from six.moves.configparser import NoOptionError, NoSectionError
from six.moves.urllib.parse import quote_plus, urlparse
def do_fork(logger, base_url, token, repo_name, namespace, cli_name):
"""
Creates a fork of the project.
:param logger: A logger object
:param base_url: a string of the URL repository
:param token: a string of the API token that has rights to make a fork
:param repo_name: a string of the repository name
:param namespace: a string determines a type of the repository
:param cli_name: string of the CLI's name (e.g. centpkg)
:return: a bool; True when fork was created, False when already exists
"""
api_url = '{0}/api/v4'.format(base_url.rstrip('/'))
project_id = quote_plus("redhat/centos-stream/{0}/{1}".format(namespace, repo_name))
fork_url = '{0}/projects/{1}/fork'.format(api_url, project_id)
headers = {
'PRIVATE-TOKEN': token,
'Accept': 'application/json',
'Content-Type': 'application/json'
}
# define a new repository name/path to avoid collision with other projects
safe_name = "centos_{0}_{1}".format(namespace, repo_name)
payload = json.dumps({
'name': safe_name, # name of the project after forking
'path': safe_name,
})
try:
rv = requests.post(
fork_url, headers=headers, data=payload, timeout=60)
except ConnectionError as error:
error_msg = ('The connection to API failed while trying to '
'create a new fork. The error was: {0}'.format(str(error)))
raise rpkgError(error_msg)
try:
# Extract response json for debugging
rv_json = rv.json()
logger.debug("Pagure API response: '{0}'".format(rv_json))
except Exception:
pass
base_error_msg = ('The following error occurred while creating a new fork: {0}')
if not rv.ok:
# fork was already created
if rv.status_code == 409 or rv.reason == "Conflict":
return False
# show hint for invalid, expired or revoked token
elif rv.status_code == 401 or rv.reason == "Unauthorized":
base_error_msg += '\nFor invalid or expired token refer to ' \
'"{0} fork -h" to set a token in your user ' \
'configuration.'.format(cli_name)
raise rpkgError(base_error_msg.format(rv.text))
return True
def do_add_remote(base_url, remote_base_url, username, repo, repo_name,
namespace):
"""
Adds remote tracked repository
:param base_url: a string of the URL repository
:param remote_base_url: a string of the remote tracked repository
:param username: a string of the (FAS) user name
:param repo: object, current project git repository
:param repo_name: a string of the repository name
:param namespace: a string determines a type of the repository
:return: a bool; True if remote was created, False when already exists
"""
parsed_url = urlparse(remote_base_url)
remote_url = '{0}://{1}/{2}/centos_{3}_{4}.git'.format(
parsed_url.scheme,
parsed_url.netloc,
username,
namespace,
repo_name,
)
# check already existing remote
for remote in repo.remotes:
if remote.name == username:
return False
try:
# create remote with username as its name
repo.create_remote(username, url=remote_url)
except git.exc.GitCommandError as e:
error_msg = "During create remote:\n {0}\n {1}".format(
" ".join(e.command), e.stderr)
raise rpkgError(error_msg)
return True
def config_get_safely(config, section, option):
"""
Returns option from the user's configuration file. In case of missing
section or option method throws an exception with a human-readable
warning and a possible hint.
The method should be used especially in situations when there are newly
added sections/options into the config. In this case, there is a risk that
the user's config wasn't properly upgraded.
:param config: ConfigParser object
:param section: section name in the config
:param option: name of the option
:return: option value from the right section
:rtype: str
"""
hint = (
"First (if possible), refer to the help of the current command "
"(-h/--help).\n"
"There also might be a new version of the config after upgrade.\n"
"Hint: you can check if you have 'centpkg.conf.rpmnew' or "
"'centpkg.conf.rpmsave' in the config directory. If yes, try to merge "
"your changes to the config with the maintainer provided version "
"(or replace centpkg.conf file with 'centpkg.conf.rpmnew')."
)
try:
return config.get(section, option)
except NoSectionError:
msg = "Missing section '{0}' in the config file.".format(section)
raise rpkgError("{0}\n{1}".format(msg, hint))
except NoOptionError:
msg = "Missing option '{0}' in the section '{1}' of the config file.".format(
option, section
)
raise rpkgError("{0}\n{1}".format(msg, hint))
except Exception:
raise