artifactory 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/Gemfile +1 -1
  4. data/lib/artifactory.rb +13 -9
  5. data/lib/artifactory/client.rb +16 -3
  6. data/lib/artifactory/errors.rb +1 -2
  7. data/lib/artifactory/resources/artifact.rb +56 -27
  8. data/lib/artifactory/resources/backup.rb +104 -0
  9. data/lib/artifactory/resources/base.rb +47 -0
  10. data/lib/artifactory/resources/layout.rb +1 -50
  11. data/lib/artifactory/resources/ldap_setting.rb +105 -0
  12. data/lib/artifactory/resources/mail_server.rb +61 -0
  13. data/lib/artifactory/resources/repository.rb +11 -14
  14. data/lib/artifactory/resources/url_base.rb +74 -0
  15. data/lib/artifactory/util.rb +41 -0
  16. data/lib/artifactory/version.rb +1 -1
  17. data/spec/integration/resources/backup.rb +22 -0
  18. data/spec/integration/resources/build_spec.rb +1 -3
  19. data/spec/integration/resources/group_spec.rb +2 -2
  20. data/spec/integration/resources/ldap_setting_spec.rb +22 -0
  21. data/spec/integration/resources/mail_server_spec.rb +22 -0
  22. data/spec/integration/resources/repository_spec.rb +1 -1
  23. data/spec/integration/resources/system_spec.rb +1 -1
  24. data/spec/integration/resources/url_base_spec.rb +22 -0
  25. data/spec/integration/resources/user_spec.rb +2 -2
  26. data/spec/spec_helper.rb +0 -1
  27. data/spec/support/api_server/system_endpoints.rb +44 -1
  28. data/spec/unit/artifactory_spec.rb +3 -3
  29. data/spec/unit/client_spec.rb +1 -1
  30. data/spec/unit/resources/artifact_spec.rb +18 -36
  31. data/spec/unit/resources/backup_spec.rb +61 -0
  32. data/spec/unit/resources/base_spec.rb +3 -3
  33. data/spec/unit/resources/build_spec.rb +3 -3
  34. data/spec/unit/resources/group_spec.rb +6 -6
  35. data/spec/unit/resources/layout_spec.rb +4 -4
  36. data/spec/unit/resources/ldap_setting_spec.rb +65 -0
  37. data/spec/unit/resources/mail_server_spec.rb +57 -0
  38. data/spec/unit/resources/plugin_spec.rb +2 -2
  39. data/spec/unit/resources/repository_spec.rb +19 -27
  40. data/spec/unit/resources/system_spec.rb +6 -6
  41. data/spec/unit/resources/url_base_spec.rb +53 -0
  42. data/spec/unit/resources/user_spec.rb +8 -8
  43. metadata +23 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f140751bb7b38da3e211b0c3fbd7332bb60754f3
4
- data.tar.gz: cf32023c6d7ade23e0237828d4a2f25f6c4ed8aa
3
+ metadata.gz: 096468dc3e965e5a8eccdbc3c0e70e56db2f3e13
4
+ data.tar.gz: a301449af639917f992d38e3ced4d7215d32612d
5
5
  SHA512:
6
- metadata.gz: bbc1d3688eee73f034dd8f39c62ad086555aea4345636f2654f428b5d1f89e4b92ee02fbc554187cb42057eaa6d02eb694a82f60afac33cd00987fc033406363
7
- data.tar.gz: 139a0c2ac153c5440dae9d6893b081ad7730139f621ce36c393af81cb89d0a116bd6ff85d9395dd2a43017baa0bf2fbc03c811bc01edf41894298ceab4203d4d
6
+ metadata.gz: f91a4477e6b82e3f2728de0ad4872269e77696e6dbc9195ec4900c27173021a0805ced4da035d8edda721e82ab81f09156616b15208d8d0df860b6fc80aee583
7
+ data.tar.gz: 4a3eaac28598ff0aee2936795f231b7e2549921131967f4448037ac36021ef595a98aba69ea4c2356b0027cdb9c1811dea7fa865815b77d81a7f671b9a7aa106
@@ -3,6 +3,21 @@ Artifactory Client CHANGELOG
3
3
  This file is used to document the changes between releases of the Artifactory
4
4
  Ruby client.
5
5
 
