The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

=head1 NAME
Dist::Mgr - Automation for Perl distribution creation, integration, pre-release,
release and post-release tasks.
=for html
=head1 DESCRIPTION
For end-users, please review the
program that we've installed for you as part of this distribution.
This software performs a full suite of automated creation, addition, pre-release,
release and post release tasks for Perl distributions. It integrates with VCS,
automates the configuration of Continuous Integration, manages version numbers
and Changes files, amongst a slew of other tasks.
This distribution is essentially a bunch of tools that revolve around a base
distribution created with C<module-starter>.
At this time, it relies on using L<Module::Starter> for initial distribution
creation, Github for repository and bugtracker, and the L<ExtUtils::MakeMaker>
build system, which utilizes C<Makefile.PL> files.
=head1 SYNOPSIS
use Dist::Mgr qw(:all)
...
=head1 EXPORT_OK
We do not automatically import anything into your namespace, you must request
functionality explicitly. Use the C<:all> tag, or have a peruse through the
L</FUNCTIONS> section for what's available.
=head1 FUNCTIONS
=head2 add_bugtracker
Adds bugtracker information to the C<Makefile.PL> file. If the required
C<META_MERGE> section doesn't exist, we'll create it.
Currently, only Github is supported.
I<Use>: After L</init>, or any time.
I<Parameters>:
$author
I<Mandatory, String>: The Github username of the software author. For example,
mine is C<stevieb9>.
$repository
I<Mandatory, String>: The name of the repository. For example, the repository
name for this distribution is C<dist-mgr>.
$makefile
I<Optional, String>: The path and name of the C<Makefile.PL> file to use. We
default to C<./Makefile.PL>.
I<Returns>: C<0> upon success.
=head2 add_repository
Adds repository information to the C<Makefile.PL> file. If the required
C<META_MERGE> section doesn't exist, we'll create it.
Currently, only Github is supported.
I<Use>: After L</init>, or any time.
I<Parameters>:
$author
I<Mandatory, String>: The Github username of the software author. For example,
mine is C<stevieb9>.
$repository
I<Mandatory, String>: The name of the repository. For example, the repository
name for this distribution is C<dist-mgr>.
$makefile
I<Optional, String>: The path and name of the C<Makefile.PL> file to use. We
default to C<./Makefile.PL>.
I<Returns>: C<0> upon success.
=head2 changes
Creates or updates the initial L<Module::Starter> C<Changes> file to my custom
standard format.
I<Use>: After L</init>.
I<Parameters>:
$module
I<Mandatory, String>: The name of the module (eg. C<Acme::STEVEB>).
$file
I<Optional, String>: The path and name of the C<Changes> file to operate on. By
default, we operate on the C<Changes> file within the current working directory,
C<.>.
I<Returns:> The contents that were added into the file.
=head2 changes_bump
Prepares the C<Changes> file for a new development cycle after a release.
I<Use>: After L</changes_date> and the release has been published.
I<Parameters>:
$version
I<Mandatory, Version>: A valid Perl version number. Must be higher than the
previous release version.
$file
I<Optional, String>: The name of the C<Changes> file to operate on. Defaults to
the one in the current working directory.
=head2 changes_date
Replaces the C<UNREL> tag with today's date, in preparation of a release.
I<Use>: As part of the release cycle, before release and L</changes_bump>.
I<Parameters>:
$file
I<Optional, String>: The name of the C<Changes> file to operate on. By default,
we operate on the one in the current working directory.
=head2 ci_badges
Inserts various CI and coverage badges into module files.
I<Use>: After L</init>, or any time.
I<Parameters>:
$author
I<Mandatory, String>: The repository owner (eg. mine is 'stevieb9').
$repository
I<Mandatory, String>: The name of the repository (eg. this one is
'dist-mgr').
$fs_entry
I<Optional, String>: The path and name of a Perl module file, or a directory
that contains Perl module files. If a directory is sent in, we'll operate
recursively.
I<Returns>: C<0> upon success.
=head2 ci_github
Installs a Github Actions configuration file into C<.github/workflows>. We'll
create the directory if it doesn't exist.
I<Use>: Any time.
I<Parameters>:
$os
I<Optional, Array Reference>: A list of the Operating Systems you want to run
your tests on.
I<Valid values>: C<l>, C<w>, C<m>, where:
l == Linux (Ubuntu to be specific)
w == Windows
m == MacOS
I<Defaults>: Test suite will be run on Operating Systems C<ubuntu-latest>,
C<windows-latest>, C<macos-latest>. Each OS will run the tests on Perls C<5.32>,
C<5.24>, C<5.18>, C<5.14> and C<5.10>.
I<Returns>: An array of the contents of the generated file.
=head2 config
Writes out a default configuration file if one doesn't exist, and updates
the C<%args> hash within a function.
I<Parameters>:
\%args
I<Mandatory, Hash reference>: Send in a reference to your C<%args> hash, and
we'll update it with any directives within the configuration file before you
send them off to other various routines.
$file
I<Optional, String>: The name of an alternate configuration file you'd like to
write out, or read from. Default is C<$ENV{USERPROFILE}/dist-mgr.json> on
Windows systems, and C<$ENV{HOME}/dist-mgr.json> on Unix systems.
I<Returns>: The reference to the C<%args> hash you sent in as the first
parameter.
=head2 config_file
Returns the path and filename of the default configuration file. this is
C<$ENV{USERPROFILE}/dist-mgr.json> on Windows systems, and
C<$ENV{HOME}/dist-mgr.json> on Unix systems.
=head2 copyright_bump
Finds and updates the copyright year of a Perl POD or module file, or all Perl
files in a directory structure. We operate on all C<*.pl>, C<*.pm> and C<*.pod>
files.
I<Use>: Before publishing a release.
I<Parameters>:
$fs_entry
I<Optional, String>: The name of a file or directory to work on. If a directory,
we'll work on all Perl and POD files. Defaults to C<.>.
I<Returns>: A hash reference with the file name as the key, and the updated year
as the value.
=head2 copyright_info
Fetches the current copyright year in a file or all files in a directory. We
operate on all C<*.pl>, C<*.pm> and C<*.pod> files.
I<Use>: Anytime.
I<Parameters>:
$fs_entry
I<Optional, String>: The name of a file or directory to work on. If a directory,
we'll work on all Perl and POD files. Defaults to C<.>.
I<Returns>: A hash reference with the file name as the key, and the current
copyright year as the value.
=head2 cpan_upload
Uploads the distribution tarball to PAUSE.
I<Use>: After L</make_dist>.
I<Parameters>:
$tarball_name
I<Mandatory, String>: The name of the distribution's tarball file.
%args
I<Optional, Hash>: See L<CPAN::Uploader> for full details. A couple of notes:
=over
=item The C<user> and C<password> parameters can be set in the C<CPAN_USERNAME>
and C<CPAN_PASSWORD> environment variables instead of passing them in with the
hash.
=item You can add C<< dry_run => 1 >> to the hash to skip the actual upload
process.
=back
I<Returns>: Copy of C<%args> hash on success.
=head2 git_add
Adds all files in the current working directory to the repository.
B<Note>: Calls C<Dist::Mgr::Git::_git_add()> internally.
I<Use>: Any time.
I<Parameters>:
$verbose
I<Optional, Bool>: Set to true to display the Git command output. Defaults to
false.
I<Returns>: Exit code from the C<system> call.
=head2 git_ignore
Generates a C<.gitignore> file.
I<Use>: Any time.
I<Parameters>:
$directory
I<Optional, String>: The directory where we'll create the file. If not
specified, we'll create it in the current directory, C<.>.
I<Returns>: An array of the file's contents.
=head2 git_commit
Commits all changes to the repository.
B<Note>: Calls C<Dist::Mgr::Git::_git_commit()> internally.
I<Use>: Any time.
I<Parameters>:
$msg
I<Mandatory, String>: The commit message.
$verbose
I<Optional, Bool>: Set to true to display the Git command output. Defaults to
false.
I<Returns>: Exit code.
=head2 git_clone
Commits all changes to the repository.
B<Note>: Calls C<Dist::Mgr::Git::_git_clone()> internally.
I<Use>: Any time.
I<Parameters>:
$author
I<Mandatory, String>: Your Github username.
$repository
I<Mandatory, String>: The name of the pre-created Github repository.
$verbose
I<Optional, Bool>: Set to true to display the Git command output. Defaults to
false.
I<Returns>: Exit code.
=head2 git_push
Pushes the repository to Github.
B<Note>: Calls C<Dist::Mgr::Git::_git_push()> internally.
I<Use>: Any time.
I<Parameters>:
$verbose
I<Optional, Bool>: Set to true to display the Git command output. Defaults to
false.
I<Returns>: Exit code.
=head2 git_pull
Does a C<git pull> to fetch any update from the upstream.
B<Note>: Calls C<Dist::Mgr::Git::_git_pull()> internally.
I<Use>: Any time.
I<Parameters>:
$verbose
I<Optional, Bool>: Set to true to display the Git command output. Defaults to
false.
I<Returns>: Exit code.
=head2 git_release
Commits and pushes the repository, and executes the CI test pipeline (if
available).
Internally, this method calls L</git_pull>, L</git_commit> then L</git_push>,
all with their respective C<$verbose> flags set to false. If you want to enable
verbosity, instead of calling this function, call each one of those in order and
set C<$verbose> to true in each one.
I<Use>: After L</make_test>.
I<Parameters>:
$version
I<Mandatory, String>: The release version of the distribution.
$wait_for_ci
I<Optional, Bool>: Whether to wait for keyboard interaction while CI testing
runs. If set, we'll wait for you to press either C<CTRL-C> to signifiy tests
were successful and we should continue with the release cycle, or C<ENTER> to
signify that we should stop and wait for you to fix any test errors before
running again.
I<Default>: C<1>, Enabled.
I<Returns>: C<1> on test success (CTRL-C), C<0> on test failure (ENTER).
=head2 git_repo
Attempts to retrieve the repository name from the C<.git> directory.
B<Note>: Calls C<Dist::Mgr::Git::_git_repo()> internally.
I<Use>: Any time.
I<Returns>: The string repository name on success, the exit code on failure.
=head2 git_status_differs
Checks whether we need to commit and push.
B<Note>: Calls C<Dist::Mgr::Git::_git_status_differs()> internally.
I<Use>: Any time.
I<Returns>: C<1> if the repository differs and C<0> if nothing needs to be done.
=head2 git_tag
Tags the current state of the repository.
I<Parameters>:
$tag
I<Mandatory, String>: The tag for the commit.
B<Note>: Calls C<Dist::Mgr::Git::_git_tag()> internally.
I<Use>: Any time.
I<Returns>: Exit code.
=head2 init
Initializes a new distribution using L<Module::Starter>. The new directory will
be placed into the current working directory (C<.>).
I<Use>: To create a brand new distribution skeleton.
I<Parameters>:
module => "Acme::STEVEB"
I<Mandatory, String>: The name of the main module of the distribution.
author => "Steve Bertrand"
I<Mandatory, String>: The name of the distribution's author.
email => "steveb@cpan.org"
I<Mandatory, String>: The email address of the author.
license => "artistic2"
I<Optional, String>: The license to apply to the new distribution. Defaults to
C<artistic2>. See L<Module::Starter> for valid entries.
verbose => 1
I<Optional, Bool>: If set, we'll display the progress of module creation.
=head2 make_dist
Perform a C<make dist> that creates a CPAN-ready distribution tarball file in
the current working directory.
I<Use>: After all other release functions have been called.
I<Parameters>:
$verbose
I<Optional, Bool>: Set to true to display the output from the command.
I<Default>: False
I<Returns>: C<0> on success. Anything other than C<0> is a failure.
=head2 make_distclean
Perform a C<make distclean> on the project directory.
I<Use>: After all other post-release functions have been called.
I<Parameters>:
$verbose
I<Optional, Bool>: Set to true to display the output from the command.
I<Default>: False
I<Returns>: C<0> on success. Anything other than C<0> is a failure.
=head2 make_test
Perform a C<%^X Makefile.PL> and C<make test>.
I<Use>: After L</changes_date> and before all other release cycle functions.
I<Parameters>:
$verbose
I<Optional, Bool>: Set to true to display the output from the command.
I<Default>: False
B<Note>: Do not call this function from within the test suite, or else it'll
spin off into an infinite loop.
B<Note>: Always check the return value of this function before proceeding with
the rest of the release cycle. Zero C<0> is success, everything else is fail.
I<Returns>: C<0> on success. Anything other than C<0> is a failure.
=head2 make_manifest
Perform a C<make manifest>.
I<Use>: Before running the release procedures.
I<Parameters>:
$verbose
I<Optional, Bool>: Set to true to display the output from the command.
I<Default>: False
I<Returns>: C<0> on success. Anything other than C<0> is a failure.
=head2 manifest_skip
Generates a C<MANIFEST.SKIP> file.
I<Use>: Any time.
I<Parameters>:
$directory
I<Optional, String>: The directory where we'll create the file. If not
specified, we'll create it in the current directory, C<.>.
I<Returns>: An array of the file's contents.
=head2 manifest_t
Generates a C<t/manifest.t> test file. This overrides the default created with
L<Module::Starter>, as some custom C<MANIFEST.SKIP> entries fail with the older
version of the file.
I<Use>: Any time.
I<Parameters>:
$directory
I<Optional, String>: The directory where we'll create the file. If not
specified, we'll create it in the C<t/> directory within the current directory, C<.>.
I<Returns>: An array of the file's contents.
=head2 move_distribution_files
After an L</init>, this method will scoop up all of the files and directories
from within the newly created temp module directory into the current working
dir, then remove the temp module directory.
I<Use>: Immediately after L</init>.
I<Parameters>:
$module
I<Mandatory, String>: The name of the module that was created with L</init>, eg.
C<Acme::STEVEB>.
I<Returns>: C<0> upon success.
=head2 remove_unwanted_files
Removes unwanted file system entries. We always operate from the perspective of
the current working directory (C<.>).
I<Use>: Immediately after L</init> and L</move_distribution_files>.
=head2 version_bump
Finds and updates the version number of a Perl module file, or all Perl
module files in a directory structure.
I<Use>: After publishing a release.
I<Parameters>:
$version
I<Mandatory, String>: The new version to update to.
$fs_entry
I<Optional, String>: The name of a file or directory to work on. If a directory,
we'll work on all Perl module files. Defaults to C<lib/>.
=head3 Dry run mode
The C<$version> parameter can be prepended with an optional dash (C<->), and if
so, we'll operate in "dry-run" mode, where we'll return the results, but won't
have written to any files. Eg: C<version_bump('-1.01')>.
I<Returns>: An HoH:
$VAR1 = {
't/data/work/Two.pm' => {
'dry_run' => 0,
'from' => '2.66',
'to' => '2.67',
'content' => '' # Module file code (snipped for brevity)
},
't/data/work/One.pm' => {
'dry_run' => 0,
'from' => '2.66',
'to' => '2.67',
'content' => '' # Module file code (snipped for brevity)
},
};
=head2 version_incr
Increments a version number by C<0.01>, and returns the result.
I<Use>: Any time
I<Parameters>:
$version
I<Mandatory, String>: A valid version number (eg: C<1.03>).
I<Returns>: The supplied version number incremented by C<0.01>.
=head2 version_info
Fetches the file version information of Perl module files. Can operate on a
single file, or iterate over a directory structure.
I<Use>: Any time.
I<Parameters>:
$fs_entry
I<Optional, String>: The directory or file to operate on. If a directory is
sent in, we'll iterate over all files in all directories recursively.
I<Default>: C<lib/>
I<Returns>: Hash reference:
$VAR1 = {
't/data/orig/One.pm' => '2.66'
't/data/orig/Two.pm' => '2.66',
't/data/orig/Three.pm' => '2.66',
't/data/orig/Bad.pm' => undef, # $VERSION can't be parsed
't/data/orig/No.pm' => undef, # No $VERSION defined
};
=head1 AUTHOR
Steve Bertrand, C<< <steveb at cpan.org> >>
=head1 LICENSE AND COPYRIGHT
Copyright 2020-2021 Steve Bertrand.
This program is free software; you can redistribute it and/or modify it
under the terms of the the Artistic License (2.0). You may obtain a
copy of the full license at: