Merge lp:~clint-fewbar/launchpad-work-items-tracker/server-team-mods into lp:launchpad-work-items-tracker
- server-team-mods
- Merge into trunk
Proposed by
Clint Byrum
Status: | Merged |
---|---|
Merged at revision: | 206 |
Proposed branch: | lp:~clint-fewbar/launchpad-work-items-tracker/server-team-mods |
Merge into: | lp:launchpad-work-items-tracker |
Diff against target: |
374 lines (+107/-35) 6 files modified
burndown-chart (+20/-12) collect (+26/-3) config/maverick.cfg (+1/-0) generate-all (+33/-0) html-report (+13/-11) report_tools.py (+14/-9) |
To merge this branch: | bzr merge lp:~clint-fewbar/launchpad-work-items-tracker/server-team-mods |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Developers of work-items-tracker | Pending | ||
Review via email: mp+31336@code.launchpad.net |
Commit message
Description of the change
Hello tracker hackers.. this branch adds these features:
* Adds indexes making report and chart generation 5 - 6 times faster
* generate-all produces a burndown and report for every single user in the u directory
* inprogress status is now recorded for teams marked as 'inprogress_teams' in config, which currently is only 'canonical-server'
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'burndown-chart' | |||
2 | --- burndown-chart 2010-07-13 08:55:43 +0000 | |||
3 | +++ burndown-chart 2010-07-29 22:19:40 +0000 | |||
4 | @@ -43,10 +43,11 @@ | |||
5 | 43 | 43 | ||
6 | 44 | for date in xrange(date_to_ordinal(start_date), date_to_ordinal(end_date)+1): | 44 | for date in xrange(date_to_ordinal(start_date), date_to_ordinal(end_date)+1): |
7 | 45 | i = data.get(ordinal_to_date(date), {}) | 45 | i = data.get(ordinal_to_date(date), {}) |
9 | 46 | count = i.get('done', 0) + i.get('todo', 0) + i.get('postponed', 0) | 46 | count = i.get('done', 0) + i.get('todo', 0) + i.get('inprogress', 0) + i.get('postponed', 0) |
10 | 47 | if max_items < count: | 47 | if max_items < count: |
11 | 48 | max_items = count | 48 | max_items = count |
12 | 49 | pcdata.append((date, i.get('todo_teamonly', 0), i.get('todo', 0), | 49 | pcdata.append((date, i.get('todo_teamonly', 0), i.get('todo', 0), |
13 | 50 | i.get('inprogress_teamonly', 0), i.get('inprogress', 0), | ||
14 | 50 | i.get('done_teamonly', 0), i.get('done', 0), | 51 | i.get('done_teamonly', 0), i.get('done', 0), |
15 | 51 | i.get('postponed_teamonly', 0), i.get('postponed', 0), count)) | 52 | i.get('postponed_teamonly', 0), i.get('postponed', 0), count)) |
16 | 52 | 53 | ||
17 | @@ -90,23 +91,30 @@ | |||
18 | 90 | plot2.fill_style = fill_style.Plain(bgcolor=color.coral1) | 91 | plot2.fill_style = fill_style.Plain(bgcolor=color.coral1) |
19 | 91 | plot2.line_style = None | 92 | plot2.line_style = None |
20 | 92 | 93 | ||
23 | 93 | plot3 = bar_plot.T(label='done (team)', hcol=3, stack_on = plot2) | 94 | plot3 = bar_plot.T(label='inprogress (team)', hcol=3, stack_on = plot2) |
24 | 94 | plot3.fill_style = fill_style.green | 95 | plot3.fill_style = fill_style.Plain(bgcolor=color.orange2) |
25 | 95 | plot3.line_style = None | 96 | plot3.line_style = None |
28 | 96 | plot4 = bar_plot.T(label='done (foreign)', hcol=4, stack_on = plot2) | 97 | plot4 = bar_plot.T(label='inprogress (foreign)', hcol=4, stack_on = plot2) |
29 | 97 | plot4.fill_style = fill_style.Plain(bgcolor=color.olivedrab1) | 98 | plot4.fill_style = fill_style.Plain(bgcolor=color.orange1) |
30 | 98 | plot4.line_style = None | 99 | plot4.line_style = None |
31 | 99 | 100 | ||
34 | 100 | plot5 = bar_plot.T(label="postponed (team)", hcol=5, stack_on = plot4) | 101 | plot5 = bar_plot.T(label='done (team)', hcol=5, stack_on = plot4) |
35 | 101 | plot5.fill_style = fill_style.Plain(bgcolor=color.yellow2) | 102 | plot5.fill_style = fill_style.green |
36 | 102 | plot5.line_style = None | 103 | plot5.line_style = None |
39 | 103 | plot6 = bar_plot.T(label="postponed (foreign) ", hcol=6, stack_on = plot4) | 104 | plot6 = bar_plot.T(label='done (foreign)', hcol=6, stack_on = plot4) |
40 | 104 | plot6.fill_style = fill_style.Plain(bgcolor=color.yellow1) | 105 | plot6.fill_style = fill_style.Plain(bgcolor=color.olivedrab1) |
41 | 105 | plot6.line_style = None | 106 | plot6.line_style = None |
42 | 106 | 107 | ||
46 | 107 | plot7 = bar_plot.T(label='total', hcol=7) | 108 | plot7 = bar_plot.T(label="postponed (team)", hcol=7, stack_on = plot6) |
47 | 108 | plot7.fill_style = None | 109 | plot7.fill_style = fill_style.Plain(bgcolor=color.yellow2) |
48 | 109 | plot7.line_style = line_style.gray30 | 110 | plot7.line_style = None |
49 | 111 | plot8 = bar_plot.T(label="postponed (foreign) ", hcol=8, stack_on = plot6) | ||
50 | 112 | plot8.fill_style = fill_style.Plain(bgcolor=color.yellow1) | ||
51 | 113 | plot8.line_style = None | ||
52 | 114 | |||
53 | 115 | plot9 = bar_plot.T(label='total', hcol=9) | ||
54 | 116 | plot9.fill_style = None | ||
55 | 117 | plot9.line_style = line_style.gray30 | ||
56 | 110 | 118 | ||
57 | 111 | # create the canvas with the specified filename and file format | 119 | # create the canvas with the specified filename and file format |
58 | 112 | can = canvas.init(filename,format) | 120 | can = canvas.init(filename,format) |
59 | 113 | 121 | ||
60 | === modified file 'collect' | |||
61 | --- collect 2010-07-22 12:08:04 +0000 | |||
62 | +++ collect 2010-07-29 22:19:40 +0000 | |||
63 | @@ -359,7 +359,7 @@ | |||
64 | 359 | return None | 359 | return None |
65 | 360 | 360 | ||
66 | 361 | def lp_import_blueprint_workitems(lp, db, bp_name, bp_url, contents, release, | 361 | def lp_import_blueprint_workitems(lp, db, bp_name, bp_url, contents, release, |
68 | 362 | allow_inprogress = False): | 362 | inprogress_teams): |
69 | 363 | '''Collect work items from a Launchpad blueprint. | 363 | '''Collect work items from a Launchpad blueprint. |
70 | 364 | 364 | ||
71 | 365 | This includes work items from the whiteboard as well as linked bugs. | 365 | This includes work items from the whiteboard as well as linked bugs. |
72 | @@ -386,6 +386,16 @@ | |||
73 | 386 | dbg('lp_import_blueprint_workitems(): processing %s (spec milestone: %s, spec assignee: %s, spec implementation: %s)' % ( | 386 | dbg('lp_import_blueprint_workitems(): processing %s (spec milestone: %s, spec assignee: %s, spec implementation: %s)' % ( |
74 | 387 | bp_name, spec_milestone, spec_assignee, spec_implementation)) | 387 | bp_name, spec_milestone, spec_assignee, spec_implementation)) |
75 | 388 | 388 | ||
76 | 389 | cur.execute('SELECT team FROM teams WHERE name = ?', (spec_assignee,)) | ||
77 | 390 | assignee_teams = [t[0] for t in cur] | ||
78 | 391 | |||
79 | 392 | allow_inprogress = False | ||
80 | 393 | for t in assignee_teams: | ||
81 | 394 | if t in inprogress_teams: | ||
82 | 395 | dbg(' %s allows in progress due to membership in team %s' % (spec_assignee, t)) | ||
83 | 396 | allow_inprogress = True | ||
84 | 397 | break | ||
85 | 398 | |||
86 | 389 | cur.execute('SELECT name FROM milestones') | 399 | cur.execute('SELECT name FROM milestones') |
87 | 390 | valid_milestones = [m[0] for m in cur] | 400 | valid_milestones = [m[0] for m in cur] |
88 | 391 | 401 | ||
89 | @@ -537,7 +547,7 @@ | |||
90 | 537 | dbg('lp_import(): downloading %s from %s' % (bp, url)) | 547 | dbg('lp_import(): downloading %s from %s' % (bp, url)) |
91 | 538 | contents = urllib.urlopen(url).read().decode('UTF-8') | 548 | contents = urllib.urlopen(url).read().decode('UTF-8') |
92 | 539 | if lp_import_blueprint(db, bp, url, contents): | 549 | if lp_import_blueprint(db, bp, url, contents): |
94 | 540 | lp_import_blueprint_workitems(lp, db, bp, url, contents, cfg.get('release')) | 550 | lp_import_blueprint_workitems(lp, db, bp, url, contents, cfg.get('release'), cfg.get('inprogress_teams')) |
95 | 541 | 551 | ||
96 | 542 | ######################################################################## | 552 | ######################################################################## |
97 | 543 | # | 553 | # |
98 | @@ -690,7 +700,7 @@ | |||
99 | 690 | cur.execute('''CREATE TABLE version ( | 700 | cur.execute('''CREATE TABLE version ( |
100 | 691 | db_layout_ref INT NOT NULL | 701 | db_layout_ref INT NOT NULL |
101 | 692 | )''') | 702 | )''') |
103 | 693 | cur.execute('''INSERT INTO version VALUES (4)''') | 703 | cur.execute('''INSERT INTO version VALUES (5)''') |
104 | 694 | 704 | ||
105 | 695 | cur.execute('''CREATE TABLE specs ( | 705 | cur.execute('''CREATE TABLE specs ( |
106 | 696 | name VARCHAR(255) PRIMARY KEY, | 706 | name VARCHAR(255) PRIMARY KEY, |
107 | @@ -742,6 +752,8 @@ | |||
108 | 742 | date TIMESTAMP NOT NULL | 752 | date TIMESTAMP NOT NULL |
109 | 743 | )''') | 753 | )''') |
110 | 744 | 754 | ||
111 | 755 | create_v5_indexes(cur) | ||
112 | 756 | |||
113 | 745 | db.commit() | 757 | db.commit() |
114 | 746 | else: | 758 | else: |
115 | 747 | # upgrade DB layout | 759 | # upgrade DB layout |
116 | @@ -788,9 +800,20 @@ | |||
117 | 788 | dbg('DB upgrade finished') | 800 | dbg('DB upgrade finished') |
118 | 789 | ver = 4 | 801 | ver = 4 |
119 | 790 | 802 | ||
120 | 803 | if ver == 4: | ||
121 | 804 | dbg('Upgrading DB to layout version 5') | ||
122 | 805 | create_v5_indexes(cur) | ||
123 | 806 | cur.execute('UPDATE version SET db_layout_ref = 5') | ||
124 | 807 | db.commit() | ||
125 | 808 | ver = 5 | ||
126 | 791 | 809 | ||
127 | 792 | return db | 810 | return db |
128 | 793 | 811 | ||
129 | 812 | def create_v5_indexes(cur): | ||
130 | 813 | cur.execute('''CREATE INDEX teams_name_idx on teams(name)''') | ||
131 | 814 | cur.execute('''CREATE INDEX work_items_date_idx ON work_items (date)''') | ||
132 | 815 | cur.execute('''CREATE INDEX work_items_status_idx ON work_items (status)''') | ||
133 | 816 | |||
134 | 794 | ######################################################################## | 817 | ######################################################################## |
135 | 795 | # | 818 | # |
136 | 796 | # Program operations and main | 819 | # Program operations and main |
137 | 797 | 820 | ||
138 | === modified file 'config/maverick.cfg' | |||
139 | --- config/maverick.cfg 2010-07-20 15:32:46 +0000 | |||
140 | +++ config/maverick.cfg 2010-07-29 22:19:40 +0000 | |||
141 | @@ -75,3 +75,4 @@ | |||
142 | 75 | 75 | ||
143 | 76 | recursive_teams = ['arm-ubuntu'] | 76 | recursive_teams = ['arm-ubuntu'] |
144 | 77 | 77 | ||
145 | 78 | inprogress_teams = ['canonical-server'] | ||
146 | 78 | 79 | ||
147 | === modified file 'generate-all' | |||
148 | --- generate-all 2010-04-06 13:48:48 +0000 | |||
149 | +++ generate-all 2010-07-29 22:19:40 +0000 | |||
150 | @@ -42,9 +42,41 @@ | |||
151 | 42 | milestones = [i[0] for i in cur] | 42 | milestones = [i[0] for i in cur] |
152 | 43 | cur.execute('SELECT DISTINCT team FROM teams') | 43 | cur.execute('SELECT DISTINCT team FROM teams') |
153 | 44 | teams = [i[0] for i in cur] | 44 | teams = [i[0] for i in cur] |
154 | 45 | cur.execute('SELECT DISTINCT name FROM teams') | ||
155 | 46 | users = [i[0] for i in cur] | ||
156 | 45 | 47 | ||
157 | 46 | my_path = os.path.dirname(sys.argv[0]) | 48 | my_path = os.path.dirname(sys.argv[0]) |
158 | 47 | 49 | ||
159 | 50 | usersubdir = os.path.join(opts.output_dir, 'u') | ||
160 | 51 | try: | ||
161 | 52 | os.mkdir(usersubdir) | ||
162 | 53 | except OSError: | ||
163 | 54 | None | ||
164 | 55 | |||
165 | 56 | for u in users: | ||
166 | 57 | for m in milestones: | ||
167 | 58 | # entire cycle report for user | ||
168 | 59 | target = u + '-' + m | ||
169 | 60 | basename = os.path.join(usersubdir, target) | ||
170 | 61 | print basename + '.html' | ||
171 | 62 | f = open(basename + '.html', 'w') | ||
172 | 63 | subprocess.call([os.path.join(my_path, 'html-report'), '-d', opts.database, | ||
173 | 64 | '-t', u, '-m', m, '--chart', '%s.svg' % target], stdout=f) | ||
174 | 65 | f.close() | ||
175 | 66 | |||
176 | 67 | print basename + '.json' | ||
177 | 68 | f = open(basename + '.json', 'w') | ||
178 | 69 | subprocess.call([os.path.join(my_path, 'json-report'), '-d', opts.database, | ||
179 | 70 | '-t', u, '-m', m, '-c', opts.config], stdout=f) | ||
180 | 71 | f.close() | ||
181 | 72 | |||
182 | 73 | print basename + '.svg' | ||
183 | 74 | argv = [os.path.join(my_path, 'burndown-chart'), '-d', opts.database, '-t', | ||
184 | 75 | u, '-m', m, '-o', basename + '.svg'] | ||
185 | 76 | if u in trend_starts: | ||
186 | 77 | argv += ['--trend-start', str(trend_starts[t])] | ||
187 | 78 | subprocess.call(argv) | ||
188 | 79 | |||
189 | 48 | # per team/milestone reports | 80 | # per team/milestone reports |
190 | 49 | for t in teams: | 81 | for t in teams: |
191 | 50 | for m in milestones: | 82 | for m in milestones: |
192 | @@ -68,6 +100,7 @@ | |||
193 | 68 | argv += ['--trend-start', str(trend_starts[(t, m)])] | 100 | argv += ['--trend-start', str(trend_starts[(t, m)])] |
194 | 69 | subprocess.call(argv) | 101 | subprocess.call(argv) |
195 | 70 | 102 | ||
196 | 103 | |||
197 | 71 | # entire cycle report for team | 104 | # entire cycle report for team |
198 | 72 | basename = os.path.join(opts.output_dir, t) | 105 | basename = os.path.join(opts.output_dir, t) |
199 | 73 | print basename + '.html' | 106 | print basename + '.html' |
200 | 74 | 107 | ||
201 | === modified file 'html-report' | |||
202 | --- html-report 2010-07-08 07:37:26 +0000 | |||
203 | +++ html-report 2010-07-29 22:19:40 +0000 | |||
204 | @@ -27,7 +27,7 @@ | |||
205 | 27 | <p>(Click header to sort)</p> | 27 | <p>(Click header to sort)</p> |
206 | 28 | <table id="byspecification"> | 28 | <table id="byspecification"> |
207 | 29 | <thead> | 29 | <thead> |
209 | 30 | <tr><th>Specification</th><th>Complexity</th> <th>todo</th><th>postponed</th><th>done</th> <th>Completion</th> <th>Priority</th> <th>Status</th></tr> | 30 | <tr><th>Specification</th><th>Complexity</th> <th>todo</th><th>inprogress</th><th>postponed</th><th>done</th> <th>Completion</th> <th>Priority</th> <th>Status</th></tr> |
210 | 31 | </thead> | 31 | </thead> |
211 | 32 | ''' | 32 | ''' |
212 | 33 | data = report_tools.blueprint_completion(db, team, milestone) | 33 | data = report_tools.blueprint_completion(db, team, milestone) |
213 | @@ -35,16 +35,16 @@ | |||
214 | 35 | completion = [] | 35 | completion = [] |
215 | 36 | for (bp, i) in data.iteritems(): | 36 | for (bp, i) in data.iteritems(): |
216 | 37 | completion.append((bp, | 37 | completion.append((bp, |
218 | 38 | int(float(i['postponed']+i['done'])/(i['todo']+i['done']+i['postponed'])*100 + 0.5))) | 38 | int(float(i['postponed']+i['done'])/(i['todo']+i['done']+i['postponed']+i['inprogress'])*100 + 0.5))) |
219 | 39 | 39 | ||
220 | 40 | completion.sort(key=lambda k: k[1]*100+report_tools.priority_value(data[k[0]]['priority']), reverse=True) | 40 | completion.sort(key=lambda k: k[1]*100+report_tools.priority_value(data[k[0]]['priority']), reverse=True) |
221 | 41 | 41 | ||
222 | 42 | for (bp, percent) in completion: | 42 | for (bp, percent) in completion: |
224 | 43 | print ' <tr><td>%s</td> <td>%s</td><td>%i</td><td>%i</td><td>%i</td> <td>%i%%<br/>' \ | 43 | print ' <tr><td>%s</td> <td>%s</td><td>%i</td><td>%i</td><td>%i</td><td>%i</td> <td>%i%%<br/>' \ |
225 | 44 | '<span style="font-size: 70%%">%s</span></td> <td>%s</td> <td>%s</td></tr>' % ( | 44 | '<span style="font-size: 70%%">%s</span></td> <td>%s</td> <td>%s</td></tr>' % ( |
226 | 45 | '<a href="%s">%s</a>' % (data[bp]['url'], escape_html(bp)), | 45 | '<a href="%s">%s</a>' % (data[bp]['url'], escape_html(bp)), |
227 | 46 | data[bp]['complexity'] or '', | 46 | data[bp]['complexity'] or '', |
229 | 47 | data[bp]['todo'], data[bp]['postponed'], data[bp]['done'], | 47 | data[bp]['todo'], data[bp]['inprogress'], data[bp]['postponed'], data[bp]['done'], |
230 | 48 | percent, | 48 | percent, |
231 | 49 | data[bp]['implementation'], | 49 | data[bp]['implementation'], |
232 | 50 | format_priority(data[bp]['priority']), | 50 | format_priority(data[bp]['priority']), |
233 | @@ -58,24 +58,24 @@ | |||
234 | 58 | <p>(Click header to sort)</p> | 58 | <p>(Click header to sort)</p> |
235 | 59 | <table id="byassignee"> | 59 | <table id="byassignee"> |
236 | 60 | <thead> | 60 | <thead> |
238 | 61 | <tr><th>Assignee</th> <th>Complexity</th><th>todo</th><th>postponed</th><th>done</th> <th>Completion</th></tr> | 61 | <tr><th>Assignee</th> <th>Complexity</th><th>todo</th><th>inprogress</th><th>postponed</th><th>done</th> <th>Completion</th></tr> |
239 | 62 | </thead> | 62 | </thead> |
240 | 63 | ''' | 63 | ''' |
241 | 64 | data = report_tools.assignee_completion(db, team, milestone) | 64 | data = report_tools.assignee_completion(db, team, milestone) |
242 | 65 | 65 | ||
243 | 66 | completion = [] | 66 | completion = [] |
244 | 67 | for a, i in data.iteritems(): | 67 | for a, i in data.iteritems(): |
246 | 68 | (todo, postponed, done) = (len(i['todo']), len(i['postponed']), len(i['done'])) | 68 | (todo, inprogress, postponed, done) = (len(i['todo']), len(i['inprogress']), len(i['postponed']), len(i['done'])) |
247 | 69 | completion.append((a, | 69 | completion.append((a, |
249 | 70 | int(float(postponed+done) / (todo+done+postponed)*100 + 0.5))) | 70 | int(float(postponed+done) / (todo+inprogress+done+postponed)*100 + 0.5))) |
250 | 71 | 71 | ||
251 | 72 | completion.sort(key=lambda k: k[0], reverse=False) | 72 | completion.sort(key=lambda k: k[0], reverse=False) |
252 | 73 | 73 | ||
253 | 74 | for (a, percent) in completion: | 74 | for (a, percent) in completion: |
254 | 75 | a_html = escape_url(a or team or 'nobody') | 75 | a_html = escape_url(a or team or 'nobody') |
255 | 76 | url = '%s/~%s/+specs?role=assignee' % (report_tools.blueprints_base_url, a_html) | 76 | url = '%s/~%s/+specs?role=assignee' % (report_tools.blueprints_base_url, a_html) |
258 | 77 | print ' <tr><td><a href="%s">%s</a></td> <td>%s</td><td>%i</td><td>%i</td><td>%i</td> <td>%i%%</td></tr>' % ( | 77 | print ' <tr><td><a href="%s">%s</a></td> <td>%s</td><td>%i</td><td>%i</td><td>%i</td><td>%i</td> <td>%i%%</td></tr>' % ( |
259 | 78 | url, a_html, data[a]['complexity'] or '', len(data[a]['todo']), len(data[a]['postponed']), | 78 | url, a_html, data[a]['complexity'] or '', len(data[a]['todo']), len(data[a]['inprogress']), len(data[a]['postponed']), |
260 | 79 | len(data[a]['done']), percent) | 79 | len(data[a]['done']), percent) |
261 | 80 | print '</table>' | 80 | print '</table>' |
262 | 81 | 81 | ||
263 | @@ -103,11 +103,13 @@ | |||
264 | 103 | todo_len = len(i['todo']) | 103 | todo_len = len(i['todo']) |
265 | 104 | postponed_len = len(i['postponed']) | 104 | postponed_len = len(i['postponed']) |
266 | 105 | done_len = len(i['done']) | 105 | done_len = len(i['done']) |
267 | 106 | inprogress_len = len(i['inprogress']) | ||
268 | 106 | a_html = escape_url(a or team or 'nobody') | 107 | a_html = escape_url(a or team or 'nobody') |
269 | 107 | a_url = '%s/~%s/+specs?role=assignee' % (report_tools.blueprints_base_url, a_html) | 108 | a_url = '%s/~%s/+specs?role=assignee' % (report_tools.blueprints_base_url, a_html) |
270 | 108 | rows = {'todo': '<td rowspan="%s">todo</td>' % todo_len, | 109 | rows = {'todo': '<td rowspan="%s">todo</td>' % todo_len, |
271 | 109 | 'postponed': '<td rowspan="%s">postponed</td>' % postponed_len, | 110 | 'postponed': '<td rowspan="%s">postponed</td>' % postponed_len, |
273 | 110 | 'done': '<td rowspan="%s">done</td>' % done_len} | 111 | 'done': '<td rowspan="%s">done</td>' % done_len, |
274 | 112 | 'inprogress': '<td rowspan="%s">inprogress</td>' % inprogress_len} | ||
275 | 111 | printed_assignee = False | 113 | printed_assignee = False |
276 | 112 | for status in report_tools.valid_states: | 114 | for status in report_tools.valid_states: |
277 | 113 | printed_status = False | 115 | printed_status = False |
278 | @@ -116,7 +118,7 @@ | |||
279 | 116 | print ' <tr>', | 118 | print ' <tr>', |
280 | 117 | if not printed_assignee: | 119 | if not printed_assignee: |
281 | 118 | print '<td rowspan="%s"><a href="%s" name="%s">%s</a></td> ' % ( | 120 | print '<td rowspan="%s"><a href="%s" name="%s">%s</a></td> ' % ( |
283 | 119 | todo_len+postponed_len+done_len, a_url, escape_url(a or team or 'nobody'), | 121 | todo_len+postponed_len+done_len+inprogress_len, a_url, escape_url(a or team or 'nobody'), |
284 | 120 | a_html) | 122 | a_html) |
285 | 121 | printed_assignee = True | 123 | printed_assignee = True |
286 | 122 | if not printed_status: | 124 | if not printed_status: |
287 | 123 | 125 | ||
288 | === modified file 'report_tools.py' | |||
289 | --- report_tools.py 2010-07-08 00:38:33 +0000 | |||
290 | +++ report_tools.py 2010-07-29 22:19:40 +0000 | |||
291 | @@ -6,7 +6,7 @@ | |||
292 | 6 | import sqlite3 as dbapi2 | 6 | import sqlite3 as dbapi2 |
293 | 7 | from cgi import escape | 7 | from cgi import escape |
294 | 8 | 8 | ||
296 | 9 | valid_states = ['todo', 'done', 'postponed'] | 9 | valid_states = ['todo', 'done', 'postponed', 'inprogress'] |
297 | 10 | blueprints_base_url = 'https://blueprints.launchpad.net' | 10 | blueprints_base_url = 'https://blueprints.launchpad.net' |
298 | 11 | 11 | ||
299 | 12 | def escape_sql(text): | 12 | def escape_sql(text): |
300 | @@ -59,7 +59,7 @@ | |||
301 | 59 | given team. | 59 | given team. |
302 | 60 | 60 | ||
303 | 61 | Return date -> state -> count mapping. states are | 61 | Return date -> state -> count mapping. states are |
305 | 62 | {todo,done,postponed}{,_teamonly}. | 62 | {todo,inprogress,done,postponed}{,_teamonly}. |
306 | 63 | ''' | 63 | ''' |
307 | 64 | data = {} | 64 | data = {} |
308 | 65 | if milestone: | 65 | if milestone: |
309 | @@ -119,7 +119,7 @@ | |||
310 | 119 | '''Determine current blueprint completion. | 119 | '''Determine current blueprint completion. |
311 | 120 | 120 | ||
312 | 121 | Return blueprint -> info mapping, with info being a map with these | 121 | Return blueprint -> info mapping, with info being a map with these |
314 | 122 | keys: todo, done, postponed, status, priority, implementation, url. | 122 | keys: todo, inprogress, done, postponed, status, priority, implementation, url. |
315 | 123 | ''' | 123 | ''' |
316 | 124 | data = {} | 124 | data = {} |
317 | 125 | if milestone == '': | 125 | if milestone == '': |
318 | @@ -155,7 +155,7 @@ | |||
319 | 155 | (s, last_date)) | 155 | (s, last_date)) |
320 | 156 | 156 | ||
321 | 157 | for (bp, num, status, priority, impl, url, roadmap_notes) in cur: | 157 | for (bp, num, status, priority, impl, url, roadmap_notes) in cur: |
323 | 158 | info = data.setdefault(bp, {'todo': 0, 'done': 0, 'postponed': 0}) | 158 | info = data.setdefault(bp, {'todo': 0, 'done': 0, 'postponed': 0, 'inprogress': 0}) |
324 | 159 | info[s] = num | 159 | info[s] = num |
325 | 160 | info['status'] = status or '' | 160 | info['status'] = status or '' |
326 | 161 | info['priority'] = priority | 161 | info['priority'] = priority |
327 | @@ -175,7 +175,7 @@ | |||
328 | 175 | '''Determine current blueprint tasks completion. | 175 | '''Determine current blueprint tasks completion. |
329 | 176 | 176 | ||
330 | 177 | Return blueprint -> info mapping, with info being a map with these | 177 | Return blueprint -> info mapping, with info being a map with these |
332 | 178 | keys: todo, done, postponed, status, priority, implementation, url, tasks. | 178 | keys: todo, inprogress, done, postponed, status, priority, implementation, url, tasks. |
333 | 179 | ''' | 179 | ''' |
334 | 180 | default = blueprint_completion(db, team=team) | 180 | default = blueprint_completion(db, team=team) |
335 | 181 | data = {} | 181 | data = {} |
336 | @@ -227,7 +227,7 @@ | |||
337 | 227 | '''Determine current by-assignee completion. | 227 | '''Determine current by-assignee completion. |
338 | 228 | 228 | ||
339 | 229 | Return assignee -> info mapping with info being a map with these | 229 | Return assignee -> info mapping with info being a map with these |
341 | 230 | keys: todo, done, postponed. Each of those values is a list of [blueprint, | 230 | keys: todo, inprogress, done, postponed. Each of those values is a list of [blueprint, |
342 | 231 | workitem, priority, spec_url]. | 231 | workitem, priority, spec_url]. |
343 | 232 | ''' | 232 | ''' |
344 | 233 | data = {} | 233 | data = {} |
345 | @@ -261,7 +261,7 @@ | |||
346 | 261 | 'WHERE w.status = ? AND w.date = ? %s ' % ms_sql, | 261 | 'WHERE w.status = ? AND w.date = ? %s ' % ms_sql, |
347 | 262 | (s, last_date)) | 262 | (s, last_date)) |
348 | 263 | for (a, bp, description, priority, url) in cur: | 263 | for (a, bp, description, priority, url) in cur: |
350 | 264 | info = data.setdefault(a, {'todo': [], 'done': [], 'postponed': []}) | 264 | info = data.setdefault(a, {'todo': [], 'done': [], 'postponed': [], 'inprogress': []}) |
351 | 265 | info[s].append([bp, description, priority, url]) | 265 | info[s].append([bp, description, priority, url]) |
352 | 266 | 266 | ||
353 | 267 | cur2 = db.cursor(); | 267 | cur2 = db.cursor(); |
354 | @@ -288,7 +288,12 @@ | |||
355 | 288 | 288 | ||
356 | 289 | ### limit by a team 'like'? (see config) | 289 | ### limit by a team 'like'? (see config) |
357 | 290 | if team: | 290 | if team: |
359 | 291 | team_sql = "AND name like '%%%s%%' " % config.get('teams')[team] | 291 | lookup = '' |
360 | 292 | try: | ||
361 | 293 | lookup = config.get('teams')[team] | ||
362 | 294 | except KeyError: | ||
363 | 295 | lookup = team | ||
364 | 296 | team_sql = "AND name like '%%%s%%' " % lookup | ||
365 | 292 | else: | 297 | else: |
366 | 293 | team_sql = "" | 298 | team_sql = "" |
367 | 294 | 299 | ||
368 | @@ -345,7 +350,7 @@ | |||
369 | 345 | ### use the todo/done/postponed numbers from blueprint_completion | 350 | ### use the todo/done/postponed numbers from blueprint_completion |
370 | 346 | csd = completion_dict.get( spec_row["name"], None ) | 351 | csd = completion_dict.get( spec_row["name"], None ) |
371 | 347 | if csd: | 352 | if csd: |
373 | 348 | for k in ("todo","done","postponed"): | 353 | for k in valid_states: |
374 | 349 | spec_dict["completion"][k] = csd[k] | 354 | spec_dict["completion"][k] = csd[k] |
375 | 350 | 355 | ||
376 | 351 | 356 |