1 # Author: Dmitriy Morozov <hg@foxcub.org>, 2007 -- 2009 |
1 # Author: Dmitriy Morozov <hg@foxcub.org>, 2007 -- 2009 |
2 |
2 |
3 """A very simple and lightweight issue tracker for Mercurial.""" |
3 """A very simple and lightweight issue tracker for Mercurial.""" |
4 |
4 |
5 from mercurial import hg, util |
5 from mercurial import hg, util |
6 from mercurial.i18n import _ |
6 from mercurial.i18n import _ |
7 import os, time, random, mailbox, glob, socket, ConfigParser |
7 import os, time, random, mailbox, glob, socket, ConfigParser |
64 for property,value in properties: |
64 for property,value in properties: |
65 if value: |
65 if value: |
66 property_match = property_match and (mbox[root][property] == value) |
66 property_match = property_match and (mbox[root][property] == value) |
67 else: |
67 else: |
68 property_match = property_match and (property not in mbox[root]) |
68 property_match = property_match and (property not in mbox[root]) |
69 |
69 |
70 if not show_all and (not properties or not property_match) and (properties or mbox[root]['State'].upper() in [f.upper() for f in state['fixed']]): continue |
70 if not show_all and (not properties or not property_match) and (properties or mbox[root]['State'].upper() in [f.upper() for f in state['fixed']]): continue |
71 if match_date and not date_match(util.parsedate(mbox[root]['date'])[0]): continue |
71 if match_date and not date_match(util.parsedate(mbox[root]['date'])[0]): continue |
72 |
72 |
73 if not list_properties: |
73 if not list_properties: |
74 ui.write("%s (%3d) [%s]: %s\n" % (issue[len(issues_path)+1:], # +1 for trailing / |
74 ui.write("%s (%3d) [%s]: %s\n" % (issue[len(issues_path)+1:], # +1 for trailing / |
112 default_issue_text += "Detailed description." |
112 default_issue_text += "Detailed description." |
113 |
113 |
114 # Get properties, and figure out if we need an explicit comment |
114 # Get properties, and figure out if we need an explicit comment |
115 properties = _get_properties(opts['property']) |
115 properties = _get_properties(opts['property']) |
116 no_comment = id and properties and opts['no_property_comment'] |
116 no_comment = id and properties and opts['no_property_comment'] |
|
117 message = opts['message'] |
117 |
118 |
118 # Create the text |
119 # Create the text |
119 if not no_comment: |
120 if message: |
|
121 if not id: |
|
122 state_str = 'State: %s\n' % state['default'] |
|
123 else: |
|
124 state_str = '' |
|
125 issue = "From: %s\nDate: %s\nSubject: %s\n%s" % \ |
|
126 (user, util.datestr(format=date_format), message, state_str) |
|
127 elif not no_comment: |
120 issue = ui.edit(default_issue_text, user) |
128 issue = ui.edit(default_issue_text, user) |
121 |
129 |
122 if issue.strip() == '': |
130 if issue.strip() == '': |
123 ui.warn('Empty issue, ignoring\n') |
131 ui.warn('Empty issue, ignoring\n') |
124 return |
132 return |
125 if issue.strip() == default_issue_text: |
133 if issue.strip() == default_issue_text: |
126 ui.warn('Unchanged issue text, ignoring\n') |
134 ui.warn('Unchanged issue text, ignoring\n') |
127 return |
135 return |
128 else: |
136 else: |
129 # Write down a comment about updated properties |
137 # Write down a comment about updated properties |
130 properties_subject = ', '.join(['%s=%s' % (property, value) for (property, value) in properties]) |
138 properties_subject = ', '.join(['%s=%s' % (property, value) for (property, value) in properties]) |
131 |
139 |
132 issue = "From: %s\nDate: %s\nSubject: changed properties (%s)\n" % \ |
140 issue = "From: %s\nDate: %s\nSubject: changed properties (%s)\n" % \ |
133 (user, util.datestr(format = date_format), properties_subject) |
141 (user, util.datestr(format = date_format), properties_subject) |
134 |
142 |
135 # Create the message |
143 # Create the message |
136 msg = mailbox.MaildirMessage(issue) |
144 msg = mailbox.MaildirMessage(issue) |
185 def ishow(ui, repo, id, comment = 0, **opts): |
193 def ishow(ui, repo, id, comment = 0, **opts): |
186 """Shows issue ID, or possibly its comment COMMENT""" |
194 """Shows issue ID, or possibly its comment COMMENT""" |
187 |
195 |
188 comment = int(comment) |
196 comment = int(comment) |
189 issue, id = _find_issue(ui, repo, id) |
197 issue, id = _find_issue(ui, repo, id) |
190 if not issue: return |
198 if not issue: |
|
199 return ui.warn('No such issue\n') |
191 |
200 |
192 issues_dir = ui.config('artemis', 'issues', default = default_issues_dir) |
201 issues_dir = ui.config('artemis', 'issues', default = default_issues_dir) |
193 _create_missing_dirs(os.path.join(repo.root, issues_dir), issue) |
202 _create_missing_dirs(os.path.join(repo.root, issues_dir), issue) |
194 |
203 |
|
204 if opts.get('mutt'): |
|
205 return util.system('mutt -R -f %s' % issue) |
|
206 |
195 mbox = mailbox.Maildir(issue, factory=mailbox.MaildirMessage) |
207 mbox = mailbox.Maildir(issue, factory=mailbox.MaildirMessage) |
196 |
208 |
197 if opts['all']: |
209 if opts['all']: |
198 ui.write('='*70 + '\n') |
210 ui.write('='*70 + '\n') |
199 i = 0 |
211 i = 0 |
200 keys = _order_keys_date(mbox) |
212 keys = _order_keys_date(mbox) |
201 for k in keys: |
213 for k in keys: |
202 _write_message(ui, mbox[k], i, skip = opts['skip']) |
214 _write_message(ui, mbox[k], i, skip = opts['skip']) |
203 ui.write('-'*70 + '\n') |
215 ui.write('-'*70 + '\n') |
204 i += 1 |
216 i += 1 |
205 return |
217 return |
393 ('p', 'property', [], |
405 ('p', 'property', [], |
394 'list issues with specific field values (e.g., -p state=fixed); lists all possible values of a property if no = sign'), |
406 'list issues with specific field values (e.g., -p state=fixed); lists all possible values of a property if no = sign'), |
395 ('d', 'date', '', 'restrict to issues matching the date (e.g., -d ">12/28/2007)"'), |
407 ('d', 'date', '', 'restrict to issues matching the date (e.g., -d ">12/28/2007)"'), |
396 ('f', 'filter', '', 'restrict to pre-defined filter (in %s/%s*)' % (default_issues_dir, filter_prefix))], |
408 ('f', 'filter', '', 'restrict to pre-defined filter (in %s/%s*)' % (default_issues_dir, filter_prefix))], |
397 _('hg ilist [OPTIONS]')), |
409 _('hg ilist [OPTIONS]')), |
398 'iadd': (iadd, |
410 'iadd': (iadd, |
399 [('a', 'attach', [], |
411 [('a', 'attach', [], |
400 'attach file(s) (e.g., -a filename1 -a filename2)'), |
412 'attach file(s) (e.g., -a filename1 -a filename2)'), |
401 ('p', 'property', [], |
413 ('p', 'property', [], |
402 'update properties (e.g., -p state=fixed)'), |
414 'update properties (e.g., -p state=fixed)'), |
403 ('n', 'no-property-comment', None, |
415 ('n', 'no-property-comment', None, |
404 'do not add a comment about changed properties')], |
416 'do not add a comment about changed properties'), |
|
417 ('m', 'message', '', |
|
418 'use <text> as an issue subject')], |
405 _('hg iadd [OPTIONS] [ID] [COMMENT]')), |
419 _('hg iadd [OPTIONS] [ID] [COMMENT]')), |
406 'ishow': (ishow, |
420 'ishow': (ishow, |
407 [('a', 'all', None, 'list all comments'), |
421 [('a', 'all', None, 'list all comments'), |
408 ('s', 'skip', '>', 'skip lines starting with a substring'), |
422 ('s', 'skip', '>', 'skip lines starting with a substring'), |
409 ('x', 'extract', [], 'extract attachments (provide attachment number as argument)')], |
423 ('x', 'extract', [], 'extract attachments (provide attachment number as argument)'), |
|
424 ('', 'mutt', False, 'use mutt to show issue')], |
410 _('hg ishow [OPTIONS] ID [COMMENT]')), |
425 _('hg ishow [OPTIONS] ID [COMMENT]')), |
411 } |
426 } |
412 |
427 |
413 # vim: expandtab |
428 # vim: expandtab |