From 782d70b8a808447c6d5c20c8f517f7848046f545 Mon Sep 17 00:00:00 2001 From: SridharIyer Date: Fri, 23 Sep 2016 11:16:31 -0700 Subject: [PATCH 1/4] Added template support for bug creation A new bug can now be created using the supplied template file. The template file needs to contain all the required parameters needed by bugzilla. Optional fields can also be supplied. --- README | 11 ++++ bugz/cli.py | 138 +++++++++++++++++++++++------------------- bugz/cli_argparser.py | 2 + pybugz.tmpl | 14 +++++ 4 files changed, 102 insertions(+), 63 deletions(-) create mode 100644 pybugz.tmpl diff --git a/README b/README index 2e6c0af..e2c89dd 100644 --- a/README +++ b/README @@ -90,6 +90,17 @@ or if we find that the bug is invalid, we can close it by using: $ bugz modify 130608 --invalid -c "Not reproducable" +5) We can post a bug by simply invoking + +$bugz post +This command will guide you through the bug creation process. However, +this does not support custom fields. + +For creating a bug with custom fields, you can could use the template support: +$bugz post --template pybugz.tmpl + +You can modify the supplied template file (or create one) to suit your needs. + Other options ------------- diff --git a/bugz/cli.py b/bugz/cli.py index df943e6..49b37bd 100644 --- a/bugz/cli.py +++ b/bugz/cli.py @@ -24,6 +24,7 @@ import sys import textwrap import xmlrpc.client +import configparser try: import readline @@ -551,18 +552,82 @@ def post(settings): raise BugzError('Unable to read from file: %s: %s' % (settings.description_from, error)) - if not hasattr(settings, 'batch'): + if not hasattr(settings, 'batch') and not hasattr(settings, 'template'): prompt_for_bug(settings) - # raise an exception if mandatory fields are not specified. - if not hasattr(settings, 'product'): - raise RuntimeError('Product not specified') - if not hasattr(settings, 'component'): - raise RuntimeError('Component not specified') - if not hasattr(settings, 'summary'): - raise RuntimeError('Title not specified') - if not hasattr(settings, 'description'): - raise RuntimeError('Description not specified') + params = {} + + if hasattr(settings, 'template'): + tmpl = configparser.RawConfigParser() + tmpl.optionxform = lambda option: option + tmpl.read(settings.template) + try: + msection = tmpl['Default']['type'] + for key in tmpl[msection]: + try: + params[key] = tmpl[msection][key] + print('%-12s: %s' % (key, params[key])) + except: + print('Could not parse %s!' % key) + except: + printf('Could not parse Default type!') + else: + # raise an exception if mandatory fields are not specified. + if not hasattr(settings, 'product'): + raise RuntimeError('Product not specified') + if not hasattr(settings, 'component'): + raise RuntimeError('Component not specified') + if not hasattr(settings, 'summary'): + raise RuntimeError('Title not specified') + if not hasattr(settings, 'description'): + raise RuntimeError('Description not specified') + print('-' * (settings.columns - 1)) + print('%-12s: %s' % ('Product', settings.product)) + print('%-12s: %s' % ('Component', settings.component)) + print('%-12s: %s' % ('Title', settings.summary)) + if hasattr(settings, 'version'): + print('%-12s: %s' % ('Version', settings.version)) + print('%-12s: %s' % ('Description', settings.description)) + if hasattr(settings, 'op_sys'): + print('%-12s: %s' % ('Operating System', settings.op_sys)) + if hasattr(settings, 'platform'): + print('%-12s: %s' % ('Platform', settings.platform)) + if hasattr(settings, 'priority'): + print('%-12s: %s' % ('Priority', settings.priority)) + if hasattr(settings, 'severity'): + print('%-12s: %s' % ('Severity', settings.severity)) + if hasattr(settings, 'alias'): + print('%-12s: %s' % ('Alias', settings.alias)) + if hasattr(settings, 'assigned_to'): + print('%-12s: %s' % ('Assigned to', settings.assigned_to)) + if hasattr(settings, 'cc'): + print('%-12s: %s' % ('CC', settings.cc)) + if hasattr(settings, 'url'): + print('%-12s: %s' % ('URL', settings.url)) + print('-' * (settings.columns - 1)) + params['product'] = settings.product + params['component'] = settings.component + if hasattr(settings, 'version'): + params['version'] = settings.version + params['summary'] = settings.summary + if hasattr(settings, 'description'): + params['description'] = settings.description + if hasattr(settings, 'op_sys'): + params['op_sys'] = settings.op_sys + if hasattr(settings, 'platform'): + params['platform'] = settings.platform + if hasattr(settings, 'priority'): + params['priority'] = settings.priority + if hasattr(settings, 'severity'): + params['severity'] = settings.severity + if hasattr(settings, 'alias'): + params['alias'] = settings.alias + if hasattr(settings, 'assigned_to'): + params['assigned_to'] = settings.assigned_to + if hasattr(settings, 'cc'): + params['cc'] = settings.cc + if hasattr(settings, 'url'): + params['url'] = settings.url # append the output from append_command to the description append_command = getattr(settings, 'append_command', None) @@ -572,35 +637,6 @@ def post(settings): '$ ' + append_command + '\n' + \ append_command_output - # print submission confirmation - print('-' * (settings.columns - 1)) - print('%-12s: %s' % ('Product', settings.product)) - print('%-12s: %s' % ('Component', settings.component)) - print('%-12s: %s' % ('Title', settings.summary)) - if hasattr(settings, 'version'): - print('%-12s: %s' % ('Version', settings.version)) - print('%-12s: %s' % ('Description', settings.description)) - if hasattr(settings, 'op_sys'): - print('%-12s: %s' % ('Operating System', settings.op_sys)) - if hasattr(settings, 'platform'): - print('%-12s: %s' % ('Platform', settings.platform)) - if hasattr(settings, 'priority'): - print('%-12s: %s' % ('Priority', settings.priority)) - if hasattr(settings, 'severity'): - print('%-12s: %s' % ('Severity', settings.severity)) - if hasattr(settings, 'alias'): - print('%-12s: %s' % ('Alias', settings.alias)) - if hasattr(settings, 'assigned_to'): - print('%-12s: %s' % ('Assigned to', settings.assigned_to)) - if hasattr(settings, 'cc'): - print('%-12s: %s' % ('CC', settings.cc)) - if hasattr(settings, 'url'): - print('%-12s: %s' % ('URL', settings.url)) - # fixme: groups - # fixme: status - # fixme: Milestone - print('-' * (settings.columns - 1)) - if not hasattr(settings, 'batch'): if settings.default_confirm in ['Y', 'y']: confirm = input('Confirm bug submission (Y/n)? ') @@ -612,30 +648,6 @@ def post(settings): log_info('Submission aborted') return - params = {} - params['product'] = settings.product - params['component'] = settings.component - if hasattr(settings, 'version'): - params['version'] = settings.version - params['summary'] = settings.summary - if hasattr(settings, 'description'): - params['description'] = settings.description - if hasattr(settings, 'op_sys'): - params['op_sys'] = settings.op_sys - if hasattr(settings, 'platform'): - params['platform'] = settings.platform - if hasattr(settings, 'priority'): - params['priority'] = settings.priority - if hasattr(settings, 'severity'): - params['severity'] = settings.severity - if hasattr(settings, 'alias'): - params['alias'] = settings.alias - if hasattr(settings, 'assigned_to'): - params['assigned_to'] = settings.assigned_to - if hasattr(settings, 'cc'): - params['cc'] = settings.cc - if hasattr(settings, 'url'): - params['url'] = settings.url result = settings.call_bz(settings.bz.Bug.create, params) log_info('Bug %d submitted' % result['id']) diff --git a/bugz/cli_argparser.py b/bugz/cli_argparser.py index 69a6c58..8486662 100644 --- a/bugz/cli_argparser.py +++ b/bugz/cli_argparser.py @@ -256,6 +256,8 @@ def make_arg_parser(): post_parser.add_argument('--batch', action="store_true", help='do not prompt for any values') + post_parser.add_argument('--template', + help='Use a template file for posting bugs') post_parser.add_argument('--default-confirm', choices=['y', 'Y', 'n', 'N'], default='y', diff --git a/pybugz.tmpl b/pybugz.tmpl new file mode 100644 index 0000000..a606127 --- /dev/null +++ b/pybugz.tmpl @@ -0,0 +1,14 @@ +[Default] +type: myfeature + +[myfeature] +product: Platform +component: featureX +version: unspecified +assigned_to: example@example.com +qa_contact: example2@example.com +cc: example3@example.com +cf_which_version: 14.31 +summary: Feature summary +description: This is a multiline description of the + the bug. you can add custom details here. From 0d4cc155d3299fa236f0395399302aa4729de581 Mon Sep 17 00:00:00 2001 From: SridharIyer Date: Sun, 25 Sep 2016 16:08:03 -0700 Subject: [PATCH 2/4] Incorporated review comments for issue 103 - Cleaned up exception handling code. - Added comment on config parsing code. --- bugz/cli.py | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/bugz/cli.py b/bugz/cli.py index 49b37bd..50871f3 100644 --- a/bugz/cli.py +++ b/bugz/cli.py @@ -558,19 +558,32 @@ def post(settings): params = {} if hasattr(settings, 'template'): + + # We are operating under the assumption that the custom fields + # can be in upper case. The default parser converts everything + # to lower case. The lambda just specifies that the keys from + # the config should be kept as is. tmpl = configparser.RawConfigParser() tmpl.optionxform = lambda option: option - tmpl.read(settings.template) + try: + tmpl.read(settings.template) msection = tmpl['Default']['type'] for key in tmpl[msection]: - try: - params[key] = tmpl[msection][key] - print('%-12s: %s' % (key, params[key])) - except: - print('Could not parse %s!' % key) - except: - printf('Could not parse Default type!') + params[key] = tmpl[msection][key] + print('%-12s: %s' % (key, params[key])) + except configparser.DuplicateOptionError as error: + log_error(error) + sys.exit(1) + except configparser.DuplicateSectionError as error: + log_error(error) + sys.exit(1) + except configparser.MissingSectionHeaderError as error: + log_error(error) + sys.exit(1) + except configparser.ParsingError as error: + log_error(error) + sys.exit(1) else: # raise an exception if mandatory fields are not specified. if not hasattr(settings, 'product'): From a502f9af97b568bfbd5803e6dce4593c905e0b74 Mon Sep 17 00:00:00 2001 From: SridharIyer Date: Wed, 28 Sep 2016 10:38:46 -0700 Subject: [PATCH 3/4] Use the default configparser Bugzilla fields are always lowercased, so a raw parser to retain the case is not needed. --- bugz/cli.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/bugz/cli.py b/bugz/cli.py index 50871f3..45e2371 100644 --- a/bugz/cli.py +++ b/bugz/cli.py @@ -559,12 +559,7 @@ def post(settings): if hasattr(settings, 'template'): - # We are operating under the assumption that the custom fields - # can be in upper case. The default parser converts everything - # to lower case. The lambda just specifies that the keys from - # the config should be kept as is. - tmpl = configparser.RawConfigParser() - tmpl.optionxform = lambda option: option + tmpl = configparser.ConfigParser() try: tmpl.read(settings.template) From 2d8da16b0d06cb4e63133e16dfa0195ae28de1b7 Mon Sep 17 00:00:00 2001 From: SridharIyer Date: Tue, 4 Aug 2020 16:05:27 -0700 Subject: [PATCH 4/4] Add support for custom parameters This adds support for custom parameters in bugzilla modify. This needs to be given in form: key1=val:key2=val:... --- bugz/cli.py | 9 +++++++++ bugz/cli_argparser.py | 2 ++ 2 files changed, 11 insertions(+) diff --git a/bugz/cli.py b/bugz/cli.py index 45e2371..994b94b 100644 --- a/bugz/cli.py +++ b/bugz/cli.py @@ -513,6 +513,15 @@ def modify(settings): params['version'] = settings.version if hasattr(settings, 'whiteboard'): params['whiteboard'] = settings.whiteboard + if hasattr(settings, 'custom'): + custom_options = settings.custom.split(':') + for custom_option in custom_options: + try: + key,value = custom_option.split('=',1) + params[key] = value + except: + print("Badly formatted option :{}".format(custom_option)) + pass if hasattr(settings, 'fixed'): params['status'] = 'RESOLVED' diff --git a/bugz/cli_argparser.py b/bugz/cli_argparser.py index 8486662..7057b4d 100644 --- a/bugz/cli_argparser.py +++ b/bugz/cli_argparser.py @@ -183,6 +183,8 @@ def make_arg_parser(): help='change the priority for this bug') modify_parser.add_argument('--product', help='change the product for this bug') + modify_parser.add_argument('--custom', + help='change custom parameters for this bug') modify_parser.add_argument('-r', '--resolution', help='set new resolution ' '(if status = RESOLVED)')