class Dependabot::Clients::Azure
Constants
- MAX_PR_DESCRIPTION_LENGTH
- RETRYABLE_ERRORS
Attributes
auth_header[R]
credentials[R]
source[R]
Public Class Methods
for_source(source:, credentials:)
click to toggle source
Constructor methods #
# File lib/dependabot/clients/azure.rb, line 29 def self.for_source(source:, credentials:) credential = credentials. select { |cred| cred["type"] == "git_source" }. find { |cred| cred["host"] == source.hostname } new(source, credential) end
new(source, credentials, max_retries: 3)
click to toggle source
Client #
# File lib/dependabot/clients/azure.rb, line 42 def initialize(source, credentials, max_retries: 3) @source = source @credentials = credentials @auth_header = auth_header_for(credentials&.fetch("token", nil)) @max_retries = max_retries || 3 end
Public Instance Methods
branch(branch_name)
click to toggle source
# File lib/dependabot/clients/azure.rb, line 122 def branch(branch_name) response = get(source.api_endpoint + source.organization + "/" + source.project + "/_apis/git/repositories/" + source.unscoped_repo + "/refs?filter=heads/" + branch_name) JSON.parse(response.body).fetch("value").first end
commits(branch_name = nil)
click to toggle source
# File lib/dependabot/clients/azure.rb, line 109 def commits(branch_name = nil) commits_url = source.api_endpoint + source.organization + "/" + source.project + "/_apis/git/repositories/" + source.unscoped_repo + "/commits" commits_url += "?searchCriteria.itemVersion.version=" + branch_name unless branch_name.to_s.empty? response = get(commits_url) JSON.parse(response.body).fetch("value") end
create_commit(branch_name, base_commit, commit_message, files, author_details)
click to toggle source
# File lib/dependabot/clients/azure.rb, line 142 def create_commit(branch_name, base_commit, commit_message, files, author_details) content = { refUpdates: [ { name: "refs/heads/" + branch_name, oldObjectId: base_commit } ], commits: [ { comment: commit_message, author: author_details, changes: files.map do |file| { changeType: "edit", item: { path: file.path }, newContent: { content: Base64.encode64(file.content), contentType: "base64encoded" } } end }.compact ] } post(source.api_endpoint + source.organization + "/" + source.project + "/_apis/git/repositories/" + source.unscoped_repo + "/pushes?api-version=5.0", content.to_json) end
create_pull_request(pr_name, source_branch, target_branch, pr_description, labels, work_item = nil)
click to toggle source
rubocop:disable Metrics/ParameterLists
# File lib/dependabot/clients/azure.rb, line 172 def create_pull_request(pr_name, source_branch, target_branch, pr_description, labels, work_item = nil) pr_description = truncate_pr_description(pr_description) content = { sourceRefName: "refs/heads/" + source_branch, targetRefName: "refs/heads/" + target_branch, title: pr_name, description: pr_description, labels: labels.map { |label| { name: label } }, workItemRefs: [{ id: work_item }] } post(source.api_endpoint + source.organization + "/" + source.project + "/_apis/git/repositories/" + source.unscoped_repo + "/pullrequests?api-version=5.0", content.to_json) end
fetch_commit(_repo, branch)
click to toggle source
# File lib/dependabot/clients/azure.rb, line 49 def fetch_commit(_repo, branch) response = get(source.api_endpoint + source.organization + "/" + source.project + "/_apis/git/repositories/" + source.unscoped_repo + "/stats/branches?name=" + branch) raise NotFound if response.status == 400 JSON.parse(response.body).fetch("commit").fetch("commitId") end
fetch_default_branch(_repo)
click to toggle source
# File lib/dependabot/clients/azure.rb, line 60 def fetch_default_branch(_repo) response = get(source.api_endpoint + source.organization + "/" + source.project + "/_apis/git/repositories/" + source.unscoped_repo) JSON.parse(response.body).fetch("defaultBranch").gsub("refs/heads/", "") end
fetch_file_contents(commit, path)
click to toggle source
# File lib/dependabot/clients/azure.rb, line 98 def fetch_file_contents(commit, path) response = get(source.api_endpoint + source.organization + "/" + source.project + "/_apis/git/repositories/" + source.unscoped_repo + "/items?path=" + path + "&versionDescriptor.versionType=commit" \ "&versionDescriptor.version=" + commit) response.body end
fetch_repo_contents(commit = nil, path = nil)
click to toggle source
# File lib/dependabot/clients/azure.rb, line 68 def fetch_repo_contents(commit = nil, path = nil) tree = fetch_repo_contents_treeroot(commit, path) response = get(source.api_endpoint + source.organization + "/" + source.project + "/_apis/git/repositories/" + source.unscoped_repo + "/trees/" + tree + "?recursive=false") JSON.parse(response.body).fetch("treeEntries") end
fetch_repo_contents_treeroot(commit = nil, path = nil)
click to toggle source
# File lib/dependabot/clients/azure.rb, line 79 def fetch_repo_contents_treeroot(commit = nil, path = nil) actual_path = path actual_path = "/" if path.to_s.empty? tree_url = source.api_endpoint + source.organization + "/" + source.project + "/_apis/git/repositories/" + source.unscoped_repo + "/items?path=" + actual_path unless commit.to_s.empty? tree_url += "&versionDescriptor.versionType=commit" \ "&versionDescriptor.version=" + commit end tree_response = get(tree_url) JSON.parse(tree_response.body).fetch("objectId") end
get(url)
click to toggle source
rubocop:enable Metrics/ParameterLists
# File lib/dependabot/clients/azure.rb, line 216 def get(url) response = nil retry_connection_failures do response = Excon.get( url, user: credentials&.fetch("username", nil), password: credentials&.fetch("password", nil), idempotent: true, **SharedHelpers.excon_defaults( headers: auth_header ) ) raise InternalServerError if response.status == 500 raise BadGateway if response.status == 502 raise ServiceNotAvailable if response.status == 503 end raise Unauthorized if response.status == 401 raise Forbidden if response.status == 403 raise NotFound if response.status == 404 response end
post(url, json)
click to toggle source
# File lib/dependabot/clients/azure.rb, line 242 def post(url, json) response = nil retry_connection_failures do response = Excon.post( url, body: json, user: credentials&.fetch("username", nil), password: credentials&.fetch("password", nil), idempotent: true, **SharedHelpers.excon_defaults( headers: auth_header.merge( { "Content-Type" => "application/json" } ) ) ) raise InternalServerError if response.status == 500 raise BadGateway if response.status == 502 raise ServiceNotAvailable if response.status == 503 end raise Unauthorized if response.status == 401 raise Forbidden if response.status == 403 raise NotFound if response.status == 404 response end
pull_request(pull_request_id)
click to toggle source
# File lib/dependabot/clients/azure.rb, line 191 def pull_request(pull_request_id) response = get(source.api_endpoint + source.organization + "/" + source.project + "/_apis/git/pullrequests/" + pull_request_id) JSON.parse(response.body) end
pull_requests(source_branch, target_branch)
click to toggle source
# File lib/dependabot/clients/azure.rb, line 131 def pull_requests(source_branch, target_branch) response = get(source.api_endpoint + source.organization + "/" + source.project + "/_apis/git/repositories/" + source.unscoped_repo + "/pullrequests?searchCriteria.status=all" \ "&searchCriteria.sourceRefName=refs/heads/" + source_branch + "&searchCriteria.targetRefName=refs/heads/" + target_branch) JSON.parse(response.body).fetch("value") end
update_ref(branch_name, old_commit, new_commit)
click to toggle source
# File lib/dependabot/clients/azure.rb, line 199 def update_ref(branch_name, old_commit, new_commit) content = [ { name: "refs/heads/" + branch_name, oldObjectId: old_commit, newObjectId: new_commit } ] response = post(source.api_endpoint + source.organization + "/" + source.project + "/_apis/git/repositories/" + source.unscoped_repo + "/refs?api-version=5.0", content.to_json) JSON.parse(response.body).fetch("value").first end
Private Instance Methods
auth_header_for(token)
click to toggle source
# File lib/dependabot/clients/azure.rb, line 286 def auth_header_for(token) return {} unless token if token.include?(":") encoded_token = Base64.encode64(token).delete("\n") { "Authorization" => "Basic #{encoded_token}" } elsif Base64.decode64(token).ascii_only? && Base64.decode64(token).include?(":") { "Authorization" => "Basic #{token.delete("\n")}" } else { "Authorization" => "Bearer #{token}" } end end
retry_connection_failures() { || ... }
click to toggle source
# File lib/dependabot/clients/azure.rb, line 275 def retry_connection_failures retry_attempt = 0 begin yield rescue *RETRYABLE_ERRORS retry_attempt += 1 retry_attempt <= @max_retries ? retry : raise end end
truncate_pr_description(pr_description)
click to toggle source
# File lib/dependabot/clients/azure.rb, line 300 def truncate_pr_description(pr_description) # Azure DevOps only support descriptions up to 4000 characters in UTF-16 # encoding. # https://developercommunity.visualstudio.com/content/problem/608770/remove-4000-character-limit-on-pull-request-descri.html pr_description = pr_description.dup.force_encoding(Encoding::UTF_16) if pr_description.length > MAX_PR_DESCRIPTION_LENGTH truncated_msg = "...\n\n_Description has been truncated_".dup.force_encoding(Encoding::UTF_16) truncate_length = MAX_PR_DESCRIPTION_LENGTH - truncated_msg.length pr_description = (pr_description[0..truncate_length] + truncated_msg) end pr_description.force_encoding(Encoding::UTF_8) end