6
+ v2.0.0 (07-15-2014)
7
+ -------------------
8
+ **Breaking Changes**
9
+ - Change the airity of uploading an Artifact
10
+ - Automatically upload checksum files during Artifact upload
11
+
12
+ **Other Changes**
13
+ - Bump to RSpec 3
14
+ - Add support for configuring the Backup resource
15
+ - Add support for configuring the LDAPSetting resource
16
+ - Add support for configuring the MailServer resource
17
+ - Add support for configuring the URLBase resource
18
+ - Set `Transfer-Encoding` to "chunked"
19
+ - Do not swallow returned errors from the server
20
+
6
21
  v1.2.0 (2014-06-02)
7
22
  -------------------
8
23
  - Change the airty of Repository#find to align with other resources
data/Gemfile CHANGED
@@ -3,6 +3,6 @@ gemspec
3
3
 
4
4
  group :test do
5
5
  gem 'sinatra', '~> 1.4'
6
- gem 'rspec', '~> 2.14'
6
+ gem 'rspec', '~> 3.0'
7
7
  gem 'webmock', '~> 1.17'
8
8
  end
@@ -14,15 +14,19 @@ module Artifactory
14
14
  end
15
15
 
16
16
  module Resource
17
- autoload :Artifact, 'artifactory/resources/artifact'
18
- autoload :Base, 'artifactory/resources/base'
19
- autoload :Build, 'artifactory/resources/build'
20
- autoload :Group, 'artifactory/resources/group'
21
- autoload :Layout, 'artifactory/resources/layout'
22
- autoload :Plugin, 'artifactory/resources/plugin'
23
- autoload :Repository, 'artifactory/resources/repository'
24
- autoload :System, 'artifactory/resources/system'
25
- autoload :User, 'artifactory/resources/user'
17
+ autoload :Artifact, 'artifactory/resources/artifact'
18
+ autoload :Backup, 'artifactory/resources/backup'
19
+ autoload :Base, 'artifactory/resources/base'
20
+ autoload :Build, 'artifactory/resources/build'
21
+ autoload :Group, 'artifactory/resources/group'
22
+ autoload :Layout, 'artifactory/resources/layout'
23
+ autoload :LDAPSetting, 'artifactory/resources/ldap_setting'
24
+ autoload :MailServer, 'artifactory/resources/mail_server'
25
+ autoload :Plugin, 'artifactory/resources/plugin'
26
+ autoload :Repository, 'artifactory/resources/repository'
27
+ autoload :System, 'artifactory/resources/system'
28
+ autoload :URLBase, 'artifactory/resources/url_base'
29
+ autoload :User, 'artifactory/resources/user'
26
30
  end
27
31
 
28
32
  class << self
@@ -32,8 +32,12 @@ module Artifactory
32
32
  include Artifactory::Configurable
33
33
 
34
34
  proxy Resource::Artifact
35
+ proxy Resource::Backup
35
36
  proxy Resource::Layout
37
+ proxy Resource::LDAPSetting
38
+ proxy Resource::MailServer
36
39
  proxy Resource::Repository
40
+ proxy Resource::URLBase
37
41
  proxy Resource::User
38
42
  proxy Resource::System
39
43
 
@@ -176,6 +180,7 @@ module Artifactory
176
180
  # Setup PATCH/POST/PUT
177
181
  if [:patch, :post, :put].include?(verb)
178
182
  if data.respond_to?(:read)
183
+ request.add_field('Transfer-Encoding', 'chunked')
179
184
  request.body_stream = data
180
185
  elsif data.is_a?(Hash)
181
186
  request.form_data = data
@@ -337,9 +342,17 @@ module Artifactory
337
342
  # the response object from the request
338
343
  #
339
344
  def error(response)
