File Coverage

File:blib/lib/App/Project/Doctor/Check/Meta.pm
Coverage:97.3%

linestmtbrancondsubtimecode
1package App::Project::Doctor::Check::Meta;
2
3
2
2
2
1867
3
28
use strict;
4
2
2
2
2
2
57
use warnings;
5
2
2
2
5
2
8
use autodie qw(:all);
6
7
2
2
2
4237
3
6
use parent -norequire, 'App::Project::Doctor::Check::Base';
8
9
2
2
2
69
2
63
use Carp qw(croak carp);
10
2
2
2
3
2
504
use Readonly;
11
12our $VERSION = '0.02';
13
14Readonly::Array my @REQUIRED_FIELDS => qw(name version author abstract license);
15Readonly::Array my @META_FILES      => qw(META.json META.yml MYMETA.json MYMETA.yml);
16
17
2
186
sub name        { 'META' }
18
1
2
sub description { 'META.yml or META.json is present, parseable, and complete.' }
19
2
4
sub can_fix     { 0 }
20
2
4
sub order       { 30 }
21
22sub check {
23
6
8
        my ($self, $ctx) = @_;
24
6
9
        croak 'check requires an App::Project::Doctor::Context' unless ref $ctx;
25
26
6
7
        my @findings;
27
28
6
24
13
37
        my ($meta_file) = grep { $ctx->has_file($_) } @META_FILES;
29
30
6
13
        unless ($meta_file) {
31
3
7
                push @findings, _f(
32                        severity => 'warning',
33                        message  => 'No META.{yml,json} -- run your builder to generate one.',
34                        detail   => 'CPAN indexers require META to discover name and version.',
35                );
36                # Fall back: at least confirm a builder file exists.
37
3
7
                unless ($ctx->builder_file) {
38
1
2
                        push @findings, _f(
39                                severity => 'error',
40                                message  => 'No Makefile.PL, Build.PL, or dist.ini found.',
41                        );
42                }
43
3
17
                return @findings;
44        }
45
46
3
6
        require CPAN::Meta;
47
3
3
4
3
        my $meta = eval { CPAN::Meta->load_file($ctx->abs_path($meta_file)) };
48
3
151
        if ($@) {
49
1
2
                return _f(
50                        severity => 'error',
51                        message  => "Failed to parse $meta_file -- file may be malformed.",
52                        file     => $meta_file,
53                );
54        }
55
56
2
2
3
5
        my %data = %{ $meta->as_struct };
57
2
8
        for my $field (@REQUIRED_FIELDS) {
58
10
44
                next if defined $data{$field} && length $data{$field};
59
1
5
                push @findings, _f(
60                        severity => 'error',
61                        message  => "META field '$field' is missing or empty in $meta_file.",
62                        file     => $meta_file,
63                );
64        }
65
66
2
7
        unless (@findings) {
67
1
3
                push @findings, _f(
68                        severity => 'pass',
69                        message  => "$meta_file is valid and all required fields are present.",
70                );
71        }
72
73
2
7
        return @findings;
74}
75
76sub _f {
77
7
11
        require App::Project::Doctor::Finding;
78
7
15
        return App::Project::Doctor::Finding->new(check_name => 'META', @_);
79}
80
811;
82