DivideTicketIntoSubtasks
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;