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