def main(): for group in types: for ticket in sf.iter_tickets(group): if ticket.is_not_closed(): bug = bz.create_bug(b, ticket) text = 'This ticket has been moved to ' \ 'https://bugzilla.wikimedia.org/show_bug.cgi?id={0}'.format(bug.id) ticket.add_comment(text) bz.add_to_see_also(bug, ticket) bz.upload_attachments(bug, ticket)
def main(): for group in types: for ticket in sf.iter_tickets(group): if ticket.is_not_closed(): bug = bz.create_bug(b, ticket) text = 'This ticket has been moved to ' \ 'https://bugzilla.wikimedia.org/show_bug.cgi?id={0}'.format(bug.id) ticket.add_comment(text) bz.add_to_see_also(bug, ticket) bz.upload_attachments(bug, ticket) if len(ticket.labels()) > 1: logging.warn('Ticket: {0} (now bug {1}) had multiple labels'.format(ticket.human_url(), bug.id))
def bzexport(ui, repo, *args, **opts): """ Export changesets to bugzilla attachments. The -e option may be used to bring up an editor that will allow editing all fields of the attachment and bug (if creating one). The --new option may be used to create a new bug rather than using an existing bug. See the newbug command for details. The -u (--update) option is equivalent to setting both 'update-patch' and 'rename-patch' to True in the [bzexport] section of your config file. """ auth, api_server, bugzilla = bugzilla_info(ui, opts.get('ffprofile')) rev, bug = infer_arguments(ui, repo, args, opts) if not opts['new']: for o in ('cc', 'depends', 'blocks'): if opts[o]: ui.write("Warning: ignoring --%s option when not creating a bug\n" % o) contents = StringIO() diffopts = patch.diffopts(ui, opts) context = ui.config("bzexport", "unified", ui.config("diff", "unified", None)) if context: diffopts.context = int(context) if rev in repo: description_from_patch = repo[rev].description().decode('utf-8') if hasattr(cmdutil, "export"): cmdutil.export(repo, [rev], fp=contents, opts=diffopts) else: # Support older hg versions patch.export(repo, [rev], fp=contents, opts=diffopts) else: q = repo.mq contents = q.opener(q.lookup(rev), "r") description_from_patch = '\n'.join(mq.patchheader(q.join(rev), q.plainmode).message) # Just always use the rev name as the patch name. Doesn't matter much, # unless you want to avoid obsoleting existing patches when uploading a # version that doesn't include whitespace changes. filename = rev if opts['ignore_all_space']: filename += "_ws" patch_comment = None reviewers = [] orig_desc = opts['description'] or description_from_patch if not orig_desc or orig_desc.startswith('[mq]'): desc = '<required>' else: # Lightly reformat changeset messages into attachment descriptions. # Only use the first line of the provided description for our actual # description - use the rest for the patch/bug comment. parts = orig_desc.split('\n', 1) firstline = parts[0] if len(parts) == 2: patch_comment = parts[1].strip() # Attempt to split the firstline into a bug number, and strip()ed # description with that bug number string removed. desc_bug_number, desc = extract_bug_num_and_desc(firstline) # Failing that try looking in the commit description for a bug number, # since orig_desc could have come from the command line instead. if not desc_bug_number: commit_firstline = description_from_patch.split('\n', 1)[0] desc_bug_number, __ = extract_bug_num_and_desc(commit_firstline) if desc_bug_number: if bug and bug != desc_bug_number: ui.warn("Warning: Bug number %s from commandline doesn't match " "bug number %s from changeset description\n" % (bug, desc_bug_number)) else: bug = desc_bug_number # Strip any remaining leading separator and whitespace, # if the original was something like "bug NNN - " if desc[0] in ['-', ':', '.']: desc = desc[1:].lstrip() # Next strip off review and approval annotations, grabbing the # reviewers from the patch comments only if -r auto was given def grab_reviewer(m): if opts['review'] == 'auto': reviewers.append(m.group(1)) return '' desc = review_re.sub(grab_reviewer, desc).rstrip() # Strip any trailing separators, if the original was something like: # "Desc; r=foo" or "Desc. r=foo" if desc and desc[-1] in (';', '.'): desc = desc[:-1].rstrip() if len(reviewers) > 0: opts['review'] = '' attachment_comment = opts['comment'] bug_comment = opts['bug_description'] if not attachment_comment: # New bugs get first shot at the patch comment if not opts['new'] or bug_comment: attachment_comment = patch_comment if not bug_comment and opts['new']: bug_comment = patch_comment if opts["review"]: search_strings = opts["review"].split(",") valid_users = validate_users(ui, api_server, auth, search_strings, multi_user_prompt, 'reviewer') reviewers = select_users(valid_users, search_strings) elif len(reviewers) > 0: # Pulled reviewers out of commit message valid_users = validate_users(ui, api_server, auth, reviewers, multi_user_prompt, 'reviewer') reviewers = select_users(valid_users, reviewers) if reviewers is None: raise util.Abort(_("Invalid reviewers")) feedback = [] if opts["feedback"]: search_strings = opts["feedback"].split(",") valid_users = validate_users(ui, api_server, auth, search_strings, multi_user_prompt, 'feedback from') feedback = select_users(valid_users, search_strings) values = {'BUGNUM': bug, 'ATTACHMENT_FILENAME': filename, 'ATTACHMENT_DESCRIPTION': desc, 'ATTACHCOMMENT': attachment_comment, 'REVIEWERS': reviewers, 'FEEDBACK': feedback, } cc = [] depends = opts["depends"].split(",") blocks = opts["blocks"].split(",") if opts['new']: if opts["cc"]: search_strings = opts["cc"].split(",") valid_users = validate_users(ui, api_server, auth, search_strings, multi_user_prompt, 'CC') cc = select_users(valid_users, search_strings) values['BUGTITLE'] = opts['title'] or desc values['PRODUCT'] = opts.get('product', '') or ui.config("bzexport", "product", '<choose-from-menu>') values['COMPONENT'] = opts.get('component', '') or ui.config("bzexport", "component", '<choose-from-menu>') values['PRODVERSION'] = opts.get('prodversion', '') or ui.config("bzexport", "prodversion", '<default>') values['BUGCOMMENT0'] = bug_comment values['CC'] = cc values['BLOCKS'] = blocks values['DEPENDS'] = depends values = fill_values(values, ui, api_server, finalize=False) if opts['edit']: if opts['new']: values = edit_form(ui, repo, values, 'new_both_template') else: values = edit_form(ui, repo, values, 'existing_bug_template') bug = values['BUGNUM'] search_strings = [] for key in ('REVIEWERS', 'CC', 'FEEDBACK'): # TODO: Handle <choose-from-menu> search_strings.extend(values.get(key, [])) users = validate_users(ui, api_server, auth, search_strings, multi_user_prompt, 'reviewer') if users is None: raise util.Abort("Invalid users") if 'REVIEWERS' in values: # Always true reviewers = select_users(users, values['REVIEWERS']) if 'CC' in values: # Only when opts['new'] cc = select_users(users, values['CC']) if 'BLOCKS' in values: # Only when opts['new'] blocks = values['BLOCKS'] if 'DEPENDS' in values: # Only when opts['new'] depends = values['DEPENDS'] if 'FEEDBACK' in values: # Always true feedback = select_users(users, values['FEEDBACK']) if 'ATTACHMENT_FILENAME' in values: filename = values['ATTACHMENT_FILENAME'] values = fill_values(values, ui, api_server, finalize=True) if opts["new"]: if bug is not None: raise util.Abort("Bug %s given but creation of new bug requested!" % bug) if opts['interactive'] and ui.prompt(_("Create bug in '%s' :: '%s' (y/n)?") % (values['PRODUCT'], values['COMPONENT'])) != 'y': ui.write(_("Exiting without creating bug\n")) return try: create_opts = {} if not opts['no_take_bug']: create_opts['assign_to'] = auth.username(api_server) result = bz.create_bug(auth, product=values['PRODUCT'], component=values['COMPONENT'], version=values['PRODVERSION'], title=values['BUGTITLE'], description=values['BUGCOMMENT0'], cc=cc, depends=depends, blocks=blocks, **create_opts) bug = result['id'] ui.write("Created bug %s at %sshow_bug.cgi?id=%s\n" % (bug, bugzilla, bug)) except Exception, e: raise util.Abort(_("Error creating bug: %s\n" % str(e)))
def newbug(ui, repo, *args, **opts): """ Create a new bug in bugzilla A menu will be displayed for the product and component unless a default has been set in the [bzexport] section of the config file (keys are 'product' and 'component'), or if something has been specified on the command line. The -e option brings up an editor that will allow editing all handled fields of the bug. The product and/or component given on the command line or the edited form may be case-insensitive substrings rather than exact matches of valid values. Ambiguous matches will be resolved with a menu. The -C (--component) option may be used to set both the product and component by separating them with a double colon ('::'), though usually just giving the component should be sufficient. """ auth, api_server, bugzilla = bugzilla_info(ui, opts.get('ffprofile')) if args: args = list(args) if args and not opts['title']: opts['title'] = args.pop(0) if args and not opts['comment']: opts['comment'] = args.pop(0) if args: raise util.Abort(_("Too many arguments to newbug command (only title and comment may be given)")) bug_comment = opts['comment'] or '<required>' values = {'BUGTITLE': opts['title'] or '<required>', 'PRODUCT': opts.get('product', '') or ui.config("bzexport", "product", '<choose-from-menu>'), 'COMPONENT': opts.get('component', '') or ui.config("bzexport", "component", '<choose-from-menu>'), 'PRODVERSION': opts.get('prodversion', '') or ui.config("bzexport", "prodversion", '<default>'), 'BUGCOMMENT0': bug_comment, 'CC': [cc for cc in opts.get('cc', '').split(',') if cc], 'DEPENDS': opts["depends"].split(","), 'BLOCKS': opts["blocks"].split(","), } fill_values(values, ui, api_server, finalize=False) if opts['edit']: values = edit_form(ui, repo, values, 'new_bug_template') fill_values(values, ui, api_server, finalize=True) cc = validate_users(ui, api_server, auth, values['CC'], multi_user_prompt, 'reviewer') if cc is None: raise util.Abort("Invalid users") cc = select_users(cc, values['CC']) if opts['interactive'] and ui.prompt(_("Create bug in '%s' :: '%s' (y/n)?") % (values['PRODUCT'], values['COMPONENT'])) != 'y': ui.write(_("Exiting without creating bug\n")) return create_opts = {} if opts['take_bug']: create_opts['assign_to'] = auth.username(api_server) try: result = bz.create_bug(auth, product=values['PRODUCT'], component=values['COMPONENT'], version=values['PRODVERSION'], title=values['BUGTITLE'], description=values['BUGCOMMENT0'], cc=cc, depends=values['DEPENDS'], blocks=values['BLOCKS'], **create_opts) except Exception as e: raise util.Abort('error creating bug: %s' % e.message) bug = result['id'] ui.write("Created bug %s at %sshow_bug.cgi?id=%s\n" % (bug, bugzilla, bug))
def bzexport(ui, repo, *args, **opts): """ Export changesets to bugzilla attachments. The -e option may be used to bring up an editor that will allow editing all fields of the attachment and bug (if creating one). The --new option may be used to create a new bug rather than using an existing bug. See the newbug command for details. The -u (--update) option is equivalent to setting both 'update-patch' and 'rename-patch' to True in the [bzexport] section of your config file. """ auth, api_server, bugzilla = bugzilla_info(ui, opts.get('ffprofile')) rev, bug = infer_arguments(ui, repo, args, opts) if not opts['new']: for o in ('cc', 'depends', 'blocks'): if opts[o]: ui.write( "Warning: ignoring --%s option when not creating a bug\n" % o) contents = StringIO() diffopts = patch.diffopts(ui, opts) context = ui.config("bzexport", "unified", ui.config("diff", "unified", None)) if context: diffopts.context = int(context) if rev in repo: description_from_patch = repo[rev].description().decode('utf-8') if hasattr(cmdutil, "export"): cmdutil.export(repo, [rev], fp=contents, opts=diffopts) else: # Support older hg versions patch.export(repo, [rev], fp=contents, opts=diffopts) else: q = repo.mq contents = q.opener(q.lookup(rev), "r") description_from_patch = '\n'.join( mq.patchheader(q.join(rev), q.plainmode).message) # Just always use the rev name as the patch name. Doesn't matter much, # unless you want to avoid obsoleting existing patches when uploading a # version that doesn't include whitespace changes. filename = rev if opts['ignore_all_space']: filename += "_ws" patch_comment = None reviewers = [] orig_desc = opts['description'] or description_from_patch if not orig_desc or orig_desc.startswith('[mq]'): desc = '<required>' else: # Lightly reformat changeset messages into attachment descriptions. # Only use the first line of the provided description for our actual # description - use the rest for the patch/bug comment. parts = orig_desc.split('\n', 1) firstline = parts[0] if len(parts) == 2: patch_comment = parts[1].strip() # Attempt to split the firstline into a bug number, and strip()ed # description with that bug number string removed. desc_bug_number, desc = extract_bug_num_and_desc(firstline) # Failing that try looking in the commit description for a bug number, # since orig_desc could have come from the command line instead. if not desc_bug_number: commit_firstline = description_from_patch.split('\n', 1)[0] desc_bug_number, __ = extract_bug_num_and_desc(commit_firstline) if desc_bug_number: if bug and bug != desc_bug_number: ui.warn( "Warning: Bug number %s from commandline doesn't match " "bug number %s from changeset description\n" % (bug, desc_bug_number)) else: bug = desc_bug_number # Strip any remaining leading separator and whitespace, # if the original was something like "bug NNN - " if desc[0] in ['-', ':', '.']: desc = desc[1:].lstrip() # Next strip off review and approval annotations, grabbing the # reviewers from the patch comments only if -r auto was given def grab_reviewer(m): if opts['review'] == 'auto': reviewers.append(m.group(1)) return '' desc = review_re.sub(grab_reviewer, desc).rstrip() # Strip any trailing separators, if the original was something like: # "Desc; r=foo" or "Desc. r=foo" if desc and desc[-1] in (';', '.'): desc = desc[:-1].rstrip() if len(reviewers) > 0: opts['review'] = '' attachment_comment = opts['comment'] bug_comment = opts['bug_description'] if not attachment_comment: # New bugs get first shot at the patch comment if not opts['new'] or bug_comment: attachment_comment = patch_comment if not bug_comment and opts['new']: bug_comment = patch_comment if opts["review"]: search_strings = opts["review"].split(",") valid_users = validate_users(ui, api_server, auth, search_strings, multi_user_prompt, 'reviewer') reviewers = select_users(valid_users, search_strings) elif len(reviewers) > 0: # Pulled reviewers out of commit message valid_users = validate_users(ui, api_server, auth, reviewers, multi_user_prompt, 'reviewer') reviewers = select_users(valid_users, reviewers) if reviewers is None: raise util.Abort(_("Invalid reviewers")) feedback = [] if opts["feedback"]: search_strings = opts["feedback"].split(",") valid_users = validate_users(ui, api_server, auth, search_strings, multi_user_prompt, 'feedback from') feedback = select_users(valid_users, search_strings) values = { 'BUGNUM': bug, 'ATTACHMENT_FILENAME': filename, 'ATTACHMENT_DESCRIPTION': desc, 'ATTACHCOMMENT': attachment_comment, 'REVIEWERS': reviewers, 'FEEDBACK': feedback, } cc = [] depends = opts["depends"].split(",") blocks = opts["blocks"].split(",") if opts['new']: if opts["cc"]: search_strings = opts["cc"].split(",") valid_users = validate_users(ui, api_server, auth, search_strings, multi_user_prompt, 'CC') cc = select_users(valid_users, search_strings) values['BUGTITLE'] = opts['title'] or desc values['PRODUCT'] = opts.get('product', '') or ui.config( "bzexport", "product", '<choose-from-menu>') values['COMPONENT'] = opts.get('component', '') or ui.config( "bzexport", "component", '<choose-from-menu>') values['PRODVERSION'] = opts.get('prodversion', '') or ui.config( "bzexport", "prodversion", '<default>') values['BUGCOMMENT0'] = bug_comment values['CC'] = cc values['BLOCKS'] = blocks values['DEPENDS'] = depends values = fill_values(values, ui, api_server, finalize=False) if opts['edit']: if opts['new']: values = edit_form(ui, repo, values, 'new_both_template') else: values = edit_form(ui, repo, values, 'existing_bug_template') bug = values['BUGNUM'] search_strings = [] for key in ('REVIEWERS', 'CC', 'FEEDBACK'): # TODO: Handle <choose-from-menu> search_strings.extend(values.get(key, [])) users = validate_users(ui, api_server, auth, search_strings, multi_user_prompt, 'reviewer') if users is None: raise util.Abort("Invalid users") if 'REVIEWERS' in values: # Always true reviewers = select_users(users, values['REVIEWERS']) if 'CC' in values: # Only when opts['new'] cc = select_users(users, values['CC']) if 'BLOCKS' in values: # Only when opts['new'] blocks = values['BLOCKS'] if 'DEPENDS' in values: # Only when opts['new'] depends = values['DEPENDS'] if 'FEEDBACK' in values: # Always true feedback = select_users(users, values['FEEDBACK']) if 'ATTACHMENT_FILENAME' in values: filename = values['ATTACHMENT_FILENAME'] values = fill_values(values, ui, api_server, finalize=True) if opts["new"]: if bug is not None: raise util.Abort( "Bug %s given but creation of new bug requested!" % bug) if opts['interactive'] and ui.prompt( _("Create bug in '%s' :: '%s' (y/n)?") % (values['PRODUCT'], values['COMPONENT'])) != 'y': ui.write(_("Exiting without creating bug\n")) return try: create_opts = {} if not opts['no_take_bug']: create_opts['assign_to'] = auth.username(api_server) result = bz.create_bug(auth, product=values['PRODUCT'], component=values['COMPONENT'], version=values['PRODVERSION'], title=values['BUGTITLE'], description=values['BUGCOMMENT0'], cc=cc, depends=depends, blocks=blocks, **create_opts) bug = result['id'] ui.write("Created bug %s at %sshow_bug.cgi?id=%s\n" % (bug, bugzilla, bug)) except Exception, e: raise util.Abort(_("Error creating bug: %s\n" % str(e)))
def newbug(ui, repo, *args, **opts): """ Create a new bug in bugzilla A menu will be displayed for the product and component unless a default has been set in the [bzexport] section of the config file (keys are 'product' and 'component'), or if something has been specified on the command line. The -e option brings up an editor that will allow editing all handled fields of the bug. The product and/or component given on the command line or the edited form may be case-insensitive substrings rather than exact matches of valid values. Ambiguous matches will be resolved with a menu. The -C (--component) option may be used to set both the product and component by separating them with a double colon ('::'), though usually just giving the component should be sufficient. """ auth, api_server, bugzilla = bugzilla_info(ui, opts.get('ffprofile')) if args: args = list(args) if args and not opts['title']: opts['title'] = args.pop(0) if args and not opts['comment']: opts['comment'] = args.pop(0) if args: raise util.Abort( _("Too many arguments to newbug command (only title and comment may be given)" )) bug_comment = opts['comment'] or '<required>' values = { 'BUGTITLE': opts['title'] or '<required>', 'PRODUCT': opts.get('product', '') or ui.config("bzexport", "product", '<choose-from-menu>'), 'COMPONENT': opts.get('component', '') or ui.config("bzexport", "component", '<choose-from-menu>'), 'PRODVERSION': opts.get('prodversion', '') or ui.config("bzexport", "prodversion", '<default>'), 'BUGCOMMENT0': bug_comment, 'CC': [cc for cc in opts.get('cc', '').split(',') if cc], 'DEPENDS': opts["depends"].split(","), 'BLOCKS': opts["blocks"].split(","), } fill_values(values, ui, api_server, finalize=False) if opts['edit']: values = edit_form(ui, repo, values, 'new_bug_template') fill_values(values, ui, api_server, finalize=True) cc = validate_users(ui, api_server, auth, values['CC'], multi_user_prompt, 'reviewer') if cc is None: raise util.Abort("Invalid users") cc = select_users(cc, values['CC']) if opts['interactive'] and ui.prompt( _("Create bug in '%s' :: '%s' (y/n)?") % (values['PRODUCT'], values['COMPONENT'])) != 'y': ui.write(_("Exiting without creating bug\n")) return create_opts = {} if opts['take_bug']: create_opts['assign_to'] = auth.username(api_server) try: result = bz.create_bug(auth, product=values['PRODUCT'], component=values['COMPONENT'], version=values['PRODVERSION'], title=values['BUGTITLE'], description=values['BUGCOMMENT0'], cc=cc, depends=values['DEPENDS'], blocks=values['BLOCKS'], **create_opts) except Exception as e: raise util.Abort('error creating bug: %s' % e.message) bug = result['id'] ui.write("Created bug %s at %sshow_bug.cgi?id=%s\n" % (bug, bugzilla, bug))