Confessions of a Dist::Zilla newbie

I've been spending a lot of time writing Perl again, after ten years or so in management, and I'm throughly enjoying myself. I recently wanted a module to interface with a third party service, and was surprised to discover there wasn't already a CPAN module for it. My initial needs were very simple, so I decided this would be a good opportunity to find out the modern way to create a module for release to CPAN. This post is based on notes I took as I worked through this.

So, what's the modern way to do Makefile.PL? Tricky to find out, but I've seen a bunch of stuff about Dist::Zilla, and it seems to have a gazillion plugins. Right, Dist::Zilla (DZ) it is. Start off with the tutorial:

http://dzil.org/tutorial/new-dist.html.

My module is going to be Mail::SendGrid, an interface to the APIs provided by SendGrid.com, a commercial mail sending service. I skimmed the various perl docs recommended for perl module authors as well. Having installed DZ, the first thing I'm told to do is:

    % dzil setup

You're prompted for some information; it creates a .dzil directory with profile.ini in it.

The modern way also seems to include github. I already had a github account; once you've got one you need to give git the credentials to access your github account:

    git config --global github.user LoginName
    git config --global github.token GitHubToken

The LoginName is your github username. The GitHubToken isn't your password; to get it:

  • go to github, click on account settings in the top right corner.
  • click on Account Admin.
  • you'll see your API Token. Note this changes when you change your password.

Next, edit ˜/.dzil/profile.ini and add the lines:

    [GitHub::Create]
    public = 1

I think that's so that when you create a new DZ distribution, it will create it on github. But that didn't seem to work for me. What did I miss / get wrong?

Ok, now I'm ready to start my distribution. Just run the following:

    % dzil new Mail::Sendgrid

It creates a directory Mail-Sendgrid, which should has two files, including a dist.ini. If your dist.ini was empty, maybe you missed the "dzil setup" step, like I did the first time :-).

Looking at dist.ini:

    name    = Mail-SendGrid
    author  = Neil Bowers 
    license = Perl_5
    copyright_holder = Neil Bowers
    copyright_year   = 2011
    
    version = 0.001
    
    [@Basic]

Hmm, perlmodstyle says the most common CPAN version numbering scheme looks like:

    1.00, 1.10, 1.11, 1.20, 1.30, 1.31, 1.32

So I changed my dist.ini file to set the version to 0.01. I must remember to submit an issue to the DZ team, or the perlmodstyle team, and say they need to talk!

That [@Basic] pulls a bunch of default stuff in. The tutorial says it's crucial that I understand what's in there. Sure. I just want to release my module; I'll read it sometime later. I could have just copied one of my old school Makefile.PL files by now.

I write a quick first version of the module. Looking at the generated Mail/SendGrid.pm it has:

    use strict;
    use warnings;
    package Mail::SendGrid;

I've always written:

    package Mail::SendGrid;
    use strict;
    use warnings;

Is there a difference?

I write some basic tests, and check they work:

    % cd Mail-SendGrid
    % ls -1F
    dist.int
    lib/
    t/
    % prove -lr t
    ...
    All tests successful.

So, back to the Dist::Zilla tutorial. Next I need to add pre-reqs:

    [Prereqs]
    Mouse       = 0.94  ; version I've tested with
    HTTP::Tiny  = 0.013 ; version I've tested with
    XML::Simple = 2.18  ; version I've tested with

I've got to give the minimum version of modules required, but I don't really know, I just know that the most recent version works fine. I could read through the changes and guess the oldest version that was probably ok. But "probably" isn't any good. So I'll just put the version number that I have.

I'm using HTTP::Tiny to talk to SendGrid.com, and the underlying URI is https. The doc for HTTP::Tiny says:

Direct https connections are supported only if IO::Socket::SSL is installed.

So, do I need to declare that as a pre-requisite? Let's have a look at the HTTP::Tiny distribution: it doesn't declare IO::Socket::SSL as a pre-req, so I better:

    IO::Socket::SSL = 1.44  ; version I've tested with

