| 1 | # -*- coding: utf-8 -*- |
|---|
| 2 | # |
|---|
| 3 | # Copyright (C) 2011-2014 Rob Guttman <guttman@alum.mit.edu> |
|---|
| 4 | # All rights reserved. |
|---|
| 5 | # |
|---|
| 6 | # This software is licensed as described in the file COPYING, which |
|---|
| 7 | # you should have received as part of this distribution. |
|---|
| 8 | # |
|---|
| 9 | |
|---|
| 10 | # several milestone-related analyses |
|---|
| 11 | |
|---|
| 12 | def get_dependency_solutions(db, args): |
|---|
| 13 | """For each blockedby ticket of this id, check that it's milestone's |
|---|
| 14 | due date is <= this ticket's milestone's due date. |
|---|
| 15 | """ |
|---|
| 16 | id = args['id1'] |
|---|
| 17 | cursor = db.cursor() |
|---|
| 18 | |
|---|
| 19 | # get the type and due date |
|---|
| 20 | cursor.execute(""" |
|---|
| 21 | SELECT t.type, t.milestone, m.due |
|---|
| 22 | FROM ticket t |
|---|
| 23 | JOIN milestone m ON t.milestone = m.name |
|---|
| 24 | WHERE t.id = %s; |
|---|
| 25 | """, (id,)) |
|---|
| 26 | result = cursor.fetchone() |
|---|
| 27 | if not result: |
|---|
| 28 | return '',[] |
|---|
| 29 | type,milestone,due = result |
|---|
| 30 | if not due: |
|---|
| 31 | return '',[] # this ticket's milestone doesn't have a due date - skip |
|---|
| 32 | |
|---|
| 33 | # find all peers that are due too late (or not scheduled at all) |
|---|
| 34 | cursor.execute(""" |
|---|
| 35 | SELECT t.id, t.milestone, m.due FROM ticket t |
|---|
| 36 | JOIN milestone m ON t.milestone = m.name |
|---|
| 37 | WHERE t.id IN (SELECT source FROM mastertickets WHERE dest = %s) |
|---|
| 38 | AND t.status != 'closed' |
|---|
| 39 | AND (t.milestone='' OR m.due=0 OR m.due > %s); |
|---|
| 40 | """, (id,due)) |
|---|
| 41 | result = zip(*[(t,m,d) for t,m,d in cursor]) |
|---|
| 42 | if not result: |
|---|
| 43 | return '',[] # no dependent tickets! skip |
|---|
| 44 | |
|---|
| 45 | issue = "#%s's dependent tickets are in future (or no) milestones." % id |
|---|
| 46 | ids,milestones,dues = result |
|---|
| 47 | solutions = [] |
|---|
| 48 | |
|---|
| 49 | # solution 1: move dependent tickets to this milestone |
|---|
| 50 | tix = ', '.join(["#%s" % tid for tid in ids]) |
|---|
| 51 | data = [] |
|---|
| 52 | for tid in ids: |
|---|
| 53 | changes = {'ticket':tid,'milestone':milestone} |
|---|
| 54 | for field in args['on_change_clear']: |
|---|
| 55 | changes.update({field:''}) |
|---|
| 56 | data.append(changes) |
|---|
| 57 | solutions.append({ |
|---|
| 58 | 'name': 'Move %s up to milestone %s' % (tix,milestone), |
|---|
| 59 | 'data': data, |
|---|
| 60 | }) |
|---|
| 61 | |
|---|
| 62 | # solution 2: move this ticket to latest dependent milestone |
|---|
| 63 | if any(m for m in milestones) and any(d for d in dues): |
|---|
| 64 | cursor.execute(""" |
|---|
| 65 | SELECT name FROM milestone WHERE due = |
|---|
| 66 | (SELECT max(due) FROM milestone WHERE name in (%s)); |
|---|
| 67 | """ % ','.join(["'%s'" % m for m in milestones if m])) |
|---|
| 68 | result = cursor.fetchone() |
|---|
| 69 | if result: |
|---|
| 70 | (latest_milestone,) = result |
|---|
| 71 | changes = {'ticket':id,'milestone':latest_milestone} |
|---|
| 72 | for field in args['on_change_clear']: |
|---|
| 73 | changes.update({field:''}) |
|---|
| 74 | solutions.append({ |
|---|
| 75 | 'name': 'Move #%s out to milestone %s' % (id,latest_milestone), |
|---|
| 76 | 'data': changes, |
|---|
| 77 | }) |
|---|
| 78 | |
|---|
| 79 | return issue,solutions |
|---|