File Coverage

blib/lib/Test2/Plugin/GitHub/Actions/AnnotateFailedTest.pm
Criterion Covered Total %
statement 47 52 90.3
branch 12 14 85.7
condition 3 6 50.0
subroutine 12 13 92.3
pod 0 1 0.0
total 74 86 86.0


line stmt bran cond sub pod time code
1             package Test2::Plugin::GitHub::Actions::AnnotateFailedTest;
2 8     8   6722 use strict;
  8         27  
  8         250  
3 8     8   45 use warnings;
  8         18  
  8         230  
4 8     8   49 use feature qw(state);
  8         17  
  8         1108  
5              
6 8     8   1253 use Encode qw(encode_utf8);
  8         23610  
  8         578  
7 8         659 use Test2::API qw(
8             test2_add_callback_post_load
9             test2_stack
10             test2_stderr
11 8     8   652 );
  8         72378  
12 8     8   3888 use URI::Escape qw(uri_escape);
  8         12519  
  8         5522  
13              
14             our $VERSION = "0.02";
15              
16             sub import {
17 10     10   38580 my ($class) = @_;
18              
19 10 100       81 return unless $ENV{GITHUB_ACTIONS};
20 7         15 state $loaded = 0; # avoid multiple callback addition
21 7 100       26 return if $loaded;
22 5         11 $loaded++;
23              
24             test2_add_callback_post_load(sub {
25 5     5   144 my $hub = test2_stack()->top;
26 5         107 $hub->listen(\&listener, inherit => 1);
27 5         37 });
28             }
29              
30             sub listener {
31 10     10 0 8181 my ($hub, $event) = @_;
32              
33 10 100       57 return unless $event->causes_fail;
34              
35 4         38 my $trace = $event->trace;
36 4         22 my $summary = _extract_summary_from_event($event);
37 4   50     24 my $file = $trace->file // '';
38 4   50     71 my $line = $trace->line // 0;
39 4         33 my $details = _extract_details_from_event($event);
40 4         12 my $message = encode_utf8(join "\n", grep { defined } ($summary, $details)); # avoid Wide character in print warning
  8         42  
41              
42 4         49 _issue_error($file, $line, $message);
43             }
44              
45             sub _extract_summary_from_event {
46 4     4   12 my ($event) = @_;
47              
48 4 100       53 my $name_or_summary = $event->isa('Test2::Event::Fail') ? $event->name : $event->summary;
49             # avoid uninitialized warning for regexp matching
50 4   50     97 $name_or_summary //= '';
51 4 100       34 return $name_or_summary =~ /Nameless Assertion/ ? '' : $name_or_summary;
52             }
53              
54             sub _extract_details_from_event {
55 4     4   10 my ($event) = @_;
56              
57 4 100       22 return undef unless exists $event->{info};
58 1         3 return join "\n", map { $_->{details} } @{$event->{info}};
  1         5  
  1         3  
59             }
60              
61             sub _issue_error {
62 0     0   0 my ($file, $line, $detail) = @_;
63              
64 0         0 my $stderr = test2_stderr();
65              
66 0 0       0 if (length $detail) {
67 0         0 $stderr->printf("::error file=%s,line=%d::%s\n", $file, $line, _escape_data($detail));
68             } else {
69 0         0 $stderr->printf("::error file=%s,line=%d\n", $file, $line);
70             }
71             }
72              
73             # escape a message of workflow command.
74             # see also: https://github.com/actions/toolkit/blob/30e0a77337213de5d4e158b05d1019c6615f69fd/packages/core/src/command.ts#L92-L97
75             sub _escape_data {
76 1     1   85 my ($msg) = @_;
77 1         6 return uri_escape($msg, "%\r\n");
78             }
79              
80             1;
81             __END__