remove default FAKE_RELEASE setting, allowing env to pass through
[p5sagit/Distar.git] / lib / Distar.pm
CommitLineData
42e08a83 1package Distar;
362ec4af 2use strict;
3use warnings FATAL => 'all';
42e08a83 4use base qw(Exporter);
ca3b3b8a 5use ExtUtils::MakeMaker ();
6use ExtUtils::MM ();
8aac77fc 7use File::Spec ();
42e08a83 8
f6286f60 9our $VERSION = '0.002000';
37e295d8 10$VERSION = eval $VERSION;
11
e076eedb 12my $MM_VER = eval $ExtUtils::MakeMaker::VERSION;
13
42e08a83 14our @EXPORT = qw(
be032607 15 author manifest_include readme_generator
42e08a83 16);
17
18sub import {
2852faf3 19 strict->import;
20 warnings->import(FATAL => 'all');
42e08a83 21 shift->export_to_level(1,@_);
22}
23
e076eedb 24sub author {
25 our $Author = shift;
26 $Author = [ $Author ]
27 if !ref $Author;
28}
42e08a83 29
30our @Manifest = (
31 'lib' => '.pm',
7b9318ce 32 'lib' => '.pod',
42e08a83 33 't' => '.t',
34 't/lib' => '.pm',
35 'xt' => '.t',
36 'xt/lib' => '.pm',
1d950b4a 37 '' => qr{[^/]*\.PL},
f1ef306e 38 '' => qr{Changes|MANIFEST|README|LICENSE|META\.yml},
42e08a83 39 'maint' => qr{[^.].*},
40);
41
42sub manifest_include {
43 push @Manifest, @_;
44}
45
6e83c113 46sub readme_generator {
f6286f60 47 die "readme_generator unsupported" if @_ && $_[0];
6e83c113 48}
49
42e08a83 50sub write_manifest_skip {
0fa73f76 51 my ($mm) = @_;
42e08a83 52 my @files = @Manifest;
53 my @parts;
54 while (my ($dir, $spec) = splice(@files, 0, 2)) {
55 my $re = ($dir ? $dir.'/' : '').
56 ((ref($spec) eq 'Regexp')
57 ? $spec
58 : !ref($spec)
59 ? ".*\Q${spec}\E"
a3e39afd 60 # print ref as well as stringification in case of overload ""
42e08a83 61 : die "spec must be string or regexp, was: ${spec} (${\ref $spec})");
62 push @parts, $re;
63 }
0fa73f76 64 my $dist_name = $mm->{DISTNAME};
65 my $include = join '|', map "${_}\$", @parts;
66 my $final = "^(?:\Q$dist_name\E-v?[0-9_.]+/|(?!$include))";
19916679 67 open my $skip, '>', 'MANIFEST.SKIP'
68 or die "can't open MANIFEST.SKIP: $!";
42e08a83 69 print $skip "${final}\n";
70 close $skip;
71}
72
ca3b3b8a 73{
74 package Distar::MM;
9af7ff2e 75 our @ISA = @MM::ISA;
76 @MM::ISA = (__PACKAGE__);
ca3b3b8a 77
78 sub new {
79 my ($class, $args) = @_;
4762e03a 80 my %test = %{$args->{test}||{}};
81 my $tests = $test{TESTS} || 't/*.t';
82 $tests !~ /\b\Q$_\E\b/ and $tests .= " $_"
83 for 'xt/*.t', 'xt/*/*.t';
84 $test{TESTS} = $tests;
ca3b3b8a 85 return $class->SUPER::new({
180e908e 86 LICENSE => 'perl_5',
53e1282f 87 MIN_PERL_VERSION => '5.006',
0cc25268 88 AUTHOR => ($MM_VER >= 6.5702 ? $Distar::Author : join(', ', @$Distar::Author)),
1f136c70 89 (exists $args->{ABSTRACT} ? () : (ABSTRACT_FROM => $args->{VERSION_FROM})),
4a4bb570 90 %$args,
4762e03a 91 test => \%test,
0a3fdb23 92 realclean => { FILES => (
93 ($args->{realclean}{FILES}||'')
94 . ' Distar/ MANIFEST.SKIP MANIFEST MANIFEST.bak'
95 ) },
ca3b3b8a 96 });
97 }
98
eddb1ce6 99 sub flush {
100 my $self = shift;
5371ff52 101 `git ls-files --error-unmatch MANIFEST.SKIP 2>&1`;
102 my $maniskip_tracked = !$?;
103
104 Distar::write_manifest_skip($self)
105 unless $maniskip_tracked;
eddb1ce6 106 $self->SUPER::flush(@_);
107 }
108
7efea54c 109 sub special_targets {
110 my $self = shift;
111 my $targets = $self->SUPER::special_targets(@_);
f57289e3 112 my $phony_targets = join ' ', qw(
113 preflight
7b418de8 114 check-version
5baee32c 115 check-manifest
b0780d0a 116 check-cpan-upload
f57289e3 117 releasetest
118 release
119 readmefile
120 distmanicheck
121 nextrelease
122 refresh
123 bump
124 bumpmajor
125 bumpminor
126 );
127 $targets =~ s/^(\.PHONY *:.*)/$1 $phony_targets/m;
7efea54c 128 $targets;
129 }
130
ee801c00 131 sub tarfile_target {
132 my $self = shift;
133 my $out = $self->SUPER::tarfile_target(@_);
134 my $verify = <<'END_FRAG';
135 $(ABSPERLRUN) $(HELPERS)/verify-tarball $(DISTVNAME).tar $(DISTVNAME)/MANIFEST --tar="$(TAR)"
136END_FRAG
137 $out =~ s{(\$\(TAR\).*\n)}{$1$verify};
138 $out;
139 }
140
ca3b3b8a 141 sub dist_test {
142 my $self = shift;
8ab5ea70 143
66a2ecde 144 my $include = '';
145 if (open my $fh, '<', 'maint/Makefile.include') {
146 $include = "\n# --- Makefile.include:\n\n" . do { local $/; <$fh> };
147 $include =~ s/\n?\z/\n/;
148 }
b0401762 149
66a2ecde 150 my @bump_targets =
151 grep { $include !~ /^bump$_(?: +\w+)*:/m } ('', 'minor', 'major');
81d518f6 152
8aac77fc 153 my $distar = File::Spec->catdir(
154 File::Spec->catpath((File::Spec->splitpath(__FILE__))[0,1], ''),
155 File::Spec->updir,
156 );
157 my $helpers = File::Spec->catdir($distar, 'helpers');
158
66a2ecde 159 my %vars = (
8aac77fc 160 DISTAR => $self->quote_literal($distar),
161 HELPERS => $self->quote_literal($helpers),
2c75254f 162 REMAKE => join(' ', '$(PERLRUN)', '-I$(DISTAR)/lib', '-mDistar', 'Makefile.PL', map { $self->quote_literal($_) } @ARGV),
190976f8 163 BRANCH => $self->{BRANCH} ||= 'master',
9b920c5c 164 CHANGELOG => $self->{CHANGELOG} ||= 'Changes',
b0780d0a 165 DEV_NULL_STDOUT => ($self->{DEV_NULL} ? '>'.File::Spec->devnull : ''),
f0bbeff7 166 DISTTEST_MAKEFILE_PARAMS => '',
66a2ecde 167 );
168
f0bbeff7 169 my $dist_test = $self->SUPER::dist_test(@_);
170 $dist_test =~ s/(\bMakefile\.PL\b)/$1 \$(DISTTEST_MAKEFILE_PARAMS)/;
171
66a2ecde 172 join('',
f0bbeff7 173 $dist_test,
66a2ecde 174 "\n\n# --- Distar section:\n\n",
175 (map "$_ = $vars{$_}\n", sort keys %vars),
176 <<'END',
81d518f6 177
b0780d0a 178preflight: check-version check-manifest check-cpan-upload
8aac77fc 179 $(ABSPERLRUN) $(HELPERS)/preflight $(VERSION) --changelog=$(CHANGELOG) --branch=$(BRANCH)
7b418de8 180check-version:
8aac77fc 181 $(ABSPERLRUN) $(HELPERS)/check-version $(VERSION) $(TO_INST_PM) $(EXE_FILES)
5baee32c 182check-manifest:
8aac77fc 183 $(ABSPERLRUN) $(HELPERS)/check-manifest
b0780d0a 184check-cpan-upload:
185 $(NOECHO) cpan-upload -h $(DEV_NULL_STDOUT)
3e632431 186releasetest:
f0bbeff7 187 $(MAKE) disttest RELEASE_TESTING=1 DISTTEST_MAKEFILE_PARAMS="PREREQ_FATAL=1" PASTHRU="$(PASTHRU) TEST_FILES=\"$(TEST_FILES)\""
49beea48 188release: preflight
189 $(MAKE) releasetest
42e08a83 190 git commit -a -m "Release commit for $(VERSION)"
401ece0b 191 git tag v$(VERSION) -m "release v$(VERSION)"
49beea48 192 $(RM_RF) $(DISTVNAME)
193 $(MAKE) $(DISTVNAME).tar$(SUFFIX)
263b723e 194 $(NOECHO) $(MAKE) pushrelease FAKE_RELEASE=$(FAKE_RELEASE)
195pushrelease ::
196 $(NOECHO) $(NOOP)
197pushrelease$(FAKE_RELEASE) ::
65a1f7d9 198 cpan-upload $(DISTVNAME).tar$(SUFFIX)
2c636792 199 git push origin v$(VERSION) HEAD
5154970c 200distdir: readmefile
75f8311c 201readmefile: create_distdir
5c5deb0a 202 $(NOECHO) $(TEST_F) $(DISTVNAME)/README || $(MAKE) $(DISTVNAME)/README
f6286f60 203$(DISTVNAME)/README: $(VERSION_FROM)
204 $(NOECHO) $(MKPATH) $(DISTVNAME)
205 pod2text $(VERSION_FROM) >$(DISTVNAME)/README
8aac77fc 206 $(NOECHO) $(ABSPERLRUN) $(HELPERS)/add-to-manifest -d $(DISTVNAME) README
7934d553 207distsignature: readmefile
de048fa8 208disttest: distmanicheck
792c9e91 209distmanicheck: create_distdir
210 cd $(DISTVNAME) && $(ABSPERLRUN) "-MExtUtils::Manifest=manicheck" -e "exit manicheck"
e7a78651 211nextrelease:
8aac77fc 212 $(ABSPERLRUN) $(HELPERS)/add-changelog-heading --git $(VERSION) $(CHANGELOG)
0edb27b8 213refresh:
41e593ee 214 cd $(DISTAR) && git pull || $(TRUE)
e9f66489 215 $(RM_F) $(FIRST_MAKEFILE)
0edb27b8 216 $(REMAKE)
8ab5ea70 217END
66a2ecde 218 map(sprintf(<<'END', "bump$_", ($_ || '$(V)')), @bump_targets),
219%s:
8aac77fc 220 $(ABSPERLRUN) $(HELPERS)/bump-version --git $(VERSION) %s
66a2ecde 221 $(RM_F) $(FIRST_MAKEFILE)
222 $(REMAKE)
42e08a83 223END
66a2ecde 224 $include,
225 "\n",
226 );
42e08a83 227 }
228}
229
42e08a83 2301;
edb4539a 231__END__
232
233=head1 NAME
234
235Distar - Additions to ExtUtils::MakeMaker for dist authors
236
237=head1 SYNOPSIS
238
239F<Makefile.PL>:
240
241 use ExtUtils::MakeMaker;
83e12da3 242 (do './maint/Makefile.PL.include' or die $@) unless -f 'META.yml';
edb4539a 243
244 WriteMakefile(...);
245
246F<maint/Makefile.PL.include>:
247
248 BEGIN { -e 'Distar' or system("git clone git://git.shadowcat.co.uk/p5sagit/Distar.git") }
249 use lib 'Distar/lib';
250 use Distar 0.001;
251
252 author 'A. U. Thor <author@cpan.org>';
253
254 manifest_include t => 'test-helper.pl';
255 manifest_include corpus => '.txt';
256
257make commmands:
258
259 $ perl Makefile.PL
260 $ make bump # bump version
261 $ make bump V=2.000000 # bump to specific version
262 $ make bumpminor # bump minor version component
263 $ make bumpmajor # bump major version component
264 $ make nextrelease # add version heading to Changes file
265 $ make releasetest # build dist and test (with xt/ and RELEASE_TESTING=1)
266 $ make preflight # check that repo and file state is release ready
83e12da3 267 $ make release # check releasetest and preflight, commits and tags,
268 # builds and uploads to CPAN, and pushes commits and
269 # tag
270 $ make release FAKE_RELEASE=1
271 # builds a release INCLUDING committing and tagging,
272 # but does not upload to cpan or push anything to git
edb4539a 273
274=head1 DESCRIPTION
275
276L<ExtUtils::MakeMaker> works well enough as development tool for
277builting and testing, but using it to release is annoying and error prone.
278Distar adds just enough to L<ExtUtils::MakeMaker> for it to be a usable dist
279author tool. This includes extra commands for releasing and safety checks, and
280automatic generation of some files. It doesn't require any non-core modules and
281is compatible with old versions of perl.
282
283=head1 FUNCTIONS
284
285=head2 author( $author )
286
287Set the author to include in generated META files. Can be a single entry, or
288an arrayref.
289
290=head2 manifest_include( $dir, $pattern )
291
292Add a pattern to include files in the MANIFEST file, and thus in the generated
293dist files.
294
295The pattern can be either a regex, or a path suffix. It will be applied to the
296full path past the directory specified.
297
298The default files that are always included are: F<.pm> and F<.pod> files in
299F<lib>, F<.t> files in F<t> and F<xt>, F<.pm> files in F<t/lib> and F<xt/lib>,
300F<Changes>, F<MANIFEST>, F<README>, F<LICENSE>, F<META.yml>, and F<.PL> files in
301the dist root, and all files in F<maint>.
302
303=head1 AUTOGENERATED FILES
304
305=over 4
306
307=item F<MANIFEST.SKIP>
308
309The F<MANIFEST.SKIP> will be automatically generated to exclude any files not
310explicitly allowed via C<manifest_include> or the included defaults. It will be
311created (or updated) at C<perl Makefile.PL> time.
312
313=item F<README>
314
315The F<README> file will be generated at dist generation time, inside the built
316dist. It will be generated using C<pod2text> on the main module.
317
318If a F<README> file exists in the repo, it will be used directly instead of
319generating the file.
320
321=back
322
323=head1 MAKE COMMMANDS
324
325=head2 test
326
327test will be adjusted to include F<xt/> tests by default. This will only apply
328for authors, not users installing from CPAN.
329
330=head2 release
331
332Releases the dist. Before releasing, checks will be done on the dist using the
333C<preflight> and C<releasetest> commands.
334
335Releasing will generate a dist tarball and upload it to CPAN using cpan-upload.
336It will also create a git tag for the release, and push the tag and branch.
337
83e12da3 338=head3 FAKE_RELEASE
263b723e 339
340If release is run with FAKE_RELEASE=1 set, it will skip uploading to CPAN and
341pushing to git. A release commit will still be created and tagged locally.
342
edb4539a 343=head2 preflight
344
345Performs a number of checks on the files and repository, ensuring it is in a
346sane state to do a release. The checks are:
347
348=over 4
349
350=item * All version numbers match
351
352=item * The F<MANIFEST> file is up to date
353
354=item * The branch is correct
355
356=item * There is no existing tag for the version
357
358=item * There are no unmerged upstream changes
359
360=item * There are no outstanding local changes
361
362=item * There is an appropriate staged Changes heading
363
364=item * cpan-upload is available
365
366=back
367
368=head2 releasetest
369
370Test the dist preparing for a release. This generates a dist dir and runs the
371tests from inside it. This ensures all appropriate files are included inside
372the dist. C<RELEASE_TESTING> will be set in the environment.
373
374=head2 nextrelease
375
376Adds an appropriate changelog heading for the release, and prompts to stage the
377change.
378
379=head2 bump
380
381Bumps the version number. This will try to preserve the length and format of
83e12da3 382the version number. The least significant digit will be incremented. Versions
383with underscores will preserve the underscore in the same position.
edb4539a 384
385Optionally accepts a C<V> option to set the version to a specific value.
386
387The version changes will automatically be committed. Unstaged modifications to
388the files will be left untouched.
389
83e12da3 390=head3 V
391
392The V option will be passed along to the version bumping script. It can accept
393a space separated list of options, including an explicit version number.
394
395Options:
396
397=over 4
398
399=item --force
400
401Updates version numbers even if they do not match the current expected version
402number.
403
404=item --stable
405
406Attempts to convert the updated version to a stable version, removing any
407underscore.
408
409=item --alpha
410
411Attempts to convert the updated version to an alpha version, adding an
412underscore in an appropriate place.
413
414=back
415
edb4539a 416=head2 bumpminor
417
418Like bump, but increments the minor segment of the version. This will treat
419numeric versions as x.yyyzzz format, incrementing the yyy segment.
420
421=head2 bumpmajor
422
423Like bumpminor, but bumping the major segment.
424
425=head2 refresh
426
427Updates Distar and re-runs C<perl Makefile.PL>
428
429=head1 SUPPORT
430
431IRC: #web-simple on irc.perl.org
432
433Git repository: L<git://git.shadowcat.co.uk/p5sagit/Distar>
434
435Git browser: L<http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit/Distar.git;a=summary>
436
437=head1 AUTHOR
438
439mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
440
441=head1 CONTRIBUTORS
442
443haarg - Graham Knop (cpan:HAARG) <haarg@cpan.org>
444
83e12da3 445ether - Karen Etheridge (cpan:ETHER) <ether@cpan.org>
edb4539a 446
447frew - Arthur Axel "fREW" Schmidt (cpan:FREW) <frioux@gmail.com>
448
449Mithaldu - Christian Walde (cpan:MITHALDU) <walde.christian@googlemail.com>
450
451=head1 COPYRIGHT
452
453Copyright (c) 2011-2015 the Distar L</AUTHOR> and L</CONTRIBUTORS>
454as listed above.
455
456=head1 LICENSE
457
458This library is free software and may be distributed under the same terms
459as perl itself. See L<http://dev.perl.org/licenses/>.
460
461=cut