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.
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 <email@example.com>" -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 - 김도형 <firstname.lastname@example.org>" -m "..." $ git commit --allow-empty --author="Chris Weyl <email@example.com>" -m "..." $ git commit --allow-empty --author="Rik Signes <firstname.lastname@example.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 <email@example.com>", "Keedi Kim - \u00ea\u00b9\u0080\u00eb\u008f\u0084\u00ed\u0098\u0095 <firstname.lastname@example.org>", "Ricardo Signes <email@example.com>", "Rik Signes <firstname.lastname@example.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]
dzil build created a new Pod section. Looking at the README generated from Pod, I saw this:
CONTRIBUTORS * Chris Weyl <email@example.com> * Keedi Kim - 김도형 <firstname.lastname@example.org> * Ricardo Signes <email@example.com> * Rik Signes <firstname.lastname@example.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 <email@example.com> · Keedi Kim - ê¹<U+0080>ë<U+008F><U+0084>í<U+0098><U+0095> <firstname.lastname@example.org> · Ricardo Signes <email@example.com> · Rik Signes <firstname.lastname@example.org>
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 <email@example.com> Ricardo Signes <firstname.lastname@example.org> <email@example.com>
After that, here's what I got from perldoc:
CONTRIBUTORS · Chris Weyl <firstname.lastname@example.org> · Keedi Kim <email@example.com> · Ricardo Signes <firstname.lastname@example.org>
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.
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 <email@example.com> +Ricardo Signes <firstname.lastname@example.org> <email@example.com> 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.