class GitBundle::Commands::Push

Public Class Methods

new(project, args) click to toggle source
# File lib/git_bundle/commands/push.rb, line 7
def initialize(project, args)
  @project = project
  @args = args
end

Public Instance Methods

invoke() click to toggle source
# File lib/git_bundle/commands/push.rb, line 12
def invoke
  @project.load_dependant_repositories
  remote = @args.first || @project.main_repository.remote
  unless remote
    puts_error "New branch '#{@project.main_repository.branch}' is not tracking a remote branch. Specify which remote to push to, example:\n\tgitb push origin"
    return false
  end
  return false unless prompt_confirm(remote)

  main_repository = @project.main_repository

  lockfile = Bundler.default_lockfile.basename.to_s
  stale_repos = @project.repositories.select { |repo| !repo.main && repo.stale? }
  stale_commits_message = stale_repos.map do |repo|
    repo.upstream_branch_exists? ? "#{repo.name}(#{repo.stale_commits_count})" : "#{repo.name}(new branch)"
  end.join(', ')

  stale_commits_description = ''
  stale_repos.select { |r| r.upstream_branch_exists? }.each do |repo|
    stale_commits_description << "== #{repo.name} ==\n"
    stale_commits_description << repo.stale_commits
    stale_commits_description << "\n\n"
  end

  if stale_repos.any?
    puts "Local gems were updated. Building new #{lockfile} with bundle install."
    unless build_gemfile_lock
      puts_error 'Bundle install failed.  Please run it manually before trying to push changes.'
      return false
    end
  end

  if main_repository.file_changed?(lockfile)
    main_repository.add_file(lockfile)
    if stale_commits_message.empty?
      message = 'Updated Gemfile.lock.'
    else
      message = "Gemfile.lock includes new commits of: #{stale_commits_message}."
    end

    main_repository.commit_with_description(message, stale_commits_description, lockfile)
    puts message
  end

  @project.dependant_repositories.select { |repo| repo.commits_not_pushed? }.each do |repo|
    puts_repo_heading(repo)

    create_upstream = repo.upstream_branch_exists? ? nil : remote
    if create_upstream && !repo.remote_exists?(create_upstream)
      puts_error "Invalid remote: #{remote}"
      return false
    end
    unless repo.push(@args, create_upstream: create_upstream)
      puts_error "Failed to push changes of #{repo.name}.  Try pulling the latest changes or resolve conflicts first."
      return false
    end
  end

  puts_repo_heading(main_repository)
  create_upstream = main_repository.upstream_branch_exists? ? nil : remote
  unless main_repository.push(@args, create_upstream: create_upstream)
    puts_error "Failed to push changes of #{main_repository.name}.  Try pulling the latest changes or resolve conflicts first."
  end
end

Private Instance Methods

build_gemfile_lock() click to toggle source
# File lib/git_bundle/commands/push.rb, line 142
def build_gemfile_lock
  Dir.chdir(@project.main_repository.path) do
    execute_live('bundle', 'install', '--quiet')
    return $?.exitstatus == 0
  end
end
gemfile_lock_stale?() click to toggle source
# File lib/git_bundle/commands/push.rb, line 138
def gemfile_lock_stale?
  @project.repositories.any? { |repo| repo.stale? }
end
prompt_confirm(remote) click to toggle source
# File lib/git_bundle/commands/push.rb, line 79
def prompt_confirm(remote)
  if @project.main_repository.file_changed?('Gemfile')
    puts_error 'Your Gemfile has uncommitted changes.  Commit them first before pushing.'
    return false
  end

  commits_to_push = false
  upstream_branches_missing = []
  diverged_repos = []
  @project.repositories.each do |repo|
    commits = repo.commits_not_pushed
    puts_repo_heading(repo)

    if repo.upstream_branch_exists?
      if commits.empty?
        puts 'No changes.'
      else
        commits_to_push = true
        diverged_repos << repo if repo.branch != @project.main_repository.branch
        puts commits
      end
    else
      upstream_branches_missing << repo.name
      puts "Remote branch #{remote}/#{repo.branch} does not exist yet."
    end
  end

  if diverged_repos.any?
    puts_prompt("\nThese repositories have changes and have diverged from the main application's branch (#{@project.main_repository.branch})")
    puts_diverged_repos(diverged_repos)
    puts_prompt("\nDo you want to continue? (Y/N)")
    if STDIN.getch.upcase == 'Y'
      puts ''
    else
      return false
    end
  end

  if !upstream_branches_missing.empty?
    puts_prompt("Missing upstream branches (#{upstream_branches_missing.join(', ')}) will be created and changes pushed.")
    puts_prompt('Do you want to continue? (Y/N)')

  elsif commits_to_push
    puts_prompt('Are you sure you want to push these changes? (Y/N)')

  elsif gemfile_lock_stale?
    puts_prompt('Although you don\'t have any commits to push, your Gemfile.lock needs to be rebuilt, committed and pushed.')
    puts_prompt('Do you want to continue? (Y/N)')

  elsif @project.main_repository.file_changed?('Gemfile.lock')
    puts_prompt('Although you don\'t have any commits to push, your Gemfile.lock needs to be committed and pushed.')
    puts_prompt('Do you want to continue? (Y/N)')
  else
    return false
  end

  STDIN.getch.upcase == 'Y'
end