A Simple dist.ini for Dist::Zilla

This is day 3 of the Perl-QA Hackathon in Lyon, France, and I decided it was time to fix some issues with the older dist.ini I was using. Erik Colson asked about my dist.ini, so I thought I should explain it here, along with comments.

The following dist.ini is designed to match my workflow, but also to make it easy for contributors to participate, thus mitigating one of the strongest complaints people have about Dist::Zilla. It's also rather git/github centric.

name             = Test-Class-Moose
author           = Curtis "Ovid" Poe <ovid@cpan.org>
license          = Perl_5
copyright_holder = Curtis "Ovid" Poe
copyright_year   = 2014

version = 0.50

[AutoPrereqs]
skip = Person
skip = ^TestsFor

[@Basic]

[MetaJSON]
[GithubMeta]
issues = 1
user   = Ovid
[@Git]
[PodWeaver]
[CheckChangeLog]
[PkgVersion]

[Prereqs]
perl = 5.010

[Prereqs / RuntimeRecommends]
Sub::Attribute = 0.05
Parallel::ForkManager = 0.7.6

[ ReadmeAnyFromPod / MarkdownInRoot ]
filename = README.md

[Run::BeforeBuild]
run = test -f Makefile.PL && rm Makefile.PL

[Run::AfterBuild]
run = cp %d/Makefile.PL ./
run = git status --porcelain | grep 'M Makefile.PL' && git commit -m 'auto-committed by dist.ini' Makefile.PL || echo Makefile.PL up to date

The top part should be self-explanatory:

name             = Test-Class-Moose
author           = Curtis "Ovid" Poe <ovid@cpan.org>
license          = Perl_5
copyright_holder = Curtis "Ovid" Poe
copyright_year   = 2014

version = 0.50

The prerequisites listed in the Makefile.PL are generated here:

[AutoPrereqs]
skip = Person
skip = ^TestsFor

The skip section is to ensure that classes I've created in my tests aren't accidentally picked up as prereqs because they're bundled with the distribution.

The [@Basic] section is from Dist::Zilla::PluginBundle::Basic. This includes many utilities that make building your distribution easier, but doesn't alter your code. Without going into detail, it includes the following:

  • Dist::Zilla::Plugin::GatherDir - Gather all of the files in your distribution for a build
  • Dist::Zilla::Plugin::PruneCruft - Get rid of stuff you don't need in the build, such as blib or Makefile
  • Dist::Zilla::Plugin::ManifestSkip - If you have a MANIFEST.SKIP file, don't build files listed in it
  • Dist::Zilla::Plugin::MetaYAML - Build a META.yml file
  • Dist::Zilla::Plugin::License - create a LICENSE file
  • Dist::Zilla::Plugin::Readme - create a README
  • Dist::Zilla::Plugin::ExtraTests - rewrites your xt/ tests to t/ tests that are skipped if you're not the author
  • Dist::Zilla::Plugin::ExecDir - install scripts as executable
  • Dist::Zilla::Plugin::ShareDir - install a directory's contents as "ShareDir" content
  • Dist::Zilla::Plugin::MakeMaker - Create your Makefile.PL
  • Dist::Zilla::Plugin::Manifest - Create a MANIFEST
  • Dist::Zilla::Plugin::TestRelease - Test your distribution before releasing
  • Dist::Zilla::Plugin::ConfirmRelease - Ask before releasing
  • Dist::Zilla::Plugin::UploadToCPAN - Upload to the cpan (login credentials are usually stored in ~/.dzil/config.ini)

The [MetaJSON] creates a META.json file.

Then there's my github section:

[GithubMeta]
issues = 1
user   = Ovid

The issues = 1 lets CPAN use the github bugtracker rather than RT. The user section lets you define a canonical user. Otherwise, if you have several people hacking on your project, the github user listed may change.

The [@Git] section does a number of various things, including tagging your releases with the correct version number.

The [PodWeaver] builds a lot of POD for you, including adding license information, copyright information, and makes your POD easier to write.

[CheckChangeLog] won't let you release unless you've remembered to update your change log. I'm constantly forgetting to do that, so it's a big win for me.

[PkgVersion] automatically adds the version number to your files.

You can guess what this does:

[Prereqs]
perl = 5.010

And this:

[Prereqs / RuntimeRecommends]
Sub::Attribute = 0.05
Parallel::ForkManager = 0.7.6

This section creates a markdown version of README. That's useful for github to display your readme correctly.

[ ReadmeAnyFromPod / MarkdownInRoot ]
filename = README.md

And here's the bit I'm adding now for Makefiles. This first bit checks to see if we have a Makefile.PL and deletes it if it exists to ensure that an old copy isn't copied to the build directory (you can also exclude it in GatherDir).

[Run::BeforeBuild]
run = test -f Makefile.PL && rm Makefile.PL

And this is my first pass at creating the feature so many people want:

[Run::AfterBuild]
run = cp %d/Makefile.PL ./
run = git status --porcelain | grep 'M Makefile.PL' && git commit -m 'auto-committed by dist.ini' Makefile.PL || echo Makefile.PL up to date

After the build is done, this copies the generated makefile into your directory and commits it if it's changed. This allows someone downloading your distribution to fall back to using the normal perl Makefile.PL incantation to install deps.

The downside of this technique is that if you install using this Makefile.PL, you'll get an installed module with no version number. David Golden mentioned that he was thinking about taking a swing at this problem later. Be sure to remind him about this :)

With the above workflow, contributors can use the Makefile.PL like normal, but dzil users can use their workflow, too. For me, I can run dzil build repeatedly to rebuild the distribution and just type dzil release when I'm ready to release it. It makes my life much, much simpler.

Many thanks to Ricardo Signes, Karen Etheridge, David Golden and several others at the Perl-QA hackathon for helping me figure out the best approach. Any errors are, of course, theirs (kidding!)

2 Comments

I think instead of “git status --porcelain | grep 'M Makefile.PL'” you just want “git diff --quiet Makefile.PL”.

Also, the way you’ve written the command line, if the grep succeeds but the git commit exits non-zero, it will claim “Makefile.PL up to date” which it clearly wouldn’t be. Just write an if/else.

Try this (untested):

[Run::AfterBuild]
run = cp %d/Makefile.PL . && if git diff --quiet Makefile.PL ; then git commit -m 'auto-committed by dist.ini' Makefile.PL ; else echo Makefile.PL is up to date ; fi

Consider yourself frowned at for encouraging people to put code in their dist.ini files that isn't crossplatform. :(

Please at least update this article to replace the apostrophes in the AfterBuild stuff with quotes.

About Ovid

user-pic Freelance Perl/Testing/Agile consultant and trainer. See http://www.allaroundtheworld.fr/ for our services. If you have a problem with Perl, we will solve it for you. And don't forget to buy my book! http://www.amazon.com/Beginning-Perl-Curtis-Poe/dp/1118013840/