artifactory-ruby 0.0.1
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 +7 -0
- data/LICENSE +12 -0
- data/README.md +14 -0
- data/lib/artifactory/client.rb +226 -0
- data/lib/artifactory/version.rb +11 -0
- metadata +81 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 60b1ba3ee0e3e8e73c67bf3183837ba477edc2c0
|
4
|
+
data.tar.gz: 8eb5c22de96241ddd66fdafaf58bdcabd97c8da8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f61eef69170467bd2a829de851d9371da8a76f1b30d76b1a8a261f63f03b7290bec8ed1bfcdb4602caedcf8fa61a5fe2afc701b69afa389a82483a06d7300b3f
|
7
|
+
data.tar.gz: c60c0ba0e330be0105acac73f26a0440bfc5c322ee5313eb9d103ce3faf94e61e4c915c7f4932cef9df08d988dfabd2e9b543e8e791a838662fbe8fa0e24dcc2
|
data/LICENSE
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
Copyright 2017 Matteo Cerutti
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
|
8
|
+
Unless required by applicable law or agreed to in writing, software
|
9
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
10
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
11
|
+
See the License for the specific language governing permissions and
|
12
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Ruby client library for JFrog Artifactory REST API
|
2
|
+
This is a simple Ruby client library that allows to interact with the JFrog Artifactory REST API.
|
3
|
+
|
4
|
+
Pull requests to add additional API features are very welcome. I only implemented what I needed.
|
5
|
+
|
6
|
+
## Install
|
7
|
+
To install it simply issue the following command:
|
8
|
+
|
9
|
+
```
|
10
|
+
gem install artifactory-ruby
|
11
|
+
```
|
12
|
+
|
13
|
+
## Contact
|
14
|
+
Matteo Cerutti - matteo.cerutti@hotmail.co.uk
|
@@ -0,0 +1,226 @@
|
|
1
|
+
#
|
2
|
+
# client.rb
|
3
|
+
#
|
4
|
+
|
5
|
+
require 'net/http'
|
6
|
+
require 'uri'
|
7
|
+
require 'openssl'
|
8
|
+
require 'json'
|
9
|
+
require 'time'
|
10
|
+
|
11
|
+
module Artifactory
|
12
|
+
class Client
|
13
|
+
attr_reader :uri, :http, :basic_auth, :headers
|
14
|
+
|
15
|
+
# Initialize an Artifactory client instance
|
16
|
+
#
|
17
|
+
# @param endpoint [String] Artifactory REST API endpoint
|
18
|
+
# @param username [String] Username for HTTP basic authentication
|
19
|
+
# @param password [String] Password for HTTP basic authentication
|
20
|
+
# @param api_key [String] API key
|
21
|
+
# @param ssl_verify [Boolean] Enable/Disable SSL verification
|
22
|
+
#
|
23
|
+
def initialize(endpoint:, username: nil, password: nil, api_key: nil, ssl_verify: true)
|
24
|
+
basic_auth = {}
|
25
|
+
uri = URI.parse(endpoint)
|
26
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
27
|
+
|
28
|
+
if (username and api_key) or (username.nil? and api_key.nil?)
|
29
|
+
raise RuntimeError, "Either HTTP basic or API key are allowed as authentication methods"
|
30
|
+
end
|
31
|
+
|
32
|
+
headers = {
|
33
|
+
'Content-type' => 'application/json',
|
34
|
+
'Accept' => 'application/json',
|
35
|
+
}
|
36
|
+
|
37
|
+
if username
|
38
|
+
basic_auth = {'username' => username, 'password' => password}
|
39
|
+
else
|
40
|
+
headers['X-JFrog-Art-Api'] = api_key
|
41
|
+
end
|
42
|
+
|
43
|
+
if uri.scheme == 'https'
|
44
|
+
http.use_ssl = true
|
45
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless ssl_verify
|
46
|
+
end
|
47
|
+
|
48
|
+
@uri = uri
|
49
|
+
@http = http
|
50
|
+
@basic_auth = basic_auth
|
51
|
+
@headers = headers
|
52
|
+
end
|
53
|
+
|
54
|
+
# Retrieves the current configuration of a repository. Supported by local, remote and virtual repositories.
|
55
|
+
#
|
56
|
+
# @param key [String] Repository key
|
57
|
+
# @return [Hash] Repository information
|
58
|
+
#
|
59
|
+
def get_repo(key:)
|
60
|
+
api_get("/repositories/#{key}").tap { |h| h.delete('key') }
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns a list of minimal repository details (unless recurse is enabled) for all repositories of the specified type.
|
64
|
+
#
|
65
|
+
# @param type [nil, local, remote, virtual] Optionally filter by repository type
|
66
|
+
# @param recurse [Boolean] Recursively retrieve repos configuration
|
67
|
+
# @return [Hash] List of repositories
|
68
|
+
#
|
69
|
+
def repos(type: nil, recurse: false)
|
70
|
+
ret = {}
|
71
|
+
params = []
|
72
|
+
params << "type=#{type}" if type
|
73
|
+
|
74
|
+
api_get(["/repositories", params.join('&')].join('?')).each do |repo|
|
75
|
+
ret[repo['key']] = recurse ? self.get_repo(key: repo['key']) : repo.tap { |h| h.delete('key') }
|
76
|
+
end
|
77
|
+
|
78
|
+
ret
|
79
|
+
end
|
80
|
+
|
81
|
+
# Lists all Docker repositories hosted in under an Artifactory Docker repository
|
82
|
+
#
|
83
|
+
# @param repo_key [String] Repository key
|
84
|
+
# @param recurse [Boolean] Recursively retrieve image tags
|
85
|
+
# @return [Hash, Array<String>] List of docker images
|
86
|
+
#
|
87
|
+
def docker_images(repo_key:, recurse: false)
|
88
|
+
ret = {}
|
89
|
+
repolist = api_get("/docker/#{repo_key}/v2/_catalog")['repositories']
|
90
|
+
|
91
|
+
if recurse
|
92
|
+
api_get("/docker/#{repo_key}/v2/_catalog")['repositories'].each do |name|
|
93
|
+
ret[name] = self.docker_tags(repo_key: repo_key, image_name: name)
|
94
|
+
end
|
95
|
+
else
|
96
|
+
ret = repolist
|
97
|
+
end
|
98
|
+
|
99
|
+
images
|
100
|
+
end
|
101
|
+
|
102
|
+
# Retrieve all tags for a docker image
|
103
|
+
#
|
104
|
+
# @param repo_key [String] Repository key
|
105
|
+
# @param image_name [String] Docker image name
|
106
|
+
# @return [Array<String>] List of tags
|
107
|
+
#
|
108
|
+
def docker_tags(repo_key:, image_name:)
|
109
|
+
api_get("/docker/#{repo_key}/v2/#{image_name}/tags/list")['tags']
|
110
|
+
end
|
111
|
+
|
112
|
+
# Retrieve a docker image tag manifest
|
113
|
+
#
|
114
|
+
# @param repo_key [String] Repository key
|
115
|
+
# @param image_name [String] Docker image name
|
116
|
+
# @param image_tag [String] Docker image tag
|
117
|
+
# @return [Hash] Docker manifest describing the tag
|
118
|
+
#
|
119
|
+
def docker_manifest(repo_key:, image_name:, image_tag:)
|
120
|
+
api_get("/docker/#{repo_key}/v2/#{image_name}/manifests/#{image_tag}")
|
121
|
+
end
|
122
|
+
|
123
|
+
# Get a flat (the default) or deep listing of the files and folders (not included by default) within a folder
|
124
|
+
#
|
125
|
+
# @param repo_key [String] Repository key
|
126
|
+
# @param image_name [String] Docker image name
|
127
|
+
# @param image_tag [String] Docker image tag
|
128
|
+
# @return [Hash] Docker manifest describing the tag
|
129
|
+
#
|
130
|
+
def file_list(repo_key:, folder_path: '/', deep: false, depth: 0, list_folders: false, md_timestamps: false, include_root_path: false)
|
131
|
+
path = ["/storage", repo_key, folder_path].join('/').chomp('/')
|
132
|
+
params = ['list']
|
133
|
+
params << "deep=#{deep ? 1 : 0}"
|
134
|
+
params << "depth=#{depth}" if depth > 0
|
135
|
+
params << "listFolders=#{list_folders ? 1 : 0}"
|
136
|
+
params << "mdTimestamps=#{md_timestamps ? 1 : 0}"
|
137
|
+
params << "includeRootPath=#{include_root_path ? 1 : 0}"
|
138
|
+
|
139
|
+
files = {}
|
140
|
+
api_get([path, params.join('&')].join('?'))['files'].each do |file|
|
141
|
+
name = file['uri']
|
142
|
+
files[name] = file.tap { |h| h.delete('uri') }
|
143
|
+
files[name]['lastModified'] = Time.parse(files[name]['lastModified'])
|
144
|
+
end
|
145
|
+
|
146
|
+
files
|
147
|
+
end
|
148
|
+
|
149
|
+
# Get file statistics like the number of times an item was downloaded, last download date and last downloader.
|
150
|
+
#
|
151
|
+
# @param repo_key [String] Repository key
|
152
|
+
# @param path [String] Path of the file to look up
|
153
|
+
# @return [Hash] File statistics
|
154
|
+
#
|
155
|
+
def file_stat(repo_key:, path:)
|
156
|
+
p = File.join("/storage", repo_key, path).chomp('/')
|
157
|
+
params = ['stats']
|
158
|
+
|
159
|
+
ret = {}
|
160
|
+
api_get([p, params.join('&')].join('?')).tap { |h| h.delete('uri') }.each do |k, v|
|
161
|
+
case k
|
162
|
+
when "lastDownloaded", "remoteLastDownloaded"
|
163
|
+
ret[k] = Time.at(v/1000) if v > 0
|
164
|
+
|
165
|
+
else
|
166
|
+
ret[k] = v
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
ret
|
171
|
+
end
|
172
|
+
|
173
|
+
# Deletes a file or a folder from the specified destination
|
174
|
+
#
|
175
|
+
# @param repo_key [String] Repository key
|
176
|
+
# @param path [String] Path of the file to delete
|
177
|
+
#
|
178
|
+
def file_delete(repo_key:, path:)
|
179
|
+
api_delete(File.join(repo_key, path))
|
180
|
+
end
|
181
|
+
|
182
|
+
private
|
183
|
+
# Dispatch a GET request to the Artifactory API interface
|
184
|
+
#
|
185
|
+
# @param query [String] HTTP request query
|
186
|
+
# @return Response from the server
|
187
|
+
#
|
188
|
+
def api_get(query)
|
189
|
+
begin
|
190
|
+
req = Net::HTTP::Get.new(File.join(self.uri.path, 'api', query), self.headers)
|
191
|
+
req.basic_auth(self.basic_auth['username'], self.basic_auth['password']) if self.basic_auth
|
192
|
+
resp = self.http.request(req)
|
193
|
+
|
194
|
+
if resp.is_a?(Net::HTTPOK)
|
195
|
+
begin
|
196
|
+
data = JSON.parse(resp.body)
|
197
|
+
rescue JSON::ParserError
|
198
|
+
raise Exception, "Failed to decode response message"
|
199
|
+
end
|
200
|
+
else
|
201
|
+
raise Exception, "Query returned a non successful HTTP code (Code: #{resp.code}, Error: #{resp.message})"
|
202
|
+
end
|
203
|
+
rescue
|
204
|
+
raise Exception, "Failed to execute GET request to Artifactory REST API (#{$!})"
|
205
|
+
end
|
206
|
+
|
207
|
+
data
|
208
|
+
end
|
209
|
+
|
210
|
+
# Dispatch a DELETE request to the Artifactory API interface
|
211
|
+
#
|
212
|
+
# @param query [String] HTTP request query
|
213
|
+
#
|
214
|
+
def api_delete(query)
|
215
|
+
begin
|
216
|
+
req = Net::HTTP::Delete.new(File.join(self.uri.path, 'api', query), self.headers)
|
217
|
+
req.basic_auth(self.basic_auth['username'], self.basic_auth['password']) if self.basic_auth
|
218
|
+
resp = self.http.request(req)
|
219
|
+
|
220
|
+
raise Exception, "Query returned a non successful HTTP code (Code: #{resp.code}, Error: #{resp.message})" unless resp.is_a?(Net::HTTPNoContent)
|
221
|
+
rescue
|
222
|
+
raise Exception, "Failed to execute DELETE request to Artifactory REST API (#{$!})"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: artifactory-ruby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matteo Cerutti
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-05-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.7.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.7.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: deep_merge
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.1.0
|
34
|
+
- - "<"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 2.0.0
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.1.0
|
44
|
+
- - "<"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 2.0.0
|
47
|
+
description: Ruby client library for Kapacitor JSON REST API
|
48
|
+
email: matteo.cerutti@hotmail.co.uk
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- LICENSE
|
54
|
+
- README.md
|
55
|
+
- lib/artifactory/client.rb
|
56
|
+
- lib/artifactory/version.rb
|
57
|
+
homepage: https://github.com/m4ce/artifactory-ruby
|
58
|
+
licenses:
|
59
|
+
- Apache 2.0
|
60
|
+
metadata: {}
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
requirements: []
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 2.6.8
|
78
|
+
signing_key:
|
79
|
+
specification_version: 4
|
80
|
+
summary: Ruby client library that allows to interact with JFrog Artifactory REST API
|
81
|
+
test_files: []
|