| |
@@ -0,0 +1,152 @@
|
| |
+ # -*- 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
|
| |
Adds new command 'fork' that calls API method which forks active repository for the given (or active) user and creates a remote record (named after user) in git configuration.
GitLab Personal Access Token have to be added to the config for proper functionality.
Signed-off-by: Ondrej Nosek onosek@redhat.com