MDK Tracker commenting
[mdk.git] / mdk / commands / tracker.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 """
5 Moodle Development Kit
6
7 Copyright (c) 2013 Frédéric Massart - FMCorz.net
8
9 This program is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
21
22 http://github.com/FMCorz/mdk
23 """
24
25 from datetime import datetime
26 import textwrap
27 import re
28 from ..command import Command
29 from ..jira import Jira
30 from ..tools import parseBranch, getText
31
32
33 class TrackerCommand(Command):
34
35 _arguments = [
36 (
37 ['-t', '--testing'],
38 {
39 'action': 'store_true',
40 'help': 'include testing instructions'
41 }
42 ),
43 (
44 ['issue'],
45 {
46 'help': 'MDL issue number. Guessed from the current branch if not specified.',
47 'nargs': '?'
48 }
49 ),
50 (
51 ['--add-labels'],
52 {
53 'action': 'store',
54 'dest': 'addlabels',
55 'help': 'add the specified labels to the issue',
56 'metavar': 'labels',
57 'nargs': '+',
58 }
59 ),
60 (
61 ['--remove-labels'],
62 {
63 'action': 'store',
64 'dest': 'removelabels',
65 'help': 'remove the specified labels from the issue',
66 'metavar': 'labels',
67 'nargs': '+',
68 }
69 ),
70 (
71 ['--comment'],
72 {
73 'action': 'store_true',
74 'help': 'add a comment to the issue',
75 }
76 )
77 ]
78 _description = 'Interact with Moodle tracker'
79
80 Jira = None
81 mdl = None
82
83 def run(self, args):
84
85 issue = None
86 if not args.issue:
87 M = self.Wp.resolve()
88 if M:
89 parsedbranch = parseBranch(M.currentBranch())
90 if parsedbranch:
91 issue = parsedbranch['issue']
92 else:
93 issue = args.issue
94
95 if not issue or not re.match('(MDL|mdl)?(-|_)?[1-9]+', issue):
96 raise Exception('Invalid or unknown issue number')
97
98 self.Jira = Jira()
99 self.mdl = 'MDL-' + re.sub(r'(MDL|mdl)(-|_)?', '', issue)
100
101 if args.addlabels:
102 if 'triaged' in args.addlabels:
103 self.argumentError('The label \'triaged\' cannot be added using MDK')
104 elif 'triaging_in_progress' in args.addlabels:
105 self.argumentError('The label \'triaging_in_progress\' cannot be added using MDK')
106 self.Jira.addLabels(self.mdl, args.addlabels)
107
108 if args.removelabels:
109 if 'triaged' in args.removelabels:
110 self.argumentError('The label \'triaged\' cannot be removed using MDK')
111 elif 'triaging_in_progress' in args.removelabels:
112 self.argumentError('The label \'triaging_in_progress\' cannot be removed using MDK')
113 self.Jira.removeLabels(self.mdl, args.removelabels)
114
115 if args.comment:
116 comment = getText()
117 self.Jira.addComment(self.mdl, comment)
118
119 self.info(args)
120
121 def info(self, args):
122 """Display classic information about an issue"""
123 issue = self.Jira.getIssue(self.mdl)
124
125 title = u'%s: %s' % (issue['key'], issue['fields']['summary'])
126 created = datetime.strftime(Jira.parseDate(issue['fields'].get('created')), '%Y-%m-%d %H:%M')
127 resolution = u'' if issue['fields']['resolution'] == None else u'(%s)' % (issue['fields']['resolution']['name'])
128 resolutiondate = u''
129 if issue['fields'].get('resolutiondate') != None:
130 resolutiondate = datetime.strftime(Jira.parseDate(issue['fields'].get('resolutiondate')), '%Y-%m-%d %H:%M')
131 print u'-' * 72
132 for l in textwrap.wrap(title, 68, initial_indent=' ', subsequent_indent=' '):
133 print l
134 print u' {0} - {1} - {2}'.format(issue['fields']['issuetype']['name'], issue['fields']['priority']['name'], u'https://tracker.moodle.org/browse/' + issue['key'])
135 status = u'{0} {1} {2}'.format(issue['fields']['status']['name'], resolution, resolutiondate).strip()
136 print u' {0}'.format(status)
137
138 print u'-' * 72
139 components = u'{0}: {1}'.format('Components', ', '.join([c['name'] for c in issue['fields']['components']]))
140 for l in textwrap.wrap(components, 68, initial_indent=' ', subsequent_indent=' '):
141 print l
142 if issue['fields']['labels']:
143 labels = u'{0}: {1}'.format('Labels', ', '.join(issue['fields']['labels']))
144 for l in textwrap.wrap(labels, 68, initial_indent=' ', subsequent_indent=' '):
145 print l
146
147 vw = u'[ V: %d - W: %d ]' % (issue['fields']['votes']['votes'], issue['fields']['watches']['watchCount'])
148 print '{0:->70}--'.format(vw)
149 print u'{0:<20}: {1} ({2}) on {3}'.format('Reporter', issue['fields']['reporter']['displayName'], issue['fields']['reporter']['name'], created)
150
151 if issue['fields'].get('assignee') != None:
152 print u'{0:<20}: {1} ({2})'.format('Assignee', issue['fields']['assignee']['displayName'], issue['fields']['assignee']['name'])
153 if issue['named'].get('Peer reviewer'):
154 print u'{0:<20}: {1} ({2})'.format('Peer reviewer', issue['named']['Peer reviewer']['displayName'], issue['named']['Peer reviewer']['name'])
155 if issue['named'].get('Integrator'):
156 print u'{0:<20}: {1} ({2})'.format('Integrator', issue['named']['Integrator']['displayName'], issue['named']['Integrator']['name'])
157 if issue['named'].get('Tester'):
158 print u'{0:<20}: {1} ({2})'.format('Tester', issue['named']['Tester']['displayName'], issue['named']['Tester']['name'])
159
160 if args.testing and issue['named'].get('Testing Instructions'):
161 print u'-' * 72
162 print u'Testing instructions:'
163 for l in issue['named'].get('Testing Instructions').split('\r\n'):
164 print ' ' + l
165
166 print u'-' * 72