# Name: RTfindbug # Authors: Shawn Doyle, Jeff Ryan # Company: ReleaseTeam, Inc. # Description: A script that finds selected defect records in a # ClearQuest user database. # 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 to search $dbname = ""; # Username with access to the above database $CQ_user = ""; # Password for the above user $CQ_password = ""; # Type of ClearQuest record to search for $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 # Allow the OARCDP options to be grouped after one dash (-) Getopt::Long::Configure ("bundling"); my ($help) = 0; # Flag for -help and -? options my ($count) = 0; # Flag for -c option my ($invoke_user) = 0; # Flag for -e option my ($suppress_msg) = 0; # Flag for -f option my ($user) = ""; # Variable for the -u option my ($submit_user) = 0; # Flag for the -s option my ($raw_output) = 0; # Flag for the -r option my ($Submitted) = 0; # Flag for the -S option my ($Opened) = 0; # Flag for the -O option my ($Assigned) = 0; # Flag for the -A option my ($Resolved) = 0; # Flag for the -R option my ($Closed) = 0; # Flag for the -C option my ($Duplicate) = 0; # Flag for the -D option my ($Postponed) = 0; # Flag for the -P option my (@all_defects); my ($num_records); # Variables for CQ queries my ($querydef); # QueryDef object my ($filterNode); # QueryFilterNode object my ($rsltset); # ResultSet object my ($status); ###################### # Start main execution ###################### GetOptions ("help|?" => \$help, "c" => \$count, "e" => \$invoke_user, "f" => \$suppress_msg, "u=s" => \$user, "s" => \$submit_user, "S" => \$Submitted, "A" => \$Assigned, "O" => \$Opened, "R" => \$Resolved, "C" => \$Closed, "D" => \$Duplicate, "P" => \$Postponed, "r" => \$raw_output) || pod2usage ({ -exitval => 2, -verbose => 0 }); pod2usage ({ -exitval => 0, -verbose => 2 }) if ($help); &verifyOpts (); &OpenSession (); $querydef = &build_query (); @all_defects = &getDefects ($querydef); &displayDefects (); &CloseSession (); exit (0); #################### # End main execution #################### ####################################################################### # Subroutine: verifyOpts () # Description: Verifies the -s option is only used with the -u or -e # options. The -s option can't be used alone. # Input: None # Output: None sub verifyOpts { if ($submit_user && !($invoke_user || $user)) { pod2usage ({-exitval => 2, -verbose => 0 }); } } ####################################################################### # Subroutine: OpenSession # Description: Creates the Session object required for communication # with ClearQuest. 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: build_query () # Description: Creates and defines the QueryDef object based on the # command line options. # Input: None # Output: $querydef - QueryDef object sub build_query { my ($querydef); my ($filterNode); # Create the QueryDef object eval ("\$querydef = \$CQSession->BuildQuery (\$recordtype);"); &CQ_error ("BuildQuery") if ($@); # The query results should only show the defect ID eval ("\$querydef->BuildField (\"id\");"); &CQ_error ("BuildField") if ($@); # Create the parent QueryFilterNode object. Any child QueryFilterNode # objects will be ANDed together for the query. eval ("\$parentFilterNode = \$querydef->BuildFilterOperator " . "(\$CQPerlExt::CQ_BOOL_OP_AND);"); &CQ_error ("BuildFilterOperator") if ($@); # If the -u option has been specified... if ($user) { $parentFilterNode = &u_option ($parentFilterNode); # If the -s option has been specified... if ($submit_user) { $parentFilterNode = &s_option ($parentFilterNode); } } # If the -e option has been specified... if ($invoke_user) { $user = $ENV{USERNAME}; $parentFilterNode = &e_option ($parentFilterNode); # If the -s option has been specified... if ($submit_user) { $parentFilterNode = &s_option ($parentFilterNode); } } # If any of the -SAORCDP options have been specified... if ($Submitted || $Assigned || $Opened || $Resolved || $Closed || $Duplicate || $Postponed) { $parentFilterNode = &states_option ($parentFilterNode); } return ($querydef); } ####################################################################### # Subroutine: u_option () # Description: Defines the QueryFilterNode object passed in as a # parameter to meet the -u command line option. The -u # option is followed by a username and should return all # records owned by the username, regardless of state. # Input: $parentFilterNode - parent QueryFilterNode object to define # Output: $par_QFN - parent QueryFilterNode object after definition sub u_option { my ($parQFN) = @_; # Add a child QueryFilterNode for the -u option to the parent # QueryFilterNode object. eval ("\$uOptQFN = \$parQFN->BuildFilterOperator " . "(\$CQPerlExt::CQ_BOOL_OP_AND);"); &CQ_error ("BuildFilterOperator") if ($@); # Define a filter for the new child QueryFilterNode object. eval ("\$uOptQFN->BuildFilter (\"Owner\", " . "$CQPerlExt::CQ_COMP_OP_EQ, [\"\$user\"]);"); &CQ_error ("BuildFilter") if ($@); return ($parQFN); } ####################################################################### # Subroutine: e_option () # Description: Defines the QueryFilterNode object passed in as a # parameter to meet the -e command line option. The -e # should return any records owned by the invoking user. # Input: $parQFN - parent QueryFilterNode object to define # Output: $parQFN - parent QueryFilterNode object after definition sub e_option { my ($parQFN) = @_; # Add a child QueryFilterNode for the -e option to the parent # QueryFilterNode object. eval ("\$eOptQFN = \$parQFN->BuildFilterOperator " . "(\$CQPerlExt::CQ_BOOL_OP_AND);"); &CQ_error ("BuildFilterOperator") if ($@); # Define a filter for the new child QueryFilterNode object. eval ("\$eOptQFN->BuildFilter (\"Owner\", " . "$CQPerlExt::CQ_COMP_OP_EQ, [\"\$user\"]);"); &CQ_error ("BuildFilter") if ($@); return ($parQFN); } ####################################################################### # Subroutine: s_option () # Description: Defines the QueryFilterNode object passed in as a # parameter to meet the -s command line option. The -s # should return all records submitted by the username. # Input: $parQFN - parent QueryFilterNode object to define # Output: $parQFN - parent QueryFilterNode object after definition sub s_option { my ($parQFN) = @_; # Add a child QueryFilterNode for the -s option to the parent # QueryFilterNode object. eval ("\$sOptQFN = \$parQFN->BuildFilterOperator " . "(\$CQPerlExt::CQ_BOOL_OP_AND);"); &CQ_error ("BuildFilterOperator") if ($@); # Define a filter for the -s option eval ("\$sOptQFN->BuildFilter (\"Submitter\", " . "$CQPerlExt::CQ_COMP_OP_EQ, [\"\$user\"]);"); &CQ_error ("BuildFilter") if ($@); return ($parQFN); } ####################################################################### # Subroutine: states_option () # Description: Defines the QueryFilterNode object passed in as a # parameter to meet the -SAORCDP command line options. The # letters stand for each of the available states: # S = Submitted # A = Assigned # O = Opened # R = Resolved # C = Closed # D = Duplicate # P = Postponed # The options can be combined (ie -SA) to look for # multiple states. All records matching the given state or # states should be returned. # Input: $parentFilterNode - parent QueryFilterNode object to define # Output: $parQFN - parent QueryFilterNode object after definition sub states_option { my ($parQFN) = @_; # Add a child QueryFilterNode for the -SAORCDP options to the parent # QueryFilterNode object. eval ("\$StateOptQFN = \$parQFN->BuildFilterOperator " . "(\$CQPerlExt::CQ_BOOL_OP_OR);"); &CQ_error ("BuildFilterOperator") if ($@); if ($Submitted) { # Define a filter for the -S option eval ("\$StateOptQFN->BuildFilter (\"State\", " . "\$CQPerlExt::CQ_COMP_OP_EQ, [\"Submitted\"]);"); &CQ_error ("BuildFilter") if ($@); } if ($Assigned) { # Define a filter for the -A option eval ("\$StateOptQFN->BuildFilter (\"State\", " . "\$CQPerlExt::CQ_COMP_OP_EQ, [\"Assigned\"]);"); &CQ_error ("BuildFilter") if ($@); } if ($Opened) { # Define a filter for the -O option eval ("\$StateOptQFN->BuildFilter (\"State\", " . "\$CQPerlExt::CQ_COMP_OP_EQ, [\"Opened\"]);"); &CQ_error ("BuildFilter") if ($@); } if ($Resolved) { # Define a filter for the -R option eval ("\$StateOptQFN->BuildFilter (\"State\", " . "\$CQPerlExt::CQ_COMP_OP_EQ, [\"Resolved\"]);"); &CQ_error ("BuildFilter") if ($@); } if ($Closed) { # Define a filter for the -C option eval ("\$StateOptQFN->BuildFilter (\"State\", " . "\$CQPerlExt::CQ_COMP_OP_EQ, [\"Closed\"]);"); &CQ_error ("BuildFilter") if ($@); } if ($Duplicate) { # Define a filter for the -D option eval ("\$StateOptQFN->BuildFilter (\"State\", " . "\$CQPerlExt::CQ_COMP_OP_EQ, [\"Duplicate\"]);"); &CQ_error ("BuildFilter") if ($@); } if ($Postponed) { # Define a filter for the -P option eval ("\$StateOptQFN->BuildFilter (\"State\", " . "\$CQPerlExt::CQ_COMP_OP_EQ, [\"Postponed\"]);"); &CQ_error ("BuildFilter") if ($@); } return ($obj); } ####################################################################### # Subroutine: getDefects () # Description: Retrieves defects from the ClearQuest database. If no # filters are defined, all defects are returned. # Input: # Output: @defects - list of defects found sub getDefects { my ($querydef) = @_; my ($defectID); my (@defects); # Create the ResultSet object eval ("\$rsltset = \$CQSession->BuildResultSet (\$querydef);"); &CQ_error ("BuildResultSet") if ($@); # Execute the query eval ("\$rsltset->Execute ();"); &CQ_error ("Execute") if ($@); eval ("\$rsltset->LookupPrimaryEntityDefName ();"); &CQ_error ("LookupPrimaryEntityDefName") if ($@); # Move to the first record in the ResultSet object eval ("\$status = \$rsltset->MoveNext ();"); &CQ_error ("MoveNext") if ($@); while ($status == $CQPerlExt::CQ_SUCCESS) { eval ("\$defectID = \$rsltset->GetColumnValue (1);"); &CQ_error ("GetColumnValue") if ($@); push (@defects, $defectID); # Move to the next record in the ResultSet object eval ("\$status = \$rsltset->MoveNext ();"); &CQ_error ("MoveNext") if ($@); } return (@defects); } ####################################################################### # Subroutine: displayDefects () # Description: Displays results from the query formatted to the user # specifications based on command line options. # Input: None # Output: None sub displayDefects { if (@all_defects) { if ($count) { $num_records = @all_defects; print ("$num_records\n"); } else { foreach $defect (@all_defects) { if ($raw_output) { $entityObj = 0; eval ("\$entityObj = \$CQSession->GetEntity " . "(\$recordtype, \$defect);"); &CQ_error ("GetEntity") if ($@); # Get a reference to a string array eval ("\$fieldNameList = \$entityObj->GetFieldNames ();"); &CQ_error ("GetFieldNames") if ($@); # Iterate through the fields and output the field name and # value. $i = 0; foreach (@$fieldNameList) { $fieldInfoObj = 0; eval ("\$fieldInfoObj = \$entityObj->GetFieldValue " . "(\$\$fieldNameList[\$i]);"); &CQ_error ("GetFieldValue") if ($@); eval ("\$fieldValue = \$fieldInfoObj->GetValue ();"); &CQ_error ("GetValue") if ($@); print ("$$fieldNameList[$i++] : $fieldValue\n"); } } else { print ("$defect\n"); } } } } else { if (!$suppress_msg) { print ("No defects were found that match the search criteria\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 RTfindbug =head1 SYNOPSIS RTfindbug [--help | -?] [-c] [-e [-s]] [-f] [-u username [-s]] [-SAORCDP] [-r] =head1 OPTIONS =over 8 =item B<--help | -?> Display online documentation. =item B<-c> Count the number of records returned by the query. Only the number is displayed to standard out. Record IDs are not displayed. =item B<-f> Suppress the printing of the message "No defects were found that match the search criteria" when no match is found. =item B<-u username> Restricts search to defect records owned by a user with the login name "username". All records where the "Owner" state equals "username" are listed, regardless of their state. =item B<-s> Can be used with the -u or -e options to only show defects submitted by the given username. =item B<-SAORCDP> Restricts search to defects in the specified state. Each letter represents a state that a defect record goes through. The letters stand for Submitted, Assigned, Opened, Resolved, Closed, Duplicate, and Postponed. =item B<-r> Instead of printing record IDs to the standard output, print the raw defect record file itself. =back =head1 DESCRIPTION B is a tool used to query the ClearQuest database. If no options are given, RTfindbug displays every defect id in the ClearQuest database. =head1 EXAMPLES Finds all bugs in the system: RTfindbug Find all of the open bugs in the system: RTfindbug -O Find all the bugs on this system which are assigned to mike: RTfindbug -u mike Find all the bugs in the system that are unresolved (states O & A) and assigned to user mike: RTfindbug -OA -u mike Find all the bugs submitted by user mike on this system: RTfindbug -s -u mike =head1 SEE ALSO RTdumpbug, RTsortbug =cut