File Coverage

blib/lib/Dist/Zilla/Plugin/ContributorsFromGit.pm
Criterion Covered Total %
statement 94 96 97.9
branch 3 6 50.0
condition 2 3 66.6
subroutine 23 23 100.0
pod 0 2 0.0
total 122 130 93.8


line stmt bran cond sub pod time code
1             #
2             # This file is part of Dist-Zilla-Plugin-ContributorsFromGit
3             #
4             # This software is Copyright (c) 2017, 2015, 2014, 2013, 2012 by Chris Weyl.
5             #
6             # This is free software, licensed under:
7             #
8             # The GNU Lesser General Public License, Version 2.1, February 1999
9             #
10             package Dist::Zilla::Plugin::ContributorsFromGit;
11             our $AUTHORITY = 'cpan:RSRCHBOY';
12             # git description: 0.017-9-ge7df715
13             $Dist::Zilla::Plugin::ContributorsFromGit::VERSION = '0.018';
14              
15             # ABSTRACT: Populate your 'CONTRIBUTORS' POD from the list of git authors
16              
17 3     3   5954436 use utf8;
  3         16  
  3         20  
18 3     3   111 use v5.10;
  3         9  
19              
20 3     3   297 use Moose;
  3         136950  
  3         21  
21 3     3   18626 use MooseX::AttributeShortcuts;
  3         739134  
  3         18  
22 3     3   198015 use MooseX::Types::Moose ':all';
  3         8  
  3         33  
23 3     3   21278 use Encode qw(decode_utf8);
  3         7225  
  3         200  
24 3     3   351 use autobox::Core;
  3         13279  
  3         35  
25 3     3   2979 use autobox::Junctions;
  3         12573  
  3         19  
26 3     3   1786 use File::Which 'which';
  3         758  
  3         181  
27 3     3   994 use List::AllUtils qw{ max uniq };
  3         22028  
  3         270  
28 3     3   315 use File::ShareDir qw/ dist_dir /;
  3         4088  
  3         177  
29 3     3   415 use YAML::Tiny;
  3         4098  
  3         151  
30 3     3   316 use Path::Class;
  3         26177  
  3         142  
31              
32 3     3   290 use autodie 'system';
  3         9543  
  3         31  
33 3     3   12532 use IPC::System::Simple ( ); # explict dep for autodie system
  3         6  
  3         54  
34              
35 3     3   14 use aliased 'Dist::Zilla::Stash::PodWeaver';
  3         7  
  3         24  
