class Artifactory::Client
Attributes
Public Class Methods
Initialize an Artifactory
client instance
@param endpoint [String] Artifactory
REST API endpoint @param username [String] Username for HTTP basic authentication @param password [String] Password for HTTP basic authentication @param api_key [String] API key @param ssl_verify [Boolean] Enable/Disable SSL verification
# File lib/artifactory/client.rb, line 19 def initialize(endpoint:, username: nil, password: nil, api_key: nil, ssl_verify: true) basic_auth = {} uri = URI.parse(endpoint) http = Net::HTTP.new(uri.host, uri.port) if (username and api_key) or (username.nil? and api_key.nil?) raise RuntimeError, "Either HTTP basic or API key are allowed as authentication methods" end headers = { 'Content-type' => 'application/json', 'Accept' => 'application/json', } if username basic_auth = {'username' => username, 'password' => password} else headers['X-JFrog-Art-Api'] = api_key end if uri.scheme == 'https' http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless ssl_verify end @uri = uri @http = http @basic_auth = basic_auth @headers = headers end
Public Instance Methods
Lists all Docker repositories hosted in under an Artifactory
Docker repository
@param repo_key [String] Repository key @param recurse [Boolean] Recursively retrieve image tags @return [Hash, Array<String>] List of docker images
# File lib/artifactory/client.rb, line 83 def docker_images(repo_key:) api_get("/docker/#{repo_key}/v2/_catalog")['repositories'] end
Retrieve a docker image tag manifest
@param repo_key [String] Repository key @param image_name [String] Docker image name @param image_tag [String] Docker image tag @return [Hash] Docker manifest describing the tag
# File lib/artifactory/client.rb, line 104 def docker_manifest(repo_key:, image_name:, image_tag:) api_get("/docker/#{repo_key}/v2/#{image_name}/manifests/#{image_tag}") end
Deletes a file or a folder from the specified destination
@param repo_key [String] Repository key @param path [String] Path of the file to delete
# File lib/artifactory/client.rb, line 186 def file_delete(repo_key:, path:) api_delete(File.join(repo_key, path)) end
Get file information like last modification time, creation time etc.
@param repo_key [String] Repository key @param path [String] Path of the file to look up @return [Hash] File information
# File lib/artifactory/client.rb, line 140 def file_info(repo_key:, path:) ret = {} api_get(File.join("/storage", repo_key, path).chomp('/')).each do |k, v| case k when "created", "lastModified", "lastUpdated" ret[k] = Time.parse(v) else ret[k] = v end end ret end
Get a flat (the default) or deep listing of the files and folders (not included by default) within a folder
@param repo_key [String] Repository key @param image_name [String] Docker image name @param image_tag [String] Docker image tag @return [Hash] Docker manifest describing the tag
# File lib/artifactory/client.rb, line 115 def file_list(repo_key:, folder_path: '/', deep: false, depth: 0, list_folders: false, md_timestamps: false, include_root_path: false) path = ["/storage", repo_key, folder_path].join('/').chomp('/') params = ['list'] params << "deep=#{deep ? 1 : 0}" params << "depth=#{depth}" if depth > 0 params << "listFolders=#{list_folders ? 1 : 0}" params << "mdTimestamps=#{md_timestamps ? 1 : 0}" params << "includeRootPath=#{include_root_path ? 1 : 0}" files = {} api_get([path, params.join('&')].join('?'))['files'].each do |file| name = file['uri'] files[name] = file.tap { |h| h.delete('uri') } files[name]['lastModified'] = Time.parse(files[name]['lastModified']) end files end
Get file statistics like the number of times an item was downloaded, last download date and last downloader.
@param repo_key [String] Repository key @param path [String] Path of the file to look up @return [Hash] File statistics
# File lib/artifactory/client.rb, line 162 def file_stat(repo_key:, path:) ret = {} p = File.join("/storage", repo_key, path).chomp('/') params = ['stats'] api_get([p, params.join('&')].join('?')).tap { |h| h.delete('uri') }.each do |k, v| case k when "lastDownloaded", "remoteLastDownloaded" ret[k] = Time.at(v/1000) if v > 0 else ret[k] = v end end ret end
Retrieves the current configuration of a repository. Supported by local, remote and virtual repositories.
@param key [String] Repository key @return [Hash] Repository information
# File lib/artifactory/client.rb, line 55 def get_repo(key:) api_get("/repositories/#{key}").tap { |h| h.delete('key') } end
Returns a list of minimal repository details (unless recurse is enabled) for all repositories of the specified type.
@param type [nil, local, remote, virtual] Optionally filter by repository type @param recurse [Boolean] Recursively retrieve repos configuration @return [Hash] List of repositories
# File lib/artifactory/client.rb, line 65 def repos(type: nil, recurse: false) ret = {} params = [] params << "type=#{type}" if type api_get(["/repositories", params.join('&')].join('?')).each do |repo| ret[repo['key']] = recurse ? self.get_repo(key: repo['key']) : repo.tap { |h| h.delete('key') } end ret end
Get all artifacts created in date range
@param repo_key [String, Array<String>] Repository key(s) @param from_date [Time] Return artifacts that have not been used since the given date @param to_date [Time] Return artifacts that have been created before the given date @return [Hash] Artifacts matching search criteria
# File lib/artifactory/client.rb, line 285 def search_creation(repo_key:, from_date: nil, to_date: Time.now) ret = [] path = File.join("/search", "creation") params = [] params << "from=#{(from_date.to_f.round(3) * 1000).to_i}" if from_date params << "to=#{(to_date.to_f.round(3) * 1000).to_i}" params << "repos=#{repo_key.is_a?(Array) ? repo_key.join(',') : repo_key}" api_get([path, params.join('&')].join('?'))['results'].each do |result| full_path = result['uri'].scan(/\/storage\/(.+?)(\/.*)/).flatten file = { "repo_key" => full_path[0], "path" => full_path[1] } result.each do |k, v| case k when "created" file[k] = Time.parse(v) else file[k] = v end end ret << file end ret end
Get all artifacts with specified dates within the given range
@param repo_key [String, Array<String>] Repository key(s) @param from_date [Time] Return artifacts that have not been used since the given date @param to_date [Time] Return artifacts that have been created before the given date @param date_fields [created, lastModified, lastDownloaded] Date fields that specify which fields the from_date and to_date values should be applied to @return [Hash] Artifacts matching search criteria
# File lib/artifactory/client.rb, line 238 def search_dates(repo_key:, from_date: nil, to_date: Time.now, date_fields:) ret = [] valid_date_fields = ["created", "lastModified", "lastDownloaded"] date_fields.each do |date_field| raise ValueError, "Not a valid date field '#{date_field}'" unless valid_date_fields.include?(date_field) end path = File.join("/search", "dates") params = [] params << "from=#{(from_date.to_f.round(3) * 1000).to_i}" if from_date params << "to=#{(to_date.to_f.round(3) * 1000).to_i}" params << "repos=#{repo_key.is_a?(Array) ? repo_key.join(',') : repo_key}" params << "dateFields=#{date_fields.join(',')}" api_get([path, params.join('&')].join('?'))['results'].each do |result| full_path = result['uri'].scan(/\/storage\/(.+?)(\/.*)/).flatten file = { "repo_key" => full_path[0], "path" => full_path[1] } result.each do |k, v| case k when *valid_date_fields file[k] = Time.parse(v) else file[k] = v end end ret << file end ret end
Get all artifacts matching the given path pattern
@param repo_key [String] Repository key @param pattern [String] File pattern @return [Hash] Artifacts matching search pattern
# File lib/artifactory/client.rb, line 324 def search_pattern(repo_key:, pattern:) path = File.join("/search", "pattern") params = ["pattern=#{repo_key}:#{pattern}"] api_get([path, params].join('?'))['files'] end
Retrieve all artifacts not downloaded since the specified Java epoch in milliseconds
@param repo_key [String, Array<String>] Repository key(s) @param not_used_since [Time] Return artifacts that have not been used since the given date @param created_before [Time] Return artifacts that have been created before the given date @return [Hash] Artifacts matching search criteria
# File lib/artifactory/client.rb, line 197 def search_usage(repo_key:, not_used_since:, created_before: nil) ret = [] path = File.join("/search", "usage") params = [] params << "notUsedSince=#{(not_used_since.to_f.round(3) * 1000).to_i}" params << "createdBefore=#{(created_before.to_f.round(3) * 1000).to_i}" if created_before params << "repos=#{repo_key.is_a?(Array) ? repo_key.join(',') : repo_key}" api_get([path, params.join('&')].join('?'))['results'].each do |result| full_path = result['uri'].scan(/\/storage\/(.+?)(\/.*)/).flatten file = { "repo_key" => full_path[0], "path" => full_path[1] } result.each do |k, v| case k when "lastDownloaded", "remoteLastDownloaded" file[k] = Time.parse(v) else file[k] = v end end ret << file end ret end
Private Instance Methods
Dispatch a DELETE request to the Artifactory
API interface
@param query [String] HTTP request query
# File lib/artifactory/client.rb, line 363 def api_delete(query) begin req = Net::HTTP::Delete.new(File.join(self.uri.path, query), self.headers) req.basic_auth(self.basic_auth['username'], self.basic_auth['password']) if self.basic_auth resp = self.http.request(req) raise Exception, "Query returned a non successful HTTP code (Code: #{resp.code}, Error: #{resp.message})" unless resp.is_a?(Net::HTTPNoContent) rescue raise Exception, "Failed to execute DELETE request to Artifactory REST API (#{$!})" end end
Dispatch a GET request to the Artifactory
API interface
@param query [String] HTTP request query @return Response from the server
# File lib/artifactory/client.rb, line 337 def api_get(query) begin req = Net::HTTP::Get.new(File.join(self.uri.path, 'api', query), self.headers) req.basic_auth(self.basic_auth['username'], self.basic_auth['password']) if self.basic_auth resp = self.http.request(req) if resp.is_a?(Net::HTTPOK) begin data = JSON.parse(resp.body) rescue JSON::ParserError raise Exception, "Failed to decode response message" end else raise Exception, "Query returned a non successful HTTP code (Code: #{resp.code}, Error: #{resp.message})" end rescue raise Exception, "Failed to execute GET request to Artifactory REST API (#{$!})" end data end