| File: | lib/CheckSpelling/SummaryTables.pm |
| Coverage: | 84.2% |
| line | stmt | bran | cond | sub | time | code |
|---|---|---|---|---|---|---|
| 1 | #! -*-perl-*- | |||||
| 2 | package CheckSpelling::SummaryTables; | |||||
| 3 | ||||||
| 4 | 1 1 1 | 153434 1 2 | use utf8; | |||
| 5 | 1 1 1 | 18 1 33 | use Cwd 'abs_path'; | |||
| 6 | 1 1 1 | 1 1 23 | use File::Basename; | |||
| 7 | 1 1 1 | 1 1 12 | use File::Temp qw/ tempfile tempdir /; | |||
| 8 | 1 1 1 | 3 1 18 | use JSON::PP; | |||
| 9 | 1 1 1 | 164 0 18 | use CheckSpelling::Util; | |||
| 10 | 1 1 1 | 185 1 502 | use CheckSpelling::GitSources; | |||
| 11 | ||||||
| 12 | 1 1 1 | 2 0 16 | unless (eval 'use URI::Escape; 1') { | |||
| 13 | eval 'use URI::Escape::XS qw/uri_escape/'; | |||||
| 14 | } | |||||
| 15 | ||||||
| 16 | my $pull_base; | |||||
| 17 | my $pull_head; | |||||
| 18 | ||||||
| 19 | sub file_ref { | |||||
| 20 | 2 | 157 | my ($file, $line) = @_; | |||
| 21 | 2 | 4 | $file =~ s/ /%20/g; | |||
| 22 | 2 | 13 | return "$file:$line"; | |||
| 23 | } | |||||
| 24 | ||||||
| 25 | sub github_blame { | |||||
| 26 | 18 | 33176 | my ($file, $line) = @_; | |||
| 27 | 18 | 12 | our (%git_roots, %github_urls, $pull_base, $pull_head); | |||
| 28 | ||||||
| 29 | 18 | 29 | return file_ref($file, $line) if ($file =~ m{^https?://}); | |||
| 30 | ||||||
| 31 | 17 | 19 | my ($parsed_file, $git_base_dir, $prefix, $remote_url, $rev) = CheckSpelling::GitSources::git_source_and_rev($file); | |||
| 32 | 17 | 12 | return file_ref($file, $line) unless defined $prefix; | |||
| 33 | 17 | 26 | my $line_delimiter = $prefix =~ m<https?://> ? '#L' : ':'; | |||
| 34 | ||||||
| 35 | 17 | 18 | $file = uri_escape($parsed_file, "^A-Za-z0-9\-\._~/"); | |||
| 36 | 17 | 164 | return "$prefix$file$line_delimiter$line"; | |||
| 37 | } | |||||
| 38 | ||||||
| 39 | sub main { | |||||
| 40 | 4 | 7565 | binmode(STDOUT, ":encoding(UTF-8)"); | |||
| 41 | 4 | 62 | my $budget = CheckSpelling::Util::get_val_from_env("summary_budget", ""); | |||
| 42 | 4 | 54 | print STDERR "Summary Tables budget: $budget\n"; | |||
| 43 | 4 | 6 | my $summary_tables = tempdir(); | |||
| 44 | 4 | 524 | my $table; | |||
| 45 | my @tables; | |||||
| 46 | ||||||
| 47 | 4 | 6 | my $head_ref = CheckSpelling::Util::get_file_from_env('GITHUB_HEAD_REF', ""); | |||
| 48 | 4 | 4 | my $github_url = CheckSpelling::Util::get_file_from_env('GITHUB_SERVER_URL', ""); | |||
| 49 | 4 | 2 | my $github_repository = CheckSpelling::Util::get_file_from_env('GITHUB_REPOSITORY', ""); | |||
| 50 | 4 | 2 | my $event_file_path = CheckSpelling::Util::get_file_from_env('GITHUB_EVENT_PATH', ""); | |||
| 51 | 4 | 22 | if ($head_ref && $github_url && $github_repository && $event_file_path) { | |||
| 52 | 4 | 43 | if (open $event_file_handle, '<', $event_file_path) { | |||
| 53 | 4 | 7 | local $/; | |||
| 54 | 4 | 28 | my $json = <$event_file_handle>; | |||
| 55 | 4 | 12 | close $event_file_handle; | |||
| 56 | 4 | 7 | my $data = decode_json($json); | |||
| 57 | 4 | 1404 | our $pull_base = "$github_url/$github_repository"; | |||
| 58 | 4 | 4 | our $pull_head = "$github_url/".$data->{'pull_request'}->{'head'}->{'repo'}->{'full_name'}; | |||
| 59 | 4 | 16 | unless ($pull_head && $pull_base && ($pull_base ne $pull_head)) { | |||
| 60 | 2 | 4 | $pull_base = $pull_head = ''; | |||
| 61 | } | |||||
| 62 | } | |||||
| 63 | } | |||||
| 64 | ||||||
| 65 | 4 | 13 | while (<>) { | |||
| 66 | 18 | 87 | next unless m{^(.+):(\d+):(\d+) \.\.\. (\d+),\s(Error|Warning|Notice)\s-\s(.+)\s\(([-a-z]+)\)$}; | |||
| 67 | 15 | 30 | my ($file, $line, $column, $endColumn, $severity, $message, $code) = ($1, $2, $3, $4, $5, $6, $7); | |||
| 68 | 15 | 9 | my $table_file = "$summary_tables/$code"; | |||
| 69 | 15 | 71 | push @tables, $code unless -e $table_file; | |||
| 70 | 15 | 227 | open $table, ">>", $table_file; | |||
| 71 | 15 | 13 | $message =~ s/\|/\\|/g; | |||
| 72 | 15 | 13 | my $blame = CheckSpelling::SummaryTables::github_blame($file, $line); | |||
| 73 | 15 | 27 | print $table "$message | $blame\n"; | |||
| 74 | 15 | 132 | close $table; | |||
| 75 | } | |||||
| 76 | 4 | 5 | return unless @tables; | |||
| 77 | ||||||
| 78 | 3 | 5 | my ($details_prefix, $footer, $suffix, $need_suffix) = ( | |||
| 79 | "<details><summary>Details ð</summary>\n\n", | |||||
| 80 | "</details>\n\n", | |||||
| 81 | "\n</details>\n\n", | |||||
| 82 | 0 | |||||
| 83 | ); | |||||
| 84 | 3 | 1 | my $footer_length = length $footer; | |||
| 85 | 3 | 2 | if ($budget) { | |||
| 86 | 3 | 5 | $budget -= (length $details_prefix) + (length $suffix); | |||
| 87 | 3 | 20 | print STDERR "Summary Tables budget reduced to: $budget\n"; | |||
| 88 | } | |||||
| 89 | 3 | 8 | for $table_file (sort @tables) { | |||
| 90 | 9 | 6 | my $header = "<details><summary>ð $table_file</summary>\n\n". | |||
| 91 | "note|path\n". | |||||
| 92 | "-|-\n"; | |||||
| 93 | 9 | 7 | my $header_length = length $header; | |||
| 94 | 9 | 5 | my $file_path = "$summary_tables/$table_file"; | |||
| 95 | 9 | 27 | my $cost = $header_length + $footer_length + -s $file_path; | |||
| 96 | 9 | 17 | if ($budget && ($budget < $cost)) { | |||
| 97 | 7 | 21 | print STDERR "::warning title=summary-table::Details for '$table_file' too big to include in Step Summary (summary-table-skipped)\n"; | |||
| 98 | 7 | 5 | next; | |||
| 99 | } | |||||
| 100 | 2 | 15 | open $table, "<:encoding(UTF-8)", $file_path; | |||
| 101 | 2 | 39 | my @entries; | |||
| 102 | 2 | 2 | my $real_cost = $header_length + $footer_length; | |||
| 103 | 2 | 11 | foreach my $line (<$table>) { | |||
| 104 | 2 | 10 | $real_cost += length $line; | |||
| 105 | 2 | 2 | push @entries, $line; | |||
| 106 | } | |||||
| 107 | 2 | 6 | close $table; | |||
| 108 | 2 | 2 | if ($real_cost > $cost) { | |||
| 109 | 0 | 0 | print STDERR "budget ($real_cost > $cost)\n"; | |||
| 110 | 0 | 0 | if ($budget && ($budget < $real_cost)) { | |||
| 111 | 0 | 0 | print STDERR "::warning title=summary-tables::budget exceeded for $table_file (summary-table-skipped)\n"; | |||
| 112 | 0 | 0 | next; | |||
| 113 | } | |||||
| 114 | } | |||||
| 115 | 2 | 2 | if ($details_prefix ne '') { | |||
| 116 | 1 | 12 | print $details_prefix; | |||
| 117 | 1 | 1 | $details_prefix = ''; | |||
| 118 | 1 | 1 | $need_suffix = 1; | |||
| 119 | } | |||||
| 120 | 2 | 8 | print $header; | |||
| 121 | 2 | 9 | print join ("", sort CheckSpelling::Util::case_biased @entries); | |||
| 122 | 2 | 5 | print $footer; | |||
| 123 | 2 | 2 | if ($budget) { | |||
| 124 | 2 | 2 | $budget -= $cost; | |||
| 125 | 2 | 6 | print STDERR "Summary Tables budget reduced to: $budget\n"; | |||
| 126 | } | |||||
| 127 | } | |||||
| 128 | 3 | 15 | print $suffix if $need_suffix; | |||
| 129 | } | |||||
| 130 | ||||||
| 131 | 1; | |||||