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   6852 use strict;
  8         28  
  8         245  
3 8     8   45 use warnings;
  8         18  
  8         239  
4 8     8   43 use feature qw(state);
  8         18  
  8         845  
5              
6 8     8   1278 use Encode qw(encode_utf8);
  8         22583  
  8         534  
7 8         609 use Test2::API qw(
8             test2_add_callback_post_load
9             test2_stack
10             test2_stderr
11 8     8   630 );
  8         69122  
12 8     8   3916 use URI::Escape qw(uri_escape);
  8         12367  
  8         5464  
13              
14             our $VERSION = "0.03";
15              
16             sub import {
17 10     10   37111 my ($class) = @_;
18              
19 10 100       79 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   136 my $hub = test2_stack()->top;
26 5         69 $hub->listen(\&listener, inherit => 1);
27 5         31 });
28             }
29              
30             sub listener {
31 10     10 0 7634 my ($hub, $event) = @_;
32              
33 10 100       51 return unless $event->causes_fail;
34              
35 4         34 my $trace = $event->trace;
36 4         29 my $summary = _extract_summary_from_event($event);
37 4   50     25 my $file = $trace->file // '';
38 4   50     61 my $line = $trace->line // 0;
39 4         30 my $details = _extract_details_from_event($event);
40 4         13 my $message = encode_utf8(join "\n", grep { defined } ($summary, $details)); # avoid Wide character in print warning
  8         44  
41              
42 4         51 _issue_error($file, $line, $message);
43             }
44              
45             sub _extract_summary_from_event {
46 4     4   12 my ($event) = @_;
47              
48 4 100       54 my $name_or_summary = $event->isa('Test2::Event::Fail') ? $event->name : $event->summary;
49             # avoid uninitialized warning for regexp matching
50 4   50     110 $name_or_summary //= '';
51 4 100       37 return $name_or_summary =~ /Nameless Assertion/ ? '' : $name_or_summary;
52             }
53              
54             sub _extract_details_from_event {
55 4     4   9 my ($event) = @_;
56              
57 4 100       22 return undef unless exists $event->{info};
58 1         2 return join "\n", map { $_->{details} } @{$event->{info}};
  1         4  
  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   101 my ($msg) = @_;
77 1         7 return uri_escape($msg, "%\r\n");
78             }
79              
80             1;
81             __END__