File Coverage

blib/lib/Dist/Zilla/Plugin/Repository.pm
Criterion Covered Total %
statement 59 71 83.1
branch 40 58 68.9
condition 11 11 100.0
subroutine 6 7 85.7
pod 0 1 0.0
total 116 148 78.3


line stmt bran cond sub pod time code
1             package Dist::Zilla::Plugin::Repository;
2             $Dist::Zilla::Plugin::Repository::VERSION = '0.24';
3             # ABSTRACT: Automatically sets repository URL from svn/svk/Git checkout for Dist::Zilla
4              
5 2     2   2164088 use Moose;
  2         395320  
  2         14  
6             with 'Dist::Zilla::Role::MetaProvider';
7              
8             has git_remote => (
9             is => 'ro',
10             isa => 'Str',
11             default => 'origin',
12             );
13              
14             has github_http => (
15             is => 'ro',
16             isa => 'Bool',
17             default => 0,
18             );
19              
20             has _found_repo => (
21             is => 'ro',
22             isa => 'HashRef',
23             lazy => 1,
24             builder => '_build__found_repo',
25             );
26              
27             sub _build__found_repo {
28 21     21   50 my $self = shift;
29 21         126 my @info = $self->_find_repo(\&_execute);
30              
31 21 50       78 unshift @info, 'url' if @info == 1;
32              
33 21         78 my %repo = @info;
34              
35 21   100     210 $repo{$_} ||= '' for qw(type url web);
36              
37 21         632 return \%repo;
38             }
39              
40             has uri => (
41             is => 'ro',
42             isa => 'Str',
43             lazy => 1,
44             default => sub { shift->_found_repo->{url} },
45             );
46              
47             has repository => (
48             is => 'ro',
49             isa => 'Str',
50             predicate => 'has_repository',
51             );
52              
53             has type => (
54             is => 'ro',
55             isa => 'Str',
56             lazy => 1,
57             default => sub { shift->_found_repo->{type} },
58             );
59              
60             has web => (
61             is => 'ro',
62             isa => 'Str',
63             lazy => 1,
64             default => sub { shift->_found_repo->{web} },
65             );
66              
67             sub metadata {
68 21     21 0 402392 my ($self, $arg) = @_;
69              
70 21         59 my %repo;
71 21 100       720 $repo{url} = $self->uri if $self->uri;
72 21 100       592 $repo{type} = $self->type if $self->type;
73 21 100       591 $repo{web} = $self->web if $self->web;
74              
75 21 100 100     103 return unless $repo{url} or $repo{web};
76              
77 18         138 return {resources => {repository => \%repo}};
78             }
79              
80             sub _execute {
81 0     0   0 my ($command) = @_;
82 0         0 $ENV{LC_ALL} = "C";
83 0         0 `$command`;
84             }
85              
86             sub _git_to_repo {
87 11     11   46 my ($self, $uri) = @_;
88              
89 11         93 $uri =~ s![\w\-]+\@([^:]+):!git://$1/!;
90              
91 11         56 my %repo = (type => 'git');
92              
93 11 100       56 $repo{url} = $uri unless $uri eq 'origin'; # RT 55136
94              
95 11 100       95 if ($uri =~ /^(?:git|https?):\/\/((?:git(?:lab|hub)\.com|bitbucket.org).*?)(?:\.git)?$/) {
96 8         53 $repo{web} = "https://$1";
97              
98 8 100       239 if ($self->github_http) {
99              
100             # I prefer https://github.com/user/repository
101             # to git://github.com/user/repository.git
102 2         7 delete $repo{url};
103 2         15 $self->log("github_http is deprecated. "
104             . "Consider using META.json instead,\n"
105             . "which can store URLs for both git clone "
106             . "and the web front-end.");
107             }
108             }
109 11         790 return %repo;
110             }
111              
112             # Copy-Paste of Module-Install-Repository, thank MIYAGAWA
113             sub _find_repo {
114 21     21   74 my ($self, $execute) = @_;
115              
116 21         52 my %repo;
117              
118 21 100       1022 if (-e ".git") {
    100          
    100          
    100          
    50          
119 11 100       531 if ($self->has_repository) {
    50          
    0          
120 2         60 %repo = $self->_git_to_repo($self->repository);
121             } elsif ($execute->('git remote show -n ' . $self->git_remote) =~ /URL: (.*)$/m) {
122 9         158 %repo = $self->_git_to_repo($1);
123             } elsif ($execute->('git svn info') =~ /URL: (.*)$/m) {
124 0         0 %repo = (qw(type svn url), $1);
125             }
126              
127             # invalid github remote might come back with just the remote name
128 11 100 100     114 if ($repo{url} && $repo{url} =~ /\A\w+\z/) {
129 1         7 delete $repo{$_} for qw/url type web/;
130 1         31 $self->log("Skipping invalid git remote " . $self->git_remote);
131             }
132             } elsif (-e ".svn") {
133 2         11 $repo{type} = 'svn';
134 2 50       27 if ($execute->('svn info') =~ /URL: (.*)$/m) {
135 2         66 my $svn_url = $1;
136 2 50       10 if ($svn_url =~ /^https(\:\/\/.*?\.googlecode\.com\/svn\/.*)$/) {
137 0         0 $svn_url = 'http' . $1;
138             }
139 2         7 $repo{url} = $svn_url;
140             }
141             } elsif (-e "_darcs") {
142             # defaultrepo is better, but that is more likely to be ssh, not http
143 2         13 $repo{type} = 'darcs';
144 2 50       13 if (my $query_repo = $execute->('darcs query repo')) {
145 2 100       31 if ($query_repo =~ m!Default Remote: (http://.+)!) {
146 1         8 return %repo, url => $1;
147             }
148             }
149              
150 1 50       63 open my $handle, '<', '_darcs/prefs/repos' or return;
151 1         34 while (<$handle>) {
152 2         7 chomp;
153 2 100       29 return %repo, url => $_ if m!^http://!;
154             }
155             } elsif (-e ".hg") {
156 2         11 $repo{type} = 'hg';
157 2 50       12 if ($execute->('hg paths') =~ /default = (.*)$/m) {
158 2         79 my $mercurial_url = $1;
159 2         6 $mercurial_url =~ s!^ssh://hg\@(bitbucket\.org/)!https://$1!;
160 2         7 $repo{url} = $mercurial_url;
161             }
162             } elsif (-e "$ENV{HOME}/.svk") {
163             # Is there an explicit way to check if it's an svk checkout?
164 0 0       0 my $svk_info = $execute->('svk info') or return;
165             SVK_INFO: {
166 0 0       0 if ($svk_info =~ /Mirrored From: (.*), Rev\./) {
  0         0  
167 0         0 return qw(type svn url) => $1;
168             }
169              
170 0 0       0 if ($svk_info =~ m!Merged From: (/mirror/.*), Rev\.!) {
171 0 0       0 $svk_info = $execute->("svk info /$1") or return;
172 0         0 redo SVK_INFO;
173             }
174             }
175             }
176              
177 19 100 100     736 if (!exists $repo{url} && $self->has_repository) {
178 3         85 $repo{url} = $self->repository;
179             }
180              
181 19         90 return %repo;
182             }
183              
184             __PACKAGE__->meta->make_immutable;
185 2     2   14618 no Moose;
  2         5  
  2         10  
186              
187             1;
188              
189             __END__
190              
191             =pod
192              
193             =encoding UTF-8
194              
195             =head1 NAME
196              
197             Dist::Zilla::Plugin::Repository - Automatically sets repository URL from svn/svk/Git checkout for Dist::Zilla
198              
199             =head1 VERSION
200              
201             version 0.24
202              
203             =head1 SYNOPSIS
204              
205             # dist.ini
206             [Repository]
207              
208             =head1 DESCRIPTION
209              
210             The code is mostly a copy-paste of L<Module::Install::Repository>
211              
212             =head2 ATTRIBUTES
213              
214             =over 4
215              
216             =item * git_remote
217              
218             This is the name of the remote to use for the public repository (if
219             you use Git). By default, unsurprisingly, to F<origin>.
220              
221             =item * github_http
222              
223             B<This attribute is deprecated.>
224             If the remote is a GitHub repository, list only the https url
225             (https://github.com/fayland/dist-zilla-plugin-repository) and not the actual
226             clonable url (git://github.com/fayland/dist-zilla-plugin-repository.git).
227             This used to default to true, but as of 0.16 it defaults to false.
228              
229             The CPAN Meta 2 spec defines separate keys for the clonable C<url> and
230             web front-end C<web>. The Meta 1 specs allowed only 1 URL. If you
231             set C<github_http> to true, the C<url> key will be removed from the v2
232             metadata, and the v1 metadata will then use the C<web> key.
233              
234             Instead of setting C<github_http>, you should use the MetaJSON plugin
235             to include a v2 META.json file with both URLs.
236              
237             =item * repository
238              
239             You can set this attribute if you want a specific repository instead of the
240             plugin to auto-identify your repository.
241              
242             An example would be if you're releasing a module from your fork, and you don't
243             want it to identify your fork, so you can specify the repository explicitly.
244              
245             In the L<Meta 2 spec|CPAN::Meta::Spec>, this is the C<url> key.
246              
247             =item * type
248              
249             This should be the (lower-case) name of the most common program used
250             to work with the repository, e.g. git, svn, cvs, darcs, bzr or hg.
251             It's normally determined automatically, but you can override it.
252              
253             =item * web
254              
255             This is a URL pointing to a human-usable web front-end for the
256             repository.
257              
258             =back
259              
260             =for Pod::Coverage metadata
261              
262             =head1 AUTHORS
263              
264             =over 4
265              
266             =item *
267              
268             Fayland Lam <fayland@gmail.com>
269              
270             =item *
271              
272             Ricardo SIGNES <rjbs@cpan.org>
273              
274             =item *
275              
276             Moritz Onken <onken@netcubed.de>
277              
278             =item *
279              
280             Christopher J. Madsen <perl@cjmweb.net>
281              
282             =back
283              
284             =head1 COPYRIGHT AND LICENSE
285              
286             This software is copyright (c) 2018 by Fayland Lam, Ricardo SIGNES, Moritz Onken, Christopher J. Madsen.
287              
288             This is free software; you can redistribute it and/or modify it under
289             the same terms as the Perl 5 programming language system itself.
290              
291             =cut