class Commit < ActiveRecord::Base
+ extend CurrentApiClient
+
class GitError < StandardError
def http_status
422
# repository can be the name of a locally hosted repository or a git
# URL (see git-fetch(1)). Currently http, https, and git schemes are
# supported.
- def self.find_commit_range(current_user, repository, minimum, maximum, exclude)
+ def self.find_commit_range repository, minimum, maximum, exclude
if minimum and minimum.empty?
minimum = nil
end
# Get the commit hash for the upper bound
max_hash = nil
- IO.foreach("|git rev-list --max-count=1 #{maximum.shellescape} --") do |line|
+ git_max_hash_cmd = "git rev-list --max-count=1 #{maximum.shellescape} --"
+ IO.foreach("|#{git_max_hash_cmd}") do |line|
max_hash = line.strip
end
- # If not found or string is invalid, nothing else to do
- return [] if !max_hash or !git_check_ref_format(max_hash)
+ # If not found, nothing else to do
+ if !max_hash
+ logger.warn "no refs found looking for max_hash: `GIT_DIR=#{gitdir} #{git_max_hash_cmd}` returned no output"
+ return []
+ end
+
+ # If string is invalid, nothing else to do
+ if !git_check_ref_format(max_hash)
+ logger.warn "ref returned by `GIT_DIR=#{gitdir} #{git_max_hash_cmd}` was invalid for max_hash: #{max_hash}"
+ return []
+ end
resolved_exclude = nil
if exclude
if minimum
# Get the commit hash for the lower bound
min_hash = nil
- IO.foreach("|git rev-list --max-count=1 #{minimum.shellescape} --") do |line|
+ git_min_hash_cmd = "git rev-list --max-count=1 #{minimum.shellescape} --"
+ IO.foreach("|#{git_min_hash_cmd}") do |line|
min_hash = line.strip
end
- # If not found or string is invalid, nothing else to do
- return [] if !min_hash or !git_check_ref_format(min_hash)
+ # If not found, nothing else to do
+ if !min_hash
+ logger.warn "no refs found looking for min_hash: `GIT_DIR=#{gitdir} #{git_min_hash_cmd}` returned no output"
+ return []
+ end
+
+ # If string is invalid, nothing else to do
+ if !git_check_ref_format(min_hash)
+ logger.warn "ref returned by `GIT_DIR=#{gitdir} #{git_min_hash_cmd}` was invalid for min_hash: #{min_hash}"
+ return []
+ end
# Now find all commits between them
IO.foreach("|git rev-list #{min_hash.shellescape}..#{max_hash.shellescape} --") do |line|
# The repo can be a remote url, but in this case sha1 must already
# be present in our local cache for that repo: e.g., sha1 was just
# returned by find_commit_range.
- def self.tag_in_internal_repository repo, sha1, tag
+ def self.tag_in_internal_repository repo_name, sha1, tag
unless git_check_ref_format tag
raise ArgumentError.new "invalid tag #{tag}"
end
unless /^[0-9a-f]{40}$/ =~ sha1
raise ArgumentError.new "invalid sha1 #{sha1}"
end
- src_gitdir, _ = git_dir_for repo
+ src_gitdir, _ = git_dir_for repo_name
+ unless src_gitdir
+ raise ArgumentError.new "no local repository for #{repo_name}"
+ end
dst_gitdir = Rails.configuration.git_internal_dir
must_pipe("echo #{sha1.shellescape}",
"git --git-dir #{src_gitdir.shellescape} pack-objects -q --revs --stdout",
protected
- def self.remote_url? repository
- /^(https?|git):\/\// =~ repository
+ def self.remote_url? repo_name
+ /^(https?|git):\/\// =~ repo_name
end
# Return [local_git_dir, is_remote]. If is_remote, caller must use
end
def self.cache_dir_for git_url
- Rails.root.join('tmp', 'git', Digest::SHA1.hexdigest(git_url) + ".git").
- to_s
+ File.join(cache_dir_base, Digest::SHA1.hexdigest(git_url) + ".git").to_s
+ end
+
+ def self.cache_dir_base
+ Rails.root.join 'tmp', 'git'
end
def self.fetch_remote_repository gitdir, git_url
unless /^[a-z]+:\/\// =~ git_url
raise ArgumentError.new "invalid git url #{git_url}"
end
- FileUtils.mkdir_p gitdir
+ begin
+ must_git gitdir, "branch"
+ rescue GitError => e
+ raise unless /Not a git repository/ =~ e.to_s
+ # OK, this just means we need to create a blank cache repository
+ # before fetching.
+ FileUtils.mkdir_p gitdir
+ must_git gitdir, "init"
+ end
must_git(gitdir,
- "init",
"fetch --no-progress --tags --prune --force --update-head-ok #{git_url.shellescape} 'refs/heads/*:refs/heads/*'")
end