340
- error = JSON.parse(response.body)['errors'].first
341
- raise Error::HTTPError.new(error)
342
- rescue JSON::ParserError
345
+ if (response.content_type || '').include?('json')
346
+ # Attempt to parse the error as JSON
347
+ begin
348
+ json = JSON.parse(response.body)
349
+
350
+ if json['errors'] && json['errors'].first
351
+ raise Error::HTTPError.new(json['errors'].first)
352
+ end
353
+ rescue JSON::ParserError; end
354
+ end
355
+
343
356
  raise Error::HTTPError.new(
344
357
  'status' => response.code,
345
358
  'message' => response.body,
@@ -6,13 +6,12 @@ module Artifactory
6
6
  # Class for all HTTP errors
7
7
  class HTTPError < ArtifactoryError
8
8
  attr_reader :code
9
- attr_reader :message
10
9
 
11
10
  def initialize(hash = {})
12
11
  @code = hash['status'].to_i
13
12
  @http = hash['message'].to_s
14
13
 
15
- super "The Artifactory server responded with an HTTP Error "\
14
+ super "The Artifactory server responded with an HTTP Error " \
16
15
  "#{@code}: `#{@http}'"
17
16
  end
18
17
  end
@@ -406,25 +406,20 @@ module Artifactory
406
406
  # @see bit.ly/1dhJRMO Artifactory Matrix Properties
407
407
  #
408
408
  # @example Upload an artifact from a File instance
409
- # file = File.new('/local/path/to/file.deb')
410
- # artifact = Artifact.new
411
- # artifact.upload(file, 'libs-release-local', file.deb')
412
- #
413
- # @example Upload an artifact from a path
414
- # artifact.upload('/local/path/to/file.deb', 'libs-release-local', 'file.deb')
409
+ # artifact = Artifact.new(local_path: '/local/path/to/file.deb')
410
+ # artifact.upload('libs-release-local', '/remote/path')
415
411
  #
416
412
  # @example Upload an artifact with matrix properties
417
- # artifact.upload('/local/path/to/file.deb', 'libs-release-local', file.deb', {
413
+ # artifact = Artifact.new(local_path: '/local/path/to/file.deb')
414
+ # artifact.upload('libs-release-local', '/remote/path', {
418
415
  # status: 'DEV',
419
416
  # rating: 5,
420
417
  # branch: 'master'
421
418
  # })
422
419
  #
423
- # @param [String] key
420
+ # @param [String] repo
424
421
  # the key of the repository to which to upload the file
425
- # @param [String, File] path_or_io
426
- # the file or path to the file to upload
427
- # @param [String] path
422
+ # @param [String] remote_path
428
423
  # the path where this resource will live in the remote artifactory
429
424
  # repository, relative to the repository key
430
425
  # @param [Hash] headers
@@ -434,20 +429,54 @@ module Artifactory
434
429
  #
435
430
  # @return [Resource::Artifact]
436
431
  #
437
- def upload(key, path_or_io, path, properties = {}, headers = {})
438
- file = if respond_to?(:read)
439
- path_or_io
440
- else
441
- File.new(File.expand_path(path_or_io))
442
- end
443
-
432
+ def upload(repo, remote_path, properties = {}, headers = {})
433
+ file = File.new(File.expand_path(local_path))
444
434
  matrix = to_matrix_properties(properties)
445
- endpoint = File.join("#{url_safe(key)}#{matrix}", path)
435
+ endpoint = File.join("#{url_safe(repo)}#{matrix}", remote_path)
446
436
 
447
437
  response = client.put(endpoint, file, headers)
438
+
439
+ # Upload checksums if they were given
440
+ upload_checksum(repo, remote_path, :md5, md5) if md5
441
+ upload_checksum(repo, remote_path, :sha1, sha1) if sha1
442
+
448
443
  self.class.from_hash(response)
449
444
  end
450
445
 
446
+ #
447
+ # Upload the checksum for this artifact. **The artifact must already be
448
+ # uploaded or Artifactory will throw an exception!**. This is both a public
449
+ # and private API. It is automatically called in {upload} if the SHA
450
+ # values are set. You may also call it manually.
451
+ #
452
+ # @example Set an artifact's md5
453
+ # artifact = Artifact.new(local_path: '/local/path/to/file.deb')
454
+ # artifact.upload_checksum('libs-release-local', '/remote/path', :md5, 'ABCD1234')
455
+ #
456
+ # @param (see Artifact#upload)
457
+ # @param [Symbol] type
458
+ # the type of checksum to write (+md5+ or +sha1+)
459
+ # @param [String] value
460
+ # the actual checksum
461
+ #
462
+ # @return [true]
463
+ #
464
+ def upload_checksum(repo, remote_path, type, value)
465
+ file = Tempfile.new("checksum.#{type}")
466
+ file.write(value)
467
+ file.rewind
468
+
469
+ endpoint = File.join(url_safe(repo), "#{remote_path}.#{type}")
470
+
471
+ client.put(endpoint, file)
472
+ true
473
+ ensure
474
+ if file
475
+ file.close
476
+ file.unlink
477
+ end
478
+ end
479
+
451
480
  #
452
481
  # Upload an artifact with the given SHA checksum. Consult the artifactory
453
482
  # documentation for the possible responses when the checksums fail to
@@ -456,15 +485,15 @@ module Artifactory
456
485
  # @see Artifact#upload More syntax examples
457
486
  #
458
487
  # @example Upload an artifact with a checksum
459
- # artifact = Artifact.new
460
- # artifact.upload_with_checksum('/local/file', 'libs-release-local', /remote/path', 'ABCD1234')
488
+ # artifact = Artifact.new(local_path: '/local/path/to/file.deb')
489
+ # artifact.upload_with_checksum('libs-release-local', /remote/path', 'ABCD1234')
461
490
  #
462
491
  # @param (see Artifact#upload)
463
492
  # @param [String] checksum
464
493
  # the SHA1 checksum of the artifact to upload
465
494
  #
466
- def upload_with_checksum(key, path_or_io, path, checksum, properties = {})
467
- upload(key, path_or_io, path, properties,
495
+ def upload_with_checksum(repo, remote_path, checksum, properties = {})
496
+ upload(repo, remote_path, properties,
468
497
  'X-Checksum-Deploy' => true,
469
498
  'X-Checksum-Sha1' => checksum,
470
499
  )
@@ -477,13 +506,13 @@ module Artifactory
477
506
  # @see Artifact#upload More syntax examples
478
507
  #
479
508
  # @example Upload an artifact with a checksum
480
- # artifact = Artifact.new('libs-release-local')
481
- # artifact.upload_from_archive('/local/archive', '/remote/path')#
509
+ # artifact = Artifact.new(local_path: '/local/path/to/file.deb')
510
+ # artifact.upload_from_archive('/remote/path')
482
511
  #
483
512
  # @param (see Repository#upload)
484
513
  #
485
- def upload_from_archive(key, path_or_io, path, properties = {})
486
- upload(key, path_or_io, path, properties,
514
+ def upload_from_archive(repo, remote_path, properties = {})
515
+ upload(repo, remote_path, properties,
487
516
  'X-Explode-Archive' => true,
488
517
  )
489
518
  end
@@ -0,0 +1,104 @@
1
+ require 'rexml/document'
2
+
3
+ module Artifactory
4
+ class Resource::Backup < Resource::Base
5
+ class << self
6
+ #
7
+ # Get a list of all backup jobs in the system.
8
+ #
9
+ # @param [Hash] options
10
+ # the list of options
11
+ #
12
+ # @option options [Artifactory::Client] :client
13
+ # the client object to make the request with
14
+ #
15
+ # @return [Array<Resource::Backup>]
16
+ # the list of backup jobs
17
+ #
18
+ def all(options = {})
19
+ config = Resource::System.configuration(options)
20
+ list_from_config('config/backups/backup', config, options)
21
+ end
22
+
23
+ #
24
+ # Find (fetch) a backup job by its key.
25
+ #
26
+ # @example Find a Backup by its key.
27
+ # backup.find('backup-daily') #=> #<Backup key: 'backup-daily' ...>
28
+ #
29
+ # @param [String] key
30
+ # the name of the backup job to find
31
+ # @param [Hash] options
32
+ # the list of options
33
+ #
34
+ # @option options [Artifactory::Client] :client
35
+ # the client object to make the request with
36
+ #
37
+ # @return [Resource::Backup, nil]
38
+ # an instance of the backup job that matches the given key, or +nil+
39
+ # if one does not exist
40
+ #
41
+ def find(key, options = {})
42
+ config = Resource::System.configuration(options)
43
+ find_from_config("config/backups/backup/key[text()='#{key}']", config, options)
44
+ rescue Error::HTTPError => e
45
+ raise unless e.code == 404
46
+ nil
47
+ end
48
+
49
+ private
50
+
51
+ #
52
+ # List all the child text elements in the Artifactory configuration file
53
+ # of a node matching the specified xpath
54
+ #
55
+ # @param [String] xpath
56
+ # xpath expression for the parent element whose children are to be listed
57
+ #
58
+ # @param [REXML] config
59
+ # Artifactory config as an REXML file
60
+ #
61
+ # @param [Hash] options
62
+ # the list of options
63
+ #
64
+ # @return [~Resource::Base]
65
+ #
66
+ def list_from_config(xpath, config, options = {})
67
+ REXML::XPath.match(config, xpath).map do |r|
68
+ hash = Util.xml_to_hash(r, 'excludedRepositories', false)
69
+ from_hash(hash, options)
70
+ end
71
+ end
72
+
73
+ #
74
+ # Find all the sibling text elements in the Artifactory configuration file
75
+ # of a node matching the specified xpath
76
+ #
77
+ # @param [String] xpath
78
+ # xpath expression for the element whose siblings are to be found
79
+ #
80
+ # @param [REXML] config
81
+ # Artifactory configuration file as an REXML doc
82
+ #
83
+ # @param [Hash] options
84
+ # the list of options
85
+ #
86
+ def find_from_config(xpath, config, options = {})
87
+ name_node = REXML::XPath.match(config, xpath)
88
+ return nil if name_node.empty?
89
+ properties = Util.xml_to_hash(name_node[0].parent, 'excludedRepositories', false)
90
+ from_hash(properties, options)
91
+ end
92
+ end
93
+
94
+ attribute :key, ->{ raise 'name missing!' }
95
+ attribute :enabled, true
96
+ attribute :dir
97
+ attribute :cron_exp
98
+ attribute :retention_period_hours
99
+ attribute :create_archive
100
+ attribute :excluded_repositories
101
+ attribute :send_mail_on_error
102
+ attribute :exclude_builds
103
+ end
104
+ end
@@ -91,6 +91,53 @@ module Artifactory
91
91
  from_hash(client.get(url), client: client)
92
92
  end
93
93
 
94
+ #
95
+ # List all the child text elements in the Artifactory configuration file
96
+ # of a node matching the specified xpath
97
+ #
98
+ # @param [String] xpath
99
+ # xpath expression for the parent element whose children are to be listed
100
+ #
101
+ # @param [REXML] config
102
+ # Artifactory config as an REXML file
103
+ #
104
+ # @param [Hash] options
105
+ # the list of options
106
+ #
107
+ def list_from_config(xpath, config, options = {})
108
+ REXML::XPath.match(config, xpath).map do |r|
109
+ hash = {}
110
+
111
+ r.each_element_with_text do |l|
112
+ hash[l.name] = l.get_text
113
+ end
114
+ from_hash(hash, options)
115
+ end
116
+ end
117
+
118
+ #
119
+ # Find the text elements matching a giving xpath
120
+ #
121
+ # @param [String] xpath
122
+ # xpath expression
123
+ #
124
+ # @param [REXML] config
125
+ # Artifactory configuration file as an REXML doc
126
+ #
127
+ # @param [Hash] options
128
+ # the list of options
129
+ #
130
+ def find_from_config(xpath, config, options = {})
131
+ name_node = REXML::XPath.match(config, xpath)
132
+ return nil if name_node.empty?
133
+ properties = {}
134
+ name_node[0].parent.each_element_with_text do |e|
135
+ properties[e.name] = Util.to_type(e.text)
136
+ end
137
+
138
+ from_hash(properties, options)
139
+ end
140
+
94
141
  #
95
142
  # Construct a new object from the hash.
96
143
  #
@@ -45,60 +45,11 @@ module Artifactory
45
45
  raise unless e.code == 404
46
46
  nil
47
47
  end
48
-
49
- private
50
- #
51
- # List all the child text elements in the Artifactory configuration file
52
- # of a node matching the specified xpath
53
- #
54
- # @param [String] xpath
55
- # xpath expression for the parent element whose children are to be listed
56
- #
57
- # @param [REXML] config
58
- # Artifactory config as an REXML file
59
- #
60
- # @param [Hash] options
61
- # the list of options
62
- #
63
- def list_from_config(xpath, config, options = {})
64
- REXML::XPath.match(config, xpath).map do |r|
65
- hash = {}
66
-
67
- r.each_element_with_text do |l|
68
- hash[l.name] = l.get_text
69
- end
70
- from_hash(hash, options)
71
- end
72
- end
73
-
74
- #
75
- # Find all the sibling text elements in the Artifactory configuration file
76
- # of a node matching the specified xpath
77
- #
78
- # @param [String] xpath
79
- # xpath expression for the element whose siblings are to be found
80
- #
81
- # @param [REXML] config
82
- # Artifactory configuration file as an REXML doc
83
- #
84
- # @param [Hash] options
85
- # the list of options
86
- #
87
- def find_from_config(xpath, config, options = {})
88
- name_node = REXML::XPath.match(config, xpath)
89
- return nil if name_node.empty?
90
- properties = {}
91
- name_node[0].parent.each_element_with_text do |e|
92
- properties[e.name] = e.text
93
- end
94
-
95
- from_hash(properties, options)
96
- end
97
48
  end
98
49
 
99
50
  attribute :name, ->{ raise 'Name missing!' }
100
51
  attribute :artifact_path_pattern
101
- attribute :distinctive_descriptor_path_pattern, 'true'
52
+ attribute :distinctive_descriptor_path_pattern, true
102
53
  attribute :descriptor_path_pattern
103
54
  attribute :folder_integration_revision_reg_exp
104
55
  attribute :file_integration_revision_reg_exp