class Manifestly::Repository

Public Class Methods

is_github_name?(value) click to toggle source
# File lib/manifestly/repository.rb, line 54
def self.is_github_name?(value)
  value.match(/\A[^\/]+\/[^\/]+\z/)
end
load(path) click to toggle source

Returns an object if can load a git repository at the specified path, otherwise nil

# File lib/manifestly/repository.rb, line 25
def self.load(path)
  repository = new(path)
  repository.is_git_repository? ? repository : nil
end
load_cached(github_name_or_path, options) click to toggle source

Loads a gem-cached copy of the specified repository, cloning it if necessary.

# File lib/manifestly/repository.rb, line 32
def self.load_cached(github_name_or_path, options)
  options[:update] ||= false

  raise(IllegalArgument, "Repository name is blank.") if github_name_or_path.blank?

  cached_path = "#{Manifestly.configuration.cached_repos_root_dir}/.manifestly/.manifest_repositories/#{github_name_or_path}"
  FileUtils.mkdir_p(cached_path)

  repository = load(cached_path)

  if repository.nil?
    remote_location = is_github_name?(github_name_or_path) ?
                        "git@github.com:#{github_name_or_path}.git" :
                        github_name_or_path
    Git.clone(remote_location, cached_path)
    repository = new(cached_path)
  end

  repository.make_like_just_cloned! if options[:update]
  repository
end
new(path) click to toggle source
# File lib/manifestly/repository.rb, line 252
def initialize(path)
  @path = path
  @commit_page = 0
  @prs_only = false
end

Public Instance Methods

checkout_commit(sha, fetch_if_unfound=false) click to toggle source
# File lib/manifestly/repository.rb, line 154
def checkout_commit(sha, fetch_if_unfound=false)
  begin
    git.checkout(sha)
  rescue Git::GitExecuteError => e
    if is_commit_not_found_exception?(e)
      if fetch_if_unfound
        git.fetch
        checkout_commit(sha, false)
      else
        raise CommitNotPresent.new(sha, self)
      end
    else
      raise
    end
  end
end
commits(options={}) click to toggle source
# File lib/manifestly/repository.rb, line 99
def commits(options={})
  begin
    log = git.log(1000000).object('master') # don't limit
    log = log.between(options[:between][0], options[:between][1]) if options[:between]
    log = log.grep("Merge pull request") if @prs_only
    log.tap(&:first) # tap to force otherwise lazy checks
  rescue Git::GitExecuteError => e
    raise NoCommitsError
  end
end
current_branch_name() click to toggle source
# File lib/manifestly/repository.rb, line 176
def current_branch_name
  git.lib.branch_current
end
current_commit() click to toggle source
# File lib/manifestly/repository.rb, line 180
def current_commit
  sha = git.show.split("\n")[0].split(" ")[1]
  find_commit(sha)
end
deepest_working_dir() click to toggle source
# File lib/manifestly/repository.rb, line 242
def deepest_working_dir
  working_dir.to_s.split(File::SEPARATOR).last
end
display_name() click to toggle source
# File lib/manifestly/repository.rb, line 246
def display_name
  "[#{deepest_working_dir}]#{' ' + github_name_or_path if !github_name_or_path.nil?}"
end
fetch() click to toggle source
# File lib/manifestly/repository.rb, line 74
def fetch
  git.fetch
end
file_commits(file) click to toggle source
# File lib/manifestly/repository.rb, line 146
def file_commits(file)
  commits = git.log
  commits = commits.select do |commit|
    diff = Diff.new(commit.diff_parent.to_s)
    diff.has_file?(file)
  end
end
find_commit(sha) click to toggle source

returns the commit matching the provided sha or raises

# File lib/manifestly/repository.rb, line 111
def find_commit(sha)
  begin
    git.gcommit(sha).tap(&:sha)
  rescue Git::GitExecuteError => e
    raise CommitNotPresent.new(sha, self)
  end
end
get_commit_content(sha) click to toggle source
# File lib/manifestly/repository.rb, line 119
def get_commit_content(sha)
  get_commit_file(sha).to_content
end
get_commit_file(sha) click to toggle source
# File lib/manifestly/repository.rb, line 127
def get_commit_file(sha)
  diff_string = begin
    git.show(sha)
  rescue Git::GitExecuteError => e
    if is_commit_not_found_exception?(e)
      raise CommitNotPresent.new(sha, self)
    else
      raise
    end
  end

  sha_diff = Diff.new(diff_string)

  raise(CommitContentError, "No content to retrieve for SHA #{sha}!") if sha_diff.num_files == 0
  raise(CommitContentError, "More than one file in the commit for SHA #{sha}!") if sha_diff.num_files > 1

  sha_diff[0]
