How I'm using Dist::Zilla to give credit to contributors

Recently, Gabor Szabo asked me how to list contributors in the META file of CPAN distributions. This seemed like a great idea to me -- I'd love to be able to credit people who contribute to my modules. I suggested using an "x_contributors" key in META.json with an array of names and email addresses, just like the "author" field has.

Unfortunately, I'm just lazy enough that I wouldn't want to maintain a contributors list by hand. At best, I note additions in Changes. If you're lucky. And catch me on a good day.

Fortunately, I love Dist::Zilla. I let it automate as much as I can of my distribution packaging, documentation and release process.

If you don't love Dist::Zilla, too, Gabor has written a tutorial on adding contributors to CPAN META files including other build systems.

As I was emailing back to Gabor, I realized that the easy thing to do is get contributors from the commit history. I looked on CPAN to see if anyone was doing something like that already.

Bingo! There was Dist::Zilla::Plugin::ContributorsFromGit waiting for me! That plugin, when combined with Pod::Weaver and Pod::Weaver::Section::Contributors, automatically grabs the commit authors list and creates a "CONTRIBUTORS" section in pod. All that was missing was dumping that same data into the META file. One pull request later, Chris Weyl shipped a new version that did just that.

Now, every distribution I release with my Dist::Zilla plugin bundle automatically credits my contributors both in the META files and the Pod.

You can see examples here and here.

If websites like metacpan.org start using the "x_contributors" key for some cool mashup, all my recent distributions will be ready and waiting.

The rest of this article will show you how you can do this, too.

An example distribution

I'm not going to give a full Dist::Zilla (dzil) tutorial here. If you're new to dzil, go see the Dist::Zilla tutorial site.

For those who know how I use dzil, I'm showing how to do this long-hand without my plugin bundle -- that would just confuse people.

You can follow along from this git repository: http://github.com/dagolden/zzz-givecreditwithdzil

First, I created a new distribution:

$ dzil new Acme::GiveCreditWithDzil

Then, I edited the dist.ini file for a pretty minimal dzil setup. It automatically sets a date-based version number. It creates a META.json. It has the PodWeaver plugin to automatically generate Pod sections like AUTHOR and LICENSE. It generates a README from the main module Pod. (Browse the dist.ini on github.)

Next, I wanted to add some committers. Normally, they'd send pull requests, but for this demonstration, I can add them with empty commits:

$ git commit --allow-empty --author="Ricardo Signes <rjbs@cpan.org>" -m "..."

This is really useful! If you have contributors on a project who didn't send you pull requests, you can still record the fact of their contribution in your git history and let dzil automatically include them in the contributors list later.

I added a few more:

$ git commit --allow-empty --author="Keedi Kim - 김도형 <keedi@cpan.org>" -m "..."
$ git commit --allow-empty --author="Chris Weyl <cweyl@alumni.drew.edu>" -m "..."
$ git commit --allow-empty --author="Rik Signes <www@rjbs.manxome.org>" -m "..."

Note that Keedi has Unicode in the author name. Also note that Ricardo is there twice, with different spellings and email addresses.

Next, I added the ContributorsFromGit plugin to the dist.ini:

--- a/dist.ini
+++ b/dist.ini
@@ -16,6 +16,9 @@ copyright_year   = 2013
 ; add $VERSION to module
 [PkgVersion]

+; gather contributors
+[ContributorsFromGit]
+
 ; generate pod sections
 [PodWeaver]

Then, after running dzil build, my META.json had a section that looked like this:

   "x_contributors" : [
      "Chris Weyl <cweyl@alumni.drew.edu>",
      "Keedi Kim - \u00ea\u00b9\u0080\u00eb\u008f\u0084\u00ed\u0098\u0095 <keedi@cpan.org>",
      "Ricardo Signes <rjbs@cpan.org>",
      "Rik Signes <www@rjbs.manxome.org>"
   ]

You can see the duplicate entries for Ricardo, but I'll show you how I fixed that later.

Next, I added the Pod::Weaver::Section::Contributors plugin to my weaver.ini file:

diff --git a/weaver.ini b/weaver.ini
index 7223daf..18494c2 100644
--- a/weaver.ini
+++ b/weaver.ini
@@ -2,3 +2,5 @@

 [-Transformer]
 transformer = List
+
+[Contributors]

Then, running dzil build created a new Pod section. Looking at the README generated from Pod, I saw this:

CONTRIBUTORS
    *   Chris Weyl <cweyl@alumni.drew.edu>

    *   Keedi Kim - 김도형 <keedi@cpan.org>

    *   Ricardo Signes <rjbs@cpan.org>

    *   Rik Signes <www@rjbs.manxome.org>

