#228 Add new command for creating override in Bodhi
Merged 5 years ago by cqi. Opened 5 years ago by cqi.

file modified
+37
@@ -15,6 +15,8 @@ 

  import re

  import platform

  

+ from datetime import datetime

+ 

  from . import cli  # noqa

  from .lookaside import FedoraLookasideCache

  from pyrpkg.utils import cached_property
@@ -234,6 +236,41 @@ 

          cmd.append(self.nvr)

          self._run_command(cmd, shell=True)

  

+     def create_buildroot_override(self, bodhi_config, build, duration,

+                                   notes=''):

+         from bodhi.client.bindings import BodhiClient

+ 

+         bodhi = BodhiClient(staging=bodhi_config['staging'])

+         result = bodhi.list_overrides(builds=build)

+         if result['total'] == 0:

+             try:

+                 self.log.debug(

+                     'Create override in %s: nvr=%s, duration=%s, notes="%s"',

+                     'staging Bodhi' if bodhi_config['staging'] else 'Bodhi',

+                     build, duration, notes)

+                 override = bodhi.save_override(

+                     nvr=build, duration=duration, notes=notes)

+             except Exception as e:

+                 self.log.error(str(e))

+                 raise pyrpkg.rpkgError('Cannot create override.')

+             else:

+                 self.log.info('Override is created.')

+                 self.log.info('Expiration date: %s',

+                               override['expiration_date'])

+                 self.log.info('Notes: %s', override['notes'])

+         else:

+             override = result['overrides'][0]

+             expiration_date = datetime.strptime(override['expiration_date'],

+                                                 '%Y-%m-%d %H:%M:%S')

+             if expiration_date < datetime.now():

+                 self.log.info(

+                     'Buildroot override for %s exists and is expired. Consider'

+                     ' using command `override extend` to extend duration.',

+                     build)

+             else:

+                 self.log.info('Buildroot override for %s already exists and '

+                               'not expired.', build)

+ 

  

  if __name__ == "__main__":

      from fedpkg.__main__ import main

file modified
+74 -6
@@ -40,7 +40,7 @@ 

          dist = pkg_resources.get_distribution('bodhi_client')

      except pkg_resources.DistributionNotFound:

          raise rpkgError('bodhi-client < 2.0 is not supported.')

-     major = int(dist.version.split('.', 1))

+     major = int(dist.version.split('.', 1)[0])

      if major >= 4:

          raise rpkgError(

              'This system has bodhi v{0}, which is unsupported.'.format(major))
@@ -72,6 +72,7 @@ 

          self.register_request_repo()

          self.register_request_tests_repo()

          self.register_request_branch()

+         self.register_override()

  

      # Target registry goes here

      def register_retire(self):
@@ -229,6 +230,62 @@ 

          )

          request_branch_parser.set_defaults(command=self.request_branch)

  

+     def register_override(self):

+         """Register command line parser for subcommand override"""

+ 

+         def validate_duration(value):

+             try:

+                 duration = int(value)

+             except ValueError:

+                 raise argparse.ArgumentTypeError('duration must be an integer.')

+             if duration > 0:

+                 return duration

+             raise argparse.ArgumentTypeError(

+                 'override should have 1 day to exist at least.')

+ 

+         override_parser = self.subparsers.add_parser(

+             'override',

+             help='Manage buildroot overrides')

+         override_subparser = override_parser.add_subparsers(

+             description='Commands on override')

+ 

+         create_parser = override_subparser.add_parser(

+             'create',

+             help='Create buildroot override from build',

+             formatter_class=argparse.RawDescriptionHelpFormatter,

+             description='''\

+ Create a buildroot override from build guessed from current release branch or

+ specified explicitly.

+ 

+ Examples:

+ 

+ Create a buildroot override from build guessed from release branch. Note that,

+ command must run inside a package repository.

+ 

+     fedpkg switch-branch f28

+     fedpkg override create --duration 5

+ 

+ Create for a specified build:

+ 

+     fedpkg override create --duration 5 package-1.0-1.fc28

+ ''')

+         create_parser.add_argument(

+             '--duration',

+             type=validate_duration,

+             default=7,

+             help='Number of days the override should exist. If omitted, '

+                  'default to 7 days.')

+         create_parser.add_argument(

+             '--notes',

+             default='No explanation given...',

+             help='Optional notes on why this override is in place.')

+         create_parser.add_argument(

+             'NVR',

+             nargs='?',

+             help='Create override from this build. If omitted, build will be'

+                  ' guessed from current release branch.')

+         create_parser.set_defaults(command=self.create_buildroot_override)

