module Circleci::Bundle::Update::Pr
Constants
- BRANCH_PREFIX
- TITLE_PREFIX
- VERSION
Public Class Methods
create_if_needed(git_username: nil, git_email: nil, git_branches: %w[master main], assignees: nil, reviewers: nil, labels: nil, allow_dup_pr: false)
click to toggle source
# File lib/circleci/bundle/update/pr.rb, line 10 def self.create_if_needed(git_username: nil, git_email: nil, git_branches: %w[master main], assignees: nil, reviewers: nil, labels: nil, allow_dup_pr: false) raise_if_env_unvalid! if skip?(allow_dup_pr) puts 'Skip because it has already existed.' return end unless target_branch?(running_branch: ENV.fetch('CIRCLE_BRANCH', nil), target_branches: git_branches) puts "Skip because CIRCLE_BRANCH[#{ENV.fetch('CIRCLE_BRANCH', nil)}] is not included in target branches[#{git_branches.join(',')}]." return end unless need_to_commit? puts 'No changes due to bundle update' return end git_username ||= client.user.login git_email ||= "#{git_username}@users.noreply.#{github_host}" branch = create_branch(git_username, git_email) pull_request = create_pull_request(branch) add_labels(pull_request[:number], labels) if labels update_pull_request_body(pull_request[:number]) add_assignees(pull_request[:number], assignees) if assignees request_review(pull_request[:number], reviewers) if reviewers end
Private Class Methods
add_assignees(pr_number, assignees)
click to toggle source
# File lib/circleci/bundle/update/pr.rb, line 189 def self.add_assignees(pr_number, assignees) client.add_assignees(repo_full_name, pr_number, assignees) end
add_labels(pr_number, labels)
click to toggle source
# File lib/circleci/bundle/update/pr.rb, line 158 def self.add_labels(pr_number, labels) client.add_labels_to_an_issue(repo_full_name, pr_number, labels) end
client()
click to toggle source
# File lib/circleci/bundle/update/pr.rb, line 199 def self.client if enterprise? Octokit::Client.new(access_token: ENV.fetch('ENTERPRISE_OCTOKIT_ACCESS_TOKEN', nil), api_endpoint: ENV.fetch('ENTERPRISE_OCTOKIT_API_ENDPOINT', nil)) else Octokit::Client.new(access_token: ENV.fetch('GITHUB_ACCESS_TOKEN', nil)) end end
create_branch(git_username, git_email)
click to toggle source
Create remote branch for bundle update PR
@return [String] remote branch name. e.g. bundle-update-20180929154455
# File lib/circleci/bundle/update/pr.rb, line 106 def self.create_branch(git_username, git_email) branch = "#{BRANCH_PREFIX}#{now.strftime('%Y%m%d%H%M%S')}" current_ref = client.ref(repo_full_name, "heads/#{ENV.fetch('CIRCLE_BRANCH', nil)}") branch_ref = client.create_ref(repo_full_name, "heads/#{branch}", current_ref.object.sha) branch_commit = client.commit(repo_full_name, branch_ref.object.sha) lockfile = File.read('Gemfile.lock') lockfile_blob_sha = client.create_blob(repo_full_name, lockfile) tree = client.create_tree( repo_full_name, [ { path: lockfile_path, mode: '100644', type: 'blob', sha: lockfile_blob_sha } ], base_tree: branch_commit.commit.tree.sha ) commit = client.create_commit( repo_full_name, '$ bundle update && bundle update --ruby', tree.sha, branch_ref.object.sha, author: { name: git_username, email: git_email } ) client.update_ref(repo_full_name, "heads/#{branch}", commit.sha) puts "#{branch} is created" branch end
create_pull_request(branch)
click to toggle source
Create bundle update PR
@param branch [String] branch name @return [Sawyer::Resource] The newly created pull request
# File lib/circleci/bundle/update/pr.rb, line 152 def self.create_pull_request(branch) title = "#{TITLE_PREFIX}#{now.strftime('%Y-%m-%d %H:%M:%S %Z')}" client.create_pull_request(repo_full_name, ENV.fetch('CIRCLE_BRANCH', nil), branch, title) end
enterprise?()
click to toggle source
# File lib/circleci/bundle/update/pr.rb, line 209 def self.enterprise? !!ENV['ENTERPRISE_OCTOKIT_ACCESS_TOKEN'] end
exists_bundle_update_pr?()
click to toggle source
Has ‘bundle update PR’ already existed?
@return [Boolean]
# File lib/circleci/bundle/update/pr.rb, line 70 def self.exists_bundle_update_pr? client.pull_requests(repo_full_name).find do |pr| pr.title =~ /\A#{TITLE_PREFIX}/ && pr.head.ref =~ /\A#{BRANCH_PREFIX}\d+/ end != nil end
github_host()
click to toggle source
# File lib/circleci/bundle/update/pr.rb, line 222 def self.github_host # A format like https://github.com/masutaka/circleci-bundle-update-pr.git return Regexp.last_match(1) if ENV.fetch('CIRCLE_REPOSITORY_URL', nil) =~ %r{https://(.+?)/} # A format like git@github.com:masutaka/compare_linker.git return Regexp.last_match(1) if ENV.fetch('CIRCLE_REPOSITORY_URL', nil) =~ /([^@]+?):/ 'github.com' end
lockfile_path()
click to toggle source
Get Gemfile.lock path relative to workdir
@return [String]
# File lib/circleci/bundle/update/pr.rb, line 243 def self.lockfile_path workdir_env = ENV.fetch('CIRCLE_WORKING_DIRECTORY', nil) return 'Gemfile.lock' unless workdir_env workdir = Pathname.new(workdir_env).expand_path gemfile_lock = Pathname.new(File.expand_path('Gemfile.lock')) gemfile_lock.relative_path_from(workdir).to_s end
need_to_commit?()
click to toggle source
Does it need to commit due to bundle update?
@return [Boolean]
# File lib/circleci/bundle/update/pr.rb, line 90 def self.need_to_commit? old_lockfile = File.read('Gemfile.lock') unless system('bundle update && bundle update --ruby') raise 'Unable to execute `bundle update && bundle update --ruby`' end new_lockfile = File.read('Gemfile.lock') old_lockfile != new_lockfile end
now()
click to toggle source
Get unified current time
@return [Time]
# File lib/circleci/bundle/update/pr.rb, line 235 def self.now @now ||= Time.now end
raise_if_env_unvalid!()
click to toggle source
# File lib/circleci/bundle/update/pr.rb, line 43 def self.raise_if_env_unvalid! raise "$CIRCLE_PROJECT_USERNAME isn't set" unless ENV['CIRCLE_PROJECT_USERNAME'] raise "$CIRCLE_PROJECT_REPONAME isn't set" unless ENV['CIRCLE_PROJECT_REPONAME'] raise "$GITHUB_ACCESS_TOKEN isn't set" unless ENV['GITHUB_ACCESS_TOKEN'] if ENV.fetch('ENTERPRISE_OCTOKIT_ACCESS_TOKEN', nil) && !ENV['ENTERPRISE_OCTOKIT_API_ENDPOINT'] raise "$ENTERPRISE_OCTOKIT_API_ENDPOINT isn't set" end if !ENV['ENTERPRISE_OCTOKIT_ACCESS_TOKEN'] && ENV.fetch('ENTERPRISE_OCTOKIT_API_ENDPOINT', nil) raise "$ENTERPRISE_OCTOKIT_ACCESS_TOKEN isn't set" end end
repo_full_name()
click to toggle source
Get repository full name
@return [String] e.g. ‘masutaka/circleci-bundle-update-pr’
# File lib/circleci/bundle/update/pr.rb, line 217 def self.repo_full_name @repo_full_name ||= "#{ENV.fetch('CIRCLE_PROJECT_USERNAME', nil)}/#{ENV.fetch('CIRCLE_PROJECT_REPONAME', nil)}" end
request_review(pr_number, reviewers)
click to toggle source
# File lib/circleci/bundle/update/pr.rb, line 194 def self.request_review(pr_number, reviewers) client.request_pull_request_review(repo_full_name, pr_number, reviewers) end
skip?(allow_dup_pr)
click to toggle source
Should skip to make PR?
@param allow_dup_pr [Boolean] @return [Boolean]
# File lib/circleci/bundle/update/pr.rb, line 60 def self.skip?(allow_dup_pr) return false if allow_dup_pr exists_bundle_update_pr? end
target_branch?(running_branch:, target_branches:)
click to toggle source
Is running branch included in target_branches?
@param running_branch [String] @param target_branches [Array<String>] @return [Boolean]
# File lib/circleci/bundle/update/pr.rb, line 82 def self.target_branch?(running_branch:, target_branches:) target_branches.include?(running_branch) end
update_pull_request_body(pr_number)
click to toggle source
# File lib/circleci/bundle/update/pr.rb, line 163 def self.update_pull_request_body(pr_number) ENV['OCTOKIT_ACCESS_TOKEN'] = ENV.fetch('GITHUB_ACCESS_TOKEN', nil) compare_linker = CompareLinker.new(repo_full_name, pr_number) compare_linker.formatter = CompareLinker::Formatter::Markdown.new body = <<-PR_BODY **Updated RubyGems:** #{compare_linker.make_compare_links.to_a.join("\n")} Powered by [circleci-bundle-update-pr](https://rubygems.org/gems/circleci-bundle-update-pr) PR_BODY if Note.exist? body << <<-PR_BODY --- #{Note.read} PR_BODY end client.update_pull_request(repo_full_name, pr_number, body: body) end