DivideTicketIntoSubtasks

From Request Tracker Wiki
Jump to navigation Jump to search

HomePage > Contributions > DivideTicketIntoSubtasks

DivideTicketIntoSubtasks

Often, we have a whole list of related tasks, and wish to create separate tickets for them all at once, perhaps for different people to work on. With these scrips You can do so through the use of bulleted list in the body of the initial ticket.

Original

This scrip action creates tickets for each list item for each task the main ticket DependsOn. It handles lists with dash or asterisk bullets:

  * thingy 1
   - thingy 2 

Scrip Fields

Description:	Split and link sub-tasks
Condition:	OnCreate
Action:        User Defined
Template:	Blank
Stage:	        TransactionCreate #With modern RTs You may need to use TransactionBatch instead.

Action preparation code

  require MIME::Entity;
   
   my $trans = $self->TransactionObj;
   my $tkt = $self->TicketObj;
   
   my $cont = $trans->Content;
   my $requestors = [ $tkt->Requestors->MemberEmailAddresses ];
   
   #Updated to require whitespace between bullet & entry
   if ($cont =~ m/^\s*[-*]\s/m) {
     $cont =~ s/^\n.*//sm;
     my @lines = split(/[\n\r]*^\s*[-*]\s+/m, $cont); #update
     shift(@lines);
     foreach my $line (@lines) {
       my $new_tkt = RT::Ticket->new($RT::SystemUser);
       my ($id, $msg) = $new_tkt->Create(
                     Queue => "General",
                     Subject => $line,
                     Status => 'new',
                     Requestor => $requestors,
                     DependedOnBy => $tkt->Id,
                     MIMEObj => MIME::Entity->build(
                       Type => 'text/plain',
                       Data => $line));
     }
   }
   
   return 1;
 

Action cleanup code

return 1;

New Variant (2)

The version below handles nested bulleted lists, and the bullet character indicates the link relationship, as defied in %links. Note that this scrip will not fire if the bulleted list is preceded by other content.

   *starfruit
   * apple
   @@ gala
   ++ fuji
   @ melons
   ** watermelon
   *** stars & stripes
   **cantaloupe

This update of the initial revision also handles signatures, long items entered via the UI, and fixes a conflict with HideTransactions.

Action preparation code

require MIME::Entity; require Text::Wrap;

   #Semi-configurable items, see also 5.10 @ Unwrap below
   local $Text::Wrap::columns = 64;
   #You probably don't want to use '#' without modifying the truncated entry comment char
   my %links = ('*' => 'DependedOnBy', '+' => 'Parents', '@' => 'RefersTo');
   
   
   #Preparation
   my $tkt = $self->TicketObj;
   my $cont = $self->TransactionObj->Content;
   my $requestors = [ $tkt->Requestors->MemberEmailAddresses ];
   my $sym = qr/[\Q@{[join '', keys %links]}\E]/;
   
   
   #Strip leading comments, e.g; untruncated entry
   $cont =~ s/^\s*(#[^\n]+\n)+\n?//s;
   
   #Strip signature
   $cont =~ s/^-- \n.+$//m;
   
   #Unwrap long lines from RT's hard-wrap textareas, use the one matching your perl
   #1 while $cont =~ s/^\s*$sym\s*[^\n]+\K\n(?!^$sym)/ /m;  #5.10
   1 while $cont =~ s/^(\s*$sym\s*[^\n]+)\n(?!^$sym)/$1 /m; #5.8
   
   #Parse bullets
   while( $cont =~ /\G\s*($sym)\s*([^\n]+)((?:\s*$sym{2,}\s*[^\n]+)+)?/mg ){
       my($link, $subj, $body) = ($1, $2, $3||'');
       $body =~ s/^$sym//mg if length($body);
   
       #Wrap our long item into a body comment before truncating
       if( length($subj) > $Text::Wrap::columns ){
           $body = Text::Wrap::wrap('# ', '# ', $subj) . "\n" . $body;
   
           my($under, $over) = ($Text::Wrap::columns-5, $Text::Wrap::columns+5);
           $subj =~ /(.{$under,$over}(?<!\s)\b)|(.{$Text::Wrap::columns})/;
           $subj = $1 ? "$1..." : ($2||$subj);
       }
   
       #$RT::SystemUser would not play nice with HideTransactions
       my $new_tkt = RT::Ticket->new($RT::Nobody);
       my ($id, $msg) = $new_tkt->Create(
                     Queue => "TODO",
                     Subject => $subj,
                     Status => 'new',
                     Owner => $tkt->Owner,
                     Requestor => $requestors,
                     $links{$link} => $tkt->Id,
                     MIMEObj => MIME::Entity->build(Data => $body)
     );
   }
   
   return 1;

Nested Subtickets Variant 3

I had problems with Variant 2 in RT 3.8 and I wanted something a little simpler that would created nested subtickets. It does not use the MIME::Entity module since I don't want to put a default comment in the subtickets.

This creates DependsOn links with either * or - symbols. Create sublinks by adding *'s or -'s.

Example:

*Level 1
**Level 1-1
**Level 1-1
***Level 1-1-1

*Level 2
** Level 2-1
* Level 3
**Level 3-1

Action Preparation Code:

 my $trans = $self->TransactionObj;
 my $tkt = $self->TicketObj;
 my $cont = $trans->Content;
 my $requestors = [ $tkt->Requestors->MemberEmailAddresses ];
 
 if ($cont =~ m/^\s*[\*-]+/m) {
     my %tickets;
     foreach (split(/[\n\r]/, $cont)) {
 
         #Split number of *'s and actual subject.
         next unless /^\s*([\*-]+)(.+)$/;
         next unless $2;
         my $lvl = $1; my $value=$2;
 
         #Count the number of *'s
         my $count = scalar split //, $lvl;
 
         #Keep track of the tickets' parents
         $tickets{$count}=[$value];
 
         #One line is one ticket
         my $new_tkt =  RT::Ticket->new($RT::SystemUser);
 
         #If there is a parent ticket create dependencies on it
         if (exists $tickets{$count-1}) {
             my ($id, $msg) = $new_tkt->Create(
                 Queue       => $tkt->Queue,     
                 Subject     => $value,
                 Status      => 'new',
                 Requestor   => $requestors,     
                 Owner       => $tkt->Owner,     
                 DependedOnBy    => $tickets{$count-1}[1],
             );          
 
             #Store ticket id for children
             push @{$tickets{$count}}, $id;
 
         #If no parent ticket, create dependencies on the new ticket
         } else {
             my ($id, $msg) = $new_tkt->Create(
                 Queue       => $tkt->Queue,     
                 Subject     => $value,
                 Status      => 'new',
                 Requestor   => $requestors,     
                 Owner       => $tkt->Owner,     
                 DependedOnBy    => $tkt->Id,    
             );          
 
             #Store ticket id for children
             push @{$tickets{$count}}, $id;
 
             #Die if we got here without recording the parent somehow
             return 0 if $count > 1; 
         }       
     }   
 }
 
 
 return 1;