class ModuleSync::Repository

Wrapper for Git in ModuleSync context

Public Class Methods

new(directory:, remote:) click to toggle source
# File lib/modulesync/repository.rb, line 6
def initialize(directory:, remote:)
  @directory = directory
  @remote = remote
end

Public Instance Methods

checkout_branch(branch) click to toggle source
# File lib/modulesync/repository.rb, line 92
def checkout_branch(branch)
  selected_branch = branch || repo.current_branch || 'master'
  repo.branch(selected_branch).checkout
  selected_branch
end
default_branch() click to toggle source
# File lib/modulesync/repository.rb, line 33
def default_branch
  symbolic_ref = repo.branches.find { |b| b.full =~ %r{remotes/origin/HEAD} }
  return unless symbolic_ref
  %r{remotes/origin/HEAD\s+->\s+origin/(?<branch>.+?)$}.match(symbolic_ref.full)[:branch]
end
git() click to toggle source
# File lib/modulesync/repository.rb, line 11
def git
  @git ||= Git.open @directory
end
local_branch_exists?(branch) click to toggle source
# File lib/modulesync/repository.rb, line 24
def local_branch_exists?(branch)
  repo.branches.local.collect(&:name).include?(branch)
end
prepare_workspace(branch) click to toggle source
# File lib/modulesync/repository.rb, line 65
def prepare_workspace(branch)
  # Repo needs to be cloned in the cwd
  if !Dir.exist?("#{@directory}/.git")
    puts "Cloning repository fresh from '#{@remote}'"
    @git = Git.clone(@remote, @directory)
    switch_branch(branch)
  # Repo already cloned, check out master and override local changes
  else
    # Some versions of git can't properly handle managing a repo from outside the repo directory
    Dir.chdir(@directory) do
      puts "Overriding any local changes to repository in '#{@directory}'"
      @git = Git.open('.')
      repo.fetch
      repo.reset_hard
      switch_branch(branch)
      git.pull('origin', branch) if remote_branch_exists?(branch)
    end
  end
end
remote_branch_differ?(local_branch, remote_branch) click to toggle source
# File lib/modulesync/repository.rb, line 28
def remote_branch_differ?(local_branch, remote_branch)
  !remote_branch_exists?(remote_branch) ||
    repo.diff("#{local_branch}..origin/#{remote_branch}").any?
end
remote_branch_exists?(branch) click to toggle source
# File lib/modulesync/repository.rb, line 20
def remote_branch_exists?(branch)
  repo.branches.remote.collect(&:name).include?(branch)
end
repo() click to toggle source

This is an alias to minimize code alteration

# File lib/modulesync/repository.rb, line 16
def repo
  git
end
show_changes(options) click to toggle source
# File lib/modulesync/repository.rb, line 145
def show_changes(options)
  checkout_branch(options[:branch])

  puts 'Files changed:'
  repo.diff('HEAD', '--').each do |diff|
    puts diff.patch
  end

  puts 'Files added:'
  untracked_unignored_files.each_key do |file|
    puts file
  end

  puts "\n\n"
  puts '--------------------------------'
end
submit_changes(files, options) click to toggle source

Git add/rm, git commit, git push

# File lib/modulesync/repository.rb, line 99
def submit_changes(files, options)
  message = options[:message]
  branch = checkout_branch(options[:branch])
  files.each do |file|
    if repo.status.deleted.include?(file)
      repo.remove(file)
    elsif File.exist?("#{@directory}/#{file}")
      repo.add(file)
    end
  end
  begin
    opts_commit = {}
    opts_push = {}
    opts_commit = { :amend => true } if options[:amend]
    opts_push = { :force => true } if options[:force]
    if options[:pre_commit_script]
      script = "#{File.dirname(File.dirname(__FILE__))}/../contrib/#{options[:pre_commit_script]}"
      `#{script} #{@directory}`
    end
    repo.commit(message, opts_commit)
    if options[:remote_branch]
      if remote_branch_differ?(branch, options[:remote_branch])
        repo.push('origin', "#{branch}:#{options[:remote_branch]}", opts_push)
      end
    else
      repo.push('origin', branch, opts_push)
    end
  rescue Git::GitExecuteError => e
    raise unless e.message.match?(/working (directory|tree) clean/)

    puts "There were no changes in '#{@directory}'. Not committing."
    return false
  end

  true
end
switch_branch(branch) click to toggle source
# File lib/modulesync/repository.rb, line 39
def switch_branch(branch)
  unless branch
    branch = default_branch
    puts "Using repository's default branch: #{branch}"
  end
  return if repo.current_branch == branch

  if local_branch_exists?(branch)
    puts "Switching to branch #{branch}"
    repo.checkout(branch)
  elsif remote_branch_exists?(branch)
    puts "Creating local branch #{branch} from origin/#{branch}"
    repo.checkout("origin/#{branch}")
    repo.branch(branch).checkout
  else
    base_branch = default_branch
    unless base_branch
      puts "Couldn't detect default branch. Falling back to assuming 'master'"
      base_branch = 'master'
    end
    puts "Creating new branch #{branch} from #{base_branch}"
    repo.checkout("origin/#{base_branch}")
    repo.branch(branch).checkout
  end
end
tag(version, tag_pattern) click to toggle source
# File lib/modulesync/repository.rb, line 85
def tag(version, tag_pattern)
  tag = tag_pattern % version
  puts "Tagging with #{tag}"
  repo.add_tag(tag)
  repo.push('origin', tag)
end
untracked_unignored_files() click to toggle source

Needed because of a bug in the git gem that lists ignored files as untracked under some circumstances github.com/schacon/ruby-git/issues/130

# File lib/modulesync/repository.rb, line 139
def untracked_unignored_files
  ignore_path = "#{@directory}/.gitignore"
  ignored = File.exist?(ignore_path) ? File.read(ignore_path).split : []
  repo.status.untracked.keep_if { |f, _| ignored.none? { |i| File.fnmatch(i, f) } }
end