class Gitlabci::Bundle::Update::Mr::Client

Constants

BRANCH_PREFIX
MAX_RETRY_COUNT
TITLE_PREFIX

Public Class Methods

new(gitlab_api_endpoint:, gitlab_api_private_token:, project_name:, branch:, author_email:, author_name:) click to toggle source

@param gitlab_api_endpoint [String] @param gitlab_api_private_token [String] @param project_name [String] @param branch [String] @param author_email [String] @param author_name [String]

# File lib/gitlabci/bundle/update/mr/client.rb, line 18
def initialize(gitlab_api_endpoint:, gitlab_api_private_token:,
               project_name:, branch:, author_email:, author_name:)
  @gitlab = Gitlab.client(endpoint: gitlab_api_endpoint, private_token: gitlab_api_private_token)
  @project_name = project_name
  @branch = branch
  @author_email = author_email
  @author_name = author_name
end

Public Instance Methods

commit_gemfile_lock(lockfile) click to toggle source

@param lockfile [String]

# File lib/gitlabci/bundle/update/mr/client.rb, line 67
def commit_gemfile_lock(lockfile)
  @gitlab.create_commit(
    @project_name,
    new_branch,
    "$ bundle update && bundle update --ruby",
    [
      {
        action:    "update",
        file_path: lockfile_name,
        content:   lockfile,
      },
    ],
    start_branch: @branch,
    author_email: @author_email,
    author_name:  @author_name,
  )
end
create_merge_request(description:, mr_labels:, assignee_ids:) click to toggle source

@param description [String] @param mr_labels [Array<String>] @param assignee_ids [Array<Integer>]

@see docs.gitlab.com/ee/api/merge_requests.html#create-mr

# File lib/gitlabci/bundle/update/mr/client.rb, line 90
def create_merge_request(description:, mr_labels:, assignee_ids:)
  params = {
    source_branch:        new_branch,
    target_branch:        @branch,
    remove_source_branch: true,
    description:          description,
  }

  unless mr_labels.empty?
    params[:labels] = mr_labels.join(",")
  end

  if assignee_ids.length == 1
    params[:assignee_id] = assignee_ids[0]
  elsif assignee_ids.length >= 2
    params[:assignee_ids] = assignee_ids
  end

  @gitlab.create_merge_request(
    @project_name,
    "#{TITLE_PREFIX}#{current_time.strftime("%Y-%m-%d %H:%M:%S %Z")}",
    params,
  )
end
find_by_username(username) click to toggle source

@param username [String]

@return [Gitlab::ObjectifiedHash] @return [nil] User isn't found

@see docs.gitlab.com/ee/api/users.html#for-normal-users

# File lib/gitlabci/bundle/update/mr/client.rb, line 141
def find_by_username(username)
  @gitlab.users(username: username).first
end
find_by_username!(username) click to toggle source

@param username [String]

@return [Gitlab::ObjectifiedHash]

@raise [Gitlabci::Bundle::Update::Mr::NotFoundUserError]

@see docs.gitlab.com/ee/api/users.html#for-normal-users

# File lib/gitlabci/bundle/update/mr/client.rb, line 152
def find_by_username!(username)
  user = find_by_username(username)

  unless user
    raise NotFoundUserError, "#{username} isn't found"
  end

  user
end
merge_request_description(old_lockfile, new_lockfile) click to toggle source

@param old_lockfile [String] @param new_lockfile [String]

@return [String]

