File Coverage

blib/lib/Dist/Zilla/Plugin/SignReleaseNotes.pm
Criterion Covered Total %
statement 24 87 27.5
branch 0 16 0.0
condition n/a
subroutine 8 16 50.0
pod 8 8 100.0
total 40 127 31.5


line stmt bran cond sub pod time code
1 1     1   1636 use strict;
  1         2  
  1         30  
2 1     1   4 use warnings;
  1         2  
  1         50  
3              
4              
5             our $VERSION = '0.0008';
6              
7             # ABSTRACT: Create and signs a 'Release' notes file
8             use Moose;
9 1     1   1456 use Exporter qw(import);
  1         506402  
  1         6  
10 1     1   6895 with 'Dist::Zilla::Role::AfterRelease';
  1         3  
  1         89  
11              
12             has sign => (is => 'ro', default => 'always');
13             has hash_alg => (is => 'ro', default => 'sha256');
14              
15             my $self = shift;
16             my $dir = shift;
17 0     0 1   my $plaintext = shift;
18 0            
19 0           use Module::Signature qw/ $SIGNATURE $Preamble /;
20              
21 1     1   1611 $SIGNATURE = 'Release' . "-" . $self->get_version();
  1         15777  
  1         302  
22             $Preamble = '';
23 0           require File::chdir;
24 0            
25 0           local $File::chdir::CWD = $dir;
26              
27 0           my $signed;
28             if (my $version = Module::Signature::_has_gpg()) {
29 0           $signed = Module::Signature::_sign_gpg($SIGNATURE, $plaintext, $version);
30 0 0         }
    0          
31 0           elsif (eval {require Crypt::OpenPGP; 1}) {
32             $signed = Module::Signature::_sign_crypt_openpgp($SIGNATURE, $plaintext);
33 0           }
  0            
34 0           }
35              
36             my $self = shift;
37             my $filename = shift;
38              
39 0     0 1   my $digest = $self->get_checksum($filename);
40 0            
41             my @sha1s_and_titles = get_git_checksums_and_titles();
42 0            
43             my $file = $self->create_release_file (
44 0           $digest,
45             $filename,
46 0           @sha1s_and_titles
47             );
48              
49             $self->do_sign('./', $file)
50             if $self->sign =~ /always/i;
51             }
52 0 0          
53             my $self = shift;
54              
55             use Git::Wrapper;
56             my $git = Git::Wrapper->new('./');
57 0     0 1    
58             my @tags = $git->RUN('for-each-ref', 'refs/tags/*', '--sort=-taggerdate', '--count=2', '--format=%(refname:short)');
59 1     1   563  
  1         33117  
  1         135  
60 0           my @sha1s_and_titles;
61              
62 0           if ((scalar @tags) lt 2) {
63             @sha1s_and_titles = $git->RUN('log', {pretty=>'%h %s' });
64 0           } else {
65             my $range = "$tags[1]...$tags[0]";
66 0 0         @sha1s_and_titles = $git->RUN('log', {pretty=>'%h %s' }, $range);
67 0           }
68              
69 0           return @sha1s_and_titles;
70 0            
71             }
72              
73 0           my $self = shift;
74             my $filename = shift;
75              
76             use Digest::SHA;
77             my $sha = Digest::SHA->new($self->{hash_alg});
78 0     0 1   my $digest;
79 0           if ( -e $filename ) {
80             open my $fh, '<:raw', $filename or die "$filename: $!";
81 1     1   1118 $sha->addfile($fh);
  1         2573  
  1         415  
82 0           $digest = $sha->hexdigest;
83 0           }
84 0 0         return $digest;
85 0 0         }
86 0            
87 0           my ($self) = @_;
88              
89 0           return $self->{zilla}->version;
90             }
91              
92             my ($self, $filename) = @_;
93 0     0 1    
94             $filename =~ s/-+\d+.*$//g;
95 0           $filename =~ s/-/::/g;
96             return $filename;
97             }
98              
99 0     0 1   my ($self, $digest, $filename, @sha1s_and_titles) = @_;
100              
101 0           my $version = $self->get_version();
102 0           my $name = $self->get_name($filename);
103 0            
104             my $file = "$name\n";
105             $file .= "\n";
106             $file .= "Release $version\n";
107 0     0 1   $file .= "\n";
108             $file .= "Change Log\n";
109 0            
110 0           foreach (@sha1s_and_titles) {
111             $file .= " - $_\n";
112 0           }
113 0            
114 0           $file .= "\n";
115 0           $file .= uc($self->{hash_alg}) . " hash of CPAN release\n";
116 0           $file .= "\n";
117             $file .= "$digest *$filename\n";
118 0           $file .= "\n";
119 0            
120             return $file;
121             }
122 0            
123 0           my $self = shift;
124 0           my $args = @_ == 1 ? shift : {@_};
125 0           $args->{sign} = $ENV{DZSIGN} if exists $ENV{DZSIGN};
126 0           $args;
127             }
128 0            
129             no Moose;
130              
131             __PACKAGE__->meta->make_immutable;
132 0     0 1   1;
133 0 0          
134 0 0          
135 0           =pod
136              
137             =encoding UTF-8
138 1     1   8  
  1         3  
  1         7  
