testrail-report 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. #! /usr/bin/env perl
  2. # ABSTRACT: Upload your TAP results to TestRail after they've finished
  3. # PODNAME: testrail-report
  4. =head1 SYNOPSIS
  5. testrail-report [OPTIONS] tapfile
  6. prove -v sometest.t > results.tap && testrail-report [OPTIONS] results.tap
  7. prove -v sometest.t | testrail-report [OPTIONS]
  8. prove -PTestRail='http://some.testlink.install/,someUser,somePassword,someProject,someRun,0,step_results' sometest.t
  9. =head1 DESCRIPTION
  10. testrail-report - report raw TAP results to a TestRail install
  11. USAGE:
  12. =head2 PARAMETERS:
  13. =head3 MANDATORY PARAMETERS
  14. --project [someproject] : associate results (if any) with theprovided project name.
  15. --run [somerun] : associates results (if any) with the provided run name.
  16. IF none of these options are provided, you will be asked to type
  17. these in as needed, supposing you are not redirecting input
  18. (such as piping into this command).
  19. =head3 CONFIG OVERRIDES
  20. In your \$HOME, put a file called .testrailrc with key=value
  21. syntax separated by newlines. Valid Keys are: apiurl,user,password
  22. =head3 CONFIG OPTIONS
  23. These override the config, if present. If neither are used, you will be prompted.
  24. --apiurl [url] : full URL to get to TestRail index document
  25. --password [key] : Your TestRail Password.
  26. --user [name] : Your TestRail User Name.
  27. =head3 BEHAVIOR
  28. --case-ok : Whether to consider each OK to correspond to a test in TestRail
  29. --step-results [name] : 'System Name' of a 'step_results' type field to set for your tests.
  30. These options are mutually exclusive. If neither is set, the
  31. overall result of the test will be used as the pass/fail for the test.
  32. =head2 PROVE PLUGIN:
  33. passing -PTestRail=apiurl,user,pass,project,run to prove will
  34. automatically upload your test results while the test is running if
  35. real-time results are desired.
  36. See L<App::Prove::Plugin::TestRail> for more information.
  37. =head2 REQUIREMENTS:
  38. Your TestRail install must have 3 custom statuses with the internal
  39. names 'skip', 'todo_pass', and 'todo_fail', to represent those
  40. states which TAP can have.
  41. =cut
  42. use strict;
  43. use warnings;
  44. use Getopt::Long;
  45. use Term::ANSIColor qw(colorstrip);
  46. use Test::Rail::Parser;
  47. use IO::Interactive::Tiny ();
  48. print "testrail-report\n----------------------\n";
  49. sub help {
  50. print "testrail-report - report raw TAP results to a TestRail install
  51. USAGE:
  52. testrail-report [OPTIONS] tapfile
  53. prove -v sometest.t > results.tap && testrail-report [OPTIONS] \\
  54. results.tap
  55. prove -v sometest.t | testrail-report [OPTIONS]
  56. prove -PTestRail='http://some.testlink.install/','someUser',\\
  57. 'somePassword' sometest.t
  58. PARAMETERS:
  59. [MANDATORY PARAMETERS]
  60. --project [someproject] : associate results (if any) with the
  61. provided project name.
  62. --run [somerun] : associates results (if any) with the provided run
  63. name.
  64. IF none of these options are provided, you will be asked to type
  65. these in as needed, supposing you are not redirecting input
  66. (such as piping into this command).
  67. [CONFIG OVERRIDES]
  68. In your \$HOME, put a file called .testrailrc with key=value
  69. syntax separated by newlines. Valid Keys are: apiurl,user,password
  70. [CONFIG OPTIONS] - These override the config, if present.
  71. If neither are used, you will be prompted.
  72. --apiurl [url] : full URL to get to TestRail index document
  73. --password [key] : Your TestRail Password.
  74. --user [name] : Your TestRail User Name.
  75. [BEHAVIOR]
  76. --case-ok : Whether to consider each OK to correspond to
  77. a test in TestRail
  78. --step-results [name] : 'System Name' of a 'step_results' type field
  79. to set for your tests.
  80. These options are mutually exclusive. If neither is set, the
  81. overall result of the test will be used as the pass/fail for the test.
  82. PROVE PLUGIN:
  83. passing -PTestRail=apiurl,user,pass,project,run to prove will
  84. automatically upload your test results while the test is running if
  85. real-time results are desired.
  86. See App::Prove::Plugin::TestRail for more information.
  87. REQUIREMENTS:
  88. Your TestRail install must have 3 custom statuses with the internal
  89. names 'skip', 'todo_pass', and 'todo_fail', to represent those
  90. states which TAP can have.
  91. ";
  92. exit 0;
  93. }
  94. sub userInput {
  95. $| = 1;
  96. my $rt = <STDIN>;
  97. chomp $rt;
  98. return $rt;
  99. }
  100. sub parseConfig {
  101. my $results = {};
  102. my $arr =[];
  103. open(my $fh, '<', $ENV{"HOME"} . '/.testrailrc') or return (undef,undef,undef);#couldn't open!
  104. while (<$fh>) {
  105. chomp;
  106. @$arr = split(/=/,$_);
  107. if (scalar(@$arr) != 2) {
  108. warn("Could not parse $_ in tlreport config\n");
  109. next;
  110. }
  111. $results->{lc($arr->[0])} = $arr->[1];
  112. }
  113. close($fh);
  114. return ($results->{'apiurl'},$results->{'password'},$results->{'user'});
  115. }
  116. #Main loop------------
  117. my ($help,$apiurl,$user,$password,$project,$run,$case_per_ok,$step_results);
  118. #parse switches
  119. GetOptions(
  120. 'run=s' => \$run,
  121. 'apiurl=s' => \$apiurl,
  122. 'password=s' => \$password,
  123. 'user=s' => \$user,
  124. 'project=s' => \$project,
  125. 'case-ok' => \$case_per_ok,
  126. 'step-results=s' => \$step_results,
  127. 'help' => \$help
  128. );
  129. if ($help) { help(); }
  130. #Parse config file if we are missing api url/key or user
  131. if (-e $ENV{"HOME"} . '/.testrailrc' && (!$apiurl || !$password || !$user) ) {
  132. ($apiurl,$password,$user) = parseConfig();
  133. }
  134. #If argument is passed use it instead of stdin
  135. my $file = $ARGV[0];
  136. die "No Such File $file" if ($file && !-e $file);
  137. my ($fh,$fcontents);
  138. if ($file) {
  139. open($fh,'<',$file);
  140. while (<$fh>) {
  141. $_ = colorstrip($_); #strip prove brain damage
  142. s/^\s*//g; #Fix more brain damage
  143. $fcontents .= $_;
  144. }
  145. close($fh);
  146. } else {
  147. #Just read STDIN, print help if no file was passed
  148. if (IO::Interactive::Tiny::is_interactive()) {
  149. print "ERROR: no file passed, and no data piped in! See --help for usage.";
  150. exit(1);
  151. }
  152. if ( !$run || !$apiurl || !$password || !$user || !$project ) {
  153. print "ERROR: Interactive mode not allowed when piping input. See --help for options.\n";
  154. exit(1);
  155. }
  156. while (<>) {
  157. $_ = colorstrip($_); #strip prove brain damage
  158. s/^\s*//g; #Fix prove brain damage
  159. $fcontents .= $_;
  160. }
  161. help() if !$fcontents; #Nothing passed to stdin!
  162. }
  163. #Interrogate user if they didn't provide info
  164. if (!$apiurl) {
  165. print "Type the API endpoint url for your testLink install below:\n";
  166. $apiurl = userInput();
  167. }
  168. if (!$user) {
  169. print "Type your testLink user name below:\n";
  170. $user = userInput();
  171. }
  172. if (!$password) {
  173. print "Type the password for your testLink user below:\n";
  174. $password = userInput();
  175. }
  176. if (!$apiurl || !$password || !$user) {
  177. print "ERROR: api url, username and password cannot be blank.\n";
  178. exit 1;
  179. }
  180. #Interrogate user if they didn't provide info
  181. if (!$project) {
  182. print "Type the name of the project you are testing under:\n";
  183. $project = userInput();
  184. }
  185. # Interrogate user if options were not passed
  186. if (!$run) {
  187. print "Type the name of the existing run you would like to run against:\n";
  188. $run = userInput();
  189. }
  190. my $tap = Test::Rail::Parser->new({
  191. 'tap' => $fcontents,
  192. 'apiurl' => $apiurl,
  193. 'user' => $user,
  194. 'pass' => $password,
  195. 'run' => $run,
  196. 'project' => $project,
  197. 'case_per_ok' => $case_per_ok,
  198. 'step_results' => $step_results,
  199. 'merge' => 1
  200. });
  201. $tap->run();
  202. print "Done.\n";
  203. #all done
  204. 0;
  205. __END__
  206. =head1 SEE ALSO
  207. L<TestRail::API>
  208. L<App::Prove::Plugin::TestRail>
  209. L<TAP::Parser>
  210. =head1 SPECIAL THANKS
  211. Thanks to cPanel Inc, for graciously funding the creation of this module.