File Coverage

blib/lib/Dist/Zilla/Plugin/ContributorsFromGit.pm
Criterion Covered Total %
statement 93 95 97.8
branch 3 6 50.0
condition 2 3 66.6
subroutine 24 24 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.018-4-g702588a
13             $Dist::Zilla::Plugin::ContributorsFromGit::VERSION = '0.019';
14              
15             # ABSTRACT: Populate your 'CONTRIBUTORS' POD from the list of git authors
16              
17 3     3   5154137 use utf8;
  3         17  
  3         17  
18 3     3   98 use v5.10;
  3         8  
19              
20 3     3   338 use Moose;
  3         129959  
  3         14  
21 3     3   17017 use MooseX::AttributeShortcuts;
  3         684112  
  3         16  
22 3     3   182955 use MooseX::Types::Moose ':all';
  3         6  
  3         27  
23 3     3   20590 use Encode qw(decode_utf8);
  3         6999  
  3         153  
24 3     3   337 use autobox::Core;
  3         12587  
  3         31  
25 3     3   2578 use autobox::Junctions;
  3         12218  
  3         17  
26 3     3   1691 use File::Which 'which';
  3         707  
  3         148  
27 3     3   931 use List::AllUtils qw{ max uniq apply };
  3         20675  
  3         245  
28 3     3   273 use File::ShareDir qw/ dist_dir /;
  3         3953  
  3         150  
29 3     3   316 use YAML::Tiny;
  3         3954  
  3         132  
30 3     3   238 use Path::Class;
  3         25398  
  3         139  
31              
32 3     3   262 use autodie 'system';
  3         9110  
  3         21  
33 3     3   11845 use IPC::System::Simple ( ); # explict dep for autodie system
  3         6  
  3         48  
34              
35 3     3   14 use aliased 'Dist::Zilla::Stash::PodWeaver';
  3         15  
  3         19  
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   5 my $self = shift @_;
48 2         53 my @authors = $self->zilla->authors->flatten;
49              
50             ### and get our list from git, filtering: "@authors"
51             my @contributors = uniq
52 6   66     282 map { $self->_contributor_emails->{$_} // $_ }
53 8         61 grep { $_ ne 'Your Name <you@example.com>' }
54 9         5384 grep { [ map { lc } @authors ]->none eq lc }
  9         107  
55 9         285 map { decode_utf8($_) }
56 9     9   30 apply { chomp; s/^\s*\d+\s*// }
  9         55  
57 2         10601 `git shortlog -s -e HEAD`
58             ;
59              
60 2         105 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   19 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   25 my ($canonical, @alternates) = @_;
83 4         7 return ( map { $_ => $canonical } @alternates );
  18         145  
84 2         4929 };
85              
86             return {
87 2         28 map { $_map_it->($_ => $mapping->{$_}->flatten) }
  4         48  
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   6 my $self = shift @_;
100              
101             # break contributor names into a stopwords-suitable list
102             my @stopwords =
103 4         17 map { (split / /) }
104 2         67 map { /^(.*) <.*$/; $1 }
  4         27  
  4         12  
105             $self->_contributor_list->flatten
106             ;
107              
108 2         107 return [ uniq sort @stopwords ];
109             },
110             );
111              
112             sub before_build {
113 2     2 0 179076 my $self = shift @_;
114              
115             # skip if we can't find git
116 2 50       19 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         350 my $stash = $self->zilla->stash_named('%PodWeaver');
126 2 50       126 do { $stash = PodWeaver->new; $self->_register_stash('%PodWeaver', $stash) }
  2         41  
  2         1977  
127             unless defined $stash;
128              
129             ### ...and config...
130 2         571 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   31 my ($key, @values) = @_;
136              
137 4         8 my $i = -1;
138 4         6 do { $i++ } while exists $config->{$key."[$i]"};
  4         21  
139 12         45 do { $config->{$key."[$i]"} = $_; $i++ }
  12         22  
140 4         12 for @values;
141              
142 4         10 return;
143 2         23 };
144              
145 2         66 $_append->('Contributors.contributors' => $self->_contributor_list->flatten);
146 2         79 $_append->('-StopWords.include' => $self->_stopwords->flatten);
147              
148             ### $config
149 2         22 return;
150             }
151              
152             sub metadata {
153 2     2 0 40831 my $self = shift @_;
154 2         82 my $list = $self->_contributor_list;
155 2 50       55 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.019 of Dist::Zilla::Plugin::ContributorsFromGit - released August 14, 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