diff options
author | Aaron Bentley <aaron.bentley@utoronto.ca> | 2006-04-04 19:46:25 -0400 |
---|---|---|
committer | Aaron Bentley <aaron.bentley@utoronto.ca> | 2006-04-04 19:46:25 -0400 |
commit | 2225a378d84f77c3512ee407af1aeb355b463084 (patch) | |
tree | bfd0ef4b969bfdcd723e405f69599107b0931bd9 | |
parent | 4dda0decb88c6bc987d3d55a1ac757104e9d0ba9 (diff) | |
parent | c1f60d534fbc5496a0e3df2cb7c0d053e5fa40a8 (diff) | |
download | bugseverywhere-2225a378d84f77c3512ee407af1aeb355b463084.tar.gz |
Merge both lines
-rw-r--r-- | NEWS | 16 | ||||
-rw-r--r-- | becommands/assign.py | 11 | ||||
-rw-r--r-- | becommands/close.py | 12 | ||||
-rw-r--r-- | becommands/comment.py | 12 | ||||
-rw-r--r-- | becommands/help.py | 6 | ||||
-rw-r--r-- | becommands/inprogress.py | 12 | ||||
-rw-r--r-- | becommands/open.py | 12 | ||||
-rw-r--r-- | becommands/set.py | 10 | ||||
-rw-r--r-- | becommands/severity.py | 11 | ||||
-rw-r--r-- | becommands/show.py | 27 | ||||
-rw-r--r-- | becommands/target.py | 11 | ||||
-rw-r--r-- | becommands/upgrade.py | 11 | ||||
-rw-r--r-- | beweb/beweb/controllers.py | 16 | ||||
-rw-r--r-- | beweb/beweb/templates/edit_bug.kid | 17 | ||||
-rw-r--r-- | libbe/bugdir.py | 22 | ||||
-rw-r--r-- | libbe/cmdutil.py | 48 |
16 files changed, 225 insertions, 29 deletions
@@ -1,2 +1,16 @@ +April 3, 2006 + * Handle replying to comments + * Better help handling (Thomas Gerigk) + +March 3, 2006 + * Better bzr compatibility + * Auto-commit support + +Jan 30, 2006 + * Creator support (Alexander Belchenko) + +Jan 26, 2006 + * Unicode support + December 3, 2005 -* Added new "webbe" web interface +* Added new "beweb" web interface diff --git a/becommands/assign.py b/becommands/assign.py index f3db6aa..2308a12 100644 --- a/becommands/assign.py +++ b/becommands/assign.py @@ -37,6 +37,7 @@ def execute(args): True >>> tests.clean_up() """ + options, args = get_parser().parse_args(args) assert(len(args) in (0, 1, 2)) if len(args) == 0: print help() @@ -51,10 +52,11 @@ def execute(args): bug.assigned = args[1] bug.save() +def get_parser(): + parser = cmdutil.CmdOptionParser("be assign bug-id [assignee]") + return parser -def help(): - return """be assign bug-id [assignee] - +longhelp = """ Assign a person to fix a bug. By default, the bug is self-assigned. If an assignee is specified, the bug @@ -65,3 +67,6 @@ appears in Creator fields. To un-assign a bug, specify "none" for the assignee. """ + +def help(): + return get_parser().help_str() + longhelp diff --git a/becommands/close.py b/becommands/close.py index 04ae4ba..3ced7eb 100644 --- a/becommands/close.py +++ b/becommands/close.py @@ -29,7 +29,19 @@ def execute(args): u'closed' >>> tests.clean_up() """ + options, args = get_parser().parse_args(args) assert(len(args) == 1) bug = cmdutil.get_bug(args[0]) bug.status = "closed" bug.save() + +def get_parser(): + parser = cmdutil.CmdOptionParser("be close bug-id") + return parser + +longhelp=""" +Close the bug identified by bug-id. +""" + +def help(): + return get_parser().help_str() + longhelp diff --git a/becommands/comment.py b/becommands/comment.py index 37fd37d..4f0bf3b 100644 --- a/becommands/comment.py +++ b/becommands/comment.py @@ -46,7 +46,7 @@ def execute(args): options, args = get_parser().parse_args(args) if len(args) < 1: raise cmdutil.UsageError() - bug = cmdutil.get_bug(args[0]) + bug, parent_comment = cmdutil.get_bug_and_comment(args[0]) if len(args) == 1: try: body = utility.editor_string() @@ -61,15 +61,21 @@ def execute(args): body+='\n' comment = bugdir.new_comment(bug, body) + if parent_comment is not None: + comment.in_reply_to = parent_comment.uuid comment.save() def get_parser(): - parser = cmdutil.CmdOptionParser("be comment BUG-ID COMMENT") + parser = cmdutil.CmdOptionParser("be comment ID COMMENT") return parser longhelp=""" -Add a comment to a bug. +To add a comment to a bug, use the bug ID as the argument. To reply to another +comment, specify the comment name (as shown in "be show" output). + +$EDITOR is used to launch an editor. If unspecified, no comment will be +created.) """ def help(): diff --git a/becommands/help.py b/becommands/help.py index cae8949..1402a2a 100644 --- a/becommands/help.py +++ b/becommands/help.py @@ -26,7 +26,11 @@ def execute(args): if len(args) == 0: print_command_list() else: - print cmdutil.help(args[0]) + try: + print cmdutil.help(args[0]) + except AttributeError: + print "No help available" + return diff --git a/becommands/inprogress.py b/becommands/inprogress.py index 214efa1..10d5cbd 100644 --- a/becommands/inprogress.py +++ b/becommands/inprogress.py @@ -29,7 +29,19 @@ def execute(args): u'in-progress' >>> tests.clean_up() """ + options, args = get_parser().parse_args(args) assert(len(args) == 1) bug = cmdutil.get_bug(args[0]) bug.status = "in-progress" bug.save() + +def get_parser(): + parser = cmdutil.CmdOptionParser("be inprogress BUG-ID") + return parser + +longhelp=""" +Mark a bug as 'in-progress'. +""" + +def help(): + return get_parser().help_str() + longhelp diff --git a/becommands/open.py b/becommands/open.py index 19b8910..89067f8 100644 --- a/becommands/open.py +++ b/becommands/open.py @@ -29,7 +29,19 @@ def execute(args): u'open' >>> tests.clean_up() """ + options, args = get_parser().parse_args(args) assert(len(args) == 1) bug = cmdutil.get_bug(args[0]) bug.status = "open" bug.save() + +def get_parser(): + parser = cmdutil.CmdOptionParser("be open BUG-ID") + return parser + +longhelp=""" +Mark a bug as 'open'. +""" + +def help(): + return get_parser().help_str() + longhelp diff --git a/becommands/set.py b/becommands/set.py index 2a977ca..6f40b5f 100644 --- a/becommands/set.py +++ b/becommands/set.py @@ -32,6 +32,7 @@ def execute(args): None >>> tests.clean_up() """ + options, args = get_parser().parse_args(args) if len(args) > 2: raise cmdutil.UserError("Too many arguments.") tree = cmdutil.bug_tree() @@ -49,9 +50,11 @@ def execute(args): del tree.settings[args[0]] tree.save_settings() -def help(): - return """be set [name] [value] +def get_parser(): + parser = cmdutil.CmdOptionParser("be set [name] [value]") + return parser +longhelp=""" Show or change per-tree settings. If name and value are supplied, the name is set to a new value. @@ -66,3 +69,6 @@ target To unset a setting, set it to "none". """ + +def help(): + return get_parser().help_str() + longhelp diff --git a/becommands/severity.py b/becommands/severity.py index 88d3f25..82ef7ca 100644 --- a/becommands/severity.py +++ b/becommands/severity.py @@ -35,6 +35,7 @@ def execute(args): UserError: Invalid severity level: none >>> tests.clean_up() """ + options, args = get_parser().parse_args(args) assert(len(args) in (0, 1, 2)) if len(args) == 0: print help() @@ -51,10 +52,11 @@ def execute(args): raise cmdutil.UserError ("Invalid severity level: %s" % e.value) bug.save() +def get_parser(): + parser = cmdutil.CmdOptionParser("be severity bug-id [severity]") + return parser -def help(): - return """be severity bug-id [severity] - +longhelp=""" Show or change a bug's severity level. If no severity is specified, the current value is printed. If a severity level @@ -67,3 +69,6 @@ wishlist: A feature that could improve usefulness, but not a bug. critical: A bug that prevents some features from working at all. fatal: A bug that makes the package unusable. """ + +def help(): + return get_parser().help_str() + longhelp diff --git a/becommands/show.py b/becommands/show.py index 9e60586..8e83a1f 100644 --- a/becommands/show.py +++ b/becommands/show.py @@ -19,9 +19,10 @@ from libbe import bugdir, cmdutil, utility import os def execute(args): - bug_dir = cmdutil.bug_tree() + options, args = get_parser().parse_args(args) if len(args) !=1: raise cmdutil.UserError("Please specify a bug id.") + bug_dir = cmdutil.bug_tree() bug = cmdutil.get_bug(args[0], bug_dir) print cmdutil.bug_summary(bug, list(bug_dir.list())).rstrip("\n") if bug.time is None: @@ -30,8 +31,22 @@ def execute(args): time_str = "%s (%s)" % (utility.handy_time(bug.time), utility.time_to_str(bug.time)) print "Created: %s" % time_str - for comment in bug.list_comments(): - print "--------- Comment ---------" - print "From: %s" % comment.From - print "Date: %s\n" % utility.time_to_str(comment.date) - print comment.body.rstrip('\n') + unique_name = cmdutil.unique_name(bug, bug_dir.list()) + comments = [] + name_map = {} + for c_name, comment in cmdutil.iter_comment_name(bug, unique_name): + name_map[comment.uuid] = c_name + comments.append(comment) + threaded = bugdir.thread_comments(comments) + cmdutil.print_threaded_comments(threaded, name_map) + +def get_parser(): + parser = cmdutil.CmdOptionParser("be show bug-id") + return parser + +longhelp=""" +Show all information about a bug. +""" + +def help(): + return get_parser().help_str() + longhelp diff --git a/becommands/target.py b/becommands/target.py index d077da5..665efad 100644 --- a/becommands/target.py +++ b/becommands/target.py @@ -35,6 +35,7 @@ def execute(args): No target assigned. >>> tests.clean_up() """ + options, args = get_parser().parse_args(args) assert(len(args) in (0, 1, 2)) if len(args) == 0: print help() @@ -52,10 +53,11 @@ def execute(args): bug.target = args[1] bug.save() +def get_parser(): + parser = cmdutil.CmdOptionParser("be target bug-id [target]") + return parser -def help(): - return """be target bug-id [target] - +longhelp=""" Show or change a bug's target for fixing. If no target is specified, the current value is printed. If a target @@ -66,3 +68,6 @@ milestone names or release numbers. The value "none" can be used to unset the target. """ + +def help(): + return get_parser().help_str() + longhelp diff --git a/becommands/upgrade.py b/becommands/upgrade.py index 0cbffa1..3dcb4eb 100644 --- a/becommands/upgrade.py +++ b/becommands/upgrade.py @@ -17,9 +17,10 @@ """Upgrade the bugs to the latest format""" import os.path import errno -from libbe import bugdir, rcs +from libbe import bugdir, rcs, cmdutil def execute(args): + options, args = get_parser().parse_args(args) root = bugdir.tree_root(".", old_version=True) for uuid in root.list_uuids(): old_bug = OldBug(root.bugs_path, uuid) @@ -98,5 +99,13 @@ class OldBug(object): else: rcs.set_file_contents(self.get_path(name), "%s\n" % value) +def get_parser(): + parser = cmdutil.CmdOptionParser("be upgrade") + return parser +longhelp=""" +Upgrade the bug storage to the latest format. +""" +def help(): + return get_parser().help_str() + longhelp diff --git a/beweb/beweb/controllers.py b/beweb/beweb/controllers.py index 6c43ecb..74c6a7d 100644 --- a/beweb/beweb/controllers.py +++ b/beweb/beweb/controllers.py @@ -13,9 +13,9 @@ def project_tree(project): except KeyError: raise Exception("Unknown project %s" % project) -def comment_url(project, bug, comment): +def comment_url(project, bug, comment, **kwargs): return turbogears.url("/project/%s/bug/%s/comment/%s" % - (project, bug, comment)) + (project, bug, comment), kwargs) class Comment(PrestHandler): @provide_action("action", "New comment") @@ -27,6 +27,18 @@ class Comment(PrestHandler): raise cherrypy.HTTPRedirect(comment_url(comment=comment.uuid, **comment_data)) + @provide_action("action", "Reply") + def reply_comment(self, comment_data, comment, *args, **kwargs): + bug_tree = project_tree(comment_data['project']) + bug = bug_tree.get_bug(comment_data['bug']) + reply_comment = new_comment(bug, "") + reply_comment.in_reply_to = comment.uuid + reply_comment.save() + reply_data = dict(comment_data) + del reply_data["comment"] + raise cherrypy.HTTPRedirect(comment_url(comment=reply_comment.uuid, + **reply_data)) + @provide_action("action", "Update") def update(self, comment_data, comment, comment_body, *args, **kwargs): comment.body = comment_body diff --git a/beweb/beweb/templates/edit_bug.kid b/beweb/beweb/templates/edit_bug.kid index 774334e..960866d 100644 --- a/beweb/beweb/templates/edit_bug.kid +++ b/beweb/beweb/templates/edit_bug.kid @@ -1,6 +1,6 @@ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <?python -from libbe.bugdir import severity_levels, active_status, inactive_status +from libbe.bugdir import severity_levels, active_status, inactive_status, thread_comments from libbe.utility import time_to_str from beweb.controllers import bug_list_url, comment_url from beweb.config import people @@ -67,13 +67,13 @@ def soft_pre(text): <body> <h1>Edit bug</h1> -<form method="post"> +<form method="post" action="."> <table> <tr><td>Status</td><td>Severity</td><td>Assigned To</td><td>Summary</td></tr> <tr><td>${select_among("status", active_status+inactive_status, bug.status)}</td><td>${select_among("severity", severity_levels, bug.severity)}</td> <td>${select_among("assigned", people.keys()+[None], bug.assigned, people)}</td><td><input name="summary" value="${bug.summary}" size="80" /></td></tr> </table> -<div py:for="comment in bug.list_comments()" class="comment"> +<div py:def="show_comment(comment, children)" class="comment"> <insetbox> <table> <tr><td>From</td><td>${comment.From}</td></tr> @@ -81,7 +81,18 @@ def soft_pre(text): </table> <div py:content="soft_pre(comment.body)" py:strip="True"></div> <a href="${comment_url(project_id, bug.uuid, comment.uuid)}">Edit</a> + <a href="${comment_url(project_id, bug.uuid, comment.uuid, + action='Reply')}">Reply</a> </insetbox> + <div style="margin-left:20px;"> + <div py:for="child, grandchildren in children" py:strip="True"> + ${show_comment(child, grandchildren)} + </div> + </div> +</div> +<div py:for="comment, children in thread_comments(bug.list_comments())" + py:strip="True"> + ${show_comment(comment, children)} </div> <p><input type="submit" name="action" value="Update"/></p> <p><input type="submit" name="action" value="New comment"/></p> diff --git a/libbe/bugdir.py b/libbe/bugdir.py index b78ec06..b680d16 100644 --- a/libbe/bugdir.py +++ b/libbe/bugdir.py @@ -370,7 +370,27 @@ class Comment(object): if name is None: return my_dir return os.path.join(my_dir, name) - + + +def thread_comments(comments): + child_map = {} + top_comments = [] + for comment in comments: + child_map[comment.uuid] = [] + for comment in comments: + if comment.in_reply_to is None or comment.in_reply_to not in child_map: + top_comments.append(comment) + continue + child_map[comment.in_reply_to].append(comment) + + def recurse_children(comment): + child_list = [] + for child in child_map[comment.uuid]: + child_list.append(recurse_children(child)) + return (comment, child_list) + return [recurse_children(c) for c in top_comments] + + def pyname_to_header(name): return name.capitalize().replace('_', '-') diff --git a/libbe/cmdutil.py b/libbe/cmdutil.py index b2c7f8a..079601e 100644 --- a/libbe/cmdutil.py +++ b/libbe/cmdutil.py @@ -19,6 +19,8 @@ import plugin import locale import os import optparse +from textwrap import TextWrapper +from StringIO import StringIO import utility def unique_name(bug, bugs): @@ -118,6 +120,34 @@ def raise_get_help(option, opt, value, parser): raise GetHelp +def iter_comment_name(bug, unique_name): + """Iterate through id, comment pairs, in date order. + (This is a user-friendly id, not the comment uuid) + """ + def key(comment): + return comment.date + for num, comment in enumerate(sorted(bug.list_comments(), key=key)): + yield ("%s:%d" % (unique_name, num+1), comment) + + +def comment_from_name(bug, unique_name, name): + """Use a comment name to look up a comment""" + for cur_name, comment in iter_comment_name(bug, unique_name): + if name == cur_name: + return comment + raise KeyError(name) + + +def get_bug_and_comment(identifier, bug_dir=None): + ids = identifier.split(':') + bug = get_bug(ids[0], bug_dir) + if len(ids) == 2: + comment = comment_from_name(bug, ids[0], identifier) + else: + comment = None + return bug, comment + + class CmdOptionParser(optparse.OptionParser): def __init__(self, usage): optparse.OptionParser.__init__(self, usage) @@ -148,6 +178,24 @@ def underlined(instring): return "%s\n%s" % (instring, "="*len(instring)) +def print_threaded_comments(comments, name_map, indent=""): + """Print a threaded display of comments""" + tw = TextWrapper(initial_indent = indent, subsequent_indent = indent, + width=80) + for comment, children in comments: + s = StringIO() + print >> s, "--------- Comment ---------" + print >> s, "Name: %s" % name_map[comment.uuid] + print >> s, "From: %s" % comment.From + print >> s, "Date: %s\n" % utility.time_to_str(comment.date) + print >> s, comment.body.rstrip('\n') + + s.seek(0) + for line in s: + print tw.fill(line).rstrip('\n') + print_threaded_comments(children, name_map, indent=indent+" ") + + def bug_tree(dir=None): """Retrieve the bug tree specified by the user. If no directory is specified, the current working directory is used. |