File Coverage

lib/Test/PAUSE/Permissions.pm
Criterion Covered Total %
statement 18 83 21.6
branch 0 40 0.0
condition 0 37 0.0
subroutine 6 11 54.5
pod 1 1 100.0
total 25 172 14.5


line stmt bran cond sub pod time code
1             package Test::PAUSE::Permissions;
2              
3 1     1   22206 use strict;
  1         2  
  1         22  
4 1     1   3 use warnings;
  1         1  
  1         20  
5 1     1   452 use parent 'Exporter';
  1         227  
  1         3  
6 1     1   36 use Test::More;
  1         1  
  1         5  
7 1     1   602 use PAUSE::Permissions;
  1         92960  
  1         27  
8 1     1   441 use Parse::LocalDistribution;
  1         46392  
  1         600  
9              
10             our $VERSION = '0.06';
11              
12             our @EXPORT = (@Test::More::EXPORT, qw/all_permissions_ok/);
13              
14             sub all_permissions_ok {
15 0 0   0 1   my ($author, $opts) = ref $_[0] ? (undef, @_) : @_;
16 0   0       $opts ||= {};
17              
18 0 0         plan skip_all => 'Set RELEASE_TESTING environmental variable to test this.' unless $ENV{RELEASE_TESTING};
19              
20             # Get your id from .pause
21 0   0       $author ||= _get_pause_user();
22              
23 0 0         plan skip_all => "Can't determine who is going to release." unless $author;
24              
25             # Get authority from META
26 0   0       my $meta_authority ||= _get_authority_in_meta();
27              
28             # Prepare 06perms for testing
29 0           my $perms = PAUSE::Permissions->new;
30              
31 0 0         local $Parse::PMFile::ALLOW_DEV_VERSION = 1 if $opts->{dev};
32              
33             # Get packages (respecting no_index)
34 0           my $provides = Parse::LocalDistribution->new->parse();
35              
36             # Iterate
37 0           my $saw_errors;
38 0           my @authorities = grep $_, $author, $meta_authority;
39 0           my %new_packages;
40 0           my %dist_maintainers = map {uc $_ => 1} @authorities;
  0            
41             SKIP:
42 0           for my $package (keys %$provides) {
43 0   0       my $authority = uc($meta_authority || $author || '');
44              
45 0           my $mp = $perms->module_permissions($package);
46              
47 0 0         if (!$mp) {
48 0           pass "$package: no one has permissions ($authority should have the first come)";
49 0           $new_packages{$package} = 1;
50 0           next;
51             }
52 0           my @module_maintainers = $mp->all_maintainers;
53 0           $dist_maintainers{uc $_} = 1 for @module_maintainers;
54              
55             # Author should have permissions, regardless of the authority
56 0 0         if (grep { uc $_ eq uc $author } @module_maintainers) {
  0            
57 0           pass "$package: $author has a permission";
58             }
59             else {
60 0           fail "$package: maintained by ".join ', ', @module_maintainers;
61 0           $saw_errors = 1;
62             }
63              
64             # $AUTHORITY has no effect in PAUSE.
65             # just see if $AUTHORITY matches x_authority for information
66 0 0         if ($meta_authority) {
67 0           my $file_authority = _get_authority_in_file($package, $provides->{$package});
68 0 0 0       if ($file_authority && $file_authority ne $meta_authority) {
69             # XXX: should fail?
70 0           diag "$package: \$AUTHORITY ($file_authority) doesn't match x_authority ($meta_authority)";
71             }
72             }
73             }
74              
75             # There are several known IDs that won't maintain any package
76 0           delete $dist_maintainers{$_} for qw/ADOPTME HANDOFF NEEDHELP LOCAL/;
77              
78             # GH #3: Adding a new module to an established distribution maintained by a large group may cause
79             # an annoying permission problem.
80 0 0 0       if (
      0        
      0        
81             !$saw_errors # having errors already means there's someone (ie. you) who can't upload it
82             and %new_packages # no problem if no new module is added
83             and (keys %new_packages < keys %$provides) # no problem if everything is new
84             and (keys %dist_maintainers > @authorities) # no problem if maintainers are few and everyone gets permissions
85             ) {
86 0           delete $dist_maintainers{$_} for @authorities;
87 0           my $message = "Some of the maintainers of this distribution (@{[sort keys %dist_maintainers]}) won't have permissions for the following package(s): @{[sort keys %new_packages]}.";
  0            
  0            
88 0 0         if ($opts->{strict}) {
89 0           fail $message;
90             } else {
91 0           diag "[WARNING] $message\n(This may or may not be a problem, depending on the policy of your team.)";
92             }
93             }
94              
95 0           done_testing;
96             }
97              
98             sub _get_pause_user {
99             # Get authority from ~/.pause
100 0     0     require Config::Identity::PAUSE;
101 0           my %config = Config::Identity::PAUSE->load;
102 0           return $config{user};
103             }
104              
105             sub _get_authority_in_meta {
106             # Get authority from META
107 0     0     my $meta = _parse_meta();
108 0 0 0       if ($meta && $meta->{x_authority}) {
109 0           my $authority = $meta->{x_authority};
110 0           $authority =~ s/^cpan://i;
111 0           return $authority;
112             }
113             }
114              
115             sub _parse_meta {
116 0     0     for my $file (qw/META.json META.yml/) {
117 0 0 0       next unless -f $file && -r _;
118 0           my $meta = Parse::CPAN::Meta->load_file($file);
119 0 0 0       return $meta if $meta && ref $meta eq ref {};
120             }
121             }
122              
123             sub _get_authority_in_file {
124 0     0     my ($package, $package_info) = @_;
125 0           my $file = $package_info->{infile};
126 0 0 0       return unless $file && -f $file && -r _;
      0        
127              
128 0 0         open my $fh, '<', $file or return;
129 0           my $in_pod = 0;
130 0           while(<$fh>) {
131 0 0         last if /__(DATA|END)__/;
132 0 0         $in_pod = /^=(?!cut?)/ ? 1 : /^=cut/ ? 0 : $in_pod;
    0          
133 0 0         next if $in_pod;
134              
135 0 0         if (/\$(?:${package}::)?AUTHORITY\s*=.+?(?i:cpan):([A-Za-z0-9]+)/) {
136 0           return $1;
137             }
138             }
139             }
140              
141             1;
142              
143             __END__