36              
37             with
38             'Dist::Zilla::Role::BeforeBuild',
39             'Dist::Zilla::Role::RegisterStash',
40             'Dist::Zilla::Role::MetaProvider',
41             ;
42              
43             has _contributor_list => (
44             is => 'lazy',
45             isa => 'ArrayRef[Str]',
46             builder => sub {
47 2     2   6 my $self = shift @_;
48 2         47 my @authors = $self->zilla->authors->flatten;
49              
50             ### and get our list from git, filtering: "@authors"
51             my @contributors = uniq
52 6   66     324 map { $self->_contributor_emails->{$_} // $_ }
53 8         67 grep { $_ ne 'Your Name <you@example.com>' }
54 9         6496 grep { [ map { lc } @authors ]->none eq lc }
  9         139  
55 9         362 map { decode_utf8($_) }
56 2         13014 map { chomp; s/^\s*\d+\s*//; $_ }
  9         56  
  9         76  
  9         47  
57             `git shortlog -s -e HEAD`
58             ;
59              
60 2         89 return [ sort @contributors ];
61             },
62             );
63              
64             has _contributor_emails => (
65             is => 'lazy',
66             isa => HashRef[Str],
67             init_arg => undef,
68              
69             builder => sub {
70              
71 2     2   31 my $mapping = YAML::Tiny
72             ->read(
73             file(
74             dist_dir('Dist-Zilla-Plugin-ContributorsFromGit'),
75             'author-emails.yaml',
76             ),
77             )
78             ->[0]
79             ;
80              
81             my $_map_it = sub {
82 4     4   26 my ($canonical, @alternates) = @_;
83 4         11 return ( map { $_ => $canonical } @alternates );
  18         167  
84 2         6630 };
85              
86             return {
87 2         50 map { $_map_it->($_ => $mapping->{$_}->flatten) }
  4         87  
88             $mapping->keys->flatten
89             };
90             },
91             );
92              
93             has _stopwords => (
94             is => 'lazy',
95             isa => ArrayRef[Str],
96             init_arg => undef,
97              
98             builder => sub {
99 2     2   7 my $self = shift @_;
100              
101             # break contributor names into a stopwords-suitable list
102             my @stopwords =
103 4         22 map { (split / /) }
104 2         77 map { /^(.*) <.*$/; $1 }
  4         46  
  4         18  
105             $self->_contributor_list->flatten
106             ;
107              
108 2         87 return [ uniq sort @stopwords ];
109             },
110             );
111              
112             sub before_build {
113 2     2 0 194005 my $self = shift @_;
114              
115             # skip if we can't find git
116 2 50       16 unless (which 'git') {
117 0         0 $self->log('The "git" executable has not been found');
118 0         0 return;
119             }
120              
121             # XXX we should also check here that we're in a git repo, but I'm going to
122             # leave that for the git stash (when it's not vaporware)
123              
124             ### get our stash...
125 2         349 my $stash = $self->zilla->stash_named('%PodWeaver');
126 2 50       127 do { $stash = PodWeaver->new; $self->_register_stash('%PodWeaver', $stash) }
  2         49  
  2         2025  
127             unless defined $stash;
128              
129             ### ...and config...
130 2         663 my $config = $stash->_config;
131              
132             # helper sub to keep us from clobbering existing values, until (and if):
133             # https://github.com/rwstauner/Dist-Zilla-Role-Stash-Plugins/pull/1
134             my $_append = sub {
135 4     4   42 my ($key, @values) = @_;
136              
137 4         10 my $i = -1;
138 4         10 do { $i++ } while exists $config->{$key."[$i]"};
  4         32  
139 12         50 do { $config->{$key."[$i]"} = $_; $i++ }
  12         28  
140 4         16 for @values;
141              
142 4         12 return;
143 2         35 };
144              
145 2         68 $_append->('Contributors.contributors' => $self->_contributor_list->flatten);
146 2         85 $_append->('-StopWords.include' => $self->_stopwords->flatten);
147              
148             ### $config
149 2         28 return;
150             }
151              
152             sub metadata {
153 2     2 0 46637 my $self = shift @_;
154 2         150 my $list = $self->_contributor_list;
155 2 50       21 return @$list ? { 'x_contributors' => $list } : {};
156             }
157              
158             __PACKAGE__->meta->make_immutable;
159             !!42;
160              
161             __END__
162              
163             =pod
164              
165             =encoding UTF-8
166              
167             =for :stopwords Chris Weyl Brendan Randy Stauner Tatsuhiko Yanick Byrd Champoux David
168             Golden Graham Greb Knop Mike Miyagawa zilla BeforeBuild metacpan shortlog
169             committer mailmap
170              
171             =head1 NAME
172              
173             Dist::Zilla::Plugin::ContributorsFromGit - Populate your 'CONTRIBUTORS' POD from the list of git authors
174              
175             =head1 VERSION
176              
177             This document describes version 0.018 of Dist::Zilla::Plugin::ContributorsFromGit - released August 13, 2017 as part of Dist-Zilla-Plugin-ContributorsFromGit.
178              
179             =head1 SYNOPSIS
180              
181             ; in your dist.ini
182             [ContributorsFromGit]
183              
184             ; in your weaver.ini
185             [Contributors]
186              
187             =head1 DESCRIPTION
188              
189             This plugin makes it easy to acknowledge the contributions of others by
190             populating a L<%PodWeaver|Dist::Zilla::Stash::PodWeaver> stash with the unique
191             list of all git commit authors reachable from the current HEAD.
192              
193             =head1 OVERVIEW
194              
195             On collecting the unique list of reachable commit authors from git, we search
196             and remove any git authors from the list of authors L<Dist::Zilla> knows
197             about. We then look for a stash named C<%PodWeaver>; if we don't find one
198             then we create an instance of L<Dist::Zilla::Stash::PodWeaver> and register it
199             with our zilla instance. Then we add the list of contributors (the filtered
200             git authors list) to the stash in such a way that
201             L<Pod::Weaver::Section::Contributors> can find them.
202              
203             Note that you do not need to have the C<%PodWeaver> stash created; it will be
204             added if it is not found. However, your L<Pod::Weaver> config (aka
205             C<weaver.ini>) must include the
206             L<Contributors|Pod::Weaver::Section::Contributors> section plugin.
207              
208             =head2 Dist::Zilla Phase
209              
210             This plugin runs during the L<BeforeBuild|Dist::Zilla::Role::BeforeBuild>
211             phase.
212              
213             =head2 Metadata Keys
214              
215             The list of contributors is also added to distribution metadata under the custom
216             C<x_contributors> key. (e.g. in C<META.yml>, C<META.json>, etc)
217              
218             If you have duplicate contributors because of differences in committer name
219             or email you can use a C<.mailmap> file to canonicalize contributor names
220             and emails. See L<git help shortlog|git-shortlog(1)> for details.
221              
222             =head2 Pod::Weaver::Section::Contributors is OPTIONAL
223              
224             Note that using the L<Pod::Weaver::Section::Contributors> section is in no way
225             mandated or necessitated by this package; if you wish to use it you must
226             include the Contributors section in your L<Pod::Weaver> configuration in the
227             traditional fashion.
228              
229             =for Pod::Coverage before_build metadata
230              
231             =head1 METACPAN CONTRIBUTOR MATCHING
232              
233             L<MetaCPAN|http://metacpan.org> will attempt to match a contributor address
234             back to a PAUSE account. However, it (currently) can only do that if the
235             contributor's email address is their C<PAUSEID@cpan.org> address. There are
236             two mechanisms for helping to resolve this, if your commits are not using this
237             address.
238              
239             Both of these approaches have pros and cons that have been discussed at
240             levels nearing the heat brought to any discussion of religion, homosexuality,
241             or Chief O'Brien's actual rank at any ST:TNG convention. However, they both
242             have the advantage of *working*, and through different modes of action. You
243             are free to use one, both or neither. These are only important if you're not
244             committing with your C<@cpan.org> email address B<and> want the MetaCPAN to
245             link to your author page from the page of the package you contributed to.
246              
247             =head2 Using a .mailmap file
248              
249             See C<git help shortlog> for help on how to use this. A C<.mailmap> file must
250             be maintained in each repository using it.
251              
252             =head2 Globally, via the authors mapping
253              
254             This package contains a YAML file containing a mapping of C<@cpan.org> author
255             addresses; this list is consulted while building the contributors list, and
256             can be used to replace a non-cpan.org address with one.
257              
258             To add to or modify this mapping, fork, add your alternate email addresses to
259             C<share/author-emails.yaml>, and submit a pull-request for inclusion. It'll
260             be merged and released; as various authors update their set of installed
261             modules and cut new releases, the mapping will appear.
262              
263             =head1 SEE ALSO
264              
265             Please see those modules/websites for more information related to this module.
266              
267             =over 4
268              
269             =item *
270              
271             L<Pod::Weaver::Section::Contributors>
272              
273             =item *
274              
275             L<Dist::Zilla::Stash::PodWeaver>
276              
277             =item *
278              
279             L<http://www.dagolden.com/index.php/1921/how-im-using-distzilla-to-give-credit-to-contributors/>
280              
281             =back
282              
283             =head1 BUGS
284              
285             Please report any bugs or feature requests on the bugtracker website
286             L<https://github.com/RsrchBoy/Dist-Zilla-Plugin-ContributorsFromGit/issues>
287              
288             When submitting a bug or request, please include a test-file or a
289             patch to an existing test-file that illustrates the bug or desired
290             feature.
291              
292             =head1 AUTHOR
293              
294             Chris Weyl <cweyl@alumni.drew.edu>
295              
296             =head1 CONTRIBUTORS
297              
298             =for stopwords Brendan Byrd David Golden Graham Knop Mike Greb Randy Stauner Tatsuhiko Miyagawa Yanick Champoux
299              
300             =over 4
301              
302             =item *
303              
304             Brendan Byrd <Perl@ResonatorSoft.org>
305              
306             =item *
307              
308             David Golden <dagolden@cpan.org>
309              
310             =item *
311              
312             Graham Knop <haarg@haarg.org>
313              
314             =item *
315              
316             Mike Greb <mikegrb@cpan.org>
317              
318             =item *
319              
320             Randy Stauner <randy@magnificent-tears.com>
321              
322             =item *
323              
324             Tatsuhiko Miyagawa <miyagawa@bulknews.net>
325              
326             =item *
327              
328             Yanick Champoux <yanick@babyl.dyndns.org>
329              
330             =back
331              
332             =head1 COPYRIGHT AND LICENSE
333              
334             This software is Copyright (c) 2017, 2015, 2014, 2013, 2012 by Chris Weyl.
335              
336             This is free software, licensed under:
337              
338             The GNU Lesser General Public License, Version 2.1, February 1999
339              
340             =cut