# File lib/gitlabci/bundle/update/mr/client.rb, line 119
          def merge_request_description(old_lockfile, new_lockfile)
            compare_linker = CompareLinker.new("dummy", "dummy")
            compare_linker.formatter = CompareLinker::Formatter::Markdown.new
            compare_links = compare_linker.
                              make_compare_links_from_lockfiles(Bundler::LockfileParser.new(old_lockfile), Bundler::LockfileParser.new(new_lockfile)).
                              to_a.join("\n")

            <<~MARKDOWN
              **Updated RubyGems:**

              #{compare_links}

              Powered by [gitlabci-bundle-update-mr](https://rubygems.org/gems/gitlabci-bundle-update-mr)
            MARKDOWN
          end
perform(allow_dup_mr:, mr_labels:, update_bundled_with:, merge_when_pipeline_succeeds:, assignees:) click to toggle source

@param allow_dup_mr [Boolean] @param mr_labels [Array<String>] @param update_bundled_with [Boolean] @param merge_when_pipeline_succeeds [Boolean] @param assignees [Array<String>]

# File lib/gitlabci/bundle/update/mr/client.rb, line 33
def perform(allow_dup_mr:, mr_labels:, update_bundled_with:, merge_when_pipeline_succeeds:, assignees:)
  if !allow_dup_mr && exists_bundle_update_mr?
    puts "Skip because it has already existed."
    return
  end

  assignee_ids = get_assignee_ids(assignees)
  old_lockfile = File.read(lockfile_name)

  system!("bundle update")
  system!("bundle update --ruby")

  restore_bundled_with unless update_bundled_with

  new_lockfile = File.read(lockfile_name)

  if old_lockfile == new_lockfile
    puts "#{lockfile_name} is not updated"
    return
  end

  commit_gemfile_lock(new_lockfile)
  description = merge_request_description(old_lockfile, new_lockfile)

  mr = create_merge_request(description: description, mr_labels: mr_labels, assignee_ids: assignee_ids)
  puts "MR is created: #{mr.web_url}"

  if merge_when_pipeline_succeeds
    accept_merge_request(mr.iid)
    puts "Set merge_when_pipeline_succeeds to #{mr.web_url}"
  end
end

Private Instance Methods

accept_merge_request(mr_id) click to toggle source
# File lib/gitlabci/bundle/update/mr/client.rb, line 209
def accept_merge_request(mr_id)
  with_retry do
    @gitlab.accept_merge_request(@project_name, mr_id, merge_when_pipeline_succeeds: true, should_remove_source_branch: true)
  end
end
current_time() click to toggle source
# File lib/gitlabci/bundle/update/mr/client.rb, line 196
def current_time
  @current_time ||= Time.now
end
exists_bundle_update_mr?() click to toggle source
# File lib/gitlabci/bundle/update/mr/client.rb, line 204
def exists_bundle_update_mr?
  merge_requests = @gitlab.merge_requests(@project_name, state: "opened", target_branch: @branch, search: TITLE_PREFIX.strip)
  merge_requests.any? {|mr| mr.title.start_with?(TITLE_PREFIX) && mr.source_branch.start_with?(BRANCH_PREFIX) }
end
gemfile_name() click to toggle source
# File lib/gitlabci/bundle/update/mr/client.rb, line 180
def gemfile_name
  return @gemfile_name if @gemfile_name

  @gemfile_name = ENV["BUNDLE_GEMFILE"] || "Gemfile"

  if @gemfile_name.start_with?("#{Dir.pwd}/")
    @gemfile_name = @gemfile_name.gsub("#{Dir.pwd}/", "")
  end

  @gemfile_name
end
get_assignee_ids(assignees) click to toggle source
# File lib/gitlabci/bundle/update/mr/client.rb, line 232
def get_assignee_ids(assignees)
  assignees.map do |username|
    user = find_by_username!(username)
    user.id
  end
end
lockfile_name() click to toggle source
# File lib/gitlabci/bundle/update/mr/client.rb, line 192
def lockfile_name
  "#{gemfile_name}.lock"
end
new_branch() click to toggle source
# File lib/gitlabci/bundle/update/mr/client.rb, line 200
def new_branch
  "#{BRANCH_PREFIX}#{current_time.strftime("%Y%m%d%H%M%S")}"
end
restore_bundled_with() click to toggle source
# File lib/gitlabci/bundle/update/mr/client.rb, line 170
def restore_bundled_with
  RestoreBundledWith::CLI.new.invoke(
    :restore,
    [],
    {
      lockfile: lockfile_name,
    },
  )
end
system!(command) click to toggle source
# File lib/gitlabci/bundle/update/mr/client.rb, line 164
def system!(command)
  # NOTE: system(exception: true) requires Ruby 2.6+
  ret = system(command)
  raise "`#{command}` is failed" unless ret
end
with_retry() { || ... } click to toggle source
# File lib/gitlabci/bundle/update/mr/client.rb, line 215
def with_retry
  retry_count ||= 0

  yield
rescue Gitlab::Error::MethodNotAllowed, Gitlab::Error::NotAcceptable => e
  retry_count += 1

  if retry_count > MAX_RETRY_COUNT
    raise e
  end

  puts "Error is occurred and auto retry (#{retry_count}/#{MAX_RETRY_COUNT}): #{e}"
  sleep 1

  retry
end