artifactory 2.2.1 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +31 -3
- data/Rakefile +6 -2
- data/lib/artifactory.rb +2 -0
- data/lib/artifactory/collections/build.rb +28 -0
- data/lib/artifactory/errors.rb +14 -0
- data/lib/artifactory/resources/artifact.rb +1 -12
- data/lib/artifactory/resources/base.rb +22 -2
- data/lib/artifactory/resources/build.rb +188 -3
- data/lib/artifactory/resources/build_component.rb +160 -0
- data/lib/artifactory/version.rb +1 -1
- data/spec/integration/resources/build_component_spec.rb +64 -0
- data/spec/integration/resources/build_spec.rb +29 -1
- data/spec/spec_helper.rb +2 -1
- data/spec/support/api_server.rb +2 -0
- data/spec/support/api_server/build_component_endpoints.rb +44 -0
- data/spec/support/api_server/build_endpoints.rb +217 -8
- data/spec/unit/resources/build_component_spec.rb +118 -0
- data/spec/unit/resources/build_spec.rb +319 -6
- data/spec/unit/resources/permission_target_spec.rb +1 -1
- metadata +11 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f36b33be0b821d20e678a3f104b7fd24a41ebd93
|
|
4
|
+
data.tar.gz: 144d1a14596dd383816dbb47158249a578cf31af
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d85c333c34fa8fcb273ccf4a8fee6598f8e748c310c6f8de1b75c57c793994e5046ff98d37983ecd771a311d81c6c65e92df25b493a82e273a20e237cf7b1720
|
|
7
|
+
data.tar.gz: 9ea0a6be40e91885a8a1ea63b62a4fa2032c4e751f8536b325e60e7eea783464e2930fdd5821e37110de890952fc685f659ea13b800827dae4d2360ad2bc8cf0
|
data/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,10 @@ 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.3.0 (08-04-2015)
|
|
7
|
+
-------------------
|
|
8
|
+
- Support for Build endpoints
|
|
9
|
+
|
|
6
10
|
v2.2.1 (12-16-2014)
|
|
7
11
|
-------------------
|
|
8
12
|
- provide data to post in `Artifact#copy_or_move`
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Artifactory Client
|
|
2
2
|
==================
|
|
3
|
-
[](http://travis-ci.org/chef/artifactory-client)
|
|
4
4
|
|
|
5
5
|
A Ruby client and interface to the Artifactory API. **The majority of API endpoints are only exposed for Artifactory Pro customers!** As such, many of the resources and actions exposed by this gem also require Artifactory Pro.
|
|
6
6
|
|
|
@@ -121,8 +121,36 @@ artifact.delete #=> true
|
|
|
121
121
|
|
|
122
122
|
#### Builds
|
|
123
123
|
```ruby
|
|
124
|
-
# Show all
|
|
125
|
-
|
|
124
|
+
# Show all components
|
|
125
|
+
BuildComponent.all #=> [#<BuildComponent ...>]
|
|
126
|
+
|
|
127
|
+
# Show all builds for a components
|
|
128
|
+
Build.all('wicket') #=> [#<Build ...>]
|
|
129
|
+
|
|
130
|
+
# Find a build component by name
|
|
131
|
+
component = BuildComponent.find('wicket')
|
|
132
|
+
|
|
133
|
+
# Delete some builds for a component
|
|
134
|
+
component.delete(build_numbers: %w( 51 52)) #=> true
|
|
135
|
+
|
|
136
|
+
# Delete all builds for a component
|
|
137
|
+
component.delete(delete_all: true) #=> true
|
|
138
|
+
|
|
139
|
+
# Delete a component and all of its associated data (including artifacts)
|
|
140
|
+
component.delete(artifacts: true, delete_all: true) #=> true
|
|
141
|
+
|
|
142
|
+
# Get a list of all buld records for a component
|
|
143
|
+
component.builds #=> #=> [#<Artifactory::Resource::Build ...>, ...]
|
|
144
|
+
|
|
145
|
+
# Create a new build record
|
|
146
|
+
build = Build.new(name: 'fricket', number: '51', properties: {...}, modules: [...])
|
|
147
|
+
build.save
|
|
148
|
+
|
|
149
|
+
# Find a build
|
|
150
|
+
build = Build.find('wicket', '51')
|
|
151
|
+
|
|
152
|
+
# Promote a build
|
|
153
|
+
build.promote('libs-release-local', status: 'staged', comment: 'Tested on all target platforms.')
|
|
126
154
|
```
|
|
127
155
|
|
|
128
156
|
#### Plugins
|
data/Rakefile
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
require 'bundler/gem_tasks'
|
|
2
2
|
|
|
3
3
|
require 'rspec/core/rake_task'
|
|
4
|
-
RSpec::Core::RakeTask.new(:integration)
|
|
5
|
-
|
|
4
|
+
RSpec::Core::RakeTask.new(:integration) do |t|
|
|
5
|
+
t.rspec_opts = "--tag integration"
|
|
6
|
+
end
|
|
7
|
+
RSpec::Core::RakeTask.new(:unit) do |t|
|
|
8
|
+
t.rspec_opts = "--tag ~integration"
|
|
9
|
+
end
|
|
6
10
|
|
|
7
11
|
namespace :travis do
|
|
8
12
|
desc 'Run tests on Travis'
|
data/lib/artifactory.rb
CHANGED
|
@@ -27,6 +27,7 @@ module Artifactory
|
|
|
27
27
|
module Collection
|
|
28
28
|
autoload :Artifact, 'artifactory/collections/artifact'
|
|
29
29
|
autoload :Base, 'artifactory/collections/base'
|
|
30
|
+
autoload :Build, 'artifactory/collections/build'
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
module Resource
|
|
@@ -34,6 +35,7 @@ module Artifactory
|
|
|
34
35
|
autoload :Backup, 'artifactory/resources/backup'
|
|
35
36
|
autoload :Base, 'artifactory/resources/base'
|
|
36
37
|
autoload :Build, 'artifactory/resources/build'
|
|
38
|
+
autoload :BuildComponent, 'artifactory/resources/build_component'
|
|
37
39
|
autoload :Group, 'artifactory/resources/group'
|
|
38
40
|
autoload :Layout, 'artifactory/resources/layout'
|
|
39
41
|
autoload :LDAPSetting, 'artifactory/resources/ldap_setting'
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2015 Chef Software, Inc.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#
|
|
16
|
+
|
|
17
|
+
module Artifactory
|
|
18
|
+
class Collection::Build < Collection::Base
|
|
19
|
+
#
|
|
20
|
+
# Create a new build collection.
|
|
21
|
+
#
|
|
22
|
+
# @param (see Collection::Base#initialize)
|
|
23
|
+
#
|
|
24
|
+
def initialize(parent, options = {}, &block)
|
|
25
|
+
super(Resource::Build, parent, options, &block)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
data/lib/artifactory/errors.rb
CHANGED
|
@@ -40,5 +40,19 @@ module Artifactory
|
|
|
40
40
|
"running an that your authentication information is correct."
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
|
+
|
|
44
|
+
# A general connection error with a more informative message
|
|
45
|
+
class InvalidBuildType < ArtifactoryError
|
|
46
|
+
def initialize(given_type)
|
|
47
|
+
super <<-EOH
|
|
48
|
+
'#{given_type}' is not a valid build type.
|
|
49
|
+
|
|
50
|
+
Valid build types include:
|
|
51
|
+
|
|
52
|
+
#{Resource::Build::BUILD_TYPES.join("\n ")}"
|
|
53
|
+
|
|
54
|
+
EOH
|
|
55
|
+
end
|
|
56
|
+
end
|
|
43
57
|
end
|
|
44
58
|
end
|
|
@@ -663,18 +663,7 @@ module Artifactory
|
|
|
663
663
|
param[:dry] = 1 if options[:dry_run]
|
|
664
664
|
end
|
|
665
665
|
|
|
666
|
-
|
|
667
|
-
# to make a POST request, but you don't actually read the contents of the
|
|
668
|
-
# POST request, you read the URL-params. Sigh, whoever claimed this was a
|
|
669
|
-
# RESTful API should seriously consider a new occupation.
|
|
670
|
-
params = params.map do |k, v|
|
|
671
|
-
key = URI.escape(k.to_s)
|
|
672
|
-
value = URI.escape(v.to_s)
|
|
673
|
-
|
|
674
|
-
"#{key}=#{value}"
|
|
675
|
-
end
|
|
676
|
-
|
|
677
|
-
endpoint = File.join('/api', action.to_s, relative_path) + '?' + params.join('&')
|
|
666
|
+
endpoint = File.join('/api', action.to_s, relative_path) + "?#{to_query_string_parameters(params)}"
|
|
678
667
|
|
|
679
668
|
client.post(endpoint, {})
|
|
680
669
|
end
|
|
@@ -297,7 +297,7 @@ module Artifactory
|
|
|
297
297
|
def to_hash
|
|
298
298
|
attributes.inject({}) do |hash, (key, value)|
|
|
299
299
|
unless Resource::Base.has_attribute?(key)
|
|
300
|
-
hash[Util.camelize(key, true)] =
|
|
300
|
+
hash[Util.camelize(key, true)] = send(key.to_sym)
|
|
301
301
|
end
|
|
302
302
|
|
|
303
303
|
hash
|
|
@@ -316,7 +316,7 @@ module Artifactory
|
|
|
316
316
|
end
|
|
317
317
|
|
|
318
318
|
#
|
|
319
|
-
# Create
|
|
319
|
+
# Create CGI-escaped string from matrix properties
|
|
320
320
|
#
|
|
321
321
|
# @see http://bit.ly/1qeVYQl
|
|
322
322
|
#
|
|
@@ -335,6 +335,26 @@ module Artifactory
|
|
|
335
335
|
end
|
|
336
336
|
end
|
|
337
337
|
|
|
338
|
+
#
|
|
339
|
+
# Create URI-escaped querystring parameters
|
|
340
|
+
#
|
|
341
|
+
# @see http://bit.ly/1qeVYQl
|
|
342
|
+
#
|
|
343
|
+
def to_query_string_parameters(hash = {})
|
|
344
|
+
properties = hash.map do |k, v|
|
|
345
|
+
key = URI.escape(k.to_s)
|
|
346
|
+
value = URI.escape(v.to_s)
|
|
347
|
+
|
|
348
|
+
"#{key}=#{value}"
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
if properties.empty?
|
|
352
|
+
nil
|
|
353
|
+
else
|
|
354
|
+
properties.join('&')
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
|
|
338
358
|
# @private
|
|
339
359
|
def to_s
|
|
340
360
|
"#<#{short_classname}>"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright
|
|
2
|
+
# Copyright 2015 Chef Software, Inc.
|
|
3
3
|
#
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
# you may not use this file except in compliance with the License.
|
|
@@ -14,12 +14,20 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
#
|
|
16
16
|
|
|
17
|
+
require 'time'
|
|
18
|
+
|
|
17
19
|
module Artifactory
|
|
18
20
|
class Resource::Build < Resource::Base
|
|
21
|
+
BUILD_SCHEMA_VERSION = '1.0.1'.freeze
|
|
22
|
+
# valid build types as dictated by the Artifactory API
|
|
23
|
+
BUILD_TYPES = %w( ANT IVY MAVEN GENERIC GRADLE )
|
|
24
|
+
|
|
19
25
|
class << self
|
|
20
26
|
#
|
|
21
27
|
# Search for all builds in the system.
|
|
22
28
|
#
|
|
29
|
+
# @param [String] name
|
|
30
|
+
# the name of the build component
|
|
23
31
|
# @param [Hash] options
|
|
24
32
|
# the list of options
|
|
25
33
|
#
|
|
@@ -29,9 +37,13 @@ module Artifactory
|
|
|
29
37
|
# @return [Array<Resource::Build>]
|
|
30
38
|
# the list of builds
|
|
31
39
|
#
|
|
32
|
-
def all(options = {})
|
|
40
|
+
def all(name, options = {})
|
|
33
41
|
client = extract_client!(options)
|
|
34
|
-
client.get(
|
|
42
|
+
client.get("/api/build/#{url_safe(name)}")['buildsNumbers'].map do |build_number|
|
|
43
|
+
# Remove the leading / from the `uri` value. Converts `/484` to `484`.
|
|
44
|
+
number = build_number['uri'].slice(1..-1)
|
|
45
|
+
find(name, number, client: client)
|
|
46
|
+
end.compact.flatten
|
|
35
47
|
rescue Error::HTTPError => e
|
|
36
48
|
# Artifactory returns a 404 instead of an empty list when there are no
|
|
37
49
|
# builds. Whoever decided that was a good idea clearly doesn't
|
|
@@ -39,6 +51,179 @@ module Artifactory
|
|
|
39
51
|
raise unless e.code == 404
|
|
40
52
|
[]
|
|
41
53
|
end
|
|
54
|
+
|
|
55
|
+
#
|
|
56
|
+
# Find (fetch) data for a particular build of a component
|
|
57
|
+
#
|
|
58
|
+
# @example Find data for a build of a component
|
|
59
|
+
# Build.find('wicket', 25) #=> #<Build name: 'wicket' ...>
|
|
60
|
+
#
|
|
61
|
+
# @param [String] name
|
|
62
|
+
# the name of the build component
|
|
63
|
+
# @param [String] number
|
|
64
|
+
# the number of the build
|
|
65
|
+
# @param [Hash] options
|
|
66
|
+
# the list of options
|
|
67
|
+
#
|
|
68
|
+
# @option options [Artifactory::Client] :client
|
|
69
|
+
# the client object to make the request with
|
|
70
|
+
#
|
|
71
|
+
# @return [Resource::Build, nil]
|
|
72
|
+
# an instance of the build that matches the given name/number
|
|
73
|
+
# combination, or +nil+ if one does not exist
|
|
74
|
+
#
|
|
75
|
+
def find(name, number, options = {})
|
|
76
|
+
client = extract_client!(options)
|
|
77
|
+
response = client.get("/api/build/#{url_safe(name)}/#{url_safe(number)}")
|
|
78
|
+
from_hash(response['buildInfo'], client: client)
|
|
79
|
+
rescue Error::HTTPError => e
|
|
80
|
+
raise unless e.code == 404
|
|
81
|
+
nil
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
#
|
|
85
|
+
# @see Artifactory::Resource::Base.from_hash
|
|
86
|
+
#
|
|
87
|
+
def from_hash(hash, options = {})
|
|
88
|
+
super.tap do |instance|
|
|
89
|
+
instance.started = Time.parse(instance.started) rescue nil
|
|
90
|
+
instance.duration_millis = instance.duration_millis.to_i
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Based on https://github.com/JFrogDev/build-info/blob/master/README.md#build-info-json-format
|
|
96
|
+
attribute :properties, {}
|
|
97
|
+
attribute :version, BUILD_SCHEMA_VERSION
|
|
98
|
+
attribute :name, ->{ raise 'Build component missing!' }
|
|
99
|
+
attribute :number, ->{ raise 'Build number missing!' }
|
|
100
|
+
attribute :type, 'GENERIC'
|
|
101
|
+
attribute :build_agent, {}
|
|
102
|
+
attribute :agent, {}
|
|
103
|
+
attribute :started, Time.now.utc.iso8601(3)
|
|
104
|
+
attribute :duration_millis
|
|
105
|
+
attribute :artifactory_principal
|
|
106
|
+
attribute :url
|
|
107
|
+
attribute :vcs_revision
|
|
108
|
+
attribute :vcs_url
|
|
109
|
+
attribute :license_control, {}
|
|
110
|
+
attribute :build_retention, {}
|
|
111
|
+
attribute :modules, []
|
|
112
|
+
attribute :governance
|
|
113
|
+
|
|
114
|
+
#
|
|
115
|
+
# Compare a build artifacts/dependencies/environment with an older
|
|
116
|
+
# build to see what has changed (new artifacts added, old dependencies
|
|
117
|
+
# deleted etc).
|
|
118
|
+
#
|
|
119
|
+
# @example List all properties for an artifact
|
|
120
|
+
# build.diff(35) #=> { 'artifacts'=>{}, 'dependencies'=>{}, 'properties'=>{} }
|
|
121
|
+
#
|
|
122
|
+
# @param [String] previous_build_number
|
|
123
|
+
# the number of the previous build to compare against
|
|
124
|
+
#
|
|
125
|
+
# @return [Hash<String, Hash>]
|
|
126
|
+
# the list of properties
|
|
127
|
+
#
|
|
128
|
+
def diff(previous_build_number)
|
|
129
|
+
endpoint = api_path + '?' "diff=#{url_safe(previous_build_number)}"
|
|
130
|
+
client.get(endpoint, {})
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
#
|
|
134
|
+
# Move a build's artifacts to a new repository optionally moving or
|
|
135
|
+
# copying the build's dependencies to the target repository
|
|
136
|
+
# and setting properties on promoted artifacts.
|
|
137
|
+
#
|
|
138
|
+
# @example promote the build to 'omnibus-stable-local'
|
|
139
|
+
# build.promote('omnibus-stable-local')
|
|
140
|
+
# @example promote a build attaching some new properites
|
|
141
|
+
# build.promote('omnibus-stable-local'
|
|
142
|
+
# properties: {
|
|
143
|
+
# 'promoted_by' => 'hipchat:schisamo@chef.io'
|
|
144
|
+
# }
|
|
145
|
+
# )
|
|
146
|
+
#
|
|
147
|
+
# @param [String] target_repo
|
|
148
|
+
# repository to move or copy the build's artifacts and/or dependencies
|
|
149
|
+
# @param [Hash] options
|
|
150
|
+
# the list of options to pass
|
|
151
|
+
#
|
|
152
|
+
# @option options [String] :status (default: 'promoted')
|
|
153
|
+
# new build status (any string)
|
|
154
|
+
# @option options [String] :comment (default: '')
|
|
155
|
+
# an optional comment describing the reason for promotion
|
|
156
|
+
# @option options [String] :user (default: +Artifactory.username+)
|
|
157
|
+
# the user that invoked promotion
|
|
158
|
+
# @option options [Boolean] :dry_run (default: +false+)
|
|
159
|
+
# pretend to do the promotion
|
|
160
|
+
# @option options [Boolean] :copy (default: +false+)
|
|
161
|
+
# whether to copy instead of move
|
|
162
|
+
# @option options [Boolean] :dependencies (default: +false+)
|
|
163
|
+
# whether to move/copy the build's dependencies
|
|
164
|
+
# @option options [Array] :scopes (default: [])
|
|
165
|
+
# an array of dependency scopes to include when "dependencies" is true
|
|
166
|
+
# @option options [Hash<String, Array<String>>] :properties (default: [])
|
|
167
|
+
# a list of properties to attach to the build's artifacts
|
|
168
|
+
# @option options [Boolean] :fail_fast (default: +true+)
|
|
169
|
+
# fail and abort the operation upon receiving an error
|
|
170
|
+
#
|
|
171
|
+
# @return [Hash]
|
|
172
|
+
# the parsed JSON response from the server
|
|
173
|
+
#
|
|
174
|
+
def promote(target_repo, options = {})
|
|
175
|
+
request_body = {}.tap do |body|
|
|
176
|
+
body[:status] = options[:status] || 'promoted'
|
|
177
|
+
body[:comment] = options[:comment] || ''
|
|
178
|
+
body[:ciUser] = options[:user] || Artifactory.username
|
|
179
|
+
body[:dryRun] = options[:dry_run] || false
|
|
180
|
+
body[:targetRepo] = target_repo
|
|
181
|
+
body[:copy] = options[:copy] || false
|
|
182
|
+
body[:artifacts] = true # always move/copy the build's artifacts
|
|
183
|
+
body[:dependencies] = options[:dependencies] || false
|
|
184
|
+
body[:scopes] = options[:scopes] || []
|
|
185
|
+
body[:properties] = options[:properties] || {}
|
|
186
|
+
body[:failFast] = options[:fail_fast] || true
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
endpoint = "/api/build/promote/#{url_safe(name)}/#{url_safe(number)}"
|
|
190
|
+
client.post(endpoint, JSON.fast_generate(request_body),
|
|
191
|
+
'Content-Type' => 'application/json'
|
|
192
|
+
)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
#
|
|
196
|
+
# Creates data about a build.
|
|
197
|
+
#
|
|
198
|
+
# @return [Boolean]
|
|
199
|
+
#
|
|
200
|
+
def save
|
|
201
|
+
raise Error::InvalidBuildType.new(type) unless BUILD_TYPES.include?(type)
|
|
202
|
+
|
|
203
|
+
file = Tempfile.new("build.json")
|
|
204
|
+
file.write(to_json)
|
|
205
|
+
file.rewind
|
|
206
|
+
|
|
207
|
+
client.put('/api/build', file,
|
|
208
|
+
'Content-Type' => 'application/json'
|
|
209
|
+
)
|
|
210
|
+
true
|
|
211
|
+
ensure
|
|
212
|
+
if file
|
|
213
|
+
file.close
|
|
214
|
+
file.unlink
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
private
|
|
219
|
+
|
|
220
|
+
#
|
|
221
|
+
# The path to this build on the server.
|
|
222
|
+
#
|
|
223
|
+
# @return [String]
|
|
224
|
+
#
|
|
225
|
+
def api_path
|
|
226
|
+
"/api/build/#{url_safe(name)}/#{url_safe(number)}"
|
|
42
227
|
end
|
|
43
228
|
end
|
|
44
229
|
end
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2015 Chef Software, Inc.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#
|
|
16
|
+
|
|
17
|
+
require 'time'
|
|
18
|
+
|
|
19
|
+
module Artifactory
|
|
20
|
+
class Resource::BuildComponent < Resource::Base
|
|
21
|
+
class << self
|
|
22
|
+
#
|
|
23
|
+
# Search for all compoenents for which build data exists.
|
|
24
|
+
#
|
|
25
|
+
# @param [Hash] options
|
|
26
|
+
# the list of options
|
|
27
|
+
#
|
|
28
|
+
# @option options [Artifactory::Client] :client
|
|
29
|
+
# the client object to make the request with
|
|
30
|
+
#
|
|
31
|
+
# @return [Array<Resource::BuildComponent>]
|
|
32
|
+
# the list of builds
|
|
33
|
+
#
|
|
34
|
+
def all(options = {})
|
|
35
|
+
client = extract_client!(options)
|
|
36
|
+
client.get('/api/build')['builds'].map do |component|
|
|
37
|
+
from_hash(component, client: client)
|
|
38
|
+
end.compact.flatten
|
|
39
|
+
rescue Error::HTTPError => e
|
|
40
|
+
# Artifactory returns a 404 instead of an empty list when there are no
|
|
41
|
+
# builds. Whoever decided that was a good idea clearly doesn't
|
|
42
|
+
# understand the point of REST interfaces...
|
|
43
|
+
raise unless e.code == 404
|
|
44
|
+
[]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
#
|
|
48
|
+
# Find (fetch) data for a particular build component
|
|
49
|
+
#
|
|
50
|
+
# @example Find a particular build component
|
|
51
|
+
# BuildComponent.find('wicket') #=> #<BuildComponent name: 'wicket' ...>
|
|
52
|
+
#
|
|
53
|
+
# @param [String] name
|
|
54
|
+
# the name of the build component
|
|
55
|
+
# @param [Hash] options
|
|
56
|
+
# the list of options
|
|
57
|
+
#
|
|
58
|
+
# @option options [Artifactory::Client] :client
|
|
59
|
+
# the client object to make the request with
|
|
60
|
+
#
|
|
61
|
+
# @return [Resource::BuildComponent, nil]
|
|
62
|
+
# an instance of the build component that matches the given name,
|
|
63
|
+
# or +nil+ if one does not exist
|
|
64
|
+
#
|
|
65
|
+
def find(name, options = {})
|
|
66
|
+
client = extract_client!(options)
|
|
67
|
+
all.find do |component|
|
|
68
|
+
component.name == name
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
#
|
|
73
|
+
# @see Artifactory::Resource::Base.from_hash
|
|
74
|
+
#
|
|
75
|
+
def from_hash(hash, options = {})
|
|
76
|
+
super.tap do |instance|
|
|
77
|
+
# Remove the leading / from the `uri` value. Converts `/foo` to `foo`.
|
|
78
|
+
instance.name = instance.uri.slice(1..-1)
|
|
79
|
+
instance.last_started = Time.parse(instance.last_started) rescue nil
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
attribute :uri
|
|
85
|
+
attribute :name, ->{ raise 'Name missing!' }
|
|
86
|
+
attribute :last_started
|
|
87
|
+
|
|
88
|
+
#
|
|
89
|
+
# The list of build data for this component.
|
|
90
|
+
#
|
|
91
|
+
# @example Get the list of artifacts for a repository
|
|
92
|
+
# component = BuildComponent.new(name: 'wicket')
|
|
93
|
+
# component.builds #=> [#<Resource::Build>, ...]
|
|
94
|
+
#
|
|
95
|
+
# @return [Collection::Build]
|
|
96
|
+
# the list of builds
|
|
97
|
+
#
|
|
98
|
+
def builds
|
|
99
|
+
@builds ||= Collection::Build.new(self, name: name) do
|
|
100
|
+
Resource::Build.all(name)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
#
|
|
105
|
+
# Remove this component's build data stored in Artifactory
|
|
106
|
+
#
|
|
107
|
+
# @option options [Array<String>] :build_numbers (default: nil)
|
|
108
|
+
# an array of build numbers that should be deleted; if not given
|
|
109
|
+
# all builds (for this component) are deleted
|
|
110
|
+
# @option options [Boolean] :artifacts (default: +false+)
|
|
111
|
+
# if true the component's artifacts are also removed
|
|
112
|
+
# @option options [Boolean] :delete_all (default: +false+)
|
|
113
|
+
# if true the entire component is removed
|
|
114
|
+
#
|
|
115
|
+
# @return [Boolean]
|
|
116
|
+
# true if the object was deleted successfully, false otherwise
|
|
117
|
+
#
|
|
118
|
+
def delete(options = {})
|
|
119
|
+
params = {}.tap do |param|
|
|
120
|
+
param[:buildNumbers] = options[:build_numbers].join(',') if options[:build_numbers]
|
|
121
|
+
param[:artifacts] = 1 if options[:artifacts]
|
|
122
|
+
param[:deleteAll] = 1 if options[:delete_all]
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
endpoint = api_path + "?#{to_query_string_parameters(params)}"
|
|
126
|
+
client.delete(endpoint, {})
|
|
127
|
+
true
|
|
128
|
+
rescue Error::HTTPError => e
|
|
129
|
+
false
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
#
|
|
133
|
+
# Rename a build component.
|
|
134
|
+
#
|
|
135
|
+
# @param [String] new_name
|
|
136
|
+
# new name for the component
|
|
137
|
+
#
|
|
138
|
+
# @return [Boolean]
|
|
139
|
+
# true if the object was renamed successfully, false otherwise
|
|
140
|
+
#
|
|
141
|
+
def rename(new_name, options = {})
|
|
142
|
+
endpoint = "/api/build/rename/#{url_safe(name)}" + "?to=#{new_name}"
|
|
143
|
+
client.post(endpoint, {})
|
|
144
|
+
true
|
|
145
|
+
rescue Error::HTTPError => e
|
|
146
|
+
false
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
private
|
|
150
|
+
|
|
151
|
+
#
|
|
152
|
+
# The path to this build component on the server.
|
|
153
|
+
#
|
|
154
|
+
# @return [String]
|
|
155
|
+
#
|
|
156
|
+
def api_path
|
|
157
|
+
"/api/build/#{url_safe(name)}"
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|