File Coverage

lib/Artifactory/Client.pm
Criterion Covered Total %
statement 795 801 99.2
branch 68 96 70.8
condition 24 60 40.0
subroutine 222 223 99.5
pod 183 184 99.4
total 1292 1364 94.7


line stmt bran cond sub pod time code
1             package Artifactory::Client;
2              
3 1     1   242496 use strict;
  1         3  
  1         32  
4 1     1   7 use warnings FATAL => 'all';
  1         2  
  1         41  
5              
6 1     1   583 use Moose;
  1         464564  
  1         8  
7              
8 1     1   7530 use Data::Dumper;
  1         2  
  1         70  
9 1     1   7 use URI;
  1         2  
  1         32  
10 1     1   6 use JSON::MaybeXS;
  1         2  
  1         66  
11 1     1   8 use LWP::UserAgent;
  1         2  
  1         26  
12 1     1   1074 use Path::Tiny qw();
  1         11399  
  1         31  
13 1     1   598 use MooseX::StrictConstructor;
  1         31195  
  1         4  
14 1     1   10399 use URI::Escape qw(uri_escape);
  1         3  
  1         85  
15 1     1   7 use File::Basename qw(basename);
  1         2  
  1         78  
16 1     1   637 use HTTP::Request::StreamingUpload;
  1         597  
  1         33  
17              
18 1     1   7 use namespace::autoclean;
  1         2  
  1         10  