Ah, I read a bit more of the DZ tutorial, and see that I can use [AutoPrereqs], and it will work out the pre-reqs by looking at my code. But I need to put the required version of modules in my use statements, which is a good thing to do anyway. So now I have:

    [AutoPrereqs]
    
    [Prereqs]
    IO::Socket::SSL = 1.44  ; version I've tested with

I still explicitly call out IO::Socket::SSL, because that's an implicit prerequisite.

Next, I write some basic documentation. Seems like DZ can help me here too. I need to add another line to dist.ini:

    [PodWeaver]

I also had to install Pod::Weaver and Dist::Zilla::Plugin::PodWeaver.

How do I build a tarball for release?

    % dzil build

Ok, that worked. But now I want to put this on github. I go to github.com and create a new repository called Mail-SendGrid. And then I want to tie my local working copy to github:

    % cd Mail-SendGrid
    % git init
    Initialized empty Git repository in /Users/neilb/src/Mail-SendGrid/.git/
    % git add *
    % git commit -m "first commit"
    ... a bunch of stuff from git ...
    % git remote add origin git@github.com:neilbowers/Mail-SendGrid.git
    % git push -u origin master
    ... bunch of output ...

But I want DZ to handle this sort of stuff for me. There seem to be (at least) two DZ plugins related to git/github, and after reading their doc, I'm not entirely sure what I need to do. So I add the following to dist.ini, at the end:

    [@GitHub]
    repo = Mail-SendGrid
    cpan = 1

Install Dist::Zilla::Plugin::PkgVersion and then add the following to dist.ini after the @Basic line:

    [PkgVersion]

This inserts a VERSION declaration line in all module and script files in the dist, taking the version number from dist.ini. Ok, seems like some of these DZ plugins are going to make my life a bit easier.

Now I want to be able to release the module, so:

    [TestRelease]
    [ConfirmRelease]
    [UploadToCPAN]

Time to bite the bullet and release it

    % dzil release

Oops, it tried uploading to PAUSE twice. Scanning the copious output, it looks like @Basic already covers the release stuff. Heh, that bit about it being crucial to read, might not have been all bluster. A quick scan of the doc shows that it does indeed cover those three things, so I can delete the three lines from my dist.ini.

Now my dist.ini looks like:

    name    = Mail-SendGrid
    author  = Neil Bowers 
    license = Perl_5
    copyright_holder = Neil Bowers 
    copyright_year   = 2011
    
    version = 0.01
    
    [@Basic]
    
    [PkgVersion]
    
    [AutoPrereqs]
    
    [Prereqs]
    IO::Socket::SSL = 1.44  ; version I've tested with
    
    [PodWeaver]
    
    [@GitHub]
    repo = Mail-SendGrid
    cpan = 1

Looking at github, and the output log, nothing got uploaded to github. I subsequently did two more releases to CPAN, but still had to manually update github. What am I missing?

5 Comments

Great post! I've just started using Dist::Zilla myself, and I've successfully pushed a couple releases to CPAN with it. I couldn't get the git stuff working either, but I didn't try very hard. Emacs magit-mode makes it really easy to stage, commit and push changes in just a few keystrokes, so I did not have sufficient motivation to look into it. :)

The @Github plugin is only meant to create the repo on the website when it doesn't exist and for munging the metadata of the dist. For actual releasing you want to use https://metacpan.org/module/Dist::Zilla::Plugin::Git

I am by no means a D::Z expert, but I have used it in several modules. The benefits I take from it are AutoPrereqs (scans and finds prereqs) and PkgVersion (inserts version code into .pm). However these don't really help on a big project or even a small one with "use if available" type dependencies.

I also like ReadmeAnyFromPod which takes my POD and turns it into the README.pod which github uses.

D::Z is nice for the simplicity of copy and pasting your dist.ini and having it be mostly correct (esp. with AutoPrereqs), but in the end I still only use D::Z for smaller projects.

https://github.com/jberger/PDL-Util/blob/master/dist.ini

Welcome back!!
Dzil has a steeper learning curve as I myself learnt a few months ago but it helps you to keep your repository clean if you use the right plugins you don't have to keep makefiles, READMEs etc. in Repos, just the lib files, tests and dist.ini :)

Leave a comment

About Neil Bowers

user-pic Perl hacker since 1992.