end
get_commit_filename(sha) click to toggle source
# File lib/manifestly/repository.rb, line 123
def get_commit_filename(sha)
  get_commit_file(sha).to_name
end
get_shas_with_tag(options={}) click to toggle source
# File lib/manifestly/repository.rb, line 205
def get_shas_with_tag(options={})
  options[:file] ||= ".*"
  options[:order] ||= :descending

  # only look for the unique tags, not the plain ones
  pattern = /.*\/#{options[:file]}\/#{options[:tag]}/

  tag_objects = git.tags.select{|tag| tag.name.match(pattern)}
                        .sort_by(&:name)

  tag_objects.reverse! if options[:order] == :descending

  tag_objects.collect do |tag_object|
    matched_sha = tag_object.contents.match(/[a-f0-9]{40}/)
    raise(TagShaNotFound, "Could not retrieve SHA for tag '#{full_tag}'") if matched_sha.nil?
    matched_sha.to_s
  end
end
git() click to toggle source
# File lib/manifestly/repository.rb, line 78
def git
  Git.open(@path)
end
github_name_or_path() click to toggle source
# File lib/manifestly/repository.rb, line 232
def github_name_or_path
  # Extract 'org/reponame' out of remote url for both HTTP and SSH clones
  return nil if origin.nil?
  origin.url[/github.com.(.*?)(.git)?$/,1]
end
has_commits?() click to toggle source
# File lib/manifestly/repository.rb, line 66
def has_commits?
  begin
    git && commits
  rescue NoCommitsError
    false
  end
end
is_commit_not_found_exception?(e) click to toggle source
# File lib/manifestly/repository.rb, line 171
def is_commit_not_found_exception?(e)
  e.message.include?("fatal: reference is not a tree") ||
  e.message.include?("fatal: ambiguous argument")
end
is_git_repository?() click to toggle source
# File lib/manifestly/repository.rb, line 58
def is_git_repository?
  begin
    git
  rescue ArgumentError
    false
  end
end
make_like_just_cloned!() click to toggle source
# File lib/manifestly/repository.rb, line 82
def make_like_just_cloned!
  git.branch('master').checkout
  # Blow away tags and fetch them back http://stackoverflow.com/a/5373319/1664216
  git.tags.map{|tag| git.delete_tag(tag.name)}
  git.fetch('origin', :tags => true)
  git.reset_hard('origin/master')
end
origin() click to toggle source
# File lib/manifestly/repository.rb, line 228
def origin
  @origin ||= git.remotes.select{|remote| remote.name == 'origin'}.first
end
push_file!(local_file_path, repository_file_path, message) click to toggle source
# File lib/manifestly/repository.rb, line 90
def push_file!(local_file_path, repository_file_path, message)
  full_repository_file_path = File.join(@path, repository_file_path)
  FileUtils.cp(local_file_path, full_repository_file_path)
  git.add(repository_file_path)
  raise ManifestUnchanged if git.status.changed.empty? && git.status.added.empty?
  git.commit(message)
  git.push
end
tag_scoped_to_file(options={}) click to toggle source
# File lib/manifestly/repository.rb, line 185
def tag_scoped_to_file(options={})
  raise(IllegalArgument, "Tag names cannot contain forward slashes") if options[:tag].include?("/")

  options[:push] ||= false
  options[:message] ||= "no message"

  existing_shas = get_shas_with_tag(tag: options[:tag])
  raise(ShaAlreadyTagged) if existing_shas.any?{|existing| existing.match(/#{options[:sha]}/)}

  filename = get_commit_filename(options[:sha])

  plain_tag = "#{filename}/#{options[:tag]}"
  git.add_tag(plain_tag, options[:sha], {annotate: true, message: options[:message], f: true})
  git.push('origin', "refs/tags/#{plain_tag}", f: true) if options[:push]

  unique_tag = "#{Time.now.utc.strftime("%Y%m%d-%H%M%S.%6N")}/#{::SecureRandom.hex(2)}/#{filename}/#{options[:tag]}"
  git.add_tag(unique_tag, options[:sha], {annotate: true, message: options[:message], f: true})
  git.push('origin', "refs/tags/#{unique_tag}", f: true) if options[:push]
end
toggle_prs_only() click to toggle source
# File lib/manifestly/repository.rb, line 224
def toggle_prs_only
  @prs_only = !@prs_only
end
working_dir() click to toggle source
# File lib/manifestly/repository.rb, line 238
def working_dir
  git.dir
end