From 146ec9c0f35d8ea1494d3f400bffbd9fcde7f5d4 Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Wed, 15 Feb 2012 20:56:14 +0100 Subject: Support for editing attachment flags. One has to first define the available flags for the bugtracker used. The only way I found is to look at the source of the bugtracker "Create New Attachment" page. Examples of use of a review: flag below. Self-review would be: review: + Requesting a review from a specific person would look like: review: ? joe@example.com To request review from a specific person as shown above, the requesteeable git-bz option of the flag has to be set to true like: git config bz-tracker.bugzilla.mozilla.org.attachment-flag.review.requesteeable true (Patch includes fixes by Owen Taylor ) https://bugzilla.gnome.org/show_bug.cgi?id=602406 --- git-bz | 116 +++++++++++++++++++++++++++++++++++++++++++++++++------------ git-bz.txt | 28 +++++++++++++++ 2 files changed, 122 insertions(+), 22 deletions(-) diff --git a/git-bz b/git-bz index 01f37d9..d9b4b69 100755 --- a/git-bz +++ b/git-bz @@ -73,6 +73,15 @@ CONFIG['bugzilla.redhat.com'] = \ https = true """ +CONFIG["bugs.webkit.org"] = \ +""" +https = true +attachment-flag.review.id = 1 +attachment-flag.review.requesteeable = false +attachment-flag.commit-queue.id = 3 +attachment-flag.commit-queue.requesteeable = false +""" + # Default values for options that can be configured via 'git config' git_config = { 'browser': 'firefox3', @@ -331,33 +340,36 @@ def resolve_host_alias(alias): except CalledProcessError: return alias -def split_local_config(config_text): - result = {} - +def add_config_param(param, value, result): + param_parts = param.split(".") + param_parts.reverse() + param_dict = result + while len(param_parts) > 1: + part = param_parts.pop() + if not part in param_dict or not isinstance(param_dict[part], dict): + param_dict[part] = {} + param_dict = param_dict[part] + param_dict[param_parts[0]] = value + +def add_config_from_string(config_text, result): for line in config_text.split("\n"): line = re.sub("#.*", "", line) line = line.strip() if line == "": continue - m = re.match("([a-zA-Z0-9-]+)\s*=\s*(.*)", line) + m = re.match("([a-zA-Z0-9-\.]+)\s*=\s*(.*)", line) if not m: die("Bad config line '%s'" % line) - param = m.group(1) - value = m.group(2) - - result[param] = value - - return result + add_config_param(m.group(1), m.group(2), result) -def get_git_config(name): +def add_config_from_git(name, result): try: name = name.replace(".", r"\.") config_options = git.config(r'bz-tracker\.' + name + r'\..*', get_regexp=True) except CalledProcessError: return {} - result = {} for line in config_options.split("\n"): line = line.strip() m = re.match("(\S+)\s+(.*)", line) @@ -367,9 +379,7 @@ def get_git_config(name): m = re.match(r'bz-tracker\.' + name + r'\.(.*)', key) param = m.group(1) - result[param] = value - - return result + add_config_param(param, value, result) # We only ever should be the config for one tracker in the course of a single run cached_config = None @@ -382,10 +392,11 @@ def get_config(tracker): if cached_config == None: cached_config_tracker = tracker host = resolve_host_alias(tracker) - cached_config = split_local_config(DEFAULT_CONFIG) + cached_config = {} + add_config_from_string(DEFAULT_CONFIG, cached_config) if host in CONFIG: - cached_config.update(split_local_config(CONFIG[host])) - cached_config.update(get_git_config(host)) + add_config_from_string(CONFIG[host], cached_config) + add_config_from_git(host, cached_config) if tracker != host: cached_config.update(get_git_config(tracker)) @@ -1289,7 +1300,7 @@ class Bug(object): print "Bug %d - %s" % (self.id, short_desc) print self.get_url() - def create_patch(self, description, comment, filename, data, obsoletes=[], status='none'): + def create_patch(self, description, comment, filename, data, obsoletes=[], status='none', flags={}): # Bugzilla 4.2+ requires you to grab a fresh token from attachment.cgi. url = "/attachment.cgi?bugid=" + str(self.id) + "&action=enter" @@ -1319,6 +1330,8 @@ class Bug(object): # name 'obsolete' for each item in the list fields['obsolete'] = map(str, obsoletes) + fields.update(flags) + files = { 'data': ( filename.encode('UTF-8'), @@ -1818,6 +1831,17 @@ def edit_attachment_comment(bug, initial_description, initial_body): template.write("%sObsoletes: %d - %s\n" % ("" if obsoleted else "#", patch.attach_id, patch.description)) template.write("\n") + config = get_config(get_tracker()) + attachment_flags = config.get('attachment-flag', {}) + flag_names = attachment_flags.keys() + if flag_names: + template.write("""# Uncomment to set flags for the attachment; flags can be set to +,- , or ?.\n""") + template.write("""# When setting a flag to ? you can optionally specify individuals as, for example: +# Review: ? joe@example.com\n""") + for name in flag_names: + template.write("""#%s: ?\n""" % name) + template.write("\n") + template.write("""# Please edit the description (first line) and comment (other lines). Lines # starting with '#' will be ignored. Delete everything to abort. """) @@ -1837,12 +1861,59 @@ def edit_attachment_comment(bug, initial_description, initial_body): lines = filter(filter_obsolete, lines) + flags = {} + def filter_flags(line): + # Lookup for a known attachment flag in the line. It has to be + # at the beginning of the line. + m = re.match(r'^\s*([^ ,]+)\s*:\s*([+-?].*?)\s*$', line) + if not m: + return True + + flag_name = m.group(1) + # If there's something that looks like a flag format in the commit message + # - say someone writes "Yay :-)" - we dont' want to produce a confusing + # error message, so hope nobody accidentally edits a real flag name when + # uncommenting it. + if not flag_name in attachment_flags: + return True + + value = m.group(2) + + # Flag found, check its value and build the form data + # that bugzilla will be able to understand. + flag_config = attachment_flags[flag_name] + requesteeable = flag_config.get('requesteeable', 'false') + + if len(value) > 1: + extra = value[1:].strip() + + if requesteeable != 'true': + print "Flag '%s' cannot be requested for a specific user. Ignoring '%s' and setting flag to fallback value: '?'." % (flag_name, extra) + value = '?' + elif not value.startswith('?'): + print "A specific user can only be requested for the '?' status. Ignoring '%s'." % extra + value = value[0] + else: + requestees = [r.strip() for r in value[1:].split(',')] + if len(requestees) > 1: + ignored_requestees = requestees[1:] + print "Flag '%s' cannot be requested for multiple users. Ignoring '%s' and setting value to '%s'" % (flag_name, + ', '.join(ignored_requestees), + requestees[0]) + flags["requestee_type-%s" % flag_config['id']] = requestees[0] + value = '?' + + flags["flag_type-%s" % flag_config['id']] = value + return False + + lines = filter(filter_flags, lines) + description, comment = split_subject_body(lines) if description == "": die("Empty description, aborting") - return description, comment, obsoletes + return description, comment, obsoletes, flags def attach_commits(bug, commits, include_comments=True, edit_comments=False, status='none'): # We want to attach the patches in chronological order @@ -1857,15 +1928,16 @@ def attach_commits(bug, commits, include_comments=True, edit_comments=False, sta else: body = None if edit_comments: - description, body, obsoletes = edit_attachment_comment(bug, commit.subject, body) + description, body, obsoletes, flags = edit_attachment_comment(bug, commit.subject, body) else: description = commit.subject obsoletes = [] + flags = {} for attachment in bug.patches: if attachment.description == commit.subject: obsoletes.append(attachment.attach_id) - bug.create_patch(description, body, filename, patch, obsoletes=obsoletes, status=status) + bug.create_patch(description, body, filename, patch, obsoletes=obsoletes, status=status, flags=flags) def do_attach(*args): if len(args) == 1: diff --git a/git-bz.txt b/git-bz.txt index 4c4ac83..eaa8eb1 100644 --- a/git-bz.txt +++ b/git-bz.txt @@ -289,6 +289,34 @@ Firefox 3, Epiphany and Galeon are supported, and only on Linux. Patches to add more support and to allow configuring username/password directly per bug tracker accepted. +ATTACHMENT FLAGS +---------------- + +When editing the description of an attachment with 'git-bz attach -e' +it is possible to set flag values, depending on the configuration of +the bug tracker. However, it is first necessary to configure the flag +types available for your bug tracker. Ask the administrator of the +tracker or inspect the HTML source code of the attachment.cgi +page. For each flag you need to configure its id and whether or not it +is requesteeable (eg. if you can ask for a specific bugzilla user to +update the flag). Here is a sample configuration: + +---------------------------------------- +attachment-flag.review.id = 1 +attachment-flag.review.requesteeable = false +---------------------------------------- + +With the above flag configuration, when editing an attachment +description you should see a template allowing setting the flag: + +---------------------------------------- +# Uncomment to set flags for the attachment; flags can be set to +,- , or ?. +# When setting a flag to ? you can optionally specify individuals as, for example: +# review: ? joe@example.com +#review: ? +---------------------------------------- + + BUG REFERENCES -------------- On the command line, there are multiple ways to refer to a bug: -- cgit