File Coverage

blib/lib/TAP/Formatter/TeamCity.pm
Criterion Covered Total %
statement 15 42 35.7
branch 0 16 0.0
condition 0 2 0.0
subroutine 5 8 62.5
pod 1 1 100.0
total 21 69 30.4


line stmt bran cond sub pod time code
1             #############################################################################
2             # $URL: http://perlcritic.tigris.org/svn/perlcritic/tags/TAP-Formatter-TeamCity-0.04/lib/TAP/Formatter/TeamCity.pm $
3             # $Date: 2009-09-09 13:03:47 -0700 (Wed, 09 Sep 2009) $
4             # $Author: thaljef $
5             # $Revision: 3641 $
6             #############################################################################
7              
8             package TAP::Formatter::TeamCity;
9              
10 1     1   854 use strict;
  1         2  
  1         41  
11 1     1   6 use warnings;
  1         3  
  1         37  
12              
13 1     1   907 use TeamCity::BuildMessages qw(:all);
  1         75062  
  1         220  
14 1     1   830 use TAP::Formatter::Session::TeamCity;
  1         3  
  1         37  
15              
16             #-----------------------------------------------------------------------------
17              
18 1     1   10 use base qw(TAP::Formatter::Base);
  1         1  
  1         1091  
19              
20             #-----------------------------------------------------------------------------
21              
22             our $VERSION = '0.04';
23              
24             #-----------------------------------------------------------------------------
25              
26             my $last_test_name;
27              
28             sub open_test {
29 0     0 1   my ($self, $test, $parser) = @_;
30              
31 0           my $session = TAP::Formatter::Session::TeamCity->new(
32             { name => $test,
33             formatter => $self,
34             parser => $parser,
35             show_count => 0,
36             }
37             );
38              
39              
40 0           teamcity_emit_build_message('testSuiteStarted', name => $test);
41              
42 0           while ( defined( my $result = $parser->next() ) ) {
43 0 0         print $result->comment(), ' ' if $result->is_comment();
44 0 0         $self->_emit_teamcity_messages($result) if $result->is_test();
45 0           $session->result($result);
46             }
47              
48 0 0         teamcity_emit_build_message('testFinished', name => $last_test_name) if $last_test_name;
49 0           teamcity_emit_build_message('testSuiteFinished', name => $test);
50              
51 0           return $session;
52             }
53              
54             #-----------------------------------------------------------------------------
55              
56             sub _emit_teamcity_messages {
57 0     0     my ($self, $result) = @_;
58              
59             # First, close out the last test, if there was one...
60 0 0         teamcity_emit_build_message('testFinished', name => $last_test_name) if $last_test_name;
61 0   0       my $test_name = $result->description() || 'No test name given';
62 0           $test_name =~ s{\A \s* - \s+}{}mx;
63              
64             # Now start this test and evaluate the results...
65 0           teamcity_emit_build_message('testStarted', captureStandardOutput => 'true', name => $test_name);
66 0           $self->_emit_teamcity_test_results($test_name, $result);
67              
68 0           $last_test_name = $test_name;
69              
70 0           return;
71             }
72              
73             #-----------------------------------------------------------------------------
74              
75             sub _emit_teamcity_test_results {
76 0     0     my ($self, $test_name, $test) = @_;
77              
78 0           my $expl = $test->explanation();
79 0 0         my %message = $expl ? (message => $expl) : ();
80 0           my %args = (name => $test_name, %message);
81              
82 0 0         if ( $test->has_todo() ) {
    0          
    0          
83 0           teamcity_emit_build_message('testIgnored', %args);
84             }
85             elsif ( $test->has_skip() ) {
86 0           teamcity_emit_build_message('testIgnored', %args);
87             }
88             elsif ( not $test->is_ok() ) {
89 0           teamcity_emit_build_message('testFailed', %args);
90             }
91              
92 0           return;
93             }
94              
95             #-----------------------------------------------------------------------------
96             1;
97              
98             =pod
99              
100             =head1 NAME
101              
102             TAP::Formatter::TeamCity - Emit test results as TeamCity service messages
103              
104             =head1 SYNOPSIS
105              
106             # When using prove(1):
107             prove -formatter TAP::Formatter::TeamCity my_test.t
108              
109             # From within a Module::Build subclass:
110             sub tap_harness_args { return {formatter_class => 'TAP::Formatter::TeamCity'} }
111              
112             =head1 DESCRIPTION
113              
114             L is a plugin for L that emits TeamCity
115             service messages to the console, rather than the usual output. The TeamCity build
116             server is able to process these messages in the build log and present your test
117             results in its web interface (along with some nice statistics and graphs).
118              
119             This is very much alpha code, and is subject to change.
120              
121             =head1 SEE IT IN ACTION
122              
123             If you're not familiar with continuous integration systems (in general) or
124             TeamCity (in particular), you're welcome to explore the TeamCity build server
125             we use for the L project. Just go to
126             L and click on the "Login as a Guest" link. From
127             there, you can browse the build history, review test results, and examine the
128             artifacts (such as test coverage reports and performance profiles). All the
129             information you see there was generated from TAP-based tests using this module
130             to communicate the results to the TeamCity server.
131              
132             =head1 SUGGESTED USAGE
133              
134             The TeamCity service messages are generally not human-readable, so you
135             probably only want to use this Formatter when the tests are being run by a
136             TeamCity build agent and the L module is available.
137             I suggest using an environment variable to activate the Formatter. If you're
138             using a recent version of L you might do something like this in
139             your F file:
140              
141             # Regular build configuration here:
142             my $builder = Module::Build->new( ... )
143              
144             # Specify this Formatter, if the environment variable is set:
145             $builder->tap_harness_args( {formatter_class => 'TAP::Formatter::TeamCity'} )
146             if $ENV{RUNNING_UNDER_TEAMCITY} && eval {require TAP::Formatter::TeamCity};
147              
148             # Generate build script as ususal:
149             $builder->create_build_script();
150              
151             And then set the C environment variable to a true value
152             in your TeamCity build configuration.
153              
154             TODO: Figure out if/how to do this with L.
155              
156             =head1 LIMITATIONS
157              
158             TeamCity comes from a jUnit culture, so it doesn't understand SKIP and TODO
159             tests in the same way that Perl testing harnesses do. Therefore, this formatter
160             simply instructs TeamCity to ignore tests that are marked SKIP or TODO.
161              
162             Also, I haven't yet figured out how to transmit test diagnostic messages, so
163             those probably won't appear in the TeamCity web interface. But I'm working
164             on it :)
165              
166             =head1 SOME EXTRA CANDY
167              
168             TeamCity, CruiseControl, and some other continuous integration systems are
169             oriented towards Java code. As such, they don't have native support for
170             Perl's customary build tools like L. But they do have nice
171             support for running Ant. This distribution contains an Ant build script at
172             F which wraps L actions in Ant targets. This makes
173             it easier to configure TeamCity and CruiseControl to build your Perl code. If
174             you're using the EPIC plug-in with Eclipse, you can also use this Ant script
175             to build your code from within the IDE. Feel free to copy the F
176             into your own projects.
177              
178             =head1 SEE ALSO
179              
180             L
181              
182             =head1 AUTHOR
183              
184             Jeffrey Ryan Thalhammer
185              
186             =head1 COPYRIGHT
187              
188             Copyright (c) 2009 Imaginative Software Systems. All rights reserved.
189              
190             This program is free software; you can redistribute it and/or modify
191             it under the same terms as Perl itself. The full text of this license
192             can be found in the LICENSE file included with this module.
193              
194             =cut
195              
196              
197             ##############################################################################
198             # Local Variables:
199             # mode: cperl
200             # cperl-indent-level: 4
201             # fill-column: 78
202             # indent-tabs-mode: nil
203             # c-indentation-style: bsd
204             # End:
205             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :