File Coverage

blib/lib/Dist/Zilla/Plugin/BumpVersionAfterRelease.pm
Criterion Covered Total %
statement 66 72 91.6
branch 16 22 72.7
condition 6 9 66.6
subroutine 12 12 100.0
pod 0 5 0.0
total 100 120 83.3


line stmt bran cond sub pod time code
1 5     5   113781 use 5.008001;
  5         11  
2 5     5   19 use strict;
  5         5  
  5         93  
3 5     5   15 use warnings;
  5         5  
  5         243  
4              
5             package Dist::Zilla::Plugin::BumpVersionAfterRelease;
6             # ABSTRACT: Bump module versions after distribution release
7              
8             our $VERSION = '0.015';
9              
10 5     5   17 use Moose;
  5         11  
  5         26  
11 5     5   20644 use namespace::autoclean;
  5         7  
  5         34  
12 5     5   268 use version ();
  5         6  
  5         4154  
13              
14             #pod =attr allow_decimal_underscore
15             #pod
16             #pod Allows use of decimal versions with underscores. Default is false. (Version
17             #pod tuples with underscores are never allowed!)
18             #pod
19             #pod =cut
20              
21             has allow_decimal_underscore => (
22             is => 'ro',
23             isa => 'Bool',
24             );
25              
26             #pod =attr global
27             #pod
28             #pod If true, all occurrences of the version pattern will be replaced. Otherwise,
29             #pod only the first occurrence is replaced. Defaults to false.
30             #pod
31             #pod =cut
32              
33             has global => (
34             is => 'ro',
35             isa => 'Bool',
36             );
37              
38             #pod =attr munge_makefile_pl
39             #pod
40             #pod If there is a F<Makefile.PL> in the root of the repository, its version will be
41             #pod set as well. Defaults to true.
42             #pod
43             #pod =cut
44              
45             has munge_makefile_pl => (
46             is => 'ro',
47             isa => 'Bool',
48             default => 1,
49             );
50              
51             #pod =attr munge_build_pl
52             #pod
53             #pod If there is a F<Build.PL> in the root of the repository, its version will be
54             #pod set as well. Defaults to true.
55             #pod
56             #pod =cut
57              
58             has munge_build_pl => (
59             is => 'ro',
60             isa => 'Bool',
61             default => 1,
62             );
63              
64             has _next_version => (
65             is => 'ro',
66             isa => 'Str',
67             lazy => 1,
68             init_arg => undef,
69             builder => '_build__next_version',
70             );
71              
72             sub _build__next_version {
73 10     10   19 my ($self) = @_;
74 10         2035 require Version::Next;
75 10         4506 my $version = $self->zilla->version;
76              
77 10         415 $self->check_valid_version($version);
78              
79 10         78 return Version::Next::next_version($version);
80             }
81              
82             sub after_release {
83 10     10 0 850006 my ($self) = @_;
84 10         26 $self->munge_file($_) for @{ $self->found_files };
  10         72  
85 10 100 66     530 $self->rewrite_makefile_pl if -f "Makefile.PL" && $self->munge_makefile_pl;
86 10 100 66     436 $self->rewrite_build_pl if -f "Build.PL" && $self->munge_build_pl;
87 10         28 return;
88             }
89              
90             sub munge_file {
91 24     24 0 18676 my ( $self, $file ) = @_;
92              
93 24 50       122 return if $file->is_bytes;
94              
95 24 50       1013 if ( $file->name =~ m/\.pod$/ ) {
96 0         0 $self->log_debug( [ 'Skipping: "%s" is pod only', $file->name ] );
97 0         0 return;
98             }
99              
100 24 100       972 if ( !-r $file->name ) {
101 1         52 $self->log_debug( [ 'Skipping: "%s" not found in source', $file->name ] );
102 1         351 return;
103             }
104              
105 23 50       1999 if ( $self->rewrite_version( $file, $self->_next_version ) ) {
106 23         735 $self->log_debug( [ 'bumped $VERSION in %s', $file->_original_name ] );
107             }
108             else {
109 0         0 $self->log( [ q[Skipping: no "our $VERSION = '...'" found in "%s"], $file->name ] );
110             }
111 23         6445 return;
112             }
113              
114             sub rewrite_version {
115 23     23 0 37 my ( $self, $file, $version ) = @_;
116              
117 23         108 require Path::Tiny;
118 23         436 Path::Tiny->VERSION(0.061);
119              
120 23         670 my $iolayer = sprintf( ":raw:encoding(%s)", $file->encoding );
121              
122             # read source file
123 23         764 my $content =
124             Path::Tiny::path( $file->_original_name )->slurp( { binmode => $iolayer } );
125              
126 23         10347 my $code = "our \$VERSION = '$version';";
127 23 100 66     125 $code .= "\n\$VERSION = eval \$VERSION;"
128             if $version =~ /_/ and scalar( $version =~ /\./g ) <= 1;
129              
130 23         93 my $assign_regex = $self->assign_re();
131              
132 23 100       960 if (
    50          
133             $self->global
134             ? ( $content =~ s{^$assign_regex[^\n]*$}{$code}msg )
135             : ( $content =~ s{^$assign_regex[^\n]*$}{$code}ms )
136             )
137             {
138             # append+truncate to preserve file mode
139 23         92 Path::Tiny::path( $file->name )
140             ->append( { binmode => $iolayer, truncate => 1 }, $content );
141 23         6312 return 1;
142             }
143              
144 0         0 return;
145             }
146              
147             sub rewrite_makefile_pl {
148 8     8 0 13 my ($self) = @_;
149              
150 8         313 my $next_version = $self->_next_version;
151              
152 8         35 require Path::Tiny;
153 8         124 Path::Tiny->VERSION(0.061);
154              
155 8         32 my $path = Path::Tiny::path("Makefile.PL");
156              
157 8         186 my $content = $path->slurp_utf8;
158              
159 8 50       804 if ( $content =~ s{"VERSION" => "[^"]+"}{"VERSION" => "$next_version"}ms ) {
160 8         50 $path->append_utf8( { truncate => 1 }, $content );
161 8         1190 return 1;
162             }
163              
164 0         0 return;
165             }
166              
167             sub rewrite_build_pl {
168 8     8 0 9 my ($self) = @_;
169              
170 8         254 my $next_version = $self->_next_version;
171              
172 8         34 require Path::Tiny;
173 8         110 Path::Tiny->VERSION(0.061);
174              
175 8         31 my $path = Path::Tiny::path("Build.PL");
176              
177 8         161 my $content = $path->slurp_utf8;
178              
179 8 50       758 if ( $content =~ s{"dist_version" => "[^"]+"}{"dist_version" => "$next_version"}ms ) {
180 8         34 $path->append_utf8( { truncate => 1 }, $content );
181 8         1072 return 1;
182             }
183              
184 0           return;
185             }
186              
187             with(
188             'Dist::Zilla::Role::AfterRelease' => { -version => 5 },
189             'Dist::Zilla::Role::FileFinderUser' =>
190             { default_finders => [ ':InstallModules', ':ExecFiles' ], },
191             'Dist::Zilla::Plugin::BumpVersionAfterRelease::_Util',
192             );
193              
194             around dump_config => sub {
195             my ( $orig, $self ) = @_;
196             my $config = $self->$orig;
197              
198             $config->{ +__PACKAGE__ } = {
199             finders => [ sort @{ $self->finder } ],
200             ( map { $_ => $self->$_ ? 1 : 0 } qw(global munge_makefile_pl) ),
201             };
202              
203             return $config;
204             };
205              
206             __PACKAGE__->meta->make_immutable;
207              
208             1;
209              
210              
211             # vim: ts=4 sts=4 sw=4 et:
212              
213             __END__
214              
215             =pod
216              
217             =encoding UTF-8
218              
219             =head1 NAME
220              
221             Dist::Zilla::Plugin::BumpVersionAfterRelease - Bump module versions after distribution release
222              
223             =head1 VERSION
224              
225             version 0.015
226              
227             =head1 SYNOPSIS
228              
229             In your code, declare C<$VERSION> like this:
230              
231             package Foo;
232             our $VERSION = '1.23';
233              
234             In your F<dist.ini>:
235              
236             [RewriteVersion]
237              
238             [BumpVersionAfterRelease]
239              
240             =head1 DESCRIPTION
241              
242             After a release, this module modifies your original source code to replace an
243             existing C<our $VERSION = '1.23'> declaration with the next number after the
244             released version as determined by L<Version::Next>.
245              
246             By default, versions B<must> be "strict" -- decimal or 3+ part tuple with a
247             leading "v". The C<allow_decimal_underscore> option, if enabled, will also
248             allow decimals to contain an underscore. All other version forms are
249             not allowed, including: "v1.2", "1.2.3" and "v1.2.3_4".
250              
251             Only the B<first>
252             occurrence is affected (unless you set the L</global> attribute) and it must
253             exactly match this regular expression:
254              
255             qr{^our \s+ \$VERSION \s* = \s* '$version::LAX'}mx
256              
257             It must be at the start of a line and any trailing comments are deleted. The
258             original may have double-quotes, but the re-written line will have single
259             quotes.
260              
261             The very restrictive regular expression format is intentional to avoid
262             the various ways finding a version assignment could go wrong and to avoid
263             using L<PPI>, which has similar complexity issues.
264              
265             For most modules, this should work just fine.
266              
267             =head1 USAGE
268              
269             This L<Dist::Zilla> plugin, along with
270             L<RewriteVersion|Dist::Zilla::Plugin::RewriteVersion> let you leave a
271             C<$VERSION> declaration in the code files in your repository but still let
272             Dist::Zilla provide automated version management.
273              
274             First, you include a very specific C<$VERSION> declaration in your code:
275              
276             our $VERSION = '0.001';
277              
278             It must be on a line by itself and should be the same in all your files.
279             (If it is not, it will be overwritten anyway.)
280              
281             L<RewriteVersion|Dist::Zilla::Plugin::RewriteVersion> is a version provider
282             plugin, so the version line from your main module will be used as the version
283             for your release.
284              
285             If you override the version with the C<V> environment variable,
286             then L<RewriteVersion|Dist::Zilla::Plugin::RewriteVersion> will overwrite the
287             C<$VERSION> declaration in the gathered files.
288              
289             V=1.000 dzil release
290              
291             Finally, after a successful release, this module
292             L<BumpVersionAfterRelease|Dist::Zilla::Plugin::BumpVersionAfterRelease> will
293             overwrite the C<$VERSION> declaration in your B<source> files to be the B<next>
294             version after the one you just released. That version will then be the default
295             one that will be used for the next release.
296              
297             You can configure which files have their C<$VERSION> declarations modified,
298             with the C<finder> option. The default finders are C<:InstallModules> and
299             C<:ExecFiles>; other predefined finders are listed in
300             L<Dist::Zilla::Role::FileFinderUser/default_finders>.
301              
302             If you tag/commit after a release, you may want to tag and commit B<before>
303             the source files are modified. Here is a sample C<dist.ini> that shows
304             how you might do that.
305              
306             name = Foo-Bar
307             author = David Golden <dagolden@cpan.org>
308             license = Apache_2_0
309             copyright_holder = David Golden
310             copyright_year = 2014
311              
312             [@Basic]
313              
314             [RewriteVersion]
315              
316             ; commit source files as of "dzil release" with any
317             ; allowable modifications (e.g Changes)
318             [Git::Commit / Commit_Dirty_Files] ; commit files/Changes (as released)
319              
320             ; tag as of "dzil release"
321             [Git::Tag]
322              
323             ; update Changes with timestamp of release
324             [NextRelease]
325              
326             [BumpVersionAfterRelease]
327              
328             ; commit source files after modification
329             [Git::Commit / Commit_Changes] ; commit Changes (for new dev)
330             allow_dirty_match = ^lib/
331             commit_msg = Commit Changes and bump $VERSION
332              
333             =head2 Using underscore in decimal $VERSION
334              
335             By default, versions must meet the 'strict' criteria from
336             L<version|version.pm>, which does not allow the use of underscores.
337              
338             If the C<allow_decimal_underscore> options is set to true, you may
339             use underscores in decimal versions. In this case, the following line will
340             be added after the C<$VERSION> assignment to ensure the underscore is
341             removed at runtime:
342              
343             $VERSION = eval $VERSION;
344              
345             Despite their long history on CPAN, the author does not recommend the use
346             of decimal underscore versions with Dist::Zilla, as Dist::Zilla supports
347             generating tarballs with a "-TRIAL" part of the name as well as putting a
348             C<release_status> in META.json – both of which prevent PAUSE from indexing
349             a distribution.
350              
351             Plus, since this plugin also adds the '# TRIAL' comment on the version
352             line, it's obvious in the source that the module is a development release.
353             With both source and tarball obviously marked "TRIAL", most of the
354             historical need for underscore in a version is taken care of.
355              
356             Using decimal underscores (with the "eval" hack ) introduces a subtle
357             difference between what the C<< MM->parse_version >> thinks the version is
358             (and what is in META) and what Perl thinks the version is at runtime.
359              
360             Foo->VERSION eq MM->parse_version( $INC{"Foo.pm"} )
361              
362             This would be false for the version "1.002_003" with
363             C<$VERSION = eval $VERSION>. Much of the toolchain has heuristics to
364             deal with this, but it may be an issue depending on exactly what
365             version of toolchain modules you have installed. You can avoid all of
366             it by just not using underscores.
367              
368             On the other hand, using underscores and B<not> using C<eval $VERSION>
369             leads to even worse problems trying to specify a version number with
370             C<use>:
371              
372             # given $Foo::VERSION = "1.002_003"
373              
374             use Foo 1.002_003; # fails!
375              
376             Underscore versions were a useful hack, but now it's time to move on and
377             leave them behind. But, if you really insist on underscores, the
378             C<allow_decimal_underscore> option will let you.
379              
380             =head2 Using underscore in tuple $VERSION
381              
382             Yes, Perl allows this: C<v1.2.3_4>. And even this: C<1.2.3_4>. And
383             this: C<v1.2_3>. Or any of those in quotes. (Maybe)
384              
385             But what happens is a random function of your version of Perl, your
386             version of L<version.pm|version>, and your version of the CPAN toolchain.
387              
388             So you really shouldn't use underscores in version tuples, and this module
389             won't let you.
390              
391             =head1 ATTRIBUTES
392              
393             =head2 allow_decimal_underscore
394              
395             Allows use of decimal versions with underscores. Default is false. (Version
396             tuples with underscores are never allowed!)
397              
398             =head2 global
399              
400             If true, all occurrences of the version pattern will be replaced. Otherwise,
401             only the first occurrence is replaced. Defaults to false.
402              
403             =head2 munge_makefile_pl
404              
405             If there is a F<Makefile.PL> in the root of the repository, its version will be
406             set as well. Defaults to true.
407              
408             =head2 munge_build_pl
409              
410             If there is a F<Build.PL> in the root of the repository, its version will be
411             set as well. Defaults to true.
412              
413             =for Pod::Coverage after_release munge_file rewrite_build_pl rewrite_makefile_pl rewrite_version
414              
415             =head1 SEE ALSO
416              
417             Here are some other plugins for managing C<$VERSION> in your distribution:
418              
419             =over 4
420              
421             =item *
422              
423             L<Dist::Zilla::Plugin::PkgVersion>
424              
425             =item *
426              
427             L<Dist::Zilla::Plugin::OurPkgVersion>
428              
429             =item *
430              
431             L<Dist::Zilla::Plugin::OverridePkgVersion>
432              
433             =item *
434              
435             L<Dist::Zilla::Plugin::SurgicalPkgVersion>
436              
437             =item *
438              
439             L<Dist::Zilla::Plugin::PkgVersionIfModuleWithPod>
440              
441             =item *
442              
443             L<Dist::Zilla::Plugin::RewriteVersion::Transitional>
444              
445             =back
446              
447             =for :stopwords cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan
448              
449             =head1 SUPPORT
450              
451             =head2 Bugs / Feature Requests
452              
453             Please report any bugs or feature requests through the issue tracker
454             at L<https://github.com/dagolden/Dist-Zilla-Plugin-BumpVersionAfterRelease/issues>.
455             You will be notified automatically of any progress on your issue.
456              
457             =head2 Source Code
458              
459             This is open source software. The code repository is available for
460             public review and contribution under the terms of the license.
461              
462             L<https://github.com/dagolden/Dist-Zilla-Plugin-BumpVersionAfterRelease>
463              
464             git clone https://github.com/dagolden/Dist-Zilla-Plugin-BumpVersionAfterRelease.git
465              
466             =head1 AUTHOR
467              
468             David Golden <dagolden@cpan.org>
469              
470             =head1 CONTRIBUTORS
471              
472             =for stopwords Dave Rolsky David Golden Karen Etheridge Kent Fredric Klaus Eichner
473              
474             =over 4
475              
476             =item *
477              
478             Dave Rolsky <autarch@urth.org>
479              
480             =item *
481              
482             David Golden <xdg@xdg.me>
483              
484             =item *
485              
486             Karen Etheridge <ether@cpan.org>
487              
488             =item *
489              
490             Kent Fredric <kentfredric@gmail.com>
491              
492             =item *
493              
494             Klaus Eichner <klaus03@gmail.com>
495              
496             =back
497              
498             =head1 COPYRIGHT AND LICENSE
499              
500             This software is Copyright (c) 2014 by David Golden.
501              
502             This is free software, licensed under:
503              
504             The Apache License, Version 2.0, January 2004
505              
506             =cut