19              
20             =head1 NAME
21              
22             Artifactory::Client - Perl client for Artifactory REST API
23              
24             =head1 VERSION
25              
26             Version 1.8.0
27              
28             =cut
29              
30             our $VERSION = 'v1.8.0';
31              
32             =head1 SYNOPSIS
33              
34             This is a Perl client for Artifactory REST API:
35             https://www.jfrog.com/confluence/display/RTF/Artifactory+REST+API Every public method provided in this module returns a
36             HTTP::Response object.
37              
38             use Artifactory::Client;
39              
40             my $h = HTTP::Headers->new();
41             $h->authorization_basic( 'admin', 'password' );
42             my $ua = LWP::UserAgent->new( default_headers => $h );
43              
44             my $args = {
45             artifactory => 'http://artifactory.server.com',
46             port => 8080,
47             repository => 'myrepository',
48             context_root => '/', # Context root for artifactory. Defaults to 'artifactory'.
49             ua => $ua # Dropping in custom UA with default_headers set. Default is a plain LWP::UserAgent.
50             };
51              
52             my $client = Artifactory::Client->new( $args );
53             my $path = '/foo'; # path on artifactory
54              
55             # Properties are a hashref of key-arrayref pairs. Note that value must be an arrayref even for a single element.
56             # This is to conform with Artifactory which treats property values as a list.
57             my $properties = {
58             one => ['two'],
59             baz => ['three'],
60             };
61             my $file = '/local/file.xml';
62              
63             # Name of methods are taken straight from Artifactory REST API documentation. 'Deploy Artifact' would map to
64             # deploy_artifact method, like below. The caller gets HTTP::Response object back.
65             my $resp = $client->deploy_artifact( path => $path, properties => $properties, file => $file );
66              
67             # Custom requests can also be made via usual get / post / put / delete requests.
68             my $resp = $client->get( 'http://artifactory.server.com/path/to/resource' );
69              
70             # Repository override for calls that have a repository in the endpoint. The passed-in repository will not persist.
71             my $resp = $client->calculate_yum_repository_metadata( repository => 'different_repo', async => 1 );
72              
73             =cut
74              
75             =head1 Dev Env Setup / Running Tests
76              
77             carton install
78              
79             # to run unit tests
80             prove -r t
81              
82             =cut
83              
84             has 'artifactory' => (
85             is => 'ro',
86             isa => 'Str',
87             required => 1,
88             writer => '_set_artifactory',
89             );
90              
91             has 'port' => (
92             is => 'ro',
93             isa => 'Int',
94             default => 80,
95             );
96              
97             has 'context_root' => (
98             is => 'ro',
99             isa => 'Str',
100             default => 'artifactory',
101             );
102              
103             has 'ua' => (
104             is => 'rw',
105             isa => 'LWP::UserAgent',
106             builder => '_build_ua',
107             lazy => 1,
108             );
109              
110             has 'repository' => (
111             is => 'ro',
112             isa => 'Str',
113             default => '',
114             writer => '_set_repository',
115             );
116              
117             has '_json' => (
118             is => 'ro',
119             builder => '_build_json',
120             lazy => 1,
121             );
122              
123             has '_api_url' => (
124             is => 'ro',
125             isa => 'Str',
126             init_arg => undef,
127             writer => '_set_api_url',
128             );
129              
130             has '_art_url' => (
131             is => 'ro',
132             isa => 'Str',
133             init_arg => undef,
134             writer => '_set_art_url',
135             );
136              
137             sub BUILD {
138 179     179 0 395 my ($self) = @_;
139              
140             # Save URIs
141 179         5838 my $uri = URI->new( $self->artifactory() );
142 179         18056 $uri->port( $self->port );
143 179         16732 my $context_root = $self->context_root();
144 179 50       469 $context_root = '' if ( $context_root eq '/' );
145              
146 179         588 $uri->path_segments( $context_root, );
147 179         10639 my $_art_url = $uri->canonical()->as_string();
148 179         19267 $_art_url =~ s{\/$}{}xi;
149 179         6539 $self->_set_art_url($_art_url);
150              
151 179         565 $uri->path_segments( $context_root, 'api' );
152 179         10754 $self->_set_api_url( $uri->canonical()->as_string() );
153              
154             # Save Repository
155 179         4916 my $repo = $self->repository;
156 179         383 $repo =~ s{^\/}{}xi;
157 179         303 $repo =~ s{\/$}{}xi;
158 179         5783 $self->_set_repository($repo);
159              
160 179         4924 return 1;
161             }
162              
163             =head1 GENERIC METHODS
164              
165             =cut
166              
167             =head2 get( @args )
168              
169             Invokes GET request on LWP::UserAgent-like object; params are passed through.
170              
171             =cut
172              
173             sub get {
174 81     81 1 1437 my ( $self, @args ) = @_;
175 81         216 return $self->_request( 'get', @args );
176             }
177              
178             =head2 post( @args )
179              
180             nvokes POST request on LWP::UserAgent-like object; params are passed through.
181              
182             =cut
183              
184             sub post {
185 70     70 1 208 my ( $self, @args ) = @_;
186 70         192 return $self->_request( 'post', @args );
187             }
188              
189             =head2 put( @args )
190              
191             Invokes PUT request on LWP::UserAgent-like object; params are passed through.
192              
193             =cut
194              
195             sub put {
196 14     14 1 50 my ( $self, @args ) = @_;
197 14         42 return $self->_request( 'put', @args );
198             }
199              
200             =head2 delete( @args )
201              
202             Invokes DELETE request on LWP::UserAgent-like object; params are passed
203             through.
204              
205             =cut
206              
207             sub delete {
208 15     15 1 44 my ( $self, @args ) = @_;
209 15         46 return $self->_request( 'delete', @args );
210             }
211              
212             =head2 request( @args )
213              
214             Invokes request() on LWP::UserAgent-like object; params are passed through.
215              
216             =cut
217              
218             sub request {
219 6     6 1 165 my ( $self, @args ) = @_;
220 6         22 return $self->_request( 'request', @args );
221             }
222              
223             =head1 BUILDS
224              
225             =cut
226              
227             =head2 all_builds
228              
229             Retrieves information on all builds from artifactory.
230              
231             =cut
232              
233             sub all_builds {
234 1     1 1 16 my $self = shift;
235 1         4 return $self->_get_build('');
236             }
237              
238             =head2 build_runs( $build_name )
239              
240             Retrieves information of a particular build from artifactory.
241              
242             =cut
243              
244             sub build_runs {
245 1     1 1 16 my ( $self, $build ) = @_;
246 1         5 return $self->_get_build($build);
247             }
248              
249             =head2 build_upload( $path_to_json )
250              
251             Upload Build
252              
253             =cut
254              
255             sub build_upload {
256 1     1 1 20 my ( $self, $json_file ) = @_;
257              
258 1         80 open( my $fh, '<', $json_file );
259 1         29 chomp( my @lines = <$fh> );
260 1         6 my $json_input = join( "", @lines );
261 1         38 my $data = $self->_json->decode($json_input);
262 1         28 my $url = $self->_api_url() . "/build";
263 1         28 return $self->put(
264             $url,
265             "Content-Type" => 'application/json',
266             Content => $self->_json->encode($data)
267             );
268             }
269              
270             =head2 build_info( $build_name, $build_number )
271              
272             Retrieves information of a particular build number.
273              
274             =cut
275              
276             sub build_info {
277 1     1 1 18 my ( $self, $build, $number ) = @_;
278 1         6 return $self->_get_build("$build/$number");
279             }
280              
281             =head2 builds_diff( $build_name, $new_build_number, $old_build_number )
282              
283             Retrieves diff of 2 builds
284              
285             =cut
286              
287             sub builds_diff {
288 1     1 1 17 my ( $self, $build, $new, $old ) = @_;
289 1         8 return $self->_get_build("$build/$new?diff=$old");
290             }
291              
292             =head2 build_promotion( $build_name, $build_number, $payload )
293              
294             Promotes a build by POSTing payload
295              
296             =cut
297              
298             sub build_promotion {
299 1     1 1 20 my ( $self, $build, $number, $payload ) = @_;
300              
301 1         29 my $url = $self->_api_url() . "/build/promote/$build/$number";
302 1         28 return $self->post(
303             $url,
304             "Content-Type" => 'application/json',
305             Content => $self->_json->encode($payload)
306             );
307             }
308              
309             =head2 promote_docker_image( targetRepo => "target_repo", dockerRepository => "dockerRepository", tag => "tag", copy => 'false' )
310              
311             Promotes a Docker image from one repository to another
312              
313             =cut
314              
315             sub promote_docker_image {
316 1     1 1 24 my ( $self, %args ) = @_;
317              
318 1   33     33 my $repo = $args{repository} || $self->repository();
319 1         28 my $url = $self->_api_url() . "/docker/$repo/v2/promote";
320 1         27 return $self->post(
321             $url,
322             "Content-Type" => 'application/json',
323             Content => $self->_json->encode( \%args )
324             );
325             }
326              
327             =head2 delete_builds( name => $build_name, buildnumbers => [ buildnumbers ], artifacts => 0,1, deleteall => 0,1 )
328              
329             Removes builds stored in Artifactory. Useful for cleaning up old build info data
330              
331             =cut
332              
333             sub delete_builds {
334 1     1 1 22 my ( $self, %args ) = @_;
335 1         3 my $build = $args{name};
336 1         2 my $buildnumbers = $args{buildnumbers};
337 1         3 my $artifacts = $args{artifacts};
338 1         3 my $deleteall = $args{deleteall};
339              
340 1         29 my $url = $self->_api_url() . "/build/$build";
341 1         5 my @params = $self->_gather_delete_builds_params( $buildnumbers, $artifacts, $deleteall );
342              
343 1 50       5 if (@params) {
344 1         3 $url .= "?";
345 1         3 $url .= join( "&", @params );
346             }
347 1         4 return $self->delete($url);
348             }
349              
350             =head2 build_rename( $build_name, $new_build_name )
351              
352             Renames a build
353              
354             =cut
355              
356             sub build_rename {
357 1     1 1 49 my ( $self, $build, $new_build ) = @_;
358              
359 1         46 my $url = $self->_api_url() . "/build/rename/$build?to=$new_build";
360 1         5 return $self->post($url);
361             }
362              
363             =head2 distribute_build( 'build_name', $build_number, %hash_of_json_payload )
364              
365             Deploys builds from Artifactory to Bintray, and creates an entry in the corresponding Artifactory distribution
366             repository specified.
367              
368             =cut
369              
370             sub distribute_build {
371 1     1 1 21 my ( $self, $build_name, $build_number, %args ) = @_;
372              
373 1         29 my $url = $self->_api_url() . "/build/distribute/$build_name/$build_number";
374 1         29 return $self->post(
375             $url,
376             'Content-Type' => 'application/json',
377             content => $self->_json->encode( \%args )
378             );
379             }
380              
381             =head2 control_build_retention( 'build_name', deleteBuildArtifacts => 'true', count => 100, ... )
382              
383             Specifies retention parameters for build info.
384              
385             =cut
386              
387             sub control_build_retention {
388 1     1 1 26 my ( $self, $build_name, %args ) = @_;
389              
390 1         30 my $url = $self->_api_url() . "/build/retention/$build_name";
391 1         28 return $self->post(
392             $url,
393             'Content-Type' => 'application/json',
394             content => $self->_json->encode( \%args )
395             );
396             }
397              
398             =head1 ARTIFACTS & STORAGE
399              
400             =cut
401              
402             =head2 folder_info( $path )
403              
404             Returns folder info
405              
406             =cut
407              
408             sub folder_info {
409 2     2 1 19 my ( $self, $path ) = @_;
410              
411 2         6 $path = $self->_merge_repo_and_path($path);
412 2         53 my $url = $self->_api_url() . "/storage/$path";
413              
414 2         7 return $self->get($url);
415             }
416              
417             =head2 file_info( $path )
418              
419             Returns file info
420              
421             =cut
422              
423             sub file_info {
424 1     1 1 18 my ( $self, $path ) = @_;
425 1         4 return $self->folder_info($path); # should be OK to do this
426             }
427              
428             =head2 get_storage_summary_info
429              
430             Returns storage summary information regarding binaries, file store and repositories
431              
432             =cut
433              
434             sub get_storage_summary_info {
435 1     1 1 17 my $self = shift;
436 1         29 my $url = $self->_api_url() . '/storageinfo';
437 1         4 return $self->get($url);
438             }
439              
440             =head2 item_last_modified( $path )
441              
442             Returns item_last_modified for a given path
443              
444             =cut
445              
446             sub item_last_modified {
447 1     1 1 18 my ( $self, $path ) = @_;
448 1         5 $path = $self->_merge_repo_and_path($path);
449 1         28 my $url = $self->_api_url() . "/storage/$path?lastModified";
450 1         3 return $self->get($url);
451             }
452              
453             =head2 file_statistics( $path )
454              
455             Returns file_statistics for a given path
456              
457             =cut
458              
459             sub file_statistics {
460 1     1 1 21 my ( $self, $path ) = @_;
461 1         5 $path = $self->_merge_repo_and_path($path);
462 1         28 my $url = $self->_api_url() . "/storage/$path?stats";
463 1         4 return $self->get($url);
464             }
465              
466             =head2 item_properties( path => $path, properties => [ key_names ] )
467              
468             Takes path and properties then get item properties.
469              
470             =cut
471              
472             sub item_properties {
473 2     2 1 754 my ( $self, %args ) = @_;
474              
475 2         5 my $path = $args{path};
476 2         5 my $properties = $args{properties};
477              
478 2         6 $path = $self->_merge_repo_and_path($path);
479 2         57 my $url = $self->_api_url() . "/storage/$path?properties";
480              
481 2 100       14 if ( ref($properties) eq 'ARRAY' ) {
482 1         2 my $str = join( ',', @{$properties} );
  1         3  
483 1         3 $url .= "=" . $str;
484             }
485 2         6 return $self->get($url);
486             }
487              
488             =head2 set_item_properties( path => $path, properties => { key => [ values ] }, recursive => 0,1 )
489              
490             Takes path and properties then set item properties. Supply recursive => 0 if you want to suppress propagation of
491             properties downstream. Note that properties are a hashref with key-arrayref pairs, such as:
492              
493             $prop = { key1 => ['a'], key2 => ['a', 'b'] }
494              
495             =cut
496              
497             sub set_item_properties {
498 1     1 1 25 my ( $self, %args ) = @_;
499              
500 1         3 my $path = $args{path};
501 1         2 my $properties = $args{properties};
502 1         3 my $recursive = $args{recursive};
503              
504 1         3 $path = $self->_merge_repo_and_path($path);
505 1         28 my $url = $self->_api_url() . "/storage/$path?properties=";
506              
507 1         5 my $request = $url . $self->_attach_properties( properties => $properties );
508 1 50       4 $request .= "&recursive=$recursive" if ( defined $recursive );
509 1         4 return $self->put($request);
510             }
511              
512             =head2 delete_item_properties( path => $path, properties => [ key_names ], recursive => 0,1 )
513              
514             Takes path and properties then delete item properties. Supply recursive => 0 if you want to suppress propagation of
515             properties downstream.
516              
517             =cut
518              
519             sub delete_item_properties {
520 1     1 1 20 my ( $self, %args ) = @_;
521              
522 1         3 my $path = $args{path};
523 1         3 my $properties = $args{properties};
524 1         2 my $recursive = $args{recursive};
525              
526 1         4 $path = $self->_merge_repo_and_path($path);
527 1         31 my $url = $self->_api_url() . "/storage/$path?properties=" . join( ",", @{$properties} );
  1         5  
528 1 50       6 $url .= "&recursive=$recursive" if ( defined $recursive );
529 1         6 return $self->delete($url);
530             }
531              
532             =head2 set_item_sha256_checksum( repoKey => 'foo', path => 'bar' )
533              
534             Calculates an artifact's SHA256 checksum and attaches it as a property (with key "sha256"). If the artifact is a folder,
535             then recursively calculates the SHA256 of each item in the folder and attaches the property to each item.
536              
537             =cut
538              
539             sub set_item_sha256_checksum {
540 1     1 1 25 my ( $self, %args ) = @_;
541 1         30 my $url = $self->_api_url() . '/checksum/sha256';
542 1         65 return $self->post(
543             $url,
544             "Content-Type" => 'application/json',
545             Content => $self->_json->encode( \%args )
546             );
547             }
548              
549             =head2 retrieve_artifact( $path, $filename )
550              
551             Takes path and retrieves artifact on the path. If $filename is given, artifact content goes into the $filename rather
552             than the HTTP::Response object.
553              
554             =cut
555              
556             sub retrieve_artifact {
557 1     1 1 17 my ( $self, $path, $filename ) = @_;
558 1         4 $path = $self->_merge_repo_and_path($path);
559 1         28 my $url = $self->_art_url() . "/$path";
560 1 50       5 return ($filename)
561             ? $self->get( $url, ":content_file" => $filename )
562             : $self->get($url);
563             }
564              
565             =head2 retrieve_latest_artifact( path => $path, version => $version, release => $release, integration => $integration,
566             flag => 'snapshot', 'release', 'integration' )
567              
568             Takes path, version, flag of 'snapshot', 'release' or 'integration' and retrieves artifact
569              
570             =cut
571              
572             sub retrieve_latest_artifact {
573 3     3 1 1556 my ( $self, %args ) = @_;
574              
575 3         8 my $path = $args{path};
576 3         7 my $version = $args{version};
577 3         6 my $release = $args{release};
578 3         7 my $integration = $args{integration};
579 3         4 my $flag = $args{flag};
580 3         9 $path = $self->_merge_repo_and_path($path);
581              
582 3         83 my $base_url = $self->_art_url() . "/$path";
583 3         109 my $basename = basename($path);
584 3         7 my $url;
585 3 100 100     20 $url = "$base_url/$version-SNAPSHOT/$basename-$version-SNAPSHOT.jar" if ( $version && $flag eq 'snapshot' );
586 3 100       10 $url = "$base_url/$release/$basename-$release.jar" if ( $flag eq 'release' );
587 3 100 100     16 $url = "$base_url/$version-$integration/$basename-$version-$integration.jar"
588             if ( $version && $flag eq 'integration' );
589 3         9 return $self->get($url);
590             }
591              
592             =head2 retrieve_build_artifacts_archive( $payload )
593              
594             Takes payload (hashref) then retrieve build artifacts archive.
595              
596             =cut
597              
598             sub retrieve_build_artifacts_archive {
599 1     1 1 20 my ( $self, $payload ) = @_;
600              
601 1         30 my $url = $self->_api_url() . "/archive/buildArtifacts";
602 1         28 return $self->post(
603             $url,
604             "Content-Type" => 'application/json',
605             Content => $self->_json->encode($payload)
606             );
607             }
608              
609             =head2 retrieve_folder_or_repository_archive( path => '/foobar', archiveType => 'zip' )
610              
611             Retrieves an archive file (supports zip/tar/tar.gz/tgz) containing all the artifacts that reside under the specified
612             path (folder or repository root). Requires Enable Folder Download to be set.
613              
614             =cut
615              
616             sub retrieve_folder_or_repository_archive {
617 1     1 1 22 my ( $self, %args ) = @_;
618 1         3 my $path = delete $args{path};
619 1         30 my $url = $self->_api_url() . '/archive/download' . $path . '?' . $self->_stringify_hash( '', %args );
620 1         4 return $self->get($url);
621             }
622              
623             =head2 trace_artifact_retrieval( $path )
624              
625             Takes path and traces artifact retrieval
626              
627             =cut
628              
629             sub trace_artifact_retrieval {
630 1     1 1 17 my ( $self, $path ) = @_;
631 1         5 $path = $self->_merge_repo_and_path($path);
632 1         29 my $url = $self->_art_url() . "/$path?trace";
633 1         4 return $self->get($url);
634             }
635              
636             =head2 archive_entry_download( $path, $archive_path )
637              
638             Takes path and archive_path, retrieves an archived resource from the specified archive destination.
639              
640             =cut
641              
642             sub archive_entry_download {
643 1     1 1 21 my ( $self, $path, $archive_path ) = @_;
644 1         4 $path = $self->_merge_repo_and_path($path);
645 1         29 my $url = $self->_art_url() . "/$path!$archive_path";
646 1         4 return $self->get($url);
647             }
648              
649             =head2 create_directory( path => $path, properties => { key => [ values ] } )
650              
651             Takes path, properties then create a directory. Directory needs to end with a /, such as "/some_dir/".
652              
653             =cut
654              
655             sub create_directory {
656 1     1 1 26 my ( $self, %args ) = @_;
657 1         5 return $self->deploy_artifact(%args);
658             }
659              
660             =head2 deploy_artifact( path => $path, properties => { key => [ values ] }, file => $file )
661              
662             Takes path on Artifactory, properties and filename then deploys the file. Note that properties are a hashref with
663             key-arrayref pairs, such as:
664              
665             $prop = { key1 => ['a'], key2 => ['a', 'b'] }
666              
667             =cut
668              
669             sub deploy_artifact {
670 5     5 1 45 my ( $self, %args ) = @_;
671              
672 5         14 my $path = $args{path};
673 5         10 my $properties = $args{properties};
674 5         11 my $file = $args{file};
675 5         10 my $header = $args{header};
676              
677 5         18 $path = $self->_merge_repo_and_path($path);
678 5         147 my @joiners = ( $self->_art_url() . "/$path" );
679 5         23 my $props = $self->_attach_properties( properties => $properties, matrix => 1 );
680 5 100       15 push @joiners, $props if ($props); # if properties aren't passed in, the function returns empty string
681              
682 5         13 my $url = join( ";", @joiners );
683             my $req = HTTP::Request::StreamingUpload->new(
684             PUT => $url,
685 5 100       10 headers => HTTP::Headers->new( %{$header} ),
  5         34  
686             ( $file ? ( fh => Path::Tiny::path($file)->openr_raw() ) : () ),
687             );
688 5         2259 return $self->request($req);
689             }
690              
691             =head2 deploy_artifact_by_checksum( path => $path, properties => { key => [ values ] }, file => $file, sha1 => $sha1 )
692              
693             Takes path, properties, filename and sha1 then deploys the file. Note that properties are a hashref with key-arrayref
694             pairs, such as:
695              
696             $prop = { key1 => ['a'], key2 => ['a', 'b'] }
697              
698             =cut
699              
700             sub deploy_artifact_by_checksum {
701 2     2 1 1623 my ( $self, %args ) = @_;
702              
703 2         5 my $sha1 = $args{sha1};
704 2         7 my $header = {
705             'X-Checksum-Deploy' => 'true',
706             'X-Checksum-Sha1' => $sha1,
707             };
708 2         6 $args{header} = $header;
709 2         9 return $self->deploy_artifact(%args);
710             }
711              
712             =head2 deploy_artifacts_from_archive( path => $path, file => $file )
713              
714             Path is the path on Artifactory, file is path to local archive. Will deploy $file to $path.
715              
716             =cut
717              
718             sub deploy_artifacts_from_archive {
719 1     1 1 40 my ( $self, %args ) = @_;
720              
721 1         5 my $header = { 'X-Explode-Archive' => 'true', };
722 1         4 $args{header} = $header;
723 1         6 return $self->deploy_artifact(%args);
724             }
725              
726             =head2 push_a_set_of_artifacts_to_bintray( descriptor => 'foo', gpgPassphrase => 'top_secret', gpgSign => 'true' )
727              
728             Push a set of artifacts to Bintray as a version. Uses a descriptor file (that must have 'bintray-info' in it's filename
729             and a .json extension) that was deployed to artifactory, the call accepts the full path to the descriptor as a
730             parameter.
731              
732             =cut
733              
734             sub push_a_set_of_artifacts_to_bintray {
735 1     1 1 29 my ( $self, %args ) = @_;
736              
737 1         33 my $url = $self->_api_url() . "/bintray/push";
738 1         7 my $params = $self->_stringify_hash( '&', %args );
739 1 50       6 $url .= "?" . $params if ($params);
740 1         7 return $self->post($url);
741             }
742              
743             =head2 push_docker_tag_to_bintray( dockerImage => 'jfrog/ubuntu:latest', async => 'true', ... )
744              
745             Push Docker tag to Bintray. Calculation can be synchronous (the default) or asynchronous. You will need to enter your
746             Bintray credentials, for more details, please refer to Entering your Bintray credentials.
747              
748             =cut
749              
750             sub push_docker_tag_to_bintray {
751 1     1 1 24 my ( $self, %args ) = @_;
752              
753 1         30 my $url = $self->_api_url() . '/bintray/docker/push/' . $self->repository();
754 1         27 return $self->post(
755             $url,
756             "Content-Type" => 'application/json',
757             Content => $self->_json->encode( \%args )
758             );
759             }
760              
761             =head2 distribute_artifact( publish => 'true', async => 'false' )
762              
763             Deploys artifacts from Artifactory to Bintray, and creates an entry in the corresponding Artifactory distribution
764             repository specified
765              
766             =cut
767              
768             sub distribute_artifact {
769 1     1 1 25 my ( $self, %args ) = @_;
770              
771 1         32 my $url = $self->_api_url() . '/distribute';
772 1         29 return $self->post(
773             $url,
774             "Content-Type" => 'application/json',
775             Content => $self->_json->encode( \%args )
776             );
777             }
778              
779             =head2 file_compliance_info( $path )
780              
781             Retrieves file compliance info of a given path.
782              
783             =cut
784              
785             sub file_compliance_info {
786 1     1 1 59 my ( $self, $path ) = @_;
787 1         6 $path = $self->_merge_repo_and_path($path);
788 1         29 my $url = $self->_api_url() . "/compliance/$path";
789 1         5 return $self->get($url);
790             }
791              
792             =head2 delete_item( $path )
793              
794             Delete $path on artifactory.
795              
796             =cut
797              
798             sub delete_item {
799 1     1 1 18 my ( $self, $path ) = @_;
800 1         4 $path = $self->_merge_repo_and_path($path);
801 1         28 my $url = $self->_art_url() . "/$path";
802 1         5 return $self->delete($url);
803             }
804              
805             =head2 copy_item( from => $from, to => $to, dry => 1, suppressLayouts => 0/1, failFast => 0/1 )
806              
807             Copies an artifact from $from to $to. Note that for this particular API call, the $from and $to must include repository
808             names as copy source and destination may be different repositories. You can also supply dry, suppressLayouts and
809             failFast values as specified in the documentation.
810              
811             =cut
812              
813             sub copy_item {
814 1     1 1 22 my ( $self, %args ) = @_;
815 1         3 $args{method} = 'copy';
816 1         6 return $self->_handle_item(%args);
817             }
818              
819             =head2 move_item( from => $from, to => $to, dry => 1, suppressLayouts => 0/1, failFast => 0/1 )
820              
821             Moves an artifact from $from to $to. Note that for this particular API call, the $from and $to must include repository
822             names as copy source and destination may be different repositories. You can also supply dry, suppressLayouts and
823             failFast values as specified in the documentation.
824              
825             =cut
826              
827             sub move_item {
828 1     1 1 18 my ( $self, %args ) = @_;
829 1         3 $args{method} = 'move';
830 1         5 return $self->_handle_item(%args);
831             }
832              
833             =head2 get_repository_replication_configuration
834              
835             Get repository replication configuration
836              
837             =cut
838              
839             sub get_repository_replication_configuration {
840 1     1 1 17 my $self = shift;
841 1         6 return $self->_handle_repository_replication_configuration('get');
842             }
843              
844             =head2 set_repository_replication_configuration( $payload )
845              
846             Set repository replication configuration
847              
848             =cut
849              
850             sub set_repository_replication_configuration {
851 1     1 1 24 my ( $self, $payload ) = @_;
852 1         6 return $self->_handle_repository_replication_configuration( 'put', $payload );
853             }
854              
855             =head2 update_repository_replication_configuration( $payload )
856              
857             Update repository replication configuration
858              
859             =cut
860              
861             sub update_repository_replication_configuration {
862 1     1 1 19 my ( $self, $payload ) = @_;
863 1         4 return $self->_handle_repository_replication_configuration( 'post', $payload );
864             }
865              
866             =head2 delete_repository_replication_configuration
867              
868             Delete repository replication configuration
869              
870             =cut
871              
872             sub delete_repository_replication_configuration {
873 0     0 1 0 my $self = shift;
874 0         0 return $self->_handle_repository_replication_configuration('delete');
875             }
876              
877             =head2 scheduled_replication_status
878              
879             Gets scheduled replication status of a repository
880              
881             =cut
882              
883             sub scheduled_replication_status {
884 1     1 1 18 my ( $self, %args ) = @_;
885 1   33     31 my $repository = $args{repository} || $self->repository();
886 1         29 my $url = $self->_api_url() . "/replication/$repository";
887 1         5 return $self->get($url);
888             }
889              
890             =head2 pull_push_replication( payload => $payload, path => $path )
891              
892             Schedules immediate content replication between two Artifactory instances
893              
894             =cut
895              
896             sub pull_push_replication {
897 1     1 1 22 my ( $self, %args ) = @_;
898 1         3 my $payload = $args{payload};
899 1         3 my $path = $args{path};
900 1         4 $path = $self->_merge_repo_and_path($path);
901 1         29 my $url = $self->_api_url() . "/replication/execute/$path";
902 1         29 return $self->post(
903             $url,
904             "Content-Type" => 'application/json',
905             Content => $self->_json->encode($payload)
906             );
907             }
908              
909             =head2 create_or_replace_local_multi_push_replication( $payload )
910              
911             Creates or replaces a local multi-push replication configuration. Supported by local and local-cached repositories
912              
913             =cut
914              
915             sub create_or_replace_local_multi_push_replication {
916 1     1 1 20 my ( $self, $payload ) = @_;
917 1         5 return $self->_handle_multi_push_replication( $payload, 'put' );
918             }
919              
920             =head2 update_local_multi_push_replication( $payload )
921              
922             Updates a local multi-push replication configuration. Supported by local and local-cached repositories
923              
924             =cut
925              
926             sub update_local_multi_push_replication {
927 1     1 1 20 my ( $self, $payload ) = @_;
928 1         17 return $self->_handle_multi_push_replication( $payload, 'post' );
929             }
930              
931             =head2 delete_local_multi_push_replication( $url )
932              
933             Deletes a local multi-push replication configuration. Supported by local and local-cached repositories
934              
935             =cut
936              
937             sub delete_local_multi_push_replication {
938 1     1 1 20 my ( $self, $url, %args ) = @_;
939 1   33     32 my $repository = $args{repository} || $self->repository();
940 1         28 my $call_url = $self->_api_url() . "/replications/$repository?url=$url";
941 1         4 return $self->delete($call_url);
942             }
943              
944             =head2 enable_or_disable_multiple_replications( 'enable|disable', include => [ ], exclude => [ ] )
945              
946             Enables/disables multiple replication tasks by repository or Artifactory server based in include and exclude patterns.
947              
948             =cut
949              
950             sub enable_or_disable_multiple_replications {
951 1     1 1 25 my ( $self, $flag, %args ) = @_;
952 1         31 my $url = $self->_api_url() . "/replications/$flag";
953 1         28 return $self->post(
954             $url,
955             "Content-Type" => 'application/json',
956             Content => $self->_json->encode( \%args )
957             );
958             }
959              
960             =head2 get_global_system_replication_configuration
961              
962             Returns the global system replication configuration status, i.e. if push and pull replications are blocked or unblocked.
963              
964             =cut
965              
966             sub get_global_system_replication_configuration {
967 1     1 1 17 my $self = shift;
968 1         30 my $url = $self->_api_url() . "/system/replications";
969 1         5 return $self->get($url);
970             }
971              
972             =head2 get_remote_repositories_registered_for_replication
973              
974             Returns a list of all the listeners subscribed for event-based pull replication on the specified repository.
975              
976             =cut
977              
978             sub get_remote_repositories_registered_for_replication {
979 1     1 1 18 my ( $self, $repo ) = @_;
980 1   33     4 my $repository = $repo || $self->repository();
981              
982 1         29 my $url = $self->_api_url() . "/replications/$repository";
983 1         4 return $self->get($url);
984             }
985              
986             =head2 block_system_replication( push => 'false', pull => 'true' )
987              
988             Blocks replications globally. Push and pull are true by default. If false, replication for the corresponding type is not
989             blocked.
990              
991             =cut
992              
993             sub block_system_replication {
994 1     1 1 24 my ( $self, %args ) = @_;
995 1         5 return $self->_handle_block_system_replication( 'block', %args );
996             }
997              
998             =head2 unblock_system_replication( push => 'false', pull => 'true' )
999              
1000             Unblocks replications globally. Push and pull are true by default. If false, replication for the corresponding type is
1001             not unblocked.
1002              
1003             =cut
1004              
1005             sub unblock_system_replication {
1006 1     1 1 22 my ( $self, %args ) = @_;
1007 1         4 return $self->_handle_block_system_replication( 'unblock', %args );
1008             }
1009              
1010             =head2 artifact_sync_download( $path, content => 'progress', mark => 1000 )
1011              
1012             Downloads an artifact with or without returning the actual content to the client. When tracking the progress marks are
1013             printed (by default every 1024 bytes). This is extremely useful if you want to trigger downloads on a remote Artifactory
1014             server, for example to force eager cache population of large artifacts, but want to avoid the bandwidth consumption
1015             involved in transferring the artifacts to the triggering client. If no content parameter is specified the file content
1016             is downloaded to the client.
1017              
1018             =cut
1019              
1020             sub artifact_sync_download {
1021 1     1 1 24 my ( $self, $path, %args ) = @_;
1022 1   33     32 my $repository = $args{repository} || $self->repository();
1023 1         28 my $url = $self->_api_url() . "/download/$repository" . $path;
1024 1 50       7 $url .= "?" . $self->_stringify_hash( '&', %args ) if (%args);
1025 1         5 return $self->get($url);
1026             }
1027              
1028             =head2 file_list( $dir, %opts )
1029              
1030             Get a flat (the default) or deep listing of the files and folders (not included by default) within a folder
1031              
1032             =cut
1033              
1034             sub file_list {
1035 1     1 1 24 my ( $self, $dir, %opts ) = @_;
1036 1         6 $dir = $self->_merge_repo_and_path($dir);
1037 1         28 my $url = $self->_api_url() . "/storage/$dir?list";
1038              
1039 1         5 for my $opt ( keys %opts ) {
1040 5         8 my $val = $opts{$opt};
1041 5         13 $url .= "&${opt}=$val";
1042             }
1043 1         4 return $self->get($url);
1044             }
1045              
1046             =head2 get_background_tasks
1047              
1048             Retrieves list of background tasks currently scheduled or running in Artifactory. In HA, the nodeId is added to each
1049             task. Task can be in one of few states: scheduled, running, stopped, canceled. Running task also shows the task start
1050             time.
1051              
1052             =cut
1053              
1054             sub get_background_tasks {
1055 1     1 1 16 my $self = shift;
1056 1         29 my $url = $self->_api_url() . "/tasks";
1057 1         4 return $self->get($url);
1058             }
1059              
1060             =head2 empty_trash_can
1061              
1062             Empties the trash can permanently deleting all its current contents.
1063              
1064             =cut
1065              
1066             sub empty_trash_can {
1067 1     1 1 16 my $self = shift;
1068 1         30 my $url = $self->_api_url() . "/trash/empty";
1069 1         4 return $self->post($url);
1070             }
1071              
1072             =head2 delete_item_from_trash_can($path)
1073              
1074             Permanently deletes an item from the trash can.
1075              
1076             =cut
1077              
1078             sub delete_item_from_trash_can {
1079 1     1 1 18 my ( $self, $path ) = @_;
1080 1         29 my $url = $self->_api_url() . "/trash/$path";
1081 1         5 return $self->delete($url);
1082             }
1083              
1084             =head2 restore_item_from_trash_can( $from, $to )
1085              
1086             Restore an item from the trash can.
1087              
1088             =cut
1089              
1090             sub restore_item_from_trash_can {
1091 1     1 1 17 my ( $self, $from, $to ) = @_;
1092 1         30 my $url = $self->_api_url() . "/trash/restore/$from?to=$to";
1093 1         4 return $self->post($url);
1094             }
1095              
1096             =head2 optimize_system_storage
1097              
1098             Raises a flag to invoke balancing between redundant storage units of a sharded filestore following the next garbage
1099             collection.
1100              
1101             =cut
1102              
1103             sub optimize_system_storage {
1104 1     1 1 16 my $self = shift;
1105 1         29 my $url = $self->_api_url() . "/system/storage/optimize";
1106 1         5 return $self->post($url);
1107             }
1108              
1109             =head1 SEARCHES
1110              
1111             =cut
1112              
1113             =head2 artifactory_query_language( $aql_statement )
1114              
1115             Flexible and high performance search using Artifactory Query Language (AQL).
1116              
1117             =cut
1118              
1119             sub artifactory_query_language {
1120 1     1 1 20 my ( $self, $aql ) = @_;
1121              
1122 1         30 my $url = $self->_api_url() . "/search/aql";
1123 1         5 return $self->post(
1124             $url,
1125             "Content-Type" => 'text/plain',
1126             Content => $aql
1127             );
1128             }
1129              
1130             =head2 artifact_search( name => $name, repos => [ @repos ], result_detail => [qw(info properties)], )
1131              
1132             Artifact search by part of file name
1133              
1134             =cut
1135              
1136             sub artifact_search {
1137 1     1 1 21 my ( $self, %args ) = @_;
1138 1         5 return $self->_handle_search( 'artifact', %args );
1139             }
1140              
1141             =head2 archive_entry_search( name => $name, repos => [ @repos ] )
1142              
1143             Search archive entries for classes or any other jar resources
1144              
1145             =cut
1146              
1147             sub archive_entry_search {
1148 1     1 1 21 my ( $self, %args ) = @_;
1149 1         5 return $self->_handle_search( 'archive', %args );
1150             }
1151              
1152             =head2 gavc_search( g => 'foo', c => 'bar', result_detail => [qw(info properties)], )
1153              
1154             Search by Maven coordinates: groupId, artifactId, version & classifier
1155              
1156             =cut
1157              
1158             sub gavc_search {
1159 1     1 1 28 my ( $self, %args ) = @_;
1160 1         6 return $self->_handle_search_props( 'gavc', %args );
1161             }
1162              
1163             =head2 property_search( p => [ 'v1', 'v2' ], repos => [ 'repo1', 'repo2' ], result_detail => [qw(info properties)], )
1164              
1165             Search by properties
1166              
1167             =cut
1168              
1169             sub property_search {
1170 1     1 1 23 my ( $self, %args ) = @_;
1171 1         4 return $self->_handle_search_props( 'prop', %args );
1172             }
1173              
1174             =head2 checksum_search( md5 => '12345', repos => [ 'repo1', 'repo2' ], result_detail => [qw(info properties)], )
1175              
1176             Artifact search by checksum (md5 or sha1)
1177              
1178             =cut
1179              
1180             sub checksum_search {
1181 1     1 1 36 my ( $self, %args ) = @_;
1182 1         6 return $self->_handle_search_props( 'checksum', %args );
1183             }
1184              
1185             =head2 bad_checksum_search( type => 'md5', repos => [ 'repo1', 'repo2' ] )
1186              
1187             Find all artifacts that have a bad or missing client checksum values (md5 or
1188             sha1)
1189              
1190             =cut
1191              
1192             sub bad_checksum_search {
1193 1     1 1 35 my ( $self, %args ) = @_;
1194 1         5 return $self->_handle_search_props( 'badChecksum', %args );
1195             }
1196              
1197             =head2 artifacts_not_downloaded_since( notUsedSince => 12345, createdBefore => 12345, repos => [ 'repo1', 'repo2' ] )
1198              
1199             Retrieve all artifacts not downloaded since the specified Java epoch in msec.
1200              
1201             =cut
1202              
1203             sub artifacts_not_downloaded_since {
1204 1     1 1 22 my ( $self, %args ) = @_;
1205 1         19 return $self->_handle_search_props( 'usage', %args );
1206             }
1207              
1208             =head2 artifacts_with_date_in_date_range( from => 12345, repos => [ 'repo1', 'repo2' ], dateFields => [ 'created' ] )
1209              
1210             Get all artifacts with specified dates within the given range. Search can be limited to specific repositories (local or
1211             caches).
1212              
1213             =cut
1214              
1215             sub artifacts_with_date_in_date_range {
1216 1     1 1 39 my ( $self, %args ) = @_;
1217 1         5 return $self->_handle_search_props( 'dates', %args );
1218             }
1219              
1220             =head2 artifacts_created_in_date_range( from => 12345, to => 12345, repos => [ 'repo1', 'repo2' ] )
1221              
1222             Get all artifacts created in date range
1223              
1224             =cut
1225              
1226             sub artifacts_created_in_date_range {
1227 1     1 1 23 my ( $self, %args ) = @_;
1228 1         5 return $self->_handle_search_props( 'creation', %args );
1229             }
1230              
1231             =head2 pattern_search( $pattern )
1232              
1233             Get all artifacts matching the given Ant path pattern
1234              
1235             =cut
1236              
1237             sub pattern_search {
1238 1     1 1 31 my ( $self, $pattern, %args ) = @_;
1239 1   33     33 my $repository = $args{repository} || $self->repository();
1240 1         27 my $url = $self->_api_url() . "/search/pattern?pattern=$repository:$pattern";
1241 1         5 return $self->get($url);
1242             }
1243              
1244             =head2 builds_for_dependency( sha1 => 'abcde' )
1245              
1246             Find all the builds an artifact is a dependency of (where the artifact is included in the build-info dependencies)
1247              
1248             =cut
1249              
1250             sub builds_for_dependency {
1251 1     1 1 21 my ( $self, %args ) = @_;
1252 1         6 return $self->_handle_search_props( 'dependency', %args );
1253             }
1254              
1255             =head2 license_search( unapproved => 1, unknown => 1, notfound => 0, neutral => 0, repos => [ 'foo', 'bar' ] )
1256              
1257             Search for artifacts with specified statuses
1258              
1259             =cut
1260              
1261             sub license_search {
1262 1     1 1 27 my ( $self, %args ) = @_;
1263 1         5 return $self->_handle_search_props( 'license', %args );
1264             }
1265              
1266             =head2 artifact_version_search( g => 'foo', a => 'bar', v => '1.0', repos => [ 'foo', 'bar' ] )
1267              
1268             Search for all available artifact versions by GroupId and ArtifactId in local, remote or virtual repositories
1269              
1270             =cut
1271              
1272             sub artifact_version_search {
1273 1     1 1 40 my ( $self, %args ) = @_;
1274 1         5 return $self->_handle_search_props( 'versions', %args );
1275             }
1276              
1277             =head2 artifact_latest_version_search_based_on_layout( g => 'foo', a => 'bar', v => '1.0', repos => [ 'foo', 'bar' ] )
1278              
1279             Search for the latest artifact version by groupId and artifactId, based on the layout defined in the repository
1280              
1281             =cut
1282              
1283             sub artifact_latest_version_search_based_on_layout {
1284 1     1 1 25 my ( $self, %args ) = @_;
1285 1         6 return $self->_handle_search_props( 'latestVersion', %args );
1286             }
1287              
1288             =head2 artifact_latest_version_search_based_on_properties( repo => '_any', path => '/a/b', listFiles => 1 )
1289              
1290             Search for artifacts with the latest value in the "version" property
1291              
1292             =cut
1293              
1294             sub artifact_latest_version_search_based_on_properties {
1295 1     1 1 23 my ( $self, %args ) = @_;
1296 1         4 my $repo = delete $args{repo};
1297 1         4 my $path = delete $args{path};
1298              
1299 1         2 $repo =~ s{^\/}{}xi;
1300 1         3 $repo =~ s{\/$}{}xi;
1301              
1302 1         4 $path =~ s{^\/}{}xi;
1303 1         3 $path =~ s{\/$}{}xi;
1304              
1305 1         30 my $url = $self->_api_url() . "/versions/$repo/$path?";
1306 1         6 $url .= $self->_stringify_hash( '&', %args );
1307 1         4 return $self->get($url);
1308             }
1309              
1310             =head2 build_artifacts_search( buildNumber => 15, buildName => 'foobar' )
1311              
1312             Find all the artifacts related to a specific build
1313              
1314             =cut
1315              
1316             sub build_artifacts_search {
1317 1     1 1 23 my ( $self, %args ) = @_;
1318              
1319 1         30 my $url = $self->_api_url() . "/search/buildArtifacts";
1320 1         29 return $self->post(
1321             $url,
1322             'Content-Type' => 'application/json',
1323             content => $self->_json->encode( \%args )
1324             );
1325             }
1326              
1327             =head2 list_docker_repositories( n => 5, last => 'last_tag_value' )
1328              
1329             Lists all Docker repositories hosted in under an Artifactory Docker repository.
1330              
1331             =cut
1332              
1333             sub list_docker_repositories {
1334 1     1 1 16 my ( $self, %args ) = @_;
1335 1   33     32 my $repository = delete $args{repository} || $self->repository();
1336 1         28 my $url = $self->_api_url() . "/docker/$repository/v2/_catalog";
1337 1 50       4 $url .= '?' . $self->_stringify_hash( '&', %args ) if (%args);
1338              
1339 1         3 return $self->get($url);
1340             }
1341              
1342             =head2 list_docker_tags( $image_name, n => 5, last => 'last_tag_value' )
1343              
1344             Lists all tags of the specified Artifactory Docker repository.
1345              
1346             =cut
1347              
1348             sub list_docker_tags {
1349 1     1 1 19 my ( $self, $image_name, %args ) = @_;
1350 1   33     33 my $repository = delete $args{repository} || $self->repository();
1351 1         28 my $url = $self->_api_url() . "/docker/$repository/v2/$image_name/tags/list";
1352 1 50       7 $url .= '?' . $self->_stringify_hash( '&', %args ) if (%args);
1353              
1354 1         5 return $self->get($url);
1355             }
1356              
1357             =head1 SECURITY
1358              
1359             =cut
1360              
1361             =head2 get_users
1362              
1363             Get the users list
1364              
1365             =cut
1366              
1367             sub get_users {
1368 1     1 1 17 my $self = shift;
1369 1         5 return $self->_handle_security( undef, 'get', 'users' );
1370             }
1371              
1372             =head2 get_user_details( $user )
1373              
1374             Get the details of an Artifactory user
1375              
1376             =cut
1377              
1378             sub get_user_details {
1379 1     1 1 20 my ( $self, $user ) = @_;
1380 1         4 return $self->_handle_security( $user, 'get', 'users' );
1381             }
1382              
1383             =head2 get_user_encrypted_password
1384              
1385             Get the encrypted password of the authenticated requestor
1386              
1387             =cut
1388              
1389             sub get_user_encrypted_password {
1390 1     1 1 18 my $self = shift;
1391 1         4 return $self->_handle_security( undef, 'get', 'encryptedPassword' );
1392             }
1393              
1394             =head2 create_or_replace_user( $user, %args )
1395              
1396             Creates a new user in Artifactory or replaces an existing user
1397              
1398             =cut
1399              
1400             sub create_or_replace_user {
1401 1     1 1 23 my ( $self, $user, %args ) = @_;
1402 1         5 return $self->_handle_security( $user, 'put', 'users', %args );
1403             }
1404              
1405             =head2 update_user( $user, %args )
1406              
1407             Updates an exiting user in Artifactory with the provided user details
1408              
1409             =cut
1410              
1411             sub update_user {
1412 1     1 1 22 my ( $self, $user, %args ) = @_;
1413 1         4 return $self->_handle_security( $user, 'post', 'users', %args );
1414             }
1415              
1416             =head2 delete_user( $user )
1417              
1418             Removes an Artifactory user
1419              
1420             =cut
1421              
1422             sub delete_user {
1423 1     1 1 21 my ( $self, $user ) = @_;
1424 1         4 return $self->_handle_security( $user, 'delete', 'users' );
1425             }
1426              
1427             =head2 expire_password_for_a_single_user( $user )
1428              
1429             Expires a user's password
1430              
1431             =cut
1432              
1433             sub expire_password_for_a_single_user {
1434 1     1 1 20 my ( $self, $user ) = @_;
1435 1         29 my $url = $self->_api_url() . "/security/users/authorization/expirePassword/$user";
1436 1         5 return $self->post($url);
1437             }
1438              
1439             =head2 expire_password_for_multiple_users( $user1, $user2 )
1440              
1441             Expires password for a list of users
1442              
1443             =cut
1444              
1445             sub expire_password_for_multiple_users {
1446 1     1 1 18 my ( $self, @users ) = @_;
1447 1         30 my $url = $self->_api_url() . "/security/users/authorization/expirePassword";
1448 1         29 return $self->post(
1449             $url,
1450             'Content-Type' => 'application/json',
1451             content => $self->_json->encode( [@users] )
1452             );
1453             }
1454              
1455             =head2 expire_password_for_all_users
1456              
1457             Expires password for all users
1458              
1459             =cut
1460              
1461             sub expire_password_for_all_users {
1462 1     1 1 17 my ( $self, @users ) = @_;
1463 1         29 my $url = $self->_api_url() . "/security/users/authorization/expirePasswordForAllUsers";
1464 1         5 return $self->post($url);
1465             }
1466              
1467             =head2 unexpire_password_for_a_single_user( $user )
1468              
1469             Unexpires a user's password
1470              
1471             =cut
1472              
1473             sub unexpire_password_for_a_single_user {
1474 1     1 1 16 my ( $self, $user ) = @_;
1475 1         30 my $url = $self->_api_url() . "/security/users/authorization/unexpirePassword/$user";
1476 1         4 return $self->post($url);
1477             }
1478              
1479             =head2 change_password( user => 'david', oldPassword => 'foo', newPassword => 'bar' )
1480              
1481             Changes a user's password
1482              
1483             =cut
1484              
1485             sub change_password {
1486 1     1 1 22 my ( $self, %info ) = @_;
1487 1         31 my $url = $self->_api_url() . "/security/users/authorization/changePassword";
1488 1         4 my $newpassword = delete $info{newPassword};
1489 1         2 $info{newPassword1} = $newpassword;
1490 1         3 $info{newPassword2} = $newpassword; # API requires new passwords twice, once for verification
1491              
1492 1         28 return $self->post(
1493             $url,
1494             'Content-Type' => 'application/json',
1495             content => $self->_json->encode( \%info )
1496             );
1497             }
1498              
1499             =head2 get_password_expiration_policy
1500              
1501             Retrieves the password expiration policy
1502              
1503             =cut
1504              
1505             sub get_password_expiration_policy {
1506 1     1 1 20 my $self = shift;
1507 1         29 my $url = $self->_api_url() . "/security/configuration/passwordExpirationPolicy";
1508 1         4 return $self->get($url);
1509             }
1510              
1511             =head2 set_password_expiration_policy
1512              
1513             Sets the password expiration policy
1514              
1515             =cut
1516              
1517             sub set_password_expiration_policy {
1518 1     1 1 22 my ( $self, %info ) = @_;
1519 1         31 my $url = $self->_api_url() . "/security/configuration/passwordExpirationPolicy";
1520 1         30 return $self->put(
1521             $url,
1522             'Content-Type' => 'application/json',
1523             content => $self->_json->encode( \%info )
1524             );
1525             }
1526              
1527             =head2 configure_user_lock_policy( enabled => 'true|false', loginAttempts => $num )
1528              
1529             Configures the user lock policy that locks users out of their account if the number of repeated incorrect login attempts
1530             exceeds the configured maximum allowed.
1531              
1532             =cut
1533              
1534             sub configure_user_lock_policy {
1535 1     1 1 22 my ( $self, %info ) = @_;
1536 1         30 my $url = $self->_api_url() . "/security/userLockPolicy";
1537 1         28 return $self->put(
1538             $url,
1539             'Content-Type' => 'application/json',
1540             content => $self->_json->encode( \%info )
1541             );
1542             }
1543              
1544             =head2 retrieve_user_lock_policy
1545              
1546             Retrieves the currently configured user lock policy.
1547              
1548             =cut
1549              
1550             sub retrieve_user_lock_policy {
1551 1     1 1 16 my $self = shift;
1552 1         30 my $url = $self->_api_url() . "/security/userLockPolicy";
1553 1         5 return $self->get($url);
1554             }
1555              
1556             =head2 get_locked_out_users
1557              
1558             If locking out users is enabled, lists all users that were locked out due to recurrent incorrect login attempts.
1559              
1560             =cut
1561              
1562             sub get_locked_out_users {
1563 1     1 1 15 my $self = shift;
1564 1         30 my $url = $self->_api_url() . "/security/lockedUsers";
1565 1         4 return $self->get($url);
1566             }
1567              
1568             =head2 unlock_locked_out_user
1569              
1570             Unlocks a single user that was locked out due to recurrent incorrect login attempts.
1571              
1572             =cut
1573              
1574             sub unlock_locked_out_user {
1575 1     1 1 17 my ( $self, $name ) = @_;
1576 1         32 my $url = $self->_api_url() . "/security/unlockUsers/$name";
1577 1         5 return $self->post($url);
1578             }
1579              
1580             =head2 unlock_locked_out_users
1581              
1582             Unlocks a list of users that were locked out due to recurrent incorrect login attempts.
1583              
1584             =cut
1585              
1586             sub unlock_locked_out_users {
1587 1     1 1 19 my ( $self, @users ) = @_;
1588 1         30 my $url = $self->_api_url() . "/security/unlockUsers";
1589 1         30 return $self->post(
1590             $url,
1591             'Content-Type' => 'application/json',
1592             content => $self->_json->encode( \@users )
1593             );
1594             }
1595              
1596             =head2 unlock_all_locked_out_users
1597              
1598             Unlocks all users that were locked out due to recurrent incorrect login attempts.
1599              
1600             =cut
1601              
1602             sub unlock_all_locked_out_users {
1603 1     1 1 17 my $self = shift;
1604 1         30 my $url = $self->_api_url() . "/security/unlockAllUsers";
1605 1         5 return $self->post($url);
1606             }
1607              
1608             =head2 create_api_key( apiKey => '3OloposOtVFyCMrT+cXmCAScmVMPrSYXkWIjiyDCXsY=' )
1609              
1610             Create an API key for the current user
1611              
1612             =cut
1613              
1614             sub create_api_key {
1615 1     1 1 24 my ( $self, %args ) = @_;
1616 1         6 return $self->_handle_api_key( 'post', %args );
1617             }
1618              
1619             =head2 get_api_key
1620              
1621             Get the current user's own API key
1622              
1623             =cut
1624              
1625             sub get_api_key {
1626 4     4 1 28 my $self = shift;
1627 4         17 return $self->_handle_api_key('get');
1628             }
1629              
1630             =head2 revoke_api_key
1631              
1632             Revokes the current user's API key
1633              
1634             =cut
1635              
1636             sub revoke_api_key {
1637 1     1 1 28 my $self = shift;
1638 1         6 return $self->_handle_revoke_api_key('/apiKey/auth');
1639             }
1640              
1641             =head2 revoke_user_api_key
1642              
1643             Revokes the API key of another user
1644              
1645             =cut
1646              
1647             sub revoke_user_api_key {
1648 1     1 1 30 my ( $self, $user ) = @_;
1649 1         7 return $self->_handle_revoke_api_key("/apiKey/auth/$user");
1650             }
1651              
1652             =head2 revoke_all_api_keys
1653              
1654             Revokes all API keys currently defined in the system
1655              
1656             =cut
1657              
1658             sub revoke_all_api_keys {
1659 1     1 1 31 my ( $self, %args ) = @_;
1660 1 50       6 my $deleteall = ( defined $args{deleteAll} ) ? $args{deleteAll} : 1;
1661 1         8 return $self->_handle_revoke_api_key("/apiKey?deleteAll=$deleteall");
1662             }
1663              
1664             =head2 get_groups
1665              
1666             Get the groups list
1667              
1668             =cut
1669              
1670             sub get_groups {
1671 1     1 1 21 my $self = shift;
1672 1         6 return $self->_handle_security( undef, 'get', 'groups' );
1673             }
1674              
1675             =head2 get_group_details( $group )
1676              
1677             Get the details of an Artifactory Group
1678              
1679             =cut
1680              
1681             sub get_group_details {
1682 1     1 1 23 my ( $self, $group ) = @_;
1683 1         5 return $self->_handle_security( $group, 'get', 'groups' );
1684             }
1685              
1686             =head2 create_or_replace_group( $group, %args )
1687              
1688             Creates a new group in Artifactory or replaces an existing group
1689              
1690             =cut
1691              
1692             sub create_or_replace_group {
1693 1     1 1 23 my ( $self, $group, %args ) = @_;
1694 1         5 return $self->_handle_security( $group, 'put', 'groups', %args );
1695             }
1696              
1697             =head2 update_group( $group, %args )
1698              
1699             Updates an exiting group in Artifactory with the provided group details
1700              
1701             =cut
1702              
1703             sub update_group {
1704 1     1 1 21 my ( $self, $group, %args ) = @_;
1705 1         5 return $self->_handle_security( $group, 'post', 'groups', %args );
1706             }
1707              
1708             =head2 delete_group( $group )
1709              
1710             Removes an Artifactory group
1711              
1712             =cut
1713              
1714             sub delete_group {
1715 1     1 1 19 my ( $self, $group ) = @_;
1716 1         4 return $self->_handle_security( $group, 'delete', 'groups' );
1717             }
1718              
1719             =head2 get_permission_targets
1720              
1721             Get the permission targets list
1722              
1723             =cut
1724              
1725             sub get_permission_targets {
1726 1     1 1 16 my $self = shift;
1727 1         5 return $self->_handle_security( undef, 'get', 'permissions' );
1728             }
1729              
1730             =head2 get_permission_target_details( $name )
1731              
1732             Get the details of an Artifactory Permission Target
1733              
1734             =cut
1735              
1736             sub get_permission_target_details {
1737 1     1 1 18 my ( $self, $name ) = @_;
1738 1         4 return $self->_handle_security( $name, 'get', 'permissions' );
1739             }
1740              
1741             =head2 create_or_replace_permission_target( $name, %args )
1742              
1743             Creates a new permission target in Artifactory or replaces an existing permission target
1744              
1745             =cut
1746              
1747             sub create_or_replace_permission_target {
1748 1     1 1 21 my ( $self, $name, %args ) = @_;
1749 1         5 return $self->_handle_security( $name, 'put', 'permissions', %args );
1750             }
1751              
1752             =head2 delete_permission_target( $name )
1753              
1754             Deletes an Artifactory permission target
1755              
1756             =cut
1757              
1758             sub delete_permission_target {
1759 1     1 1 18 my ( $self, $name ) = @_;
1760 1         4 return $self->_handle_security( $name, 'delete', 'permissions' );
1761             }
1762              
1763             =head2 effective_item_permissions( $path )
1764              
1765             Returns a list of effective permissions for the specified item (file or folder)
1766              
1767             =cut
1768              
1769             sub effective_item_permissions {
1770 1     1 1 18 my ( $self, $arg ) = @_;
1771              
1772 1         6 my $path = $self->_merge_repo_and_path($arg);
1773 1         28 my $url = $self->_api_url() . "/storage/$path?permissions";
1774 1         4 return $self->get($url);
1775             }
1776              
1777             =head2 security_configuration
1778              
1779             Retrieve the security configuration (security.xml)
1780              
1781             =cut
1782              
1783             sub security_configuration {
1784 1     1 1 17 my ( $self, $path ) = @_;
1785              
1786 1         29 my $url = $self->_api_url() . "/system/security";
1787 1         5 return $self->get($url);
1788             }
1789              
1790             =head2 activate_master_key_encryption
1791              
1792             Creates a new master key and activates master key encryption
1793              
1794             =cut
1795              
1796             sub activate_master_key_encryption {
1797 1     1 1 17 my $self = shift;
1798 1         29 my $url = $self->_api_url() . "/system/encrypt";
1799 1         6 return $self->post($url);
1800             }
1801              
1802             =head2 deactivate_master_key_encryption
1803              
1804             Removes the current master key and deactivates master key encryption
1805              
1806             =cut
1807              
1808             sub deactivate_master_key_encryption {
1809 1     1 1 16 my $self = shift;
1810 1         29 my $url = $self->_api_url() . "/system/decrypt";
1811 1         5 return $self->post($url);
1812             }
1813              
1814             =head2 set_gpg_public_key( key => $string )
1815              
1816             Sets the public key that Artifactory provides to Debian clients to verify packages
1817              
1818             =cut
1819              
1820             sub set_gpg_public_key {
1821 1     1 1 17 my ( $self, %args ) = @_;
1822 1         3 my $key = $args{key};
1823 1         5 return $self->_handle_gpg_key( 'public', 'put', content => $key );
1824             }
1825              
1826             =head2 get_gpg_public_key
1827              
1828             Gets the public key that Artifactory provides to Debian clients to verify packages
1829              
1830             =cut
1831              
1832             sub get_gpg_public_key {
1833 1     1 1 16 my $self = shift;
1834 1         4 return $self->_handle_gpg_key( 'public', 'get' );
1835             }
1836              
1837             =head2 set_gpg_private_key( key => $string )
1838              
1839             Sets the private key that Artifactory will use to sign Debian packages
1840              
1841             =cut
1842              
1843             sub set_gpg_private_key {
1844 1     1 1 16 my ( $self, %args ) = @_;
1845 1         3 my $key = $args{key};
1846 1         4 return $self->_handle_gpg_key( 'private', 'put', content => $key );
1847             }
1848              
1849             =head2 set_gpg_pass_phrase( $passphrase )
1850              
1851             Sets the pass phrase required signing Debian packages using the private key
1852              
1853             =cut
1854              
1855             sub set_gpg_pass_phrase {
1856 1     1 1 17 my ( $self, $pass ) = @_;
1857 1         4 return $self->_handle_gpg_key( 'passphrase', 'put', 'X-GPG-PASSPHRASE' => $pass );
1858             }
1859              
1860             =head2 create_token( username => 'johnq', scope => 'member-of-groups:readers' )
1861              
1862             Creates an access token
1863              
1864             =cut
1865              
1866             sub create_token {
1867 2     2 1 23 my ( $self, %data ) = @_;
1868 2         57 my $url = $self->_api_url() . "/security/token";
1869 2         8 return $self->post( $url, content => \%data );
1870             }
1871              
1872             =head2 refresh_token( grant_type => 'refresh_token', refresh_token => 'fgsg53t3g' )
1873              
1874             Refresh an access token to extend its validity. If only the access token and the refresh token are provided (and no
1875             other parameters), this pair is used for authentication. If username or any other parameter is provided, then the
1876             request must be authenticated by a token that grants admin permissions.
1877              
1878             =cut
1879              
1880             sub refresh_token {
1881 1     1 1 18 my ( $self, %data ) = @_;
1882 1         6 return $self->create_token(%data);
1883             }
1884              
1885             =head2 revoke_token( token => 'fgsg53t3g' )
1886              
1887             Revoke an access token
1888              
1889             =cut
1890              
1891             sub revoke_token {
1892 1     1 1 18 my ( $self, %data ) = @_;
1893 1         30 my $url = $self->_api_url() . "/security/token/revoke";
1894 1         5 return $self->post( $url, content => \%data );
1895             }
1896              
1897             =head2 get_service_id
1898              
1899             Provides the service ID of an Artifactory instance or cluster
1900              
1901             =cut
1902              
1903             sub get_service_id {
1904 1     1 1 17 my $self = shift;
1905 1         28 my $url = $self->_api_url() . "/system/service_id";
1906 1         5 return $self->get($url);
1907             }
1908              
1909             =head2 get_certificates
1910              
1911             Returns a list of installed SSL certificates.
1912              
1913             =cut
1914              
1915             sub get_certificates {
1916 1     1 1 16 my $self = shift;
1917 1         31 my $url = $self->_api_url() . "/system/security/certificates";
1918 1         4 return $self->get($url);
1919             }
1920              
1921             =head2 add_certificate( $alias, $file_path )
1922              
1923             Adds an SSL certificate.
1924              
1925             =cut
1926              
1927             sub add_certificate {
1928 1     1 1 20 my ( $self, $alias, $file ) = @_;
1929 1         30 my $url = $self->_api_url() . "/system/security/certificates/$alias";
1930 1         8 my $data = Path::Tiny::path($file)->slurp();
1931 1         358 return $self->post( $url, 'Content-Type' => 'application/text', content => $data );
1932             }
1933              
1934             =head2 delete_certificate( $alias )
1935              
1936             Deletes an SSL certificate.
1937              
1938             =cut
1939              
1940             sub delete_certificate {
1941 1     1 1 17 my ( $self, $alias ) = @_;
1942 1         29 my $url = $self->_api_url() . "/system/security/certificates/$alias";
1943 1         5 return $self->delete($url);
1944             }
1945              
1946             =head1 REPOSITORIES
1947              
1948             =cut
1949              
1950             =head2 get_repositories( $type )
1951              
1952             Returns a list of minimal repository details for all repositories of the specified type
1953              
1954             =cut
1955              
1956             sub get_repositories {
1957 1     1 1 18 my ( $self, $type ) = @_;
1958              
1959 1         30 my $url = $self->_api_url() . "/repositories";
1960 1 50       5 $url .= "?type=$type" if ($type);
1961              
1962 1         4 return $self->get($url);
1963             }
1964              
1965             =head2 repository_configuration( $name, %args )
1966              
1967             Retrieves the current configuration of a repository
1968              
1969             =cut
1970              
1971             sub repository_configuration {
1972 1     1 1 21 my ( $self, $repo, %args ) = @_;
1973              
1974 1         3 $repo =~ s{^\/}{}xi;
1975 1         2 $repo =~ s{\/$}{}xi;
1976              
1977 1 50       32 my $url =
1978             (%args)
1979             ? $self->_api_url() . "/repositories/$repo?"
1980             : $self->_api_url() . "/repositories/$repo";
1981 1 50       8 $url .= $self->_stringify_hash( '&', %args ) if (%args);
1982 1         6 return $self->get($url);
1983             }
1984              
1985             =head2 create_or_replace_repository_configuration( $name, \%payload, %args )
1986              
1987             Creates a new repository in Artifactory with the provided configuration or replaces the configuration of an existing
1988             repository
1989              
1990             =cut
1991              
1992             sub create_or_replace_repository_configuration {
1993 1     1 1 26 my ( $self, $repo, $payload, %args ) = @_;
1994 1         6 return $self->_handle_repositories( $repo, $payload, 'put', %args );
1995             }
1996              
1997             =head2 update_repository_configuration( $name, \%payload )
1998              
1999             Updates an exiting repository configuration in Artifactory with the provided configuration elements
2000              
2001             =cut
2002              
2003             sub update_repository_configuration {
2004 1     1 1 20 my ( $self, $repo, $payload ) = @_;
2005 1         4 return $self->_handle_repositories( $repo, $payload, 'post' );
2006             }
2007              
2008             =head2 delete_repository( $name )
2009              
2010             Removes a repository configuration together with the whole repository content
2011              
2012             =cut
2013              
2014             sub delete_repository {
2015 1     1 1 20 my ( $self, $repo ) = @_;
2016 1         3 return $self->_handle_repositories( $repo, undef, 'delete' );
2017             }
2018              
2019             =head2 calculate_yum_repository_metadata( async => 0/1 )
2020              
2021             Calculates/recalculates the YUM metdata for this repository, based on the RPM package currently hosted in the repository
2022              
2023             =cut
2024              
2025             sub calculate_yum_repository_metadata {
2026 1     1 1 21 my ( $self, %args ) = @_;
2027 1   33     35 my $repository = $args{repository} || $self->repository();
2028 1         7 return $self->_handle_repository_reindex( "/yum/$repository", %args );
2029             }
2030              
2031             =head2 calculate_nuget_repository_metadata
2032              
2033             Recalculates all the NuGet packages for this repository (local/cache/virtual), and re-annotate the NuGet properties for
2034             each NuGet package according to it's internal nuspec file
2035              
2036             =cut
2037              
2038             sub calculate_nuget_repository_metadata {
2039 1     1 1 18 my ( $self, %args ) = @_;
2040 1   33     32 my $repository = $args{repository} || $self->repository();
2041 1         6 return $self->_handle_repository_reindex("/nuget/$repository/reindex");
2042             }
2043              
2044             =head2 calculate_npm_repository_metadata
2045              
2046             Recalculates the npm search index for this repository (local/virtual). Please see the Npm integration documentation for
2047             more details.
2048              
2049             =cut
2050              
2051             sub calculate_npm_repository_metadata {
2052 1     1 1 18 my ( $self, %args ) = @_;
2053 1   33     32 my $repository = $args{repository} || $self->repository();
2054 1         7 return $self->_handle_repository_reindex("/npm/$repository/reindex");
2055             }
2056              
2057             =head2 calculate_maven_index( repos => [ 'repo1', 'repo2' ], force => 0/1 )
2058              
2059             Calculates/caches a Maven index for the specified repositories
2060              
2061             =cut
2062              
2063             sub calculate_maven_index {
2064 1     1 1 22 my ( $self, %args ) = @_;
2065              
2066 1         30 my $url = $self->_api_url() . "/maven?";
2067 1         7 $url .= $self->_stringify_hash( '&', %args );
2068 1         5 return $self->post($url);
2069             }
2070              
2071             =head2 calculate_maven_metadata( $path )
2072              
2073             Calculates Maven metadata on the specified path (local repositories only)
2074              
2075             =cut
2076              
2077             sub calculate_maven_metadata {
2078 1     1 1 18 my ( $self, $path ) = @_;
2079 1         4 $path = $self->_merge_repo_and_path($path);
2080 1         28 my $url = $self->_api_url() . "/maven/calculateMetadata/$path";
2081 1         34 return $self->post($url);
2082             }
2083              
2084             =head2 calculate_debian_repository_metadata( async => 0/1 )
2085              
2086             Calculates/recalculates the Packages and Release metadata for this repository,based on the Debian packages in it.
2087             Calculation can be synchronous (the default) or asynchronous.
2088              
2089             =cut
2090              
2091             sub calculate_debian_repository_metadata {
2092 1     1 1 20 my ( $self, %args ) = @_;
2093 1   33     33 my $repository = $args{repository} || $self->repository();
2094 1         7 return $self->_handle_repository_reindex( "/deb/reindex/$repository", %args );
2095             }
2096              
2097             =head2 calculate_cached_remote_debian_repository_coordinates( 'repokey' )
2098              
2099             Calculates/recalculates the Debian packages coordinates
2100              
2101             =cut
2102              
2103             sub calculate_cached_remote_debian_repository_coordinates {
2104 1     1 1 18 my ( $self, $repo_key ) = @_;
2105 1   33     5 my $repository = $repo_key || $self->repository();
2106 1         30 my $url = $self->_api_url() . "/deb/indexCached/$repository";
2107 1         4 return $self->post($url);
2108             }
2109              
2110             =head2 calculate_opkg_repository_metadata( async => 0/1, writeProps => 1 )
2111              
2112             Calculates/recalculates the Packages and Release metadata for this repository,based on the ipk packages in it (in each
2113             feed location).
2114              
2115             =cut
2116              
2117             sub calculate_opkg_repository_metadata {
2118 1     1 1 24 my ( $self, %args ) = @_;
2119 1   33     37 my $repository = $args{repository} || $self->repository();
2120 1         7 return $self->_handle_repository_reindex( "/opkg/reindex/$repository", %args );
2121             }
2122              
2123             =head2 calculate_bower_index
2124              
2125             Recalculates the index for a Bower repository.
2126              
2127             =cut
2128              
2129             sub calculate_bower_index {
2130 1     1 1 17 my ( $self, %args ) = @_;
2131 1   33     32 my $repository = $args{repository} || $self->repository();
2132 1         6 return $self->_handle_repository_reindex("/bower/$repository/reindex");
2133             }
2134              
2135             =head2 calculate_helm_chart_index
2136              
2137             Calculates Helm chart index on the specified path (local repositories only).
2138              
2139             =cut
2140              
2141             sub calculate_helm_chart_index {
2142 1     1 1 17 my ( $self, %args ) = @_;
2143 1   33     33 my $repository = $args{repository} || $self->repository();
2144 1         6 return $self->_handle_repository_reindex("/helm/$repository/reindex");
2145             }
2146              
2147             =head2 calculate_cran_repository_metadata
2148              
2149             Calculates/recalculates the Packages and Release metadata for this repository, based on the CRAN packages in it.
2150              
2151             =cut
2152              
2153             sub calculate_cran_repository_metadata {
2154 1     1 1 16 my ( $self, %args ) = @_;
2155 1   33     34 my $repository = $args{repository} || $self->repository();
2156 1         6 return $self->_handle_repository_reindex("/cran/reindex/$repository", %args);
2157             }
2158              
2159             =head2 calculate_conda_repository_metadata
2160              
2161             Calculates/recalculates the Conda packages and release metadata for this repository.
2162              
2163             =cut
2164              
2165             sub calculate_conda_repository_metadata {
2166 1     1 1 17 my ( $self, %args ) = @_;
2167 1   33     47 my $repository = $args{repository} || $self->repository();
2168 1         8 return $self->_handle_repository_reindex("/conda/reindex/$repository", %args);
2169             }
2170              
2171             =head1 SYSTEM & CONFIGURATION
2172              
2173             =cut
2174              
2175             =head2 system_info
2176              
2177             Get general system information
2178              
2179             =cut
2180              
2181             sub system_info {
2182 1     1 1 17 my $self = shift;
2183 1         4 return $self->_handle_system();
2184             }
2185              
2186             =head2 verify_connection( endpoint => 'http://server/foobar', username => 'admin', password => 'password' )
2187              
2188             Verifies a two-way connection between Artifactory and another product
2189              
2190             =cut
2191              
2192             sub verify_connection {
2193 1     1 1 26 my ( $self, %args ) = @_;
2194 1         30 my $url = $self->_api_url() . "/system/verifyconnection";
2195              
2196 1         30 return $self->post(
2197             $url,
2198             'Content-Type' => 'application/json',
2199             content => $self->_json->encode( \%args )
2200             );
2201             }
2202              
2203             =head2 system_health_ping
2204              
2205             Get a simple status response about the state of Artifactory
2206              
2207             =cut
2208              
2209             sub system_health_ping {
2210 1     1 1 18 my $self = shift;
2211 1         5 return $self->_handle_system('ping');
2212             }
2213              
2214             =head2 general_configuration
2215              
2216             Get the general configuration (artifactory.config.xml)
2217              
2218             =cut
2219              
2220             sub general_configuration {
2221 1     1 1 16 my $self = shift;
2222 1         4 return $self->_handle_system('configuration');
2223             }
2224              
2225             =head2 save_general_configuration( $file )
2226              
2227             Save the general configuration (artifactory.config.xml)
2228              
2229             =cut
2230              
2231             sub save_general_configuration {
2232 1     1 1 29 my ( $self, $xml ) = @_;
2233              
2234 1         6 my $file = Path::Tiny::path($xml)->slurp( { binmode => ":raw" } );
2235 1         80 my $url = $self->_api_url() . "/system/configuration";
2236 1         5 return $self->post(
2237             $url,
2238             'Content-Type' => 'application/xml',
2239             content => $file
2240             );
2241             }
2242              
2243             =head2 update_custom_url_base( $url )
2244              
2245             Changes the Custom URL base
2246              
2247             =cut
2248              
2249             sub update_custom_url_base {
2250 1     1 1 18 my ( $self, $base ) = @_;
2251 1         30 my $url = $self->_api_url() . '/system/configuration/baseUrl';
2252 1         5 return $self->put(
2253             $url,
2254             'Content-Type' => 'text/plain',
2255             content => $base
2256             );
2257             }
2258              
2259             =head2 license_information
2260              
2261             Retrieve information about the currently installed license
2262              
2263             =cut
2264              
2265             sub license_information {
2266 1     1 1 20 my $self = shift;
2267              
2268 1         30 my $url = $self->_api_url() . "/system/license";
2269 1         6 return $self->get($url);
2270             }
2271              
2272             =head2 install_license( $licensekey )
2273              
2274             Install new license key or change the current one
2275              
2276             =cut
2277              
2278             sub install_license {
2279 1     1 1 19 my ( $self, $key ) = @_;
2280 1         30 my $url = $self->_api_url() . "/system/license";
2281              
2282 1         29 return $self->post(
2283             $url,
2284             'Content-Type' => 'application/json',
2285             content => $self->_json->encode( { licenseKey => $key } )
2286             );
2287             }
2288              
2289             =head2 ha_license_information
2290              
2291             Retrieve information about the currently installed licenses in an HA cluster
2292              
2293             =cut
2294              
2295             sub ha_license_information {
2296 1     1 1 16 my $self = shift;
2297              
2298 1         31 my $url = $self->_api_url() . "/system/licenses";
2299 1         4 return $self->get($url);
2300             }
2301              
2302             =head2 install_ha_cluster_licenses( [ { licenseKey => 'foobar' }, { licenseKey => 'barbaz' } ] )
2303              
2304             Install a new license key(s) on an HA cluster
2305              
2306             =cut
2307              
2308             sub install_ha_cluster_licenses {
2309 1     1 1 20 my ( $self, $ref ) = @_;
2310 1         31 my $url = $self->_api_url() . "/system/licenses";
2311              
2312 1         28 return $self->post(
2313             $url,
2314             'Content-Type' => 'application/json',
2315             content => $self->_json->encode($ref)
2316             );
2317             }
2318              
2319             =head2 delete_ha_cluster_license( 'licenseHash1', 'licenseHash2' )
2320              
2321             Deletes a license key from an HA cluster
2322              
2323             =cut
2324              
2325             sub delete_ha_cluster_license {
2326 1     1 1 18 my ( $self, @licenses ) = @_;
2327 1         29 my $url = $self->_api_url() . "/system/licenses?";
2328 1         6 $url .= $self->_handle_non_matrix_props( 'licenseHash', \@licenses );
2329 1         5 return $self->delete( $url, 'Content-Type' => 'application/json' );
2330             }
2331              
2332             =head2 version_and_addons_information
2333              
2334             Retrieve information about the current Artifactory version, revision, and currently installed Add-ons
2335              
2336             =cut
2337              
2338             sub version_and_addons_information {
2339 1     1 1 17 my $self = shift;
2340              
2341 1         29 my $url = $self->_api_url() . "/system/version";
2342 1         6 return $self->get($url);
2343             }
2344              
2345             =head2 get_reverse_proxy_configuration
2346              
2347             Retrieves the reverse proxy configuration
2348              
2349             =cut
2350              
2351             sub get_reverse_proxy_configuration {
2352 1     1 1 17 my $self = shift;
2353              
2354 1         30 my $url = $self->_api_url() . "/system/configuration/webServer";
2355 1         5 return $self->get($url);
2356             }
2357              
2358             =head2 update_reverse_proxy_configuration(%data)
2359              
2360             Updates the reverse proxy configuration
2361              
2362             =cut
2363              
2364             sub update_reverse_proxy_configuration {
2365 1     1 1 25 my ( $self, %data ) = @_;
2366              
2367 1         31 my $url = $self->_api_url() . "/system/configuration/webServer";
2368 1         30 return $self->post(
2369             $url,
2370             'Content-Type' => 'application/json',
2371             content => $self->_json->encode( \%data )
2372             );
2373             }
2374              
2375             =head2 get_reverse_proxy_snippet
2376              
2377             Gets the reverse proxy configuration snippet in text format
2378              
2379             =cut
2380              
2381             sub get_reverse_proxy_snippet {
2382 1     1 1 18 my $self = shift;
2383              
2384 1         30 my $url = $self->_api_url() . "/system/configuration/reverseProxy/nginx";
2385 1         5 return $self->get($url);
2386             }
2387              
2388             =head2 start_sha256_migration_task( "batchThreshold" => 10, etc etc )
2389              
2390             Starts the SHA-256 migration process.
2391              
2392             =cut
2393              
2394             sub start_sha256_migration_task {
2395 1     1 1 20 my ( $self, %data ) = @_;
2396              
2397 1         30 my $url = $self->_api_url() . "/system/migration/sha2/start";
2398 1         28 return $self->post(
2399             $url,
2400             'Content-Type' => 'application/json',
2401             content => $self->_json->encode( \%data )
2402             );
2403             }
2404              
2405             =head2 stop_sha256_migration_task( "sleepIntervalMillis" => 5000, etc etc )
2406              
2407             Stops the SHA-256 migration process
2408              
2409             =cut
2410              
2411             sub stop_sha256_migration_task {
2412 1     1 1 21 my ( $self, %data ) = @_;
2413              
2414 1         31 my $url = $self->_api_url() . "/system/migration/sha2/stop";
2415 1         29 return $self->post(
2416             $url,
2417             'Content-Type' => 'application/json',
2418             content => $self->_json->encode( \%data )
2419             );
2420             }
2421              
2422             =head1 PLUGINS
2423              
2424             =cut
2425              
2426             =head2 execute_plugin_code( $execution_name, $params, $async )
2427              
2428             Executes a named execution closure found in the executions section of a user plugin
2429              
2430             =cut
2431              
2432             sub execute_plugin_code {
2433 1     1 1 26 my ( $self, $execution_name, $params, $async ) = @_;
2434              
2435 1 50       32 my $url =
2436             ($params)
2437             ? $self->_api_url() . "/plugins/execute/$execution_name?params="
2438             : $self->_api_url() . "/plugins/execute/$execution_name";
2439              
2440 1         6 $url = $url . $self->_attach_properties( properties => $params );
2441 1 50       5 $url .= "&" . $self->_stringify_hash( '&', %{$async} ) if ($async);
  1         6  
2442 1         5 return $self->post($url);
2443             }
2444              
2445             =head2 retrieve_all_available_plugin_info
2446              
2447             Retrieves all available user plugin information (subject to the permissions of the provided credentials)
2448              
2449             =cut
2450              
2451             sub retrieve_all_available_plugin_info {
2452 1     1 1 16 my $self = shift;
2453 1         6 return $self->_handle_plugins();
2454             }
2455              
2456             =head2 retrieve_plugin_info_of_a_certain_type( $type )
2457              
2458             Retrieves all available user plugin information (subject to the permissions of the provided credentials) of the
2459             specified type
2460              
2461             =cut
2462              
2463             sub retrieve_plugin_info_of_a_certain_type {
2464 1     1 1 17 my ( $self, $type ) = @_;
2465 1         4 return $self->_handle_plugins($type);
2466             }
2467              
2468             =head2 retrieve_build_staging_strategy( strategyName => 'strategy1', buildName => 'build1', %args )
2469              
2470             Retrieves a build staging strategy defined by a user plugin
2471              
2472             =cut
2473              
2474             sub retrieve_build_staging_strategy {
2475 1     1 1 26 my ( $self, %args ) = @_;
2476 1         4 my $strategy_name = delete $args{strategyName};
2477 1         3 my $build_name = delete $args{buildName};
2478              
2479 1         31 my $url = $self->_api_url() . "/plugins/build/staging/$strategy_name?buildName=$build_name&params=";
2480 1         6 $url = $url . $self->_attach_properties( properties => \%args );
2481 1         4 return $self->get($url);
2482             }
2483              
2484             =head2 execute_build_promotion( promotionName => 'promotion1', buildName => 'build1', buildNumber => 3, %args )
2485              
2486             Executes a named promotion closure found in the promotions section of a user plugin
2487              
2488             =cut
2489              
2490             sub execute_build_promotion {
2491 1     1 1 27 my ( $self, %args ) = @_;
2492 1         3 my $promotion_name = delete $args{promotionName};
2493 1         4 my $build_name = delete $args{buildName};
2494 1         3 my $build_number = delete $args{buildNumber};
2495              
2496 1         30 my $url = $self->_api_url() . "/plugins/build/promote/$promotion_name/$build_name/$build_number?params=";
2497 1         5 $url = $url . $self->_attach_properties( properties => \%args );
2498 1         6 return $self->post($url);
2499             }
2500              
2501             =head2 reload_plugins
2502              
2503             Reloads user plugins if there are modifications since the last user plugins reload. Works regardless of the automatic
2504             user plugins refresh interval
2505              
2506             =cut
2507              
2508             sub reload_plugins {
2509 1     1 1 15 my $self = shift;
2510 1         30 my $url = $self->_api_url() . '/plugins/reload';
2511 1         5 return $self->post($url);
2512             }
2513              
2514             =head1 IMPORT & EXPORT
2515              
2516             =cut
2517              
2518             =head2 import_repository_content( path => 'foobar', repo => 'repo', metadata => 1, verbose => 0 )
2519              
2520             Import one or more repositories
2521              
2522             =cut
2523              
2524             sub import_repository_content {
2525 1     1 1 25 my ( $self, %args ) = @_;
2526              
2527 1         30 my $url = $self->_api_url() . "/import/repositories?";
2528 1         11 $url .= $self->_stringify_hash( '&', %args );
2529 1         5 return $self->post($url);
2530             }
2531              
2532             =head2 import_system_settings_example
2533              
2534             Returned default Import Settings JSON
2535              
2536             =cut
2537              
2538             sub import_system_settings_example {
2539 1     1 1 16 my $self = shift;
2540 1         5 return $self->_handle_system_settings('import');
2541             }
2542              
2543             =head2 full_system_import( importPath => '/import/path', includeMetadata => 'false' etc )
2544              
2545             Import full system from a server local Artifactory export directory
2546              
2547             =cut
2548              
2549             sub full_system_import {
2550 1     1 1 24 my ( $self, %args ) = @_;
2551 1         5 return $self->_handle_system_settings( 'import', %args );
2552             }
2553              
2554             =head2 export_system_settings_example
2555              
2556             Returned default Export Settings JSON
2557              
2558             =cut
2559              
2560             sub export_system_settings_example {
2561 1     1 1 29 my $self = shift;
2562 1         7 return $self->_handle_system_settings('export');
2563             }
2564              
2565             =head2 export_system( exportPath => '/export/path', includeMetadata => 'true' etc )
2566              
2567             Export full system to a server local directory
2568              
2569             =cut
2570              
2571             sub export_system {
2572 1     1 1 32 my ( $self, %args ) = @_;
2573 1         7 return $self->_handle_system_settings( 'export', %args );
2574             }
2575              
2576             =head2 ignore_xray_alert( $path )
2577              
2578             Sets an alert to be ignored until next time the repository hosting the artifact about which the alert was issued, is scanned. Note that this endpoint does not
2579             affect artifacts that are blocked because they have not been scanned at all.
2580              
2581             =cut
2582              
2583             sub ignore_xray_alert {
2584 1     1 1 16 my ( $self, $path ) = @_;
2585 1         31 my $url = $self->_api_url() . "/xray/setAlertIgnored?path=$path";
2586 1         32 return $self->post($url);
2587             }
2588              
2589             =head2 allow_download_of_blocked_artifacts( 'true'|'false' )
2590              
2591             When a repository is configured to block downloads of artifacts, you may override that configuration (and allow download of blocked artifacts). Note that this
2592             setting cannot override the blocking of unscanned artifacts.
2593              
2594             =cut
2595              
2596             sub allow_download_of_blocked_artifacts {
2597 1     1 1 18 my ( $self, $bool ) = @_;
2598 1         29 my $url = $self->_api_url() . "/xray/allowBlockedArtifactsDownload?allow=$bool";
2599 1         5 return $self->post($url);
2600             }
2601              
2602             =head2 allow_download_when_xray_is_unavailable( 'true'|'false' )
2603              
2604             You may configure Artifactory to block downloads of artifacts when the connected Xray instance is unavailable. This endpoint lets you override that
2605             configuration (and allow download of artifacts).
2606              
2607             =cut
2608              
2609             sub allow_download_when_xray_is_unavailable {
2610 1     1 1 16 my ( $self, $bool ) = @_;
2611 1         29 my $url = $self->_api_url() . "/xray/allowDownloadWhenUnavailable?allow=$bool";
2612 1         5 return $self->post($url);
2613             }
2614              
2615             =head2 create_bundle( %hash of data structure )
2616              
2617             Create a new support bundle
2618              
2619             =cut
2620              
2621             sub create_bundle {
2622 1     1 1 18 my ( $self, %args ) = @_;
2623 1         30 my $url = $self->_api_url() . '/support/bundles';
2624 1 50       6 %args = () unless %args;
2625              
2626 1         29 return $self->post(
2627             $url,
2628             "Content-Type" => 'application/json',
2629             Content => $self->_json->encode( \%args )
2630             );
2631             }
2632              
2633             =head2 list_bundles
2634              
2635             Lists previously created bundle currently stored in the system
2636              
2637             =cut
2638              
2639             sub list_bundles {
2640 1     1 1 17 my $self = shift;
2641 1         29 my $url = $self->_api_url() . '/support/bundles';
2642 1         6 return $self->get( $url, "Content-Type" => 'application/json', );
2643             }
2644              
2645             =head2 get_bundle_metadata( $name )
2646              
2647             Downloads a previously created bundle currently stored in the system
2648              
2649             =cut
2650              
2651             sub get_bundle_metadata {
2652 1     1 1 18 my ( $self, $bundle ) = @_;
2653 1         30 my $url = $self->_api_url() . '/support/bundles/' . $bundle;
2654 1         5 return $self->get( $url, "Content-Type" => 'application/json', );
2655             }
2656              
2657             =head2 get_bundle( $name )
2658              
2659             Downloads a previously created bundle currently stored in the system
2660              
2661             =cut
2662              
2663             sub get_bundle {
2664 1     1 1 18 my ( $self, $bundle ) = @_;
2665 1         30 my $url = $self->_api_url() . '/support/bundles/' . $bundle . '/archive';
2666 1         5 return $self->get( $url, "Content-Type" => 'application/json', );
2667             }
2668              
2669             =head2 delete_bundle( $name )
2670              
2671             Deletes a previously created bundle from the system.
2672              
2673             =cut
2674              
2675             sub delete_bundle {
2676 1     1 1 16 my ( $self, $bundle ) = @_;
2677 1         32 my $url = $self->_api_url() . '/support/bundles/' . $bundle;
2678 1         5 return $self->delete( $url, "Content-Type" => 'application/json', );
2679             }
2680              
2681             sub _build_ua {
2682 179     179   325 my $self = shift;
2683 179         846 return LWP::UserAgent->new( agent => 'perl-artifactory-client/' . $VERSION, );
2684             }
2685              
2686             sub _build_json {
2687 42     42   94 my ($self) = @_;
2688 42         258 return JSON::MaybeXS->new( utf8 => 1 );
2689             }
2690              
2691             sub _request {
2692 186     186   427 my ( $self, $method, @args ) = @_;
2693 186         5103 return $self->ua->$method(@args);
2694             }
2695              
2696             sub _get_build {
2697 4     4   8 my ( $self, $path ) = @_;
2698              
2699 4         114 my $url = $self->_api_url() . "/build/$path";
2700 4         12 return $self->get($url);
2701             }
2702              
2703             sub _attach_properties {
2704 9     9   32 my ( $self, %args ) = @_;
2705 9         21 my $properties = $args{properties};
2706 9         21 my $matrix = $args{matrix};
2707 9         19 my @strings;
2708              
2709 9         15 for my $key ( keys %{$properties} ) {
  9         34  
2710 8         26 push @strings, $self->_handle_prop_multivalue( $key, $properties->{$key}, $matrix );
2711             }
2712              
2713 9 100       39 return join( ";", @strings ) if $matrix;
2714 4         18 return join( "|", @strings );
2715             }
2716              
2717             sub _handle_prop_multivalue {
2718 8     8   23 my ( $self, $key, $values, $matrix ) = @_;
2719              
2720             # need to handle matrix vs non-matrix situations.
2721 8 100       31 if ($matrix) {
2722 2         8 return $self->_handle_matrix_props( $key, $values );
2723             }
2724 6         19 return $self->_handle_non_matrix_props( $key, $values );
2725             }
2726              
2727             sub _handle_matrix_props {
2728 2     2   5 my ( $self, $key, $values ) = @_;
2729              
2730             # string looks like key=val;key=val2;key=val3;
2731 2         2 my @strings;
2732 2         5 for my $value ( @{$values} ) {
  2         5  
2733 3 50       7 $value = '' if ( !defined $value );
2734              
2735             #$value = uri_escape( $value );
2736 3         9 push @strings, "$key=$value";
2737             }
2738 2         9 return join( ";", @strings );
2739             }
2740              
2741             sub _handle_non_matrix_props {
2742 7     7   16 my ( $self, $key, $values ) = @_;
2743              
2744             # string looks like key=val1,val2,val3|
2745 7         19 my $str = "$key=";
2746 7         11 my @value_holder;
2747 7         14 for my $value ( @{$values} ) {
  7         14  
2748 14 50       34 $value = '' if ( !defined $value );
2749 14         38 $value = uri_escape($value);
2750 14         185 push @value_holder, $value;
2751             }
2752 7         20 $str .= join( ",", @value_holder );
2753 7         23 return $str;
2754             }
2755              
2756             sub _handle_item {
2757 2     2   39 my ( $self, %args ) = @_;
2758              
2759             my ( $from, $to, $dry, $suppress_layouts, $fail_fast, $method ) =
2760 2         9 ( $args{from}, $args{to}, $args{dry}, $args{suppress_layouts}, $args{fail_fast}, $args{method} );
2761              
2762 2         63 my $url = $self->_api_url() . "/$method$from?to=$to";
2763 2 50       6 $url .= "&dry=$dry" if ( defined $dry );
2764 2 50       7 $url .= "&suppressLayouts=$suppress_layouts"
2765             if ( defined $suppress_layouts );
2766 2 50       5 $url .= "&failFast=$fail_fast" if ( defined $fail_fast );
2767 2         7 return $self->post($url);
2768             }
2769              
2770             sub _handle_repository_replication_configuration {
2771 3     3   8 my ( $self, $method, $payload ) = @_;
2772 3         86 my $repository = $self->repository();
2773 3         81 my $url = $self->_api_url() . "/replications/$repository";
2774              
2775 3 100       61 return $self->$method(
2776             $url,
2777             'Content-Type' => 'application/json',
2778             content => $self->_json->encode($payload),
2779             ) if ($payload);
2780              
2781 1         4 return $self->$method($url);
2782             }
2783              
2784             sub _handle_search {
2785 2     2   8 my ( $self, $api, %args ) = @_;
2786 2         5 my $name = $args{name};
2787 2         5 my $repos = $args{repos};
2788 2         4 my $result_detail = $args{result_detail};
2789              
2790 2         62 my $url = $self->_api_url() . "/search/$api?name=$name";
2791              
2792 2 50       8 if ( ref($repos) eq 'ARRAY' ) {
2793 2         5 $url .= "&repos=" . join( ",", @{$repos} );
  2         6  
2794             }
2795              
2796 2         4 my %headers;
2797 2 50       7 if ( ref($result_detail) eq 'ARRAY' ) {
2798 0         0 $headers{'X-Result-Detail'} = join( ',', @{$result_detail} );
  0         0  
2799             }
2800              
2801 2         33 return $self->get( $url, %headers );
2802             }
2803              
2804             sub _handle_search_props {
2805 11     11   36 my ( $self, $method, %args ) = @_;
2806 11         23 my $result_detail = delete $args{result_detail};
2807              
2808 11         351 my $url = $self->_api_url() . "/search/$method?";
2809              
2810 11         53 $url .= $self->_stringify_hash( '&', %args );
2811              
2812 11         22 my %headers;
2813 11 50       25 if ( ref($result_detail) eq 'ARRAY' ) {
2814 0         0 $headers{'X-Result-Detail'} = join( ',', @{$result_detail} );
  0         0  
2815             }
2816              
2817 11         25 return $self->get( $url, %headers );
2818             }
2819              
2820             sub _stringify_hash {
2821 26     26   87 my ( $self, $delimiter, %args ) = @_;
2822              
2823 26         48 my @strs;
2824 26         74 for my $key ( keys %args ) {
2825 63         109 my $val = $args{$key};
2826              
2827 63 100       143 if ( ref($val) eq 'ARRAY' ) {
2828 13         22 $val = join( ",", @{$val} );
  13         34  
2829             }
2830 63         174 push @strs, "$key=$val";
2831             }
2832 26         115 return join( $delimiter, @strs );
2833             }
2834              
2835             sub _handle_security {
2836 15     15   46 my ( $self, $label, $method, $element, %args ) = @_;
2837              
2838 15 100       450 my $url =
2839             ($label)
2840             ? $self->_api_url() . "/security/$element/$label"
2841             : $self->_api_url() . "/security/$element";
2842              
2843 15 100       43 if (%args) {
2844 5         137 return $self->$method(
2845             $url,
2846             'Content-Type' => 'application/json',
2847             content => $self->_json->encode( \%args )
2848             );
2849             }
2850 10         42 return $self->$method($url);
2851             }
2852              
2853             sub _handle_repositories {
2854 3     3   10 my ( $self, $repo, $payload, $method, %args ) = @_;
2855              
2856 3         7 $repo =~ s{^\/}{}xi;
2857 3         6 $repo =~ s{\/$}{}xi;
2858              
2859 3 100       94 my $url =
2860             (%args)
2861             ? $self->_api_url() . "/repositories/$repo?"
2862             : $self->_api_url() . "/repositories/$repo";
2863 3 100       12 $url .= $self->_stringify_hash( '&', %args ) if (%args);
2864              
2865 3 100       8 if ($payload) {
2866 2         57 return $self->$method(
2867             $url,
2868             'Content-Type' => 'application/json',
2869             content => $self->_json->encode($payload)
2870             );
2871             }
2872 1         5 return $self->$method($url);
2873             }
2874              
2875             sub _handle_system {
2876 3     3   10 my ( $self, $arg ) = @_;
2877              
2878 3 100       91 my $url =
2879             ($arg)
2880             ? $self->_api_url() . "/system/$arg"
2881             : $self->_api_url() . "/system";
2882 3         12 return $self->get($url);
2883             }
2884              
2885             sub _handle_plugins {
2886 2     2   5 my ( $self, $type ) = @_;
2887              
2888 2 100       64 my $url =
2889             ($type)
2890             ? $self->_api_url() . "/plugins/$type"
2891             : $self->_api_url() . "/plugins";
2892 2         7 return $self->get($url);
2893             }
2894              
2895             sub _handle_system_settings {
2896 4     4   13 my ( $self, $action, %args ) = @_;
2897              
2898 4         118 my $url = $self->_api_url() . "/$action/system";
2899              
2900 4 100       12 if (%args) {
2901 2         55 return $self->post(
2902             $url,
2903             'Content-Type' => 'application/json',
2904             content => $self->_json->encode( \%args )
2905             );
2906             }
2907 2         6 return $self->get($url);
2908             }
2909              
2910             sub _handle_gpg_key {
2911 4     4   15 my ( $self, $type, $method, %args ) = @_;
2912 4         113 my $url = $self->_api_url() . "/gpg/key/$type";
2913 4         18 return $self->$method( $url, %args );
2914             }
2915              
2916             sub _handle_repository_reindex {
2917 9     9   26 my ( $self, $endpoint, %args ) = @_;
2918 9 100       286 my $url =
2919             (%args)
2920             ? $self->_api_url() . $endpoint . "?"
2921             : $self->_api_url() . $endpoint;
2922 9 100       33 $url .= $self->_stringify_hash( '&', %args ) if (%args);
2923 9         29 return $self->post($url);
2924             }
2925              
2926             sub _handle_multi_push_replication {
2927 2     2   7 my ( $self, $payload, $method ) = @_;
2928              
2929 2         61 my $url = $self->_api_url() . '/replications/multiple';
2930 2         54 return $self->$method(
2931             $url,
2932             "Content-Type" => 'application/json',
2933             Content => $self->_json->encode($payload)
2934             );
2935             }
2936              
2937             sub _merge_repo_and_path {
2938 25     25   58 my ( $self, $_path ) = @_;
2939              
2940 25 50       71 $_path = '' if not defined $_path;
2941 25         114 $_path =~ s{^\/}{}xi;
2942              
2943 25         798 return join( '/', grep { $_ } $self->repository(), $_path );
  50         149  
2944             }
2945              
2946             sub _gather_delete_builds_params {
2947 1     1   5 my ( $self, $buildnumbers, $artifacts, $deleteall ) = @_;
2948              
2949 1         2 my @params;
2950 1 50       6 if ( ref($buildnumbers) eq 'ARRAY' ) {
2951 1         2 my $str = "buildNumbers=";
2952 1         2 $str .= join( ",", @{$buildnumbers} );
  1         4  
2953 1         3 push @params, $str;
2954             }
2955 1 50       6 push @params, "artifacts=$artifacts" if ( defined $artifacts );
2956 1 50       4 push @params, "deleteAll=$deleteall" if ( defined $deleteall );
2957 1         4 return @params;
2958             }
2959              
2960             sub _handle_api_key {
2961 5     5   15 my ( $self, $method, %args ) = @_;
2962              
2963 5         155 my $url = $self->_api_url() . "/apiKey/auth";
2964 5         139 return $self->$method(
2965             $url,
2966             'Content-Type' => 'application/json',
2967             content => $self->_json->encode( \%args )
2968             );
2969             }
2970              
2971             sub _handle_revoke_api_key {
2972 3     3   8 my ( $self, $endpoint ) = @_;
2973              
2974 3         12 my $resp = $self->get_api_key();
2975 3         102 my $content = $self->_json->decode( $resp->content );
2976 3         64 my %header;
2977 3         10 $header{'X-Api-Key'} = $content->{apiKey};
2978 3         86 my $url = $self->_api_url() . $endpoint;
2979 3         16 return $self->delete( $url, %header );
2980             }
2981              
2982             sub _handle_block_system_replication {
2983 2     2   8 my ( $self, $ep, %args ) = @_;
2984 2         10 my %merged = (
2985             push => 'true',
2986             pull => 'true',
2987             %args # overriding defaults
2988             );
2989 2         60 my $repo = $self->repository();
2990 2         53 my $url = $self->_api_url() . "/system/replications/$ep?" . $self->_stringify_hash( '&', %merged );
2991 2         9 return $self->post($url);
2992             }
2993              
2994             __PACKAGE__->meta->make_immutable;
2995              
2996             =head1 AUTHOR
2997              
2998             Satoshi Yagi, C<< <satoshi.yagi at yahoo.com> >>
2999              
3000             =head1 BUGS
3001              
3002             Please report any bugs or feature requests to C<bug-artifactory-client at
3003             rt.cpan.org>, or through the web interface at
3004             L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Artifactory-Client>. I will
3005             be notified, and then you'll automatically be notified of progress on your bug
3006             as I make changes.
3007              
3008             =head1 SUPPORT
3009              
3010             You can find documentation for this module with the perldoc command.
3011              
3012             perldoc Artifactory::Client
3013              
3014             You can also look for information at:
3015              
3016             =over 4
3017              
3018             =item * RT: CPAN's request tracker (report bugs here)
3019              
3020             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Artifactory-Client>
3021              
3022             =item * AnnoCPAN: Annotated CPAN documentation
3023              
3024             L<http://annocpan.org/dist/Artifactory-Client>
3025              
3026             =item * CPAN Ratings
3027              
3028             L<http://cpanratings.perl.org/d/Artifactory-Client>
3029              
3030             =item * Search CPAN
3031              
3032             L<http://search.cpan.org/dist/Artifactory-Client/>
3033              
3034             =back
3035              
3036             =head1 ACKNOWLEDGEMENTS
3037              
3038             =head1 LICENSE AND COPYRIGHT
3039              
3040             Copyright 2014-2015, Yahoo! Inc.
3041              
3042             This program is free software; you can redistribute it and/or modify it under
3043             the terms of the the Artistic License (2.0). You may obtain a copy of the full
3044             license at:
3045              
3046             L<http://www.perlfoundation.org/artistic_license_2_0>
3047              
3048             Any use, modification, and distribution of the Standard or Modified Versions is
3049             governed by this Artistic License. By using, modifying or distributing the
3050             Package, you accept this license. Do not use, modify, or distribute the
3051             Package, if you do not accept this license.
3052              
3053             If your Modified Version has been derived from a Modified Version made by
3054             someone other than you, you are nevertheless required to ensure that your
3055             Modified Version complies with the requirements of this license.
3056              
3057             This license does not grant you the right to use any trademark, service mark,
3058             tradename, or logo of the Copyright Holder.
3059              
3060             This license includes the non-exclusive, worldwide, free-of-charge patent
3061             license to make, have made, use, offer to sell, sell, import and otherwise
3062             transfer the Package with respect to any patent claims licensable by the
3063             Copyright Holder that are necessarily infringed by the Package. If you
3064             institute patent litigation (including a cross-claim or counterclaim) against
3065             any party alleging that the Package constitutes direct or contributory patent
3066             infringement, then this Artistic License to you shall terminate on the date
3067             that such litigation is filed.
3068              
3069             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND
3070             CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED
3071             WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
3072             NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW.
3073             UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR
3074             ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY
3075             OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
3076             DAMAGE.
3077              
3078             =cut
3079              
3080             1;