Unfortunately, Pod::Weaver isn't very smart about Unicode by default, so I got this when I ran perldoc on the generated file:

CONTRIBUTORS
       ·   Chris Weyl <cweyl@alumni.drew.edu>

       ·   Keedi Kim - ê¹<U+0080>ë<U+008F><U+0084>í<U+0098><U+0095> <keedi@cpan.org>

       ·   Ricardo Signes <rjbs@cpan.org>

       ·   Rik Signes <www@rjbs.manxome.org>

Oops.

I fixed that and Rik's name with a somewhat undocumented feature of git: the .mailmap file. Put simply, it remaps commit author name and email address.

Here's one I created to map Ricardo's commits together and strip the Unicode characters from Keedi (sorry!):

Keedi Kim <keedi@cpan.org>
Ricardo Signes <rjbs@cpan.org> <www@rjbs.manxome.org>

After that, here's what I got from perldoc:

CONTRIBUTORS
       ·   Chris Weyl <cweyl@alumni.drew.edu>

       ·   Keedi Kim <keedi@cpan.org>

       ·   Ricardo Signes <rjbs@cpan.org>

Excellent!

I've since learned that I can add "=encoding utf-8" to the top of my Pod and the Unicode bits will work, but I'm still leery of Pod::Weaver and UTF-8, so I tend not to rely on it.

Stepping back

I walked you through that step-by-step, but if I look at the diff between the original distribution and the one that reports contributors, the difference is two plugins and a .mailmap file:

diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000..f229d28
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,2 @@
+Keedi Kim <keedi@cpan.org>
+Ricardo Signes <rjbs@cpan.org> <www@rjbs.manxome.org>
diff --git a/dist.ini b/dist.ini
index 4c0a7d8..a501a49 100644
--- a/dist.ini
+++ b/dist.ini
@@ -16,6 +16,9 @@ copyright_year   = 2013
 ; add $VERSION to module
 [PkgVersion]

+; gather contributors
+[ContributorsFromGit]
+
 ; generate pod sections
 [PodWeaver]

diff --git a/weaver.ini b/weaver.ini
index 7223daf..18494c2 100644
--- a/weaver.ini
+++ b/weaver.ini
@@ -2,3 +2,5 @@

 [-Transformer]
 transformer = List
+
+[Contributors]

That's four non-whitespace lines.

If you use Dist::Zilla, giving credit to contributors is that easy!

You've got no excuse. Even if you don't put Contributors in Pod, use ContributorsFromGit and put it into your metadata. Let's give credit where credit is due.

This entry was posted in Uncategorized. Bookmark the permalink. Both comments and trackbacks are currently closed.

7 Comments

  1. Posted March 13, 2013 at 9:32 am | Permalink

    Although using unicode is cumbersome work, there is Pod::Weaver::Plugin::Encoding. It is a weaver plugin to save typing '=encoding ...' section in each of your perl modules. Due to it's default encoding is 'utf-8', so all I have to do is just add '[-Encoding]' in my 'weaver.ini'. :-)

    • Posted March 13, 2013 at 11:08 am | Permalink

      Awesome! I'll go add that to my bundle now.

  2. Posted March 13, 2013 at 12:42 pm | Permalink

    Now if only there was some way of mapping these contributor entries back to PAUSE ids... we could build a really neat network graph of author contributions across the cpan web...

  3. Posted March 13, 2013 at 1:33 pm | Permalink

    As long as people use their @cpan.org email address in their git commits, then it's trivial. Or, if .mailmap file maps to them.

    What's nice is that if contributors want their @cpan.org email addressed used, they can patch the .mailmap file itself and send a pull request.

  4. Posted September 30, 2013 at 2:43 am | Permalink

    Thanks, This is a useful article.
    I use ContributorsFromGit myself.

    By the way you should also convert gt(>) and lt(<) signs around your emails to E and E to follow proper escaping conventions. Although you will get by in most cases without escaping, I found that podlint tends to croak if you don't escape your signs properly.

  5. Posted September 30, 2013 at 2:45 am | Permalink

    oops my my tags got escaped in the last comment!! I meant use E>gt< for > and E>lt< for <

  6. Posted September 30, 2013 at 2:47 am | Permalink

    crap!! writing HTML codes by hand is a pain. I hope you will remove my last useless comment!!
    I meant use E<gt> for > amd <lt> for <

© 2009-2014 David Golden All Rights Reserved