File Coverage

blib/lib/Dist/Zilla/Plugin/UploadToCPAN.pm
Criterion Covered Total %
statement 44 46 95.6
branch 6 6 100.0
condition n/a
subroutine 13 15 86.6
pod 0 4 0.0
total 63 71 88.7


line stmt bran cond sub pod time code
1             package Dist::Zilla::Plugin::UploadToCPAN 6.037;
2             # ABSTRACT: upload the dist to CPAN
3              
4 9     9   7989 use Moose;
  9         25  
  9         86  
5             with 'Dist::Zilla::Role::BeforeRelease',
6             'Dist::Zilla::Role::Releaser';
7              
8 9     9   67134 use Dist::Zilla::Pragmas;
  9         23  
  9         87  
9              
10 9     9   69 use File::Spec;
  9         18  
  9         332  
11 9     9   50 use Moose::Util::TypeConstraints;
  9         14  
  9         100  
12 9     9   20493 use Scalar::Util qw(weaken);
  9         24  
  9         757  
13 9     9   60 use Dist::Zilla::Util;
  9         23  
  9         272  
14 9     9   46 use Try::Tiny;
  9         18  
  9         612  
15              
16 9     9   59 use namespace::autoclean;
  9         19  
  9         95  
17              
18             #pod =head1 SYNOPSIS
19             #pod
20             #pod If loaded, this plugin will allow the F<release> command to upload to the CPAN.
21             #pod
22             #pod =head1 DESCRIPTION
23             #pod
24             #pod This plugin looks for configuration in your C<dist.ini> or (more
25             #pod likely) C<~/.dzil/config.ini>:
26             #pod
27             #pod [%PAUSE]
28             #pod username = YOUR-PAUSE-ID
29             #pod password = YOUR-PAUSE-PASSWORD
30             #pod
31             #pod If this configuration does not exist, it can read the configuration from
32             #pod C<~/.pause>, in the same format that L<cpan-upload> requires:
33             #pod
34             #pod user YOUR-PAUSE-ID
35             #pod password YOUR-PAUSE-PASSWORD
36             #pod
37             #pod If neither configuration exists, it will prompt you to enter your
38             #pod username and password during the BeforeRelease phase. Entering a
39             #pod blank username or password will abort the release.
40             #pod
41             #pod You can't put your password in your F<dist.ini>. C'mon now!
42             #pod
43             #pod =cut
44              
45             {
46             package
47             Dist::Zilla::Plugin::UploadToCPAN::_Uploader;
48             # CPAN::Uploader will be loaded later if used
49             our @ISA = 'CPAN::Uploader';
50             # Report CPAN::Uploader's version, not ours:
51 0     0   0 sub _ua_string { CPAN::Uploader->_ua_string }
52              
53             sub log {
54 6     6   1523 my $self = shift;
55 6         33 $self->{'Dist::Zilla'}{plugin}->log(@_);
56             }
57             }
58              
59             #pod =attr credentials_stash
60             #pod
61             #pod This attribute holds the name of a L<PAUSE stash|Dist::Zilla::Stash::Login>
62             #pod that will contain the credentials to be used for the upload. By default,
63             #pod UploadToCPAN will look for a C<%PAUSE> stash.
64             #pod
65             #pod =cut
66              
67             has credentials_stash => (
68             is => 'ro',
69             isa => 'Str',
70             default => '%PAUSE'
71             );
72              
73             has _credentials_stash_obj => (
74             is => 'ro',
75             isa => maybe_type( role_type('Dist::Zilla::Role::Stash::Login') ),
76             lazy => 1,
77             init_arg => undef,
78             default => sub { $_[0]->zilla->stash_named( $_[0]->credentials_stash ) },
79             );
80              
81             sub _credential {
82 8     8   17 my ($self, $name) = @_;
83              
84 8 100       214 return unless my $stash = $self->_credentials_stash_obj;
85 2         45 return $stash->$name;
86             }
87              
88             sub mvp_aliases {
89 13     13 0 2197 return { user => 'username' };
90             }
91              
92             #pod =attr username
93             #pod
94             #pod This option supplies the user's PAUSE username.
95             #pod It will be looked for in the user's PAUSE configuration; if not
96             #pod found, the user will be prompted.
97             #pod
98             #pod =cut
99              
100             has username => (
101             is => 'ro',
102             isa => 'Str',
103             lazy => 1,
104             default => sub {
105             my ($self) = @_;
106             return $self->_credential('username')
107             || $self->pause_cfg->{user}
108             || $self->zilla->chrome->prompt_str("PAUSE username: ");
109             },
110             );
111              
112 0     0 0 0 sub cpanid { shift->username }
113              
114             #pod =attr password
115             #pod
116             #pod This option supplies the user's PAUSE password. It cannot be provided via
117             #pod F<dist.ini>. It will be looked for in the user's PAUSE configuration; if not
118             #pod found, the user will be prompted.
119             #pod
120             #pod =cut
121              
122             has password => (
123             is => 'ro',
124             isa => 'Str',
125             init_arg => undef,
126             lazy => 1,
127             default => sub {
128             my ($self) = @_;
129             my $pw = $self->_credential('password') || $self->pause_cfg->{password};
130              
131             unless ($pw){
132             my $uname = $self->username;
133             $pw = $self->zilla->chrome->prompt_str(
134             "PAUSE password for $uname: ",
135             { noecho => 1 },
136             );
137             }
138              
139             return $pw;
140             },
141             );
142              
143             #pod =attr pause_cfg_file
144             #pod
145             #pod This is the name of the file containing your pause credentials. It defaults
146             #pod F<.pause>. If you give a relative path, it is taken to be relative to
147             #pod L</pause_cfg_dir>.
148             #pod
149             #pod =cut
150              
151             has pause_cfg_file => (
152             is => 'ro',
153             isa => 'Str',
154             lazy => 1,
155             default => sub { '.pause' },
156             );
157              
158             #pod =attr pause_cfg_dir
159             #pod
160             #pod This is the directory for resolving a relative L</pause_cfg_file>.
161             #pod it defaults to the glob expansion of F<~>.
162             #pod
163             #pod =cut
164              
165             has pause_cfg_dir => (
166             is => 'ro',
167             isa => 'Str',
168             lazy => 1,
169             default => sub { Dist::Zilla::Util->homedir },
170             );
171              
172             #pod =attr pause_cfg
173             #pod
174             #pod This is a hashref of defaults loaded from F<~/.pause> -- this attribute is
175             #pod subject to removal in future versions, as the config-loading behavior in
176             #pod CPAN::Uploader is improved.
177             #pod
178             #pod =cut
179              
180             has pause_cfg => (
181             is => 'ro',
182             isa => 'HashRef[Str]',
183             lazy => 1,
184             default => sub {
185             my $self = shift;
186             require CPAN::Uploader;
187             my $file = $self->pause_cfg_file;
188             $file = File::Spec->catfile($self->pause_cfg_dir, $file)
189             unless File::Spec->file_name_is_absolute($file);
190             return {} unless -e $file && -r _;
191             my $cfg = try {
192             CPAN::Uploader->read_config_file($file)
193             } catch {
194             $self->log("Couldn't load credentials from '$file': $_");
195             {};
196             };
197             return $cfg;
198             },
199             );
200              
201             #pod =attr subdir
202             #pod
203             #pod If given, this specifies a subdirectory under the user's home directory to
204             #pod which to upload. Using this option is not recommended.
205             #pod
206             #pod =cut
207              
208             has subdir => (
209             is => 'ro',
210             isa => 'Str',
211             predicate => 'has_subdir',
212             );
213              
214             #pod =attr upload_uri
215             #pod
216             #pod If given, this specifies an alternate URI for the PAUSE upload form. By
217             #pod default, the default supplied by L<CPAN::Uploader> is used. Using this option
218             #pod is not recommended in most cases.
219             #pod
220             #pod =cut
221              
222             has upload_uri => (
223             is => 'ro',
224             isa => 'Str',
225             predicate => 'has_upload_uri',
226             );
227              
228             #pod =attr retries
229             #pod
230             #pod The number of retries to perform on upload failure (5xx response). The default
231             #pod is set to 3 by this plugin. This option will be passed to L<CPAN::Uploader>.
232             #pod
233             #pod =cut
234              
235             has retries => (
236             is => 'ro',
237             isa => 'Int',
238             default => 3,
239             );
240              
241             #pod =attr retry_delay
242             #pod
243             #pod The number of seconds to wait between retries. The default is set to 5 seconds
244             #pod by this plugin. This option will be passed to L<CPAN::Uploader>.
245             #pod
246             #pod =cut
247              
248             has retry_delay => (
249             is => 'ro',
250             isa => 'Int',
251             default => 5,
252             );
253              
254             has uploader => (
255             is => 'ro',
256             isa => 'CPAN::Uploader',
257             lazy => 1,
258             default => sub {
259             my ($self) = @_;
260              
261             # Load the module lazily
262             require CPAN::Uploader;
263             CPAN::Uploader->VERSION('0.103004'); # require HTTPS
264              
265             my $uploader = Dist::Zilla::Plugin::UploadToCPAN::_Uploader->new({
266             user => $self->username,
267             password => $self->password,
268             ($self->has_subdir
269             ? (subdir => $self->subdir) : ()),
270             ($self->has_upload_uri
271             ? (upload_uri => $self->upload_uri) : ()),
272             ($self->retries
273             ? (retries => $self->retries) : ()),
274             ($self->retry_delay
275             ? (retry_delay => $self->retry_delay) : ()),
276             });
277              
278             $uploader->{'Dist::Zilla'}{plugin} = $self;
279             weaken $uploader->{'Dist::Zilla'}{plugin};
280              
281             return $uploader;
282             }
283             );
284              
285             sub before_release {
286 5     5 0 10 my $self = shift;
287              
288 5         10 my $sentinel = [];
289              
290 5         11 for my $attr (qw(username password)) {
291 9         9 my $value;
292 9         14 my $ok = eval { $value = $self->$attr; 1 };
  9         278  
  8         15  
293              
294 9 100       403 unless ($ok) {
295 1         9 $self->log_fatal([ "Couldn't figure out %s: %s", $attr, $@ ]);
296             }
297              
298 8 100       19 unless (length $value) {
299 2         15 $self->log_fatal([ "No $attr was provided" ]);
300             }
301             }
302              
303 2         7 return;
304             }
305              
306             sub release {
307 2     2 0 4 my ($self, $archive) = @_;
308              
309 2         49 $self->uploader->upload_file("$archive");
310             }
311              
312             __PACKAGE__->meta->make_immutable;
313             1;
314              
315             __END__
316              
317             =pod
318              
319             =encoding UTF-8
320              
321             =head1 NAME
322              
323             Dist::Zilla::Plugin::UploadToCPAN - upload the dist to CPAN
324              
325             =head1 VERSION
326              
327             version 6.037
328              
329             =head1 SYNOPSIS
330              
331             If loaded, this plugin will allow the F<release> command to upload to the CPAN.
332              
333             =head1 DESCRIPTION
334              
335             This plugin looks for configuration in your C<dist.ini> or (more
336             likely) C<~/.dzil/config.ini>:
337              
338             [%PAUSE]
339             username = YOUR-PAUSE-ID
340             password = YOUR-PAUSE-PASSWORD
341              
342             If this configuration does not exist, it can read the configuration from
343             C<~/.pause>, in the same format that L<cpan-upload> requires:
344              
345             user YOUR-PAUSE-ID
346             password YOUR-PAUSE-PASSWORD
347              
348             If neither configuration exists, it will prompt you to enter your
349             username and password during the BeforeRelease phase. Entering a
350             blank username or password will abort the release.
351              
352             You can't put your password in your F<dist.ini>. C'mon now!
353              
354             =head1 PERL VERSION
355              
356             This module should work on any version of perl still receiving updates from
357             the Perl 5 Porters. This means it should work on any version of perl
358             released in the last two to three years. (That is, if the most recently
359             released version is v5.40, then this module should work on both v5.40 and
360             v5.38.)
361              
362             Although it may work on older versions of perl, no guarantee is made that the
363             minimum required version will not be increased. The version may be increased
364             for any reason, and there is no promise that patches will be accepted to
365             lower the minimum required perl.
366              
367             =head1 ATTRIBUTES
368              
369             =head2 credentials_stash
370              
371             This attribute holds the name of a L<PAUSE stash|Dist::Zilla::Stash::Login>
372             that will contain the credentials to be used for the upload. By default,
373             UploadToCPAN will look for a C<%PAUSE> stash.
374              
375             =head2 username
376              
377             This option supplies the user's PAUSE username.
378             It will be looked for in the user's PAUSE configuration; if not
379             found, the user will be prompted.
380              
381             =head2 password
382              
383             This option supplies the user's PAUSE password. It cannot be provided via
384             F<dist.ini>. It will be looked for in the user's PAUSE configuration; if not
385             found, the user will be prompted.
386              
387             =head2 pause_cfg_file
388              
389             This is the name of the file containing your pause credentials. It defaults
390             F<.pause>. If you give a relative path, it is taken to be relative to
391             L</pause_cfg_dir>.
392              
393             =head2 pause_cfg_dir
394              
395             This is the directory for resolving a relative L</pause_cfg_file>.
396             it defaults to the glob expansion of F<~>.
397              
398             =head2 pause_cfg
399              
400             This is a hashref of defaults loaded from F<~/.pause> -- this attribute is
401             subject to removal in future versions, as the config-loading behavior in
402             CPAN::Uploader is improved.
403              
404             =head2 subdir
405              
406             If given, this specifies a subdirectory under the user's home directory to
407             which to upload. Using this option is not recommended.
408              
409             =head2 upload_uri
410              
411             If given, this specifies an alternate URI for the PAUSE upload form. By
412             default, the default supplied by L<CPAN::Uploader> is used. Using this option
413             is not recommended in most cases.
414              
415             =head2 retries
416              
417             The number of retries to perform on upload failure (5xx response). The default
418             is set to 3 by this plugin. This option will be passed to L<CPAN::Uploader>.
419              
420             =head2 retry_delay
421              
422             The number of seconds to wait between retries. The default is set to 5 seconds
423             by this plugin. This option will be passed to L<CPAN::Uploader>.
424              
425             =head1 AUTHOR
426              
427             Ricardo SIGNES 😏 <cpan@semiotic.systems>
428              
429             =head1 COPYRIGHT AND LICENSE
430              
431             This software is copyright (c) 2026 by Ricardo SIGNES.
432              
433             This is free software; you can redistribute it and/or modify it under
434             the same terms as the Perl 5 programming language system itself.
435              
436             =cut