artifactory-ruby 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|