# Name: RTsortbug # Author: Jeff Ryan # Company: ReleaseTeam, Inc. # Description: Sorts Rational ClearQuest records by particular fields. # Mulitple fields can be sorted on and reverse sort is # available. Default output is just the list of record ids # in sorted order. It is possible to display the value of # the fields used for the sort. # Support: If you have any problems or would like to see additional # functionality, send an email to support@releaseteam.com ####################################################################### ######################## # USER DEFINED VARIABLES ######################## # Name of the ClearQuest database $dbname = ""; # Username with read access to the above database $CQ_user = ""; # Password for the above user $CQ_password = ""; # Type of ClearQuest record $recordtype = "defect"; ########################################### # NO USER DEFINED VARIABLES BELOW THIS LINE ########################################### use CQPerlExt; use Getopt::Long; use Pod::Usage; require 5.6.0; # CQPerlExt module requires at least Perl version 5.6.0 my ($help) = 0; # Flag for the -help and -? options my ($reverse) = 0; # Flag for the -r option my ($printValue) = 0; # Flag for the -v option ###################### # Start main execution ###################### GetOptions ("help|?" => \$help, "r" => \$reverse, "v" => \$printValue) || pod2usage ({ -exitval => 2, -verbose => 0 }); pod2usage ({ -exitval => 0, -verbose => 2 }) if ($help); # Read the defect record IDs we should sort from standard input @records = ; chomp (@records); # Create array of references to hashes $i = 0; foreach $record (@records) { $record_refs[$i] = \%$record; $record_refs[$i]->{id} = $record; $i++; } # Read the field values we should sort on @fields = @ARGV; chomp (@fields); if (scalar (@fields) == 0) { print ("No sort fields specified. Exiting\n"); exit (1); } # Create array of references to hashes $i = 0; foreach $field (@fields) { $field_refs[$i] = \%$field; $field_refs[$i]->{name} = $field; $i++; } &OpenSession (); &GetValues (); @sorted = &SortRecords (); &DisplayResults (); &CloseSession (); exit (0); #################### # End main execution #################### ####################################################################### # Subroutine: OpenSession () # Description: Creates the Session object required for communication # with ClearQuest. # Input: None # Output: None sub OpenSession { eval ("\$CQSession = CQPerlExt::CQSession_Build ();"); &CQ_error ("CQSession_Build") if ($@); eval ("\$CQSession->UserLogon (\$CQ_user, \$CQ_password, " . "\$dbname, \"\");"); &CQ_error ("UserLogon") if ($@); } ####################################################################### # Subroutine: GetValues () # Description: Retrieves values for the fields to sort on. Also gets # the type of the field for use in the sort code. # Input: None # Output: None sub GetValues { foreach $record_ptr (@record_refs) { # Get the Entity object for the record $entityObj = 0; eval ("\$entityObj = \$CQSession->GetEntity (\$recordtype, " . "\$\$record_ptr{id});"); &CQ_error ("GetEntity") if ($@); foreach $field (@fields) { # Get the FieldInfo object for the field. $fieldInfoObj = 0; eval ("\$fieldInfoObj = \$entityObj->GetFieldValue " . "(\$field);"); if ($@) { print ("Problem retrieving information for \"$field\" field.\n"); print ("Check the spelling and verify the field exists in "); print ("ClearQuest.\n\n"); &CQ_error ("GetFieldValue"); } # Get the current value of the field. eval ("\$\$record_ptr{\$field} = " . "\$fieldInfoObj->GetValue ();"); &CQ_error ("GetValue") if ($@); } } # Now get the field type for each field in the first record. This # part is done separately from above since we only need to get the # field type once. # Get an Entity object for the first record $entityObj = 0; eval ("\$entityObj = \$CQSession->GetEntity (\$recordtype, " . "\$record_refs[0]->{id});"); &CQ_error ("GetEntity") if ($@); foreach $field_ptr (@field_refs) { # Get the FieldInfo object for the field $fieldInfoObj = 0; eval ("\$fieldInfoObj = \$entityObj->GetFieldValue " . "(\$\$field_ptr{name});"); &CQ_error ("GetFieldValue") if ($@); # Get the field type. eval ("\$\$field_ptr{type} = \$fieldInfoObj->GetType ();"); &CQ_error ("GetType") if ($@); # Determine the comparison operator from the field type if (($$field_ptr{type} == $CQPerlExt::CQ_SHORT_STRING) || ($$field_ptr{type} == $CQPerlExt::CQ_MULTILINE_STRING) || ($$field_ptr{type} == $CQPerlExt::CQ_DATE_TIME) || ($$field_ptr{type} == $CQPerlExt::CQ_REFERENCE) || ($$field_ptr{type} == $CQPerlExt::CQ_STATE) || ($$field_ptr{type} == $CQPerlExt::CQ_ID)) { $$field_ptr{op} = "cmp"; } elsif (($$field_ptr{type} == $CQPerlExt::CQ_INT) || ($$field_ptr{type} == $CQPerlExt::CQ_DBID)) { $$field_ptr{op} = "<=>"; } else { $$field_ptr{op} = "UNDEF"; } } } ####################################################################### # Subroutine: SortRecords () # Description: # Input: # Output: sub SortRecords { my ($sortCodeStr) = ""; my (@sortCode); if ($reverse) { $a = 'b'; $b = 'a'; } else { $a = 'a'; $b = 'b'; } foreach $sort_field (@fields) { foreach $field_ref (@field_refs) { if ($field_ref->{name} eq $sort_field) { $sortCodeStr = "\$${a}->{" . $sort_field . "} " . $field_ref->{op} . " \$${b}->{" . $sort_field . "}"; push (@sortCode, $sortCodeStr); } } } eval ("\@record_refs = sort { " . join (" or ", @sortCode) . " } " . "\@record_refs;"); } ####################################################################### # Subroutine: DisplayResults () # Description: # Input: None # Output: None sub DisplayResults { foreach $record_ptr (@record_refs) { print ("$record_ptr->{id}"); if ($printValue) { foreach $field_ptr (@field_refs) { print (" " . $record_ptr->{$field_ptr->{name}}); } } print ("\n"); } } ####################################################################### # Subroutine: CloseSession () # Description: Destroys Session object. # Input: None # Output: None sub CloseSession { eval ("CQSession::Unbuild (\$CQSession);"); &CQ_error ("Unbuild") if ($@); } ####################################################################### # Subroutine: CQ_error () # Description: Displays the error given by a failed ClearQuest API # command. # Input: $method - Name of the ClearQuest API method that failed # Output: None sub CQ_error { my ($method) = @_; print ("ERROR: $method failed with the following message:\n$@\n"); exit (1); } __END__ =head1 NAME RTsortbug - sort ClearQuest defect records by particular field(s) =head1 SYNOPSIS RTsortbug [-r] [-v] keyword ... =head1 OPTIONS =over 8 =item B<-r> Causes RTsortbug to reverse the order of the sorted output. =item B<-v> Causes RTsortbug to print the values of the specified keywords for each defect record, one record per line, instead of just the record IDs. =back =head1 DESCRIPTION Use RTsortbug to sort defect record IDs into an order for convenient postprocessing by other programs, such as RTdumpbug or RTbugval. Note you should not use the -v option if you are going to pipe the output of RTsortbug to another script like RTdumpbug or RTbugval. It reads the defect record IDs from the standard input. When invoked without options, RTsortbug sorts the defect records based on the values in the specified keyword fields into ascending order, and writes the defect record IDs to the standard output in that order. =head1 EXAMPLES This command finds defect records that are open (O), sorts them by their severity and then by the name of the owner, and prints out their defect record IDs: RTfindbug -O | RTsortbug Severity Owner This command finds defect records that are open (O), sorts them by their severity and then by the name of the owner, and prints out their defect record IDs. In addition to the record IDs, the value of each field is also displayed. RTfindbug -O | RTsortbug -v Severity Owner =head1 SEE ALSO RTbugval, RTdumpbug, RTfindbug =cut