+ 

      # Target functions go here

      def retire(self):

          # Skip if package is already retired...
@@ -254,20 +311,21 @@ 

          log.append('#')

          return lines[0], "\n".join(log)

  

-     def update(self):

-         check_bodhi_version()

- 

+     def _get_bodhi_config(self):

          try:

              section = '%s.bodhi' % self.name

-             bodhi_config = {

+             return {

                  'staging': self.config.getboolean(section, 'staging'),

-                 }

+             }

          except (ValueError, NoOptionError, NoSectionError) as e:

              self.log.error(str(e))

              raise rpkgError('Could not get bodhi options. It seems configuration is changed. '

                              'Please try to reinstall %s or consult developers to see what '

                              'is wrong with it.' % self.name)

  

+     def update(self):

+         check_bodhi_version()

+         bodhi_config = self._get_bodhi_config()

          template = """\

  [ %(nvr)s ]

  
@@ -630,3 +688,13 @@ 

                      name=name,

                      config=config,

                  )

+ 

+     def create_buildroot_override(self):

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

+         check_bodhi_version()

+         bodhi_config = self._get_bodhi_config()

+         self.cmd.create_buildroot_override(

+             bodhi_config,

+             build=self.args.NVR or self.cmd.nvr,

+             duration=self.args.duration,

+             notes=self.args.notes)

file modified
+133 -1
@@ -15,7 +15,16 @@ 

  import sys

  import json

  import pkg_resources

- import unittest

+ 

+ try:

+     import unittest2 as unittest

+ except ImportError:

+     import unittest

+ 

+ try:

+     import bodhi

+ except ImportError:

+     bodhi = None

  

  from datetime import datetime, timedelta

  from tempfile import mkdtemp
@@ -1122,3 +1131,126 @@ 

          six.assertRaisesRegex(

              self, rpkgError, r'bodhi-client < 2\.0 is not supported\.',

              check_bodhi_version)

+ 

+ 

+ @unittest.skipUnless(bodhi, 'Skip if no supported bodhi-client is available')

+ class TestBodhiOverride(CliTestCase):

+     """Test command override"""

+ 

+     @patch('fedpkg.cli.check_bodhi_version')

+     @patch('bodhi.client.bindings.BodhiClient')

+     def test_create_for_given_build(self, BodhiClient, check_bodhi_version):

+         bodhi_client = BodhiClient.return_value

+         bodhi_client.list_overrides.return_value = {'total': 0}

+         expiration_date = datetime.now() + timedelta(days=7)

+         new_override = {

+             'expiration_date': expiration_date.strftime('%Y-%m-%d %H:%M:%S'),

+             'notes': 'build for fedpkg'

+         }

+         bodhi_client.save_override.return_value = new_override

+ 

+         cli_cmd = [

+             'fedpkg', '--path', self.cloned_repo_path,

+             'override', 'create',

+             '--duration', '7', '--notes', 'build for fedpkg',

+             'rpkg-1.54-1.fc28'

+         ]

+ 

+         with patch('sys.argv', new=cli_cmd):

+             cli = self.new_cli()

+             with patch.object(cli.cmd, 'log') as log:

+                 cli.create_buildroot_override()

+ 

+                 log.info.assert_any_call('Expiration date: %s',

+                                          new_override['expiration_date'])

+                 log.info.assert_any_call('Notes: %s', new_override['notes'])

+ 

+         bodhi_client.save_override.assert_called_once_with(

+             nvr='rpkg-1.54-1.fc28',

+             duration=7,

+             notes='build for fedpkg')

+ 

+     @patch('fedpkg.cli.check_bodhi_version')

+     @patch('bodhi.client.bindings.BodhiClient')

+     @patch('fedpkg.Commands.nvr', new_callable=PropertyMock)

+     def test_create_from_current_branch(

+             self, nvr, BodhiClient, check_bodhi_version):

+         nvr.return_value = 'rpkg-1.54-2.fc28'

+         bodhi_client = BodhiClient.return_value

+         bodhi_client.list_overrides.return_value = {'total': 0}

+ 

+         cli_cmd = [

+             'fedpkg', '--path', self.cloned_repo_path,

+             'override', 'create',

+             '--duration', '7', '--notes', 'build for fedpkg',

+         ]

+ 

+         with patch('sys.argv', new=cli_cmd):

+             cli = self.new_cli()

+             cli.create_buildroot_override()

+ 

+         bodhi_client.save_override.assert_called_once_with(

+             nvr='rpkg-1.54-2.fc28',

+             duration=7,

+             notes='build for fedpkg')

+ 

+     @patch('fedpkg.cli.check_bodhi_version')

+     @patch('bodhi.client.bindings.BodhiClient')

+     @patch('fedpkg.Commands.nvr', new_callable=PropertyMock)

+     def test_override_already_exists_but_expired(

+             self, nvr, BodhiClient, check_bodhi_version):

+         nvr.return_value = 'rpkg-1.54-2.fc28'

+         today = datetime.today()

+         fake_expiration_date = today - timedelta(days=10)

+         BodhiClient.return_value.list_overrides.return_value = {

+             'total': 1,

+             'overrides': [{

+                 'expiration_date': fake_expiration_date.strftime(

+                     '%Y-%m-%d %H:%M:%S')

+             }]

+         }

+ 

+         cli_cmd = [

+             'fedpkg', '--path', self.cloned_repo_path,

+             'override', 'create',

+             '--duration', '7', '--notes', 'build for fedpkg',

+         ]

+ 

+         with patch('sys.argv', new=cli_cmd):

+             cli = self.new_cli()

+             with patch.object(cli.cmd, 'log') as log:

+                 cli.create_buildroot_override()

+                 log.info.assert_any_call(

+                     'Buildroot override for %s exists and is expired. Consider'

+                     ' using command `override extend` to extend duration.',

+                     'rpkg-1.54-2.fc28')

+ 

+     @patch('fedpkg.cli.check_bodhi_version')

+     @patch('bodhi.client.bindings.BodhiClient')

+     @patch('fedpkg.Commands.nvr', new_callable=PropertyMock)

+     def test_override_already_exists_but_not_expired(

+             self, nvr, BodhiClient, check_bodhi_version):

+         nvr.return_value = 'rpkg-1.54-2.fc28'

+         today = datetime.today()

+         fake_expiration_date = today + timedelta(days=10)

+         BodhiClient.return_value.list_overrides.return_value = {

+             'total': 1,

+             'overrides': [{

+                 'expiration_date': fake_expiration_date.strftime(

+                     '%Y-%m-%d %H:%M:%S')

+             }]

+         }

+ 

+         cli_cmd = [

+             'fedpkg', '--path', self.cloned_repo_path,

+             'override', 'create',

+             '--duration', '7', '--notes', 'build for fedpkg',

+         ]

+ 

+         with patch('sys.argv', new=cli_cmd):

+             cli = self.new_cli()

+             with patch.object(cli.cmd, 'log') as log:

+                 cli.create_buildroot_override()

+                 log.info.assert_any_call(

+                     'Buildroot override for %s already exists and not '

+                     'expired.', 'rpkg-1.54-2.fc28')

file modified
+1
@@ -2,6 +2,7 @@ 

  envlist = py26,py27,py36,flake8

  

  [testenv]

+ sitepackages=True
cqi commented 5 years ago

bodhi-client cannot be installed from pypi.org due to https://github.com/fedora-infra/bodhi/issues/2401

  deps =

      -r{toxinidir}/requirements.txt

      -r{toxinidir}/tests-requirements.txt

To create a buildroot override, run inside a package repo:

fedpkg override create --duration 5

It also accepts a specified build:

fedpkg override create --duration 5 rpkg-1.54-2.fc27

Fixes #92

Signed-off-by: Chenxiong Qi cqi@redhat.com

bodhi-client cannot be installed from pypi.org due to https://github.com/fedora-infra/bodhi/issues/2401

Looks like a typo: expieration -> expiration.

There's some inconsistency here: nvr:%s but notes=%s. Maybe use = everywhere?

I think Consider using command is grammatically better.

Actually which command is this? I don't see fedpkg override extend, will you add it later? Or are users expected to use bodhi cli?

This looks pretty cool!

I'm not a big fan of the default note No explanation given.... Is the value required by Bodhi? If yes, fedpkg should force users to give some notes. If not, maybe it could be left blank?

Yes. It is fedpkg override extend that will be added after this.

rebased onto 532c117

5 years ago

I'm not a big fan of the default note No explanation given.... Is the value required by Bodhi? If yes, fedpkg should force users to give some notes. If not, maybe it could be left blank?

Notes must contain some text. I didn't figure out a better choice, so just keep it same as the default text bodhi has.

@lsedlar all the issues are fixed. Also add more command description.

Looks good to me. I didn't try to run it though.

pretty please pagure-ci rebuild

Pretty please pagure-ci rebuild

@lsedlar for your convenience, there is f28 build containing this patch
https://koji.fedoraproject.org/koji/taskinfo?taskID=27450619

Pull-Request has been merged by cqi

5 years ago