File Coverage

blib/lib/Docker/Registry/V2.pm
Criterion Covered Total %
statement 75 78 96.1
branch 6 8 75.0
condition n/a
subroutine 18 21 85.7
pod 0 7 0.0
total 99 114 86.8


line stmt bran cond sub pod time code
1             package Docker::Registry::Call::Repositories;
2 5     5   159815 use Moo;
  5         11766  
  5         27  
3 5     5   3434 use Types::Standard qw/Int Str/;
  5         75405  
  5         36  
4             has n => (is => 'ro', isa => Int);
5             has last => (is => 'ro', isa => Str);
6              
7             package Docker::Registry::Result::Repositories;
8 5     5   4200 use Moo;
  5         12  
  5         27  
9 5     5   1833 use Types::Standard qw/ArrayRef Str/;
  5         15  
  5         55  
10             has repositories => (is => 'ro', isa => ArrayRef[Str]);
11             has last => (is => 'ro', isa => Str);
12              
13             package Docker::Registry::Call::RepositoryTags;
14 5     5   3324 use Moo;
  5         12  
  5         20  
15 5     5   1606 use Types::Standard qw/Int Str/;
  5         10  
  5         22  
16             has repository => (is => 'ro', isa => Str, required => 1);
17             has n => (is => 'ro', isa => Int);
18             has last => (is => 'ro', isa => Str);
19              
20             package Docker::Registry::Result::RepositoryTags;
21 5     5   3265 use Moo;
  5         10  
  5         24  
22 5     5   1641 use Types::Standard qw/ArrayRef Str/;
  5         14  
  5         31  
23             has name => (is => 'ro', isa => Str, required => 1);
24             has tags => (is => 'ro', isa => ArrayRef[Str], required => 1);
25             has last => (is => 'ro', isa => Str);
26              
27             package Docker::Registry::V2;
28 5     5   3279 use Moo;
  5         10  
  5         23  
29 5     5   3597 use Docker::Registry::Types qw(DockerRegistryURI);
  5         17  
  5         50  
30 5     5   1866 use Types::Standard qw/Str ConsumerOf InstanceOf/;
  5         11  
  5         26  
31              
32             has url => (is => 'ro', coerce => 1, isa => DockerRegistryURI, required => 1);
33             has api_base => (is => 'ro', default => 'v2');
34              
35             has caller => (is => 'ro', isa => ConsumerOf['Docker::Registry::IO'], default => sub {
36             require Docker::Registry::IO::Simple;
37             Docker::Registry::IO::Simple->new;
38             });
39             has auth => (is => 'ro', isa => ConsumerOf['Docker::Registry::Auth'], lazy => 1, builder => 'build_auth' );
40             has request_builder => (is => 'ro', isa => InstanceOf['Docker::Registry::RequestBuilder'], lazy => 1, default => sub {
41             my $self = shift;
42             require Docker::Registry::RequestBuilder;
43             Docker::Registry::RequestBuilder->new(url => $self->url, api_base => $self->api_base);
44             });
45              
46             sub build_auth {
47 1     1 0 473 require Docker::Registry::Auth::None;
48 1         6 Docker::Registry::Auth::None->new;
49             };
50              
51 5     5   7545 use JSON::MaybeXS qw//;
  5         24247  
  5         962  
52             has _json => (is => 'ro', default => sub {
53             JSON::MaybeXS->new;
54             });
55             sub process_json_response {
56 15     15 0 79 my ($self, $response) = @_;
57 15 100       130 if ($response->status == 200) {
    50          
58 12         28 my $struct = eval {
59 12         175 $self->_json->decode($response->content);
60             };
61 12 50       42 if ($@) {
62 0         0 Docker::Registry::Exception->throw({ message => $@ });
63             }
64 12         54 my $pagination = $self->_parse_pagination_header($response);
65 12         312 return { %$struct, %$pagination };
66             } elsif ($response->status == 401) {
67 0         0 Docker::Registry::Exception::Unauthorized->throw({
68             message => $response->content,
69             status => $response->status,
70             });
71             } else {
72 3         77 Docker::Registry::Exception::HTTP->throw({
73             message => $response->content,
74             status => $response->status
75             });
76             }
77             }
78              
79 5     5   40 use URI;
  5         21  
  5         2347  
80             sub _parse_pagination_header {
81 12     12   29 my ($self, $response) = @_;
82              
83 12 100       259 return {} unless($response->headers->{link});
84              
85 1         23 my ($link) = ($response->headers->{link} =~ /<([^>]*)>/);
86 1         14 my $url = URI->new($link);
87 1         71 my %url_params = $url->query_form;
88              
89 1         73 return {last => $url_params{last}};
90             }
91              
92             sub repositories {
93 7     7 0 15667 my $self = shift;
94             # Inputs n, last
95             #
96             # GET /v2/_catalog
97             #
98             # Header next
99             # {
100             # "repositories": [
101             # ,
102             # ...
103             # ]
104             # }
105 7         22 my $call_class = 'Docker::Registry::Call::Repositories';
106 7         118 my $call = $call_class->new({ @_ });
107              
108 7         8245 my $request = $self->request_builder->build_request($call);
109              
110 7         22 my $scope = 'registry:catalog:*';
111 7         167 $request = $self->auth->authorize($request, $scope);
112 7         71 my $response = $self->caller->send_request($request);
113 7         11637 my $result_class = 'Docker::Registry::Result::Repositories';
114 7         52 my $result = $result_class->new($self->process_json_response($response));
115 4         8687 return $result;
116             }
117              
118             sub repository_tags {
119 8     8 0 12591 my $self = shift;
120              
121             # n, last
122             #GET /v2/$repository/tags/list
123             #
124             #{"name":"$repository","tags":["2017.09","latest"]}
125 8         19 my $call_class = 'Docker::Registry::Call::RepositoryTags';
126 8         135 my $call = $call_class->new({ @_ });
127              
128 8         13421 my $request = $self->request_builder->build_request($call);
129              
130 8         58 my $scope = sprintf 'repository:%s:%s', $call->repository, 'pull';
131 8         163 $request = $self->auth->authorize($request, $scope);
132 8         49 my $response = $self->caller->send_request($request);
133 8         815 my $result_class = 'Docker::Registry::Result::RepositoryTags';
134 8         27 my $result = $result_class->new($self->process_json_response($response));
135 8         14070 return $result;
136             }
137              
138             sub is_registry {
139 0     0 0   my $self = shift;
140             # GET /v2
141             # if (200 or 401) and (header.Docker-Distribution-API-Version eq 'registry/2.0')
142             }
143              
144             # Actionable failure conditions, covered in detail in their relevant sections,
145             # are reported as part of 4xx responses, in a json response body. One or more
146             # errors will be returned in the following format:
147             # {
148             # "errors:" [{
149             # "code": ,
150             # "message": ,
151             # "detail":
152             # },
153             # ...
154             # ]
155             # }
156              
157             # ECR: returns 401 error body as "Not Authorized"
158       0 0   sub process_error {
159            
160             }
161              
162       0 0   sub request {
163            
164             }
165             1;