139             =head1 NAME
140              
141             Dist::Zilla::Plugin::SignReleaseNotes - Create and signs a 'Release' notes file
142              
143             =head1 VERSION
144              
145             version 0.0008
146              
147             =head1 SYNOPSIS
148              
149             In your F<dist.ini>:
150              
151             [SignReleaseNotes]
152             sign = always ; default is always
153             sig_alg = sha512 ; default is sha256
154              
155             =head1 DESCRIPTION
156              
157             This plugin will sign a 'Release' file that includes:
158              
159             1. Git commits since the last tag
160             2. the sha checksum of the file that is being distributed to CPAN
161              
162             the file is then signed using Module::Signature.
163              
164             The resulting file can be used as the Release information for GitHub or similar.
165              
166             This plugin should appear after any other AfterBuild plugin in your C<dist.ini> file
167              
168             =head1 SAMPLE OUTPUT
169              
170             =over
171              
172             -----BEGIN PGP SIGNED MESSAGE-----
173             Hash: RIPEMD160
174              
175             Dist::Zilla::Plugin::SignReleaseNotes
176              
177             Release 0.0004
178              
179             Change Log
180             - 5c4df12 v0.0004
181             - 9000d39 Increment version number
182             - 1835a25 rev-list --tags matching commits that it should not
183              
184             SHA256 hash of CPAN release
185              
186             0b05776713165ad90d1385669e56dcd9f0abed8701f4e4652f5aa270687a3435 *Dist-Zilla-Plugin-SignReleaseNotes-0.0004.tar.gz
187              
188             -----BEGIN PGP SIGNATURE-----
189              
190             iQIzBAEBAwAdFiEEMguXHBCUSzAt6mNu1fh7LgYGpfkFAmH91iYACgkQ1fh7LgYG
191             pfmwrg//TXpyu8UeAaotLR0RFuLdmt9IrFmpflJ0SqwyY8MPBJOdb5BiwzSLDthi
192             1BNUtj4P+UsVlWrmXVufUYMEsGPyim6fD656NrUNds+PQQok3bTfR9qf341CY9Cq
193             MoR0an/u5APRaB4SurHs/lA3Nf/TRfAjkwBX4hzaRG1Iw9IcSHi5/gRBMA1E/+zT
194             /1GxkICjo0CrSe7REUiGmVf96TYGi/3D18pP/09Gnc6f1DMuKihiLy8BY57j9MCW
195             g6BWL8aXDpNvJFwwZv2h6OPLKF04xfjnVYzaAloCOaf2vHxb2ocv2KbOas8oWglf
196             BmameSAIHpxRTdV01M40V8eA6IHEDT4pUXGydggb9LQ/2s3X2n0AJN4HDwxtclvI
197             cF85Kfp2e5lqYJwHKN+tmQm3NUEJkvj+yM5tKeSoJWmba87fe7DKfhKHUSL7rqT5
198             PI2aKbs0auR2b5cXegUnNqKAjnF+I4pY/yWkmhUNPqQ+ctE/dy85opI6sQ1nIQ4v
199             Q3oIFhs4y+XkQorsorJJn3MtdrxTow/CoOjQ/Mydd11xpQSlXkTAO3TqxEiXIz0l
200             i4RybXbqlFB9MAbs9dbC96Lq5hxroxeIVxo99r9Q327it1gQWPMCnfUV9LKmzusZ
201             2j18EynyALPs/onwA4VOIi1kC3As8d+1cBfhaFaZf9vgryXQx84=
202             =kzjP
203             -----END PGP SIGNATURE-----
204              
205             =back
206              
207             =head1 ATTRIBUTES
208              
209             =over
210              
211             =item sign
212              
213             A string value. If C<always> then a signature will be created after an archive is created.
214             If C<always> then the 'Release' file will be signed after the release. Default is C<always>
215              
216             This attribute can be overridden by an environment variable C<DZSIGN>
217              
218             =item hash_alg
219              
220             A string value for the B<Digest::SHA> supported hash algorithm to use for the hash of the
221             cpan upload file.
222              
223             =back
224              
225             =head1 METHODS
226              
227             =over
228              
229             =item after_release
230              
231             The main processing function includes getting the git information. Should likely
232             be split up.
233              
234             =item create_release_file
235              
236             Create's the plaintext Release file contents.
237              
238             =item do_sign
239              
240             Signs the 'Release' file to Module::Signature. Unfortunately we cannot use
241             the Module::Signature::sign function as it gets its plaintext from the list
242             of files that are normally used.
243              
244             =item sub get_git_checksums_and_titles
245              
246             Gets the short version of the checksums and the titles of each git commit since the
247             most recent tag that was found in the repo.
248              
249             =item get_checksum
250              
251             Get's the checksum of the file being released. Expects the filename and returns
252             the checksum with the requested Digest::SHA algorithim.
253              
254             =item get_name
255              
256             Get's the name of the Distribution being released. This takes it from
257             the filename. There is likely a better way to obtain it.
258              
259             =item get_version
260              
261             Get's the version of the Distribution being released. This takes it from
262             the $self->{zilla}->version. There is likely a better way to obtain it.
263              
264             =back
265              
266             =head1 AUTHOR
267              
268             Timothy Legge <timlegge@cpan.org>
269              
270             =head1 COPYRIGHT AND LICENSE
271              
272             This software is copyright (c) 2021 by Timothy Legge.
273              
274             This is free software; you can redistribute it and/or modify it under
275             the same terms as the Perl 5 programming language system itself.
276              
277             =head1 AUTHOR
278              
279             Timothy Legge
280              
281             =head1 COPYRIGHT AND LICENSE
282              
283             This software is copyright (c) 2022 by Timothy Legge.
284              
285             This is free software; you can redistribute it and/or modify it under
286             the same terms as the Perl 5 programming language system itself.
287              
288             =cut