Commits

Alex Willmer  committed 27452a0

Recursive check for blocking tickets

  • Participants
  • Parent commits e88d39c
  • Branches ticket-links-trunk

Comments (0)

Files changed (1)

File trac/ticket/links.py

 from copy import copy
 from trac.core import Component, implements
 
+def uniq(seq):
+    """Yield unique elements from sequence of hashables, preserving order.
+    """
+    seen = set()
+    for x in seq:
+        if x not in seen:
+            seen.add(x)
+            yield x
+    
 class LinksProvider(Component):
     """Link controller that provides links as specified in the [ticket-links]
     section in the trac.ini configuration file.
         return self._labels[end]
     
     def is_blocker(self, end):
-        return self.blockers[end]
+        return self._blockers[end]
     
     def prepare_ticket(self, req, ticket, fields, actions):
         pass
         
     def validate_ticket(self, req, ticket):
+        action = req.args.get('action')
+        ticket_system = TicketSystem(self.env)
+        
         for end, validator in self._validators.items():
             check = validator(ticket, end)
             if check:
                 yield None, check
-        
+            
+            if action == 'resolve' and self.is_blocker(end):
+                blockers = self.find_blockers(ticket, end, [])
+                if blockers:
+                    blockers_str = ', '.join('#%s' % x for x in uniq(blockers))
+                    msg = ("Cannot resolve this ticket because it is "
+                           "blocked by '%s' tickets [%s]" 
+                           % (end,  blockers_str))
+                    yield None, msg
+    
     def validate_no_cycle(self, ticket, end):
         cycle = self.find_cycle(ticket, end, [])
         if cycle != None:
                 blockers[end2] = config.getbool(end2 + '.blocks', default=False)
             
         return links, labels, validators, blockers
-
-
+    
+    def find_blockers(self, ticket, field, blockers):
+        ticket_system = TicketSystem(self.env)
+        links = ticket_system.parse_links(ticket[field])
+        for link in links:
+            linked_ticket = Ticket(self.env, link)
+            if linked_ticket['status'] != 'closed':
+                blockers.append(link)
+            else:
+                self.find_blockers(linked_ticket, field, blockers)
+        return blockers
+        
     def find_cycle(self, ticket, field, path):
         if ticket.id in path:
             path.append(ticket.id)