#369 Create fork of the active repository
Merged 4 years ago by onosek. Opened 4 years ago by onosek.
onosek/fedpkg fork  into  master

@@ -62,3 +62,7 @@ 

  

  [fedpkg-stage.greenwave]

  url = https://greenwave.stg.fedoraproject.org/

+ 

+ [fedpkg-stage.distgit]

+ apibaseurl = https://src.stg.fedoraproject.org

+ token = 

@@ -63,3 +63,7 @@ 

  

  [fedpkg.greenwave]

  url = https://greenwave.fedoraproject.org/

+ 

+ [fedpkg.distgit]

+ apibaseurl = https://src.fedoraproject.org

+ token = 

file modified
+74 -10
@@ -31,10 +31,12 @@ 

  from six.moves.urllib_parse import urlparse

  from pyrpkg import rpkgError

  from fedpkg.bugzilla import BugzillaClient

- from fedpkg.utils import (

-     get_fedora_release_state, get_release_branches, sl_list_to_dict, verify_sls,

-     new_pagure_issue, get_pagure_token, is_epel, assert_valid_epel_package,

-     assert_new_tests_repo, get_dist_git_url, get_stream_branches, expand_release)

+ from fedpkg.utils import (assert_new_tests_repo, assert_valid_epel_package,

+                           do_fork, expand_release, get_dist_git_url,

+                           get_fedora_release_state, get_distgit_token,

+                           get_pagure_token, get_release_branches,

+                           get_stream_branches, is_epel, new_pagure_issue,

+                           sl_list_to_dict, verify_sls)

  

  RELEASE_BRANCH_REGEX = r'^(f\d+|el\d+|epel\d+)$'

  LOCAL_PACKAGE_CONFIG = 'package.cfg'
@@ -120,6 +122,7 @@ 

          self.register_request_repo()

          self.register_request_tests_repo()

          self.register_request_branch()

+         self.register_do_fork()

          self.register_override()

  

      # Target registry goes here
@@ -260,9 +263,9 @@ 

          description = textwrap.dedent('''

              Request a new dist-git repository

  

-             Before requesting a new dist-git repository for a new package, you need to

-             generate a pagure.io API token at https://{1}/settings/token/new, select the

-             "Create a new ticket" ACL and save it in your local user configuration located

+             Before the operation, you need to generate a pagure.io API token at

+             https://{1}/settings/token/new, select the relevant ACL(s)

+             and save it in your local user configuration located

              at ~/.config/rpkg/{0}.conf. For example:

  

                  [{0}.pagure]
@@ -343,7 +346,7 @@ 

              Below is a basic example of the command to request a dist-git repository for

              the space tests/foo:

  

-                 fedpkg request-tests-repo foo "Description of the repository"

+                 {0} request-tests-repo foo "Description of the repository"

  

              Note that the space name needs to reflect the intent of the tests and will

              undergo a manual review.
@@ -367,8 +370,8 @@ 

          description = textwrap.dedent('''

              Request a new dist-git branch

  

-             Please refer to the request-repo command to see what has to be done before

-             requesting a dist-git branch.

+             Please refer to the help of the request-repo command to see what has

+             to be done before requesting a dist-git branch.

  

              Branch name could be one of current active Fedora and EPEL releases. Use

              command ``{0} releases-info`` to get release names that can be used to request
@@ -437,6 +440,44 @@ 

          )

          request_branch_parser.set_defaults(command=self.request_branch)

  

+     def register_do_fork(self):

+         help_msg = 'Create a new fork of the current repository'

+         description = textwrap.dedent('''

+             Create a new fork of the current repository

+ 

+             Before the operation, you need to generate an API token at

+             https://{1}/settings/token/new, select the relevant ACL(s)

+             and save it in your local user configuration located

+             at ~/.config/rpkg/{0}.conf. For example:

+ 

+                 [{0}.distgit]

+                 token = <api_key_here>

+ 

+             Below is a basic example of the command to fork a current repository:

+ 

+                 {0} fork

+ 

+             Operation requires username (FAS_ID). by default, current logged

+             username is taken. It could be overridden by reusing an argument:

+ 

+                 {0} --user FAS_ID fork

+         '''.format(self.name, urlparse(self.config.get(

+             '{0}.distgit'.format(self.name), 'apibaseurl')).netloc))

+ 

+         fork_parser = self.subparsers.add_parser(

+             'fork',

+             formatter_class=argparse.RawDescriptionHelpFormatter,

+             help=help_msg,

+             description=description)

+         fork_parser.add_argument(

+             '--namespace',

+             required=False,

+             default='rpms',

+             choices=self.get_distgit_namespaces(),

+             dest='fork_namespace',

+             help='Namespace of the fork. If omitted, default to rpms.')

+         fork_parser.set_defaults(command=self.do_distgit_fork)

+ 

      def register_releases_info(self):

          help_msg = 'Print Fedora or EPEL current active releases'

          parser = self.subparsers.add_parser(
@@ -1052,6 +1093,29 @@ 

                      config=config,

                  )

  

+     def do_distgit_fork(self):

+         """create fork of the distgit repository"""

+         distgit_api_base_url = self.config.get('{0}.distgit'.format(self.name), "apibaseurl")

+         distgit_remote_base_url = self.config.get(

+             '{0}'.format(self.name),

+             "gitbaseurl",

+             vars={'user': 'any', 'repo': 'any'},

+         )

+         distgit_token = get_distgit_token(self.config, self.name)

+ 

+         fork_url = do_fork(

+             base_url=distgit_api_base_url,

+             remote_base_url=distgit_remote_base_url,

+             token=distgit_token,

+             username=self.cmd.user,

+             repo=self.cmd.repo,

+             namespace=self.args.fork_namespace,

+             cli_name=self.name,

+         )

+         if fork_url:

+             msg = "Fork of the repository has been created: {0}"

+             self.log.info(msg.format(fork_url))

+ 

      def create_buildroot_override(self):

          """Create a buildroot override in Bodhi"""

          check_bodhi_version()

file modified
+90 -2
@@ -10,7 +10,9 @@ 

  # option) any later version.  See http://www.gnu.org/copyleft/gpl.html for

  # the full text of the license.

  

+ import git

  import json

+ import os

  import re

  from datetime import datetime

  
@@ -134,6 +136,76 @@ 

          url.rstrip('/'), rv.json()['issue']['id'])

  

  

+ def do_fork(base_url, remote_base_url, token, username, repo, namespace, cli_name):

+     """

+     Creates a fork of the project.

+     :param base_url: a string of the URL repository

+     :param remote_base_url: a string of the remote tracked repository

+     :param token: a string of the API token that has rights to make a fork

+     :param username: a string of the (FAS) user name

+     :param repo: object, current project git repository

+     :param namespace: a string determines a type of the repository

+     :param cli_name: string of the CLI's name (e.g. fedpkg)

+     :return: a string of the URL to the created fork in the UI

+     """

+     api_url = '{0}/api/0'.format(base_url.rstrip('/'))

+     fork_url = '{0}/fork'.format(api_url)

+ 

+     repo_name = os.path.basename(repo.working_dir)

+ 

+     parsed_url = urlparse(remote_base_url)

+     remote_url = '{0}://{1}/forks/{2}/{3}/{4}.git'.format(

+         parsed_url.scheme,

+         parsed_url.netloc,

+         username,

+         namespace,

+         repo_name,

+     )

+ 

+     headers = {

+         'Authorization': 'token {0}'.format(token),

+         'Accept': 'application/json',

+         'Content-Type': 'application/json'

+     }

+     payload = json.dumps({

+         'wait': True,

+         'namespace': namespace,

+         'repo': repo_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)

+ 

+     base_error_msg = ('The following error occurred while creating a new fork: {0}')

+     if not rv.ok:

+         # Lets see if the API returned an error message in JSON that we can

+         # show the user

+         try:

+             rv_error = rv.json().get('error')

+         except ValueError:

+             rv_error = rv.text

+         # show hint for expired token

+         if re.search(r"Invalid or expired token", rv_error, re.IGNORECASE):

+             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_error))

+ 

+     try:

+         repo.create_remote(username, url=remote_url)

+     except git.exc.GitCommandError as e:

+         error_msg = "Fork was created; during create remote:\n  {0}\n  {1}".format(

+             " ".join(e.command), e.stderr)

+         raise rpkgError(error_msg)

+ 

+     return '{0}/fork/{1}/{2}'.format(

+         base_url.rstrip('/'), username, repo_name)

+ 

+ 

  def get_release_branches(server_url):

      """

      Get the active Fedora release branches from PDC
@@ -232,8 +304,24 @@ 

          return config.get(conf_section, 'token')

      except (NoSectionError, NoOptionError):

          raise rpkgError(

-             'Missing a Pagure token. Refer to "{0} request-repo -h" to set a '

-             'token in your user configuration.'.format(cli_name))

+             'Missing a Pagure token. Refer to the help of the current command '

+             '(-h/--help)" to set a token in your user configuration.')

+ 

+ 

+ def get_distgit_token(config, cli_name):

+     """

+     Gets the distgit token configured in the user's configuration file

+     :param config: ConfigParser object

+     :param cli_name: string of the CLI's name (e.g. fedpkg)

+     :return: string of the distgit token

+     """

+     conf_section = '{0}.distgit'.format(cli_name)

+     try:

+         return config.get(conf_section, 'token')

+     except (NoSectionError, NoOptionError):

+         raise rpkgError(

+             'Missing a distgit token. Refer to the help of the current command '

+             '(-h/--help)" to set a token in your user configuration.')

  

  

  def is_epel(branch):

Adds new command 'fork' that call API method which forks active
repository for the given (or active) user and creates remote record in
git configuration.

Fixes: #276

Signed-off-by: Ondrej Nosek onosek@redhat.com

Typo here: crated -> created.

rebased onto 1f132788d90cab36b48663f58b0ba8014ef1d06b

4 years ago

rebased onto 30fa952498ed8b2fd81fe8e0f2cd6550c20962a1

4 years ago

rebased onto fbfc341

4 years ago

Pull-Request has been merged by onosek

4 years ago