———————————# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#
# file: lib/Dist/Zilla/PluginBundle/Author/VDB.pm
#pod =encoding UTF-8
#pod
#pod =head1 COPYRIGHT AND LICENSE
#pod
#pod Copyright © 2015 Van de Bugger
#pod
#pod This file is part of perl-Dist-Zilla-PluginBundle-Author-VDB.
#pod
#pod perl-Dist-Zilla-PluginBundle-Author-VDB is free software: you can redistribute it and/or modify
#pod it under the terms of the GNU General Public License as published by the Free Software
#pod Foundation, either version 3 of the License, or (at your option) any later version.
#pod
#pod perl-Dist-Zilla-PluginBundle-Author-VDB is distributed in the hope that it will be useful, but
#pod WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
#pod PARTICULAR PURPOSE. See the GNU General Public License for more details.
#pod
#pod You should have received a copy of the GNU General Public License along with
#pod perl-Dist-Zilla-PluginBundle-Author-VDB. If not, see <http://www.gnu.org/licenses/>.
#pod
#pod =cut
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#pod =head1 DESCRIPTION
#pod
#pod It is unlikely that someone else will want to use it, so I will not bother with documenting it, at
#pod least for now.
#pod
#pod =for Pod::Coverage configure
#pod
#pod =cut
use
Moose;
use
namespace::autoclean;
# PODNAME: Dist::Zilla::PluginBundle::Author::VDB
# ABSTRACT: VDB's plugin bundle
our
$VERSION
=
'v0.8.2'
;
# VERSION
# These modules used by the bundle directly.
use
Path::Tiny;
# These modules are used by hooks. Require all the modules explicitly now to avoid unexpected
# failures in the middle of build or release.
use
IPC::Run3 ();
use
IPC::System::Simple ();
use
Path::Tiny 0.070 ();
use
Perl::Version ();
# Implicitly required module.
# --------------------------------------------------------------------------------------------------
#pod =option minimum_perl
#pod
#pod Optional, default value C<5.006>.
#pod
#pod =cut
has
minimum_perl
=> (
is
=>
'ro'
,
isa
=>
'Str'
,
lazy
=> 1,
default
=>
sub
{
my
(
$self
) =
@_
;
return
$self
->payload->{ minimum_perl } //
'5.006'
;
},
);
# --------------------------------------------------------------------------------------------------
#pod =option copying
#pod
#pod Name of POD file to generate distribution F<COPYING> text file. Empty value disables generation
#pod F<COPYING> file.
#pod
#pod C<Str>, optional, default value C<doc/copying.pod>.
#pod
#pod =cut
has
copying
=> (
is
=>
'ro'
,
isa
=>
'Str'
,
lazy
=> 1,
default
=>
sub
{
my
(
$self
) =
@_
;
return
$self
->payload->{ copying } //
'doc/copying.pod'
;
},
);
# --------------------------------------------------------------------------------------------------
#pod =option readme
#pod
#pod Names of POD files to generate distribution F<README> text file. This is a multi-value option.
#pod Empty values are ignored. Empty list disables generating F<README>file.
#pod
#pod C<ArrayRef[Str]>, optional, default value C<[ 'doc/what.pod', 'doc/why.pod', 'doc/naming.pod', 'doc/forms.pod', 'doc/source.pod', 'doc/distribution.pod', 'doc/installing.pod', 'doc/hacking.pod', 'doc/documentation.pod', 'doc/feedback.pod', 'doc/glossary.pod' ]>.
#pod
#pod =cut
has
readme
=> (
is
=>
'ro'
,
isa
=>
'Maybe[ArrayRef[Str]]'
,
lazy
=> 1,
default
=>
sub
{
my
(
$self
) =
@_
;
my
$readme
=
$self
->payload->{ readme } // [
'doc/what.pod'
,
'doc/why.pod'
,
'doc/naming.pod'
,
'doc/forms.pod'
,
'doc/source.pod'
,
'doc/distribution.pod'
,
'doc/installing.pod'
,
'doc/hacking.pod'
,
'doc/documentation.pod'
,
'doc/feedback.pod'
,
'doc/glossary.pod'
];
$readme
= [
grep
( {
$_
ne
''
}
@$readme
) ];
# Ignore empty items.
if
( not
@$readme
) {
$readme
=
undef
;
};
return
$readme
;
},
);
# --------------------------------------------------------------------------------------------------
#pod =option local_release
#pod
#pod If true, release will be a local one, i. e. no external operations will be done: C<UploadToCPAN>
#pod and C<hg push> will be skipped, <hg tag> will create a local tag.
#pod
#pod Option can be set trough F<dist.ini> file or with C<DZIL_LOCAL_RELEASE> environment variable.
#pod
#pod Optional, default value is 0.
#pod
#pod =cut
has
local_release
=> (
is
=>
'ro'
,
isa
=>
'Bool'
,
lazy
=> 1,
default
=>
sub
{
my
(
$self
) =
@_
;
return
$self
->payload->{ local_release } //
$ENV
{ DZIL_LOCAL_RELEASE };
},
);
# --------------------------------------------------------------------------------------------------
#pod =option archive
#pod
#pod Directory to archive files to. If empty, release will not be archived. If such directory does not
#pod exist, it will be created before release.
#pod
#pod Optional, default value C<".releases">.
#pod
#pod =cut
has
archive
=> (
is
=>
'ro'
,
isa
=>
'Str'
,
lazy
=> 1,
default
=>
sub
{
my
(
$self
) =
@_
;
return
$self
->payload->{ archive } //
".releases"
;
},
);
# --------------------------------------------------------------------------------------------------
#pod =option templates
#pod
#pod This option will be passed to C<Templates> plugin. If you no not want C<Templates> to process
#pod files, specify C<:NoFiles>. This is multi-value option (i. e. may be specified several times).
#pod
#pod Optional, default value C<[ ':InstallModules' ]>.
#pod
#pod =cut
has
templates
=> (
is
=>
'ro'
,
isa
=>
'Maybe[ArrayRef[Str]]'
,
lazy
=> 1,
default
=>
sub
{
my
(
$self
) =
@_
;
my
$templates
=
$self
->payload->{ templates } // [
':InstallModules'
];
$templates
= [
grep
( {
$_
ne
''
}
@$templates
) ];
# Ignore empty items.
if
( not
@$templates
) {
$templates
=
undef
;
};
return
$templates
;
},
);
# --------------------------------------------------------------------------------------------------
#pod =option unwanted_module
#pod
#pod =option unwanted_modules
#pod
#pod TODO C<[ qw{ DPP Data::Printer } ]>.
#pod
#pod =cut
has
unwanted_modules
=> (
isa
=>
'ArrayRef[Str]'
,
is
=>
'ro'
,
lazy
=> 1,
default
=>
sub
{
my
(
$self
) =
@_
;
my
$p
=
$self
->payload;
my
$u1
=
$p
->{ unwanted_module };
my
$u2
=
$p
->{ unwanted_modules };
return
$u1
||
$u2
? [
$u1
?
@$u1
: (),
$u2
?
@$u2
: () ] : [
qw{ DPP Data::Printer }
];
},
);
# --------------------------------------------------------------------------------------------------
#pod =option spellchecker
#pod
#pod Command to run spellchecker. Spellchecker command is expected to read text from stdin, and print to
#pod stdout misspelled words. If empty, spellchecking will be skipped. This involve C<Test::PodSpelling>
#pod plugin and internally implemented checking the F<Changes> file.
#pod
#pod Optional, default value C<aspell list -l en -p ./xt/aspell.en.pws>.
#pod
#pod =cut
has
spellchecker
=> (
is
=>
'ro'
,
isa
=>
'Str'
,
lazy
=> 1,
default
=>
sub
{
my
(
$self
) =
@_
;
return
$self
->payload->{ spellchecker } //
'aspell list -l en -p ./xt/aspell.en.pws'
;
# Leading dot (in `./xt/aspell.en.pws`) is important! Whitout the dot `aspell`
# fails to find the dictionary.
},
);
# --------------------------------------------------------------------------------------------------
#pod =method mvp_multivalue_args
#pod
#pod =cut
sub
mvp_multivalue_args {
return
qw{ templates unwanted_module unwanted_modules readme }
;
};
# --------------------------------------------------------------------------------------------------
#pod =method _quote
#pod
#pod Convert an attribute to a form suitable for using in source. C<Str> attribute is converted into a
#pod string literal, C<ArrayRef> attribute is converted to a list of string literals.
#pod
#pod =cut
sub
_quote {
my
(
$self
,
@args
) =
@_
;
my
@names
;
for
my
$arg
(
@args
) {
for
(
ref
(
$arg
) eq
'ARRAY'
?
@$arg
:
$arg
) {
my
$name
=
$_
;
$name
=~ s{([\\'])}{\$1}gx;
push
(
@names
,
"'$name'"
);
};
};
return
join
(
', '
,
@names
);
};
# --------------------------------------------------------------------------------------------------
# Helper func: Iterate through distribution prerequisities.
sub
MY::prereqs($$) {
## no critic ( ProhibitSubroutinePrototypes )
my
(
$plugin
,
$callback
) =
@_
;
my
$prereqs
=
$plugin
->zilla->prereqs->cpan_meta_prereqs;
for
my
$phase
(
$prereqs
->__legal_phases ) {
for
my
$type
(
$prereqs
->__legal_types ) {
my
$reqs
=
$prereqs
->requirements_for(
$phase
,
$type
) or
next
;
for
my
$module
(
keys
( %{
$reqs
->{ requirements } } ) ) {
$callback
->(
$plugin
,
$module
,
$phase
,
$type
,
$reqs
);
};
};
};
return
;
};
sub
MY::file {
my
(
$plugin
,
$name
) =
@_
;
our
$Self
;
## no critic ( ProhibitPackageVars )
my
$data
=
$Self
->merged_section_data;
my
$root
= path(
$plugin
->zilla->root );
my
$file
;
if
(
$root
->child(
$name
)->
exists
) {
$file
= Dist::Zilla::File::OnDisk->new( {
name
=>
$name
,
} );
}
elsif
(
$data
->{
$name
} ) {
$file
= Dist::Zilla::File::InMemory->new( {
name
=>
$name
,
content
=> ${
$data
->{
$name
} },
} );
}
else
{
croak
"$name: file not found"
;
};
return
$file
;
};
# --------------------------------------------------------------------------------------------------
sub
configure {
my
(
$self
) =
@_
;
our
$Self
=
$self
;
## no critic ( ProhibitPackageVars )
$self
->add_plugins(
[
'Hook'
=>
'prologue'
=> {
# DOES NOT WORK because plugin name will be '@Author::VDB/prologue'.
'hook'
=> [
q{
use autodie ':all';
use IPC::System::Simple qw{ capture }
;
} ],
} ],
[
'Hook::VersionProvider'
=> {
'hook'
=> [
q{
use Path::Tiny;
my $file = path( $zilla->root )->child( 'VERSION' );
my $version = $file->slurp =~ s{\s+\z}
{}r;
if
(
$version
!~ m{\A@{ [ Perl::Version::REGEX ] }\z} ) {
$self
->abort( [
'Invalid version string "%s" at %s line 1'
,
$version
,
"$file"
] );
};
$version
;
} ],
} ],
[
'Hook::Init'
=>
'my vars'
=> {
'hook'
=> [
q{
pack}
.
q{age MY { # Hide declaration from `new-version.t`.
our $name = $dist->name;
our $package = $name =~ s{-}
{::}gr;
our
$version
=
$dist
->version;
our
$Abstract
=
$dist
->abstract;
our
$abstract
=
lcfirst
(
$Abstract
);
our
$author
=
$dist
->authors->[ -1 ];
our
$cpan_rt_mailto
=
"mailto:bug-$name\@rt.cpan.org"
;
our
$repo_type
=
"hg"
;
our
$repo_host
=
"fedorapeople.org"
;
our
$repo_web
=
undef
;
our
$repo_clone
=
"$repo_type clone $repo_url"
.
(
$repo_url
=~ m{/\Qperl-
$name
\E\z} ?
''
:
" \\\n perl-$name"
);
our
$bundle
=
$Dist::Zilla::PluginBundle::Author::VDB::Self
;
};
$ENV
{
'TEST_FIX'
.
'ME_FORMAT'
} =
'perl'
;
# Hide keyword from `fixme.t`.
} ],
} ],
#
# Files to include
#
[
'Manifest::Read'
],
#
# Generated files
#
$self
->copying ne
''
? (
[
'GenerateFile'
=>
'COPYING'
=> {
'filename'
=>
'COPYING'
,
'content'
=> [
q[{]
.
q[{]
,
q[ include( MY::file( $plugin, ]
.
$self
->_quote(
$self
->copying ) .
q[ ) )]
,
q[ ->fill_in]
,
q[ ->pod2text( width => 80, indent => 0, loose => 1, quotes => 'none' );]
,
q[}]
.
q[}]
,
],
} ],
) : (
),
$self
->readme ? (
[
'GenerateFile'
=>
'README'
=> {
'filename'
=>
'README'
,
'content'
=> [
q[{]
.
q[{]
,
q[ for my $file ( ]
.
$self
->_quote(
$self
->readme ) .
q[ ) {]
,
q[ $OUT .= include( MY::file( $plugin, $file ) )]
,
q[ ->fill_in]
,
q[ ->pod2text( width => 80, indent => 0, loose => 1, quotes => 'none' );]
,
q[ };]
,
q[}]
.
q[}]
,
],
} ],
) : (
),
[
'Manifest::Write'
=> {
'source_providers'
=> [
'Manifest::Read'
,
'GenerateFile'
,
],
} ],
#
# File mungers
#
[
'Templates'
=> {
# REQUIRE: v0.5.0 for including `Dist::Zilla::File` objects.
'templates'
=> [
'@Author::VDB/src doc'
,
@{
$self
->templates // [] },
],
} ],
[
'OurPkgVersion'
],
[
'SurgicalPodWeaver'
=> {
'config_plugin'
=>
'@Author::VDB'
,
'replacer'
=>
'replace_with_comment'
,
} ],
[
'FileFinder::ByName'
=>
'src doc'
=> {
# Plugin name will be `@Author::VDB/doc`.
'file'
=> [
$self
->copying ne
''
? (
'COPYING'
) : (),
$self
->readme ? (
'README'
) : (),
],
} ],
#
# Update sources
#
# Copy built doc files back to source directory.
[
'Hook::AfterBuild'
=>
'update src doc'
=> {
'hook'
=> [
q{
use Path::Tiny;
my $files = $zilla->plugin_named( '@Author::VDB/src doc' )->find_files();
my $build = path( $arg->{ build_root }
);
my
$root
= path(
$dist
->root );
for
my
$file
(
@$files
) {
my
$new_file
=
$build
->child(
$file
->name );
my
$old_file
=
$root
->child(
$file
->name );
my
$new_bulk
=
$new_file
->slurp;
my
$old_bulk
=
$old_file
->
exists
?
$old_file
->slurp :
undef
;
if
( not
defined
(
$old_bulk
) or
$new_bulk
ne
$old_bulk
) {
$self
->
log
( [
'updating %s'
,
$file
->name ] );
$old_file
->spew(
$new_bulk
);
};
};
} ],
} ],
#
# Tests
#
[
'Test::DiagINC'
],
# Files
[
'Test::EOL'
=> {
'finder'
=>
'@Author::VDB/Manifest::Read'
,
} ],
[
'Test::NoTabs'
=> {
'finder'
=>
'@Author::VDB/Manifest::Read'
,
} ],
[
'MojibakeTests'
],
# Code
[
'Test::Compile'
=> {
'fake_home'
=> 1,
} ],
[
'Test::Version'
=> {
# All modules have version.
#~ 'is_strict' => 1, # Does not work for trial releases.
} ],
[
'Test::NewVersion'
],
# This is not a version already uploaded to CPAN.
[
'Test::MinimumVersion'
=> {
'max_target_perl'
=>
$self
->minimum_perl,
} ],
[
'Test::Fixme'
],
[
'Test::Perl::Critic'
=> {
'critic_config'
=>
'xt/perlcritic.ini'
,
# The test does not check tests. TODO: How to fix?
} ],
# POD
[
'PodSyntaxTests'
],
# `Dist-Zilla`-bundled test, uses `Test::pod`.
[
'PodCoverageTests'
],
# `Dist-Zilla`-bundled test, uses `Pod::Coverage::TrustPod`.
$self
->spellchecker ? (
[
'Test::PodSpelling'
=> {
'spell_cmd'
=>
$self
->spellchecker,
} ],
) : (
),
[
'Test::Pod::No404s'
],
# No dead URLs.
# Metadata
[
'MetaTests'
],
# `Dist-Zilla`-bundled test, uses `Test::CPAN::Meta`, checks `META.yml`.
[
'Test::CPAN::Meta::JSON'
],
# Uses `Test::CPAN::Meta::JSON`.
[
'Test::CPAN::Changes'
],
# Does not check that `Changes` has a record for current version, see
[
'Test::DistManifest'
],
# Overall
[
'Test::Kwalitee'
],
#
# Metainfo
#
[
'MinimumPerl'
],
[
'AutoPrereqs'
],
# `Prereqs::AuthorDeps` has a problem:
# It adds local plugins (e. g. tools::GenerateHooks) to the dependencies,
# which obviously are not indexed on CPAN.
[
'Prereqs::AuthorDeps'
=> {
#~ 'exclude' => [
#~ # Exclude option requires a list of specific files, while I want to ignore all
#~ # files in specific directory.
#~ ],
} ],
# TODO: Remove when possible.
# This is a dirty hack. Remove it when `Prereqs::AuthorDeps` allows me to ignore all the
# modules from `tools/` directory. Meanwhile, find and remove all the dependencies on
# modules with `tools::` prefix.
[
'Hook::PrereqSource'
=>
'tools'
=> {
'hook'
=> [
q{
MY::prereqs( $self, sub {
my ( $self, $module, $phase, $type, $reqs ) = @_;
if ( $module =~ m{^tools::}
) {
$self
->log_debug( [
'found dependency on module %s (phase %s, type %s), deleting it'
,
$module
,
$phase
,
$type
] );
delete
(
$reqs
->{ requirements }->{
$module
} );
};
} );
} ],
} ],
# `use autodie ':all';` implicitly requires `IPC::System::Simple` module, but this
# dependency is not detected by `AutoPrereqs`. If there is dependency on `autodie`, let
# us add dependency on `IPC::System::Simple`.
[
'Hook::PrereqSource'
=>
'autodie'
=> {
'hook'
=> [
q{
MY::prereqs( $self, sub {
my ( $self, $module, $phase, $type ) = @_;
if ( $module eq 'autodie' ) {
$self->log_debug( [
'found dependency on module %s (phase %s, type %s), ' .
'adding dependency on IPC::System::Simple',
$module, $phase, $type
] );
$dist->register_prereqs(
{ phase => $phase, type => $type }
,
'IPC::System::Simple'
=> 0,
);
};
} );
} ],
} ],
[
'CheckPrereqsIndexed'
],
# Make sure all prereqs are published in CPAN.
[
'MetaProvides::Package'
],
[
'MetaResources::Template'
=> {
'delimiters'
=>
'{ }'
,
'homepage'
=>
'{$MY::metacpan}'
,
'license'
=>
'{$dist->license->url}'
,
'repository.type'
=>
'{$MY::repo_type}'
,
'repository.url'
=>
'{$MY::repo_url}'
,
'repository.web'
=>
'{$MY::repo_web}'
,
'bugtracker.mailto'
=>
'{$MY::cpan_rt_mailto}'
,
'bugtracker.web'
=>
'{$MY::cpan_rt_browse}'
,
} ],
[
'MetaYAML'
],
# Generate `META.yml`.
[
'MetaJSON'
],
# Generate `META.json`.
#
# Installer
#
[
'ModuleBuildTiny'
],
#
# Release
#
$self
->archive ? (
# Make sure archive directory exists. Do it in the very beginnig of release because
# it is simple and fast operation. It will be annoying to pass all the tests and
# stop release because `dzil` fails to create archive directory.
[
'Hook::BeforeRelease'
=>
'archive directory'
=> {
'hook'
=> [
q{
my $root = path( $self->zilla->root . '' );
my $dir = path( "}
.
$self
->archive .
q{" );
if ( $dir->is_absolute ) {
$self->log_error( [ 'bad archive directory: %s', "$dir" ] );
$self->log_error( [ 'absolute path not allowed' ] );
$self->abort();
}
;
if
( not
$dir
->is_dir ) {
$self
->
log
( [
'creating archive directory %s'
,
"$dir"
] );
$dir
->mkpath();
};
} ],
} ]
) : (
),
#~ [ 'RunExtraTests' ], # Does not work for me, see <https://github.com/dagolden/Dist-Zilla-Plugin-CheckExtraTests/issues/26>.
[
'CheckExtraTests'
],
# So use CheckExtraTest meanwhile.
[
'TestRelease'
],
# Unpack tarball and run tests.
# Make sure the distro does not depend on unwanted modules. Unwanted module, for example,
# is `Data::Printer`. I use it often for debugging purposes and forget to remove
# debugging code.
[
'Hook::BeforeRelease'
=>
'unwanted deps'
=> {
# REQUIRTE: HHH
'hook'
=> [
q{
my @unwanted = (}
.
$self
->_quote(
$self
->unwanted_modules ) .
q{);
my %unwanted = map( { $_ => 1 }
@unwanted
);
my
$heading
=
'unwanted modules found:'
;
MY::prereqs(
$self
,
sub
{
my
(
$self
,
$module
,
$phase
,
$type
) =
@_
;
if
(
$unwanted
{
$module
} ) {
if
(
$heading
) {
$self
->log_error(
$heading
);
$heading
=
undef
;
};
$self
->log_error( [
' %s (phase %s, type %s)'
,
$module
,
$phase
,
$type
] );
};
} );
$self
->abort_if_error();
} ],
} ],
[
'CheckChangesHasContent'
],
$self
->spellchecker ? (
[
'Hook::BeforeRelease'
=>
'spellcheck changes'
=> {
'hook'
=> [
q{
$self->log( 'spellchecking Changes' );
use File::chdir;
local $CWD = $zilla->built_in . '';
#
# Run spellchecker, collect list of unknown words.
#
use IPC::Run3;
my @list;
run3( '}
.
$self
->spellchecker .
q{', 'Changes', \@list );
if ( $? > 0 ) {
$self->abort();
}
;
chomp
(
@list
);
#
# Steal list of words to ignore from `PodSpelling` plugin.
#
my
$podspelling
=
$zilla
->plugin_named(
'@Author::VDB/Test::PodSpelling'
);
my
%ignore
=
map
( {
$_
=> 1 } @{
$podspelling
->stopwords } );
#
# Add all module names.
#
my
$prereqs
=
$dist
->prereqs->cpan_meta_prereqs;
for
my
$phase
(
$prereqs
->__legal_phases ) {
for
my
$type
(
$prereqs
->__legal_types ) {
my
$reqs
=
$prereqs
->requirements_for(
$phase
,
$type
) or
next
;
for
my
$module
(
keys
( %{
$reqs
->{ requirements } } ) ) {
$ignore
{
$_
} = 1
for
split
(
'::'
,
$module
);
};
};
};
#
# Build maps: word => count and count => word.
#
my
%w2c
;
# word => count
$w2c
{
$_
} += 1
for
grep
( { not
$ignore
{
$_
} and not
$ignore
{
lc
(
$_
) } }
@list
);
my
%c2w
;
# count => word
push
( @{
$c2w
{
$w2c
{
$_
} } },
$_
)
for
keys
(
%w2c
);
#
# Now print the list of spelling errors.
#
for
my
$count
(
sort
( {
$b
<=>
$a
}
keys
(
%c2w
) ) ) {
printf
(
"%2d: %s\n"
,
$count
,
join
(
', '
,
sort
( @{
$c2w
{
$count
} } ) ) );
};
if
(
%w2c
) {
$self
->abort(
'spelling errors found in Changes'
);
};
} ],
} ],
) : (
),
# Make sure there is no such tag yet, neither global nor local.
[
'Hook::BeforeRelease'
=>
'hg check tag'
=> {
'hook'
=> [
q{
use Path::Tiny;
my $version = $dist->version;
my $tags = path( '.hgtags' );
if ( $tags->slurp_utf8 =~ m{ \Q$version\E$}
m ) {
$self
->abort( [
'tag %s already exists'
,
$version
] );
};
my
$ltags
= path(
'.hg/localtags'
);
if
(
$ltags
->
exists
and
$ltags
->slurp_utf8 =~ m{ \Q
$version
\E$}m ) {
$self
->abort( [
'local tag %s already exists'
,
$version
] );
};
} ],
} ],
[
'Hook::BeforeRelease'
=>
'hg stat'
=> {
'hook'
=> [
q{
# Make sure all the files committed.
use IPC::System::Simple 'capture';
my @stdout = capture( 'hg', 'status' );
if ( @stdout ) {
chomp( @stdout );
$self->log_error( 'hg status:' );
$self->log_error( " $_" ) for @stdout;
$self->abort( 'hg status is not clean' );
}
;
} ],
} ],
$self
->local_release ? (
[
'Hook::BeforeRelease'
=>
'release note'
=> {
'hook'
=> [
q{
$self->log( '*** Preparing to *local* release ***' );
}
],
} ],
) : (
),
[
'ConfirmRelease'
],
# Ask confirmation before uploading the release.
[
'Hook::Releaser'
=>
'tgz'
=> {
'hook'
=> [
q{
$MY::tgz = $arg;
}
],
} ],
# `Archive` is a good plugin, but I need to copy, not move tarball, because I want to
# archive the tarball first, and then upload it to CPAN.
$self
->archive ? (
[
'Hook::Releaser'
=>
'archive release'
=> {
'hook'
=> [
q{
use Path::Tiny;
my $tgz = path( $arg );
my $dir = path( "}
.
$self
->archive .
q{" );
$self->log( [ 'copying %s to %s', "$tgz", "$dir" ] );
$tgz->copy( $dir->child( $tgz->basename ) );
}
],
} ],
) : (
),
$self
->local_release ? (
# No need in `FakeRelease`: we have at least one releaser, it is enough.
) : (
[
'UploadToCPAN'
],
),
[
'Hook::AfterRelease'
=>
'hg add tag'
=> {
'hook'
=> [
q{
use IPC::System::Simple 'capture';
my @stdout = capture( 'hg', 'id', '--debug' );
chomp( @stdout );
@stdout == 1 and $stdout[ 0 ] =~ m{^([0-9a-f]{40}
)(\+?) tip$} or
do
{
$self
->log_error(
'fail to parse "hg id" output:'
);
$self
->log_error(
" $_"
)
for
@stdout
;
$self
->abort();
};
my
(
$id
,
$dirty
) = ( $1, $2 );
if
(
$dirty
) {
$self
->abort(
'hg status is not clean'
);
};
path(
'} . ( $self->local_release ? '
.hg/localtags
' : '
.hgtags
' ) . q{'
)->append(
sprintf
(
"%s %s\n"
,
$id
,
$dist
->version ) );
} ],
} ],
[
'NextRelease'
=> {
'format'
=>
'%V @ %{yyyy-MM-dd HH:mm zzz}d'
,
'time_zone'
=>
'UTC'
,
} ],
[
'Hook::AfterRelease'
=>
'bump version'
=> {
'hook'
=> [
q{
use Path::Tiny;
use Perl::Version;
my $version = Perl::Version->new( $dist->version );
$version->inc_alpha();
path( $zilla->root )->child( 'VERSION' )->spew( $version );
$self->log( [ 'next release will be %s', "$version" ] );
}
],
} ],
[
'Hook::AfterRelease'
=>
'hg post-commit'
=> {
'hook'
=> [
q{
use autodie ':all';
system(
'hg', 'commit', '-m', 'post-release',
qw{ .hgtags Changes VERSION }
);
} ],
} ],
$self
->local_release ? (
) : (
[
'Hook::AfterRelease'
=>
'hg push'
=> {
'hook'
=> [
q{
use IPC::System::Simple 'capture';
my @stdout = capture( 'hg', 'push' );
chomp( @stdout );
$self->log( " $_" ) for @stdout;
}
],
} ],
),
[
'Hook::AfterRelease'
=>
'install'
=> {
'hook'
=> [
q{
use autodie ':all';
use File::chdir;
$self->log( [ 'installing %s-%s', $dist->name, $dist->version ] );
local $CWD = $zilla->built_in;
system( 'cpanm', '--notest', '.' );
# ^ We run the tests on unpacked tarball before release, no need in running
# tests one more time.
}
],
} ],
[
'Hook::AfterRelease'
=>
'clean'
=> {
'hook'
=> [
q{
$zilla->clean();
}
],
} ],
);
return
;
};
__PACKAGE__->meta->make_immutable();
1;
# doc/what.pod #
#pod =encoding UTF-8
#pod
#pod =head1 WHAT?
#pod
#pod C<Dist-Zilla-PluginBundle-Author-VDB> (or just C<@Author::VDB>) is a C<Dist-Zilla> plugin bundle used by VDB.
#pod
#pod =cut
# end of file #
# doc/why.pod #
#pod =encoding UTF-8
#pod
#pod =head1 WHY?
#pod
#pod I have published few distributions on CPAN. Every distribution have F<dist.ini> file. All the
#pod F<dist.ini> files are very similar. Maintaining multiple very similar F<dist.ini> files is boring.
#pod Plugin bundle solves the problem.
#pod
#pod =cut
# end of file #
=pod
=encoding UTF-8
=head1 NAME
Dist::Zilla::PluginBundle::Author::VDB - VDB's plugin bundle
=head1 VERSION
Version v0.8.2, released on 2015-09-26 11:17 UTC.
=head1 WHAT?
C<Dist-Zilla-PluginBundle-Author-VDB> (or just C<@Author::VDB>) is a C<Dist-Zilla> plugin bundle used by VDB.
=head1 DESCRIPTION
It is unlikely that someone else will want to use it, so I will not bother with documenting it, at
least for now.
=head1 OBJECT METHODS
=head2 mvp_multivalue_args
=head2 _quote
Convert an attribute to a form suitable for using in source. C<Str> attribute is converted into a
string literal, C<ArrayRef> attribute is converted to a list of string literals.
=head1 OPTIONS
=head2 minimum_perl
Optional, default value C<5.006>.
=head2 copying
Name of POD file to generate distribution F<COPYING> text file. Empty value disables generation
F<COPYING> file.
C<Str>, optional, default value C<doc/copying.pod>.
=head2 readme
Names of POD files to generate distribution F<README> text file. This is a multi-value option.
Empty values are ignored. Empty list disables generating F<README>file.
C<ArrayRef[Str]>, optional, default value C<[ 'doc/what.pod', 'doc/why.pod', 'doc/naming.pod', 'doc/forms.pod', 'doc/source.pod', 'doc/distribution.pod', 'doc/installing.pod', 'doc/hacking.pod', 'doc/documentation.pod', 'doc/feedback.pod', 'doc/glossary.pod' ]>.
=head2 local_release
If true, release will be a local one, i. e. no external operations will be done: C<UploadToCPAN>
and C<hg push> will be skipped, <hg tag> will create a local tag.
Option can be set trough F<dist.ini> file or with C<DZIL_LOCAL_RELEASE> environment variable.
Optional, default value is 0.
=head2 archive
Directory to archive files to. If empty, release will not be archived. If such directory does not
exist, it will be created before release.
Optional, default value C<".releases">.
=head2 templates
This option will be passed to C<Templates> plugin. If you no not want C<Templates> to process
files, specify C<:NoFiles>. This is multi-value option (i. e. may be specified several times).
Optional, default value C<[ ':InstallModules' ]>.
=head2 unwanted_module
=head2 unwanted_modules
TODO C<[ qw{ DPP Data::Printer } ]>.
=head2 spellchecker
Command to run spellchecker. Spellchecker command is expected to read text from stdin, and print to
stdout misspelled words. If empty, spellchecking will be skipped. This involve C<Test::PodSpelling>
plugin and internally implemented checking the F<Changes> file.
Optional, default value C<aspell list -l en -p ./xt/aspell.en.pws>.
=head1 WHY?
I have published few distributions on CPAN. Every distribution have F<dist.ini> file. All the
F<dist.ini> files are very similar. Maintaining multiple very similar F<dist.ini> files is boring.
Plugin bundle solves the problem.
=for Pod::Coverage configure
=head1 AUTHOR
Van de Bugger <van.de.bugger@gmail.com>
=head1 COPYRIGHT AND LICENSE
Copyright © 2015 Van de Bugger
This file is part of perl-Dist-Zilla-PluginBundle-Author-VDB.
perl-Dist-Zilla-PluginBundle-Author-VDB is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later version.
perl-Dist-Zilla-PluginBundle-Author-VDB is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
perl-Dist-Zilla-PluginBundle-Author-VDB. If not, see <http://www.gnu.org/licenses/>.
=cut
__DATA__
__[ doc/copying.pod ]__
=encoding UTF-8
=head1 COPYRIGHT AND LICENSE
Copyright © 2015 Van de Bugger
C<perl-{{$MY::name}}> is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software Foundation, either
version 3 of the License, or (at your option) any later version.
C<perl-{{$MY::name}}> is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
C<perl-{{$MY::name}}>. If not, see L<http://www.gnu.org/licenses/>.
C<perl-{{$MY::name}}> I<distribution> may contain files generated by C<Dist-Zilla> and/or its
plugins from third-party templates; copyright and license specified above are I<not> applicable to
that files.
=cut
__[ doc/distribution.pod ]__
=encoding UTF-8
=head1 DISTRIBUTION
C<{{$MY::name}}> distributions are published on L<CPAN|{{$MY::metacpan}}>.
=head2 Generated Files
Distribution may contain files preprocessed or generated by C<Dist-Zilla> and its plugins. Some
generated files are made from C<{{$MY::name}}> source, but some are generated from
third-party templates. Files generated from third-party templates usually include a comment near
the top of the file:
This file was generated with NAME
(where I<NAME> is a name of the plugin generated the file). Such files are I<not> part of
C<{{$MY::name}}> source, and C<{{$MY::name}}> copyright and license are not applicable
to such files.
=cut
__[ doc/documentation.pod ]__
=encoding UTF-8
=head1 DOCUMENTATION
=head2 Online
The easiest way is browsing the documentation L<online at meta::cpan|{{$MY::metacpan}}>.
=head2 Locally Installed
If you have the distribution installed, use C<perldoc> tool to browse locally
installed documentation:
$ perldoc {{$MY::package}}::Manual
$ perldoc {{$MY::package}}
=head2 Built from Source
Build C<{{$MY::name}}> first (see L</"HACKING">), then:
$ cd {{$MY::name}}-VERSION
$ perldoc {{$MY::package}}::Manual
$ perldoc {{$MY::package}}
where I<VERSION> is a version of built distribution.
=cut
__[ doc/feedback.pod ]__
=encoding UTF-8
=head1 FEEDBACK
=head2 CPAN Request Tracker
The quickest way to report a bug in C<{{$MY::name}}> is by sending email to
bug-{{$MY::name}} [at] rt.cpan.org.
CPAN request tracker can be used via web interface also:
=over
=item L<Browse bugs|{{$MY::cpan_rt_browse}}>
Browsing bugs does not require authentication.
=item L<Report bugs|{{$MY::cpan_rt_report}}>
You need to be a CPAN author, have a L<BitCard|https://www.bitcard.org/> account, or OpenID in
order to report bugs via the web interface.
(On 2015-04-27 I have logged in successfully with my LiveJournal OpenID, but my Google OpenID did
not work for CPAN. I did not check other OpenID providers.)
=back
=head2 Send Email to Author
As a last resort, send email to author: {{$MY::author}}. Please start message subject with
"perl-{{$MY::name}}:".
=cut
__[ doc/forms.pod ]__
=encoding UTF-8
=head1 FORMS
You may face C<{{$MY::name}}> in I<source> or I<distribution> forms.
If you are going to {{$MY::abstract}}, you will likely be interested in I<using>
C<{{$MY::name}}> I<distribution>. If you are going to I<develop> (or I<hack>) the
C<{{$MY::name}}> itself, you will likely need the I<source>, not distribution.
Since Perl is an interpreting language, modules in the distribution I<look> like sources. Actually,
they are Perl source files. But they are not I<actual> sources, because they are I<built>
(preprocessed or generated) by L<Dist-Zilla>.
How to distinguish source and distribution:
=over
=item *
Source may contain Mercurial files and directories F<.hgignore>, F<.hgtags>, F<.hg/>, while
distribution should not.
=item *
Source should contain files F<dist.ini>, F<weaver.ini>, while distribution may not.
=item *
Source should I<not> contain F<xt/> directory, while distribution should.
=item *
Name of source directory does I<not> include version (e. g. C<{{$MY::name}}>), while name of
distribution does (e. g. C<{{$MY::name}}-0.007>).
=back
=cut
__[ doc/glossary.pod ]__
=encoding UTF-8
=head1 GLOSSARY
=over
=item CPAN
Comprehensive Perl Archive Network, a B<large> collection of Perl software and documentation. See
L<cpan.org|http://www.cpan.org>, L<What is
=item Distribution
Tarball, containing Perl modules and accompanying files (documentation, metainfo, tests). Usually
distributions are uploaded to CPAN, and can be installed with dedicated tools (C<cpan>, C<cpanm>,
and others).
=item Module
Perl library file, usually with C<.pm> suffix. Usually contains one package. See
=item Package
Perl language construct. See L<package|http://perldoc.perl.org/functions/package.html> and
L<perlmod|http://perldoc.perl.org/perlmod.html#Packages>.
=back
=cut
__[ doc/hacking.pod ]__
=encoding UTF-8
=head1 HACKING
For hacking, you will need Mercurial, Perl interpreter and C<Dist-Zilla> (with some plugins), and
likely C<cpanm> to install missed parts.
Clone the repository first:
$ {{$MY::repo_clone}}
$ cd perl-{{$MY::name}}
To build a distribution from the source, run:
$ dzil build
If required C<Dist-Zilla> plugins are missed, C<dzil> tool will warn you and show the command to
install all the required plugins, e. g.:
Required plugin Dist::Zilla::Plugin::Test::EOL isn't installed.
Run 'dzil authordeps' to see a list of all required plugins.
You can pipe the list to your CPAN client to install or update them:
dzil authordeps --missing | cpanm
To run the tests:
$ dzil test
To run all the tests, including release tests:
$ dzil test --release
To install the distribution:
$ dzil install
or
$ cpanm ./{{$MY::name}}-VERSION.tar.gz
where I<VERSION> is a version of built distribution.
To clean the directory:
$ dzil clean
=cut
__[ doc/installing.pod ]__
=encoding UTF-8
=head1 INSTALLING
=head2 With C<cpanm>
C<cpanm> tool is (probably) the easiest way to install distribution. It automates downloading,
building, testing, installing, and uninstalling.
To install the latest version from CPAN:
$ cpanm {{$MY::package}}
To install a specific version (e. g. I<0.007>) from CPAN:
$ cpanm {{$MY::package}}@0.007
To install locally available distribution (e. g. previously downloaded from CPAN or built from
sources):
$ cpanm ./{{$MY::name}}-0.007.tar.gz
To uninstall the distribution:
$ cpanm -U {{$MY::package}}
=head2 Manually
To install distribution tarball manually (let us assume you have version I<0.007> of the
distribution):
$ tar xaf {{$MY::name}}-0.007.tar.gz
$ cd {{$MY::name}}-0.007
$ perl Build.PL
$ ./Build build
$ ./Build test
$ ./Build install
=head2 See Also
L<How to install CPAN modules|http://www.cpan.org/modules/INSTALL.html>
=cut
__[ doc/naming.pod ]__
=encoding UTF-8
=head1 NAMING
C<perl-{{$MY::name}}> is official software name.
However, in Perl world prefix "perl-" is redundant and not used. For example, on
L<meta::cpan|https://metacpan.org/> this software is named as C<{{$MY::name}}>. In the rest
of the documentation shortened name C<{{$MY::name}}> is used as synonym for full name
C<perl-{{$MY::name}}>. We are in the Perl world, aren't we?
You may notice that name may be spelled with dashes (C<{{$MY::name}}>) or with double colons
(C<{{$MY::package}}>). Strictly speaking, there is difference: the first one is software
name, while the second is name of Perl package, but often these names are interchangeable
especially if software consists of single package.
=cut
__[ doc/source.pod ]__
=encoding UTF-8
=head1 SOURCE
C<{{$MY::name}}> source is in Mercurial repository hosted on {{$MY::repo_host}}.
{{$MY::repo_web ? "You can either L<browse the source online|{{$MY::repo_web}}> or " : "To
"}} clone the entire repository:
$ {{$MY::repo_clone}}
=head2 Source Files
C<{{$MY::name}}> source files usually include a comment near the top of the file:
This file is part of perl-{{$MY::name}}.
Not all source files are included into distribution. Some source files are used at distribution
build time only, and not required for installation.
=cut
__END__
# end of file #