Merge branch 'refactor/gitlab_git'
This commit is contained in:
commit
76a4cbe464
71 changed files with 827 additions and 745 deletions
|
@ -12,7 +12,6 @@ class CommitLoadContext < BaseContext
|
||||||
commit = project.repository.commit(params[:id])
|
commit = project.repository.commit(params[:id])
|
||||||
|
|
||||||
if commit
|
if commit
|
||||||
commit = CommitDecorator.decorate(commit)
|
|
||||||
line_notes = project.notes.for_commit_id(commit.id).inline
|
line_notes = project.notes.for_commit_id(commit.id).inline
|
||||||
|
|
||||||
result[:commit] = commit
|
result[:commit] = commit
|
||||||
|
|
|
@ -8,7 +8,6 @@ class BlameController < ProjectResourceController
|
||||||
before_filter :require_non_empty_project
|
before_filter :require_non_empty_project
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@repo = @project.repo
|
@blame = Gitlab::Git::Blame.new(project.repository, @commit.id, @path)
|
||||||
@blame = Grit::Blob.blame(@repo, @commit.id, @path)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,7 +13,6 @@ class CommitsController < ProjectResourceController
|
||||||
@limit, @offset = (params[:limit] || 40), (params[:offset] || 0)
|
@limit, @offset = (params[:limit] || 40), (params[:offset] || 0)
|
||||||
|
|
||||||
@commits = @repo.commits(@ref, @path, @limit, @offset)
|
@commits = @repo.commits(@ref, @path, @limit, @offset)
|
||||||
@commits = CommitDecorator.decorate_collection(@commits)
|
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html # index.html.erb
|
format.html # index.html.erb
|
||||||
|
|
|
@ -8,15 +8,13 @@ class CompareController < ProjectResourceController
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
result = Commit.compare(project, params[:from], params[:to])
|
compare = Gitlab::Git::Compare.new(project.repository, params[:from], params[:to])
|
||||||
|
|
||||||
@commits = result[:commits]
|
@commits = compare.commits
|
||||||
@commit = result[:commit]
|
@commit = compare.commit
|
||||||
@diffs = result[:diffs]
|
@diffs = compare.diffs
|
||||||
@refs_are_same = result[:same]
|
@refs_are_same = compare.same
|
||||||
@line_notes = []
|
@line_notes = []
|
||||||
|
|
||||||
@commits = CommitDecorator.decorate_collection(@commits)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
|
|
@ -94,12 +94,10 @@ class MergeRequestsController < ProjectResourceController
|
||||||
|
|
||||||
def branch_from
|
def branch_from
|
||||||
@commit = @repository.commit(params[:ref])
|
@commit = @repository.commit(params[:ref])
|
||||||
@commit = CommitDecorator.decorate(@commit)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def branch_to
|
def branch_to
|
||||||
@commit = @repository.commit(params[:ref])
|
@commit = @repository.commit(params[:ref])
|
||||||
@commit = CommitDecorator.decorate(@commit)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def ci_status
|
def ci_status
|
||||||
|
@ -143,7 +141,6 @@ class MergeRequestsController < ProjectResourceController
|
||||||
# Get commits from repository
|
# Get commits from repository
|
||||||
# or from cache if already merged
|
# or from cache if already merged
|
||||||
@commits = @merge_request.commits
|
@commits = @merge_request.commits
|
||||||
@commits = CommitDecorator.decorate_collection(@commits)
|
|
||||||
|
|
||||||
@allowed_to_merge = allowed_to_merge?
|
@allowed_to_merge = allowed_to_merge?
|
||||||
@show_merge_controls = @merge_request.opened? && @commits.any? && @allowed_to_merge
|
@show_merge_controls = @merge_request.opened? && @commits.any? && @allowed_to_merge
|
||||||
|
|
|
@ -34,7 +34,6 @@ class RefsController < ProjectResourceController
|
||||||
@logs = contents.map do |content|
|
@logs = contents.map do |content|
|
||||||
file = params[:path] ? File.join(params[:path], content.name) : content.name
|
file = params[:path] ? File.join(params[:path], content.name) : content.name
|
||||||
last_commit = @repo.commits(@commit.id, file, 1).last
|
last_commit = @repo.commits(@commit.id, file, 1).last
|
||||||
last_commit = CommitDecorator.decorate(last_commit)
|
|
||||||
{
|
{
|
||||||
file_name: content.name,
|
file_name: content.name,
|
||||||
commit: last_commit
|
commit: last_commit
|
||||||
|
@ -49,9 +48,7 @@ class RefsController < ProjectResourceController
|
||||||
|
|
||||||
@repo = project.repository
|
@repo = project.repository
|
||||||
@commit = @repo.commit(@ref)
|
@commit = @repo.commit(@ref)
|
||||||
@commit = CommitDecorator.decorate(@commit)
|
|
||||||
@tree = Tree.new(@commit.tree, @ref, params[:path])
|
@tree = Tree.new(@commit.tree, @ref, params[:path])
|
||||||
@tree = TreeDecorator.new(@tree)
|
|
||||||
@hex_path = Digest::SHA1.hexdigest(params[:path] || "")
|
@hex_path = Digest::SHA1.hexdigest(params[:path] || "")
|
||||||
|
|
||||||
if params[:path]
|
if params[:path]
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
class CommitDecorator < ApplicationDecorator
|
|
||||||
decorates :commit
|
|
||||||
|
|
||||||
# Returns a string describing the commit for use in a link title
|
|
||||||
#
|
|
||||||
# Example
|
|
||||||
#
|
|
||||||
# "Commit: Alex Denisov - Project git clone panel"
|
|
||||||
def link_title
|
|
||||||
"Commit: #{author_name} - #{title}"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the commits title.
|
|
||||||
#
|
|
||||||
# Usually, the commit title is the first line of the commit message.
|
|
||||||
# In case this first line is longer than 80 characters, it is cut off
|
|
||||||
# after 70 characters and ellipses (`&hellp;`) are appended.
|
|
||||||
def title
|
|
||||||
title = safe_message
|
|
||||||
|
|
||||||
return no_commit_message if title.blank?
|
|
||||||
|
|
||||||
title_end = title.index(/\n/)
|
|
||||||
if (!title_end && title.length > 80) || (title_end && title_end > 80)
|
|
||||||
title[0..69] << "…".html_safe
|
|
||||||
else
|
|
||||||
title.split(/\n/, 2).first
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the commits description
|
|
||||||
#
|
|
||||||
# cut off, ellipses (`&hellp;`) are prepended to the commit message.
|
|
||||||
def description
|
|
||||||
description = safe_message
|
|
||||||
|
|
||||||
title_end = description.index(/\n/)
|
|
||||||
if (!title_end && description.length > 80) || (title_end && title_end > 80)
|
|
||||||
"…".html_safe << description[70..-1]
|
|
||||||
else
|
|
||||||
description.split(/\n/, 2)[1].try(:chomp)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns a link to the commit author. If the author has a matching user and
|
|
||||||
# is a member of the current @project it will link to the team member page.
|
|
||||||
# Otherwise it will link to the author email as specified in the commit.
|
|
||||||
#
|
|
||||||
# options:
|
|
||||||
# avatar: true will prepend the avatar image
|
|
||||||
# size: size of the avatar image in px
|
|
||||||
def author_link(options = {})
|
|
||||||
person_link(options.merge source: :author)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Just like #author_link but for the committer.
|
|
||||||
def committer_link(options = {})
|
|
||||||
person_link(options.merge source: :committer)
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def no_commit_message
|
|
||||||
"--no commit message"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Private: Returns a link to a person. If the person has a matching user and
|
|
||||||
# is a member of the current @project it will link to the team member page.
|
|
||||||
# Otherwise it will link to the person email as specified in the commit.
|
|
||||||
#
|
|
||||||
# options:
|
|
||||||
# source: one of :author or :committer
|
|
||||||
# avatar: true will prepend the avatar image
|
|
||||||
# size: size of the avatar image in px
|
|
||||||
def person_link(options = {})
|
|
||||||
source_name = send "#{options[:source]}_name".to_sym
|
|
||||||
source_email = send "#{options[:source]}_email".to_sym
|
|
||||||
text = if options[:avatar]
|
|
||||||
avatar = h.image_tag h.gravatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: ""
|
|
||||||
%Q{#{avatar} <span class="commit-#{options[:source]}-name">#{source_name}</span>}
|
|
||||||
else
|
|
||||||
source_name
|
|
||||||
end
|
|
||||||
|
|
||||||
user = User.where('name like ? or email like ?', source_name, source_email).first
|
|
||||||
|
|
||||||
if user.nil?
|
|
||||||
h.mail_to(source_email, text.html_safe, class: "commit-#{options[:source]}-link")
|
|
||||||
else
|
|
||||||
h.link_to(text.html_safe, h.user_path(user), class: "commit-#{options[:source]}-link")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,33 +0,0 @@
|
||||||
class TreeDecorator < ApplicationDecorator
|
|
||||||
decorates :tree
|
|
||||||
|
|
||||||
def breadcrumbs(max_links = 2)
|
|
||||||
if path
|
|
||||||
part_path = ""
|
|
||||||
parts = path.split("\/")
|
|
||||||
|
|
||||||
yield('..', nil) if parts.count > max_links
|
|
||||||
|
|
||||||
parts.each do |part|
|
|
||||||
part_path = File.join(part_path, part) unless part_path.empty?
|
|
||||||
part_path = part if part_path.empty?
|
|
||||||
|
|
||||||
next unless parts.last(2).include?(part) if parts.count > max_links
|
|
||||||
yield(part, h.tree_join(ref, part_path))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def up_dir?
|
|
||||||
path.present?
|
|
||||||
end
|
|
||||||
|
|
||||||
def up_dir_path
|
|
||||||
file = File.join(path, "..")
|
|
||||||
h.tree_join(ref, file)
|
|
||||||
end
|
|
||||||
|
|
||||||
def readme
|
|
||||||
@readme ||= contents.find { |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i }
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -96,7 +96,7 @@ module ApplicationHelper
|
||||||
]
|
]
|
||||||
|
|
||||||
project_nav = []
|
project_nav = []
|
||||||
if @project && @project.repository && @project.repository.root_ref
|
if @project && @project.repository.exists? && @project.repository.root_ref
|
||||||
project_nav = [
|
project_nav = [
|
||||||
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Issues", url: project_issues_path(@project) },
|
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Issues", url: project_issues_path(@project) },
|
||||||
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Commits", url: project_commits_path(@project, @ref || @project.repository.root_ref) },
|
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Commits", url: project_commits_path(@project, @ref || @project.repository.root_ref) },
|
||||||
|
|
|
@ -1,4 +1,20 @@
|
||||||
module CommitsHelper
|
module CommitsHelper
|
||||||
|
# Returns a link to the commit author. If the author has a matching user and
|
||||||
|
# is a member of the current @project it will link to the team member page.
|
||||||
|
# Otherwise it will link to the author email as specified in the commit.
|
||||||
|
#
|
||||||
|
# options:
|
||||||
|
# avatar: true will prepend the avatar image
|
||||||
|
# size: size of the avatar image in px
|
||||||
|
def commit_author_link(commit, options = {})
|
||||||
|
commit_person_link(commit, options.merge(source: :author))
|
||||||
|
end
|
||||||
|
|
||||||
|
# Just like #author_link but for the committer.
|
||||||
|
def commit_committer_link(commit, options = {})
|
||||||
|
commit_person_link(commit, options.merge(source: :committer))
|
||||||
|
end
|
||||||
|
|
||||||
def identification_type(line)
|
def identification_type(line)
|
||||||
if line[0] == "+"
|
if line[0] == "+"
|
||||||
"new"
|
"new"
|
||||||
|
@ -93,9 +109,7 @@ module CommitsHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def commit_to_html commit
|
def commit_to_html commit
|
||||||
if commit.model
|
escape_javascript(render 'commits/commit', commit: commit)
|
||||||
escape_javascript(render 'commits/commit', commit: commit)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def diff_line_content(line)
|
def diff_line_content(line)
|
||||||
|
@ -105,4 +119,58 @@ module CommitsHelper
|
||||||
line
|
line
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Breadcrumb links for a Project and, if applicable, a tree path
|
||||||
|
def commits_breadcrumbs
|
||||||
|
return unless @project && @ref
|
||||||
|
|
||||||
|
# Add the root project link and the arrow icon
|
||||||
|
crumbs = content_tag(:li) do
|
||||||
|
content_tag(:span, nil, class: 'arrow') +
|
||||||
|
link_to(@project.name, project_commits_path(@project, @ref))
|
||||||
|
end
|
||||||
|
|
||||||
|
if @path
|
||||||
|
parts = @path.split('/')
|
||||||
|
|
||||||
|
parts.each_with_index do |part, i|
|
||||||
|
crumbs += content_tag(:span, '/', class: 'divider')
|
||||||
|
crumbs += content_tag(:li) do
|
||||||
|
# The text is just the individual part, but the link needs all the parts before it
|
||||||
|
link_to part, project_commits_path(@project, tree_join(@ref, parts[0..i].join('/')))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
crumbs.html_safe
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
# Private: Returns a link to a person. If the person has a matching user and
|
||||||
|
# is a member of the current @project it will link to the team member page.
|
||||||
|
# Otherwise it will link to the person email as specified in the commit.
|
||||||
|
#
|
||||||
|
# options:
|
||||||
|
# source: one of :author or :committer
|
||||||
|
# avatar: true will prepend the avatar image
|
||||||
|
# size: size of the avatar image in px
|
||||||
|
def commit_person_link(commit, options = {})
|
||||||
|
source_name = commit.send "#{options[:source]}_name".to_sym
|
||||||
|
source_email = commit.send "#{options[:source]}_email".to_sym
|
||||||
|
text = if options[:avatar]
|
||||||
|
avatar = image_tag(gravatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "")
|
||||||
|
%Q{#{avatar} <span class="commit-#{options[:source]}-name">#{source_name}</span>}
|
||||||
|
else
|
||||||
|
source_name
|
||||||
|
end
|
||||||
|
|
||||||
|
user = User.where('name like ? or email like ?', source_name, source_email).first
|
||||||
|
|
||||||
|
if user.nil?
|
||||||
|
mail_to(source_email, text.html_safe, class: "commit-#{options[:source]}-link")
|
||||||
|
else
|
||||||
|
link_to(text.html_safe, user_path(user), class: "commit-#{options[:source]}-link")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -70,28 +70,26 @@ module TreeHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Breadcrumb links for a Project and, if applicable, a tree path
|
def tree_breadcrumbs(tree, max_links = 2)
|
||||||
def breadcrumbs
|
if tree.path
|
||||||
return unless @project && @ref
|
part_path = ""
|
||||||
|
parts = tree.path.split("\/")
|
||||||
|
|
||||||
# Add the root project link and the arrow icon
|
yield('..', nil) if parts.count > max_links
|
||||||
crumbs = content_tag(:li) do
|
|
||||||
content_tag(:span, nil, class: 'arrow') +
|
|
||||||
link_to(@project.name, project_commits_path(@project, @ref))
|
|
||||||
end
|
|
||||||
|
|
||||||
if @path
|
parts.each do |part|
|
||||||
parts = @path.split('/')
|
part_path = File.join(part_path, part) unless part_path.empty?
|
||||||
|
part_path = part if part_path.empty?
|
||||||
|
|
||||||
parts.each_with_index do |part, i|
|
next unless parts.last(2).include?(part) if parts.count > max_links
|
||||||
crumbs += content_tag(:span, '/', class: 'divider')
|
yield(part, tree_join(tree.ref, part_path))
|
||||||
crumbs += content_tag(:li) do
|
|
||||||
# The text is just the individual part, but the link needs all the parts before it
|
|
||||||
link_to part, project_commits_path(@project, tree_join(@ref, parts[0..i].join('/')))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
crumbs.html_safe
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def up_dir_path tree
|
||||||
|
file = File.join(tree.path, "..")
|
||||||
|
tree_join(tree.ref, file)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,6 @@ module Emails
|
||||||
def note_commit_email(recipient_id, note_id)
|
def note_commit_email(recipient_id, note_id)
|
||||||
@note = Note.find(note_id)
|
@note = Note.find(note_id)
|
||||||
@commit = @note.noteable
|
@commit = @note.noteable
|
||||||
@commit = CommitDecorator.decorate(@commit)
|
|
||||||
@project = @note.project
|
@project = @note.project
|
||||||
mail(to: recipient(recipient_id), subject: subject("note for commit #{@commit.short_id}", @commit.title))
|
mail(to: recipient(recipient_id), subject: subject("note for commit #{@commit.short_id}", @commit.title))
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,174 +8,70 @@ class Commit
|
||||||
#
|
#
|
||||||
DIFF_SAFE_SIZE = 100
|
DIFF_SAFE_SIZE = 100
|
||||||
|
|
||||||
attr_accessor :commit, :head, :refs
|
def self.decorate(commits)
|
||||||
|
commits.map { |c| self.new(c) }
|
||||||
delegate :message, :authored_date, :committed_date, :parents, :sha,
|
|
||||||
:date, :committer, :author, :diffs, :tree, :id, :stats,
|
|
||||||
:to_patch, to: :commit
|
|
||||||
|
|
||||||
class << self
|
|
||||||
def find_or_first(repo, commit_id = nil, root_ref)
|
|
||||||
commit = if commit_id
|
|
||||||
repo.commit(commit_id)
|
|
||||||
else
|
|
||||||
repo.commits(root_ref).first
|
|
||||||
end
|
|
||||||
|
|
||||||
Commit.new(commit) if commit
|
|
||||||
end
|
|
||||||
|
|
||||||
def fresh_commits(repo, n = 10)
|
|
||||||
commits = repo.heads.map do |h|
|
|
||||||
repo.commits(h.name, n).map { |c| Commit.new(c, h) }
|
|
||||||
end.flatten.uniq { |c| c.id }
|
|
||||||
|
|
||||||
commits.sort! do |x, y|
|
|
||||||
y.committed_date <=> x.committed_date
|
|
||||||
end
|
|
||||||
|
|
||||||
commits[0...n]
|
|
||||||
end
|
|
||||||
|
|
||||||
def commits_with_refs(repo, n = 20)
|
|
||||||
commits = repo.branches.map { |ref| Commit.new(ref.commit, ref) }
|
|
||||||
|
|
||||||
commits.sort! do |x, y|
|
|
||||||
y.committed_date <=> x.committed_date
|
|
||||||
end
|
|
||||||
|
|
||||||
commits[0..n]
|
|
||||||
end
|
|
||||||
|
|
||||||
def commits_since(repo, date)
|
|
||||||
commits = repo.heads.map do |h|
|
|
||||||
repo.log(h.name, nil, since: date).each { |c| Commit.new(c, h) }
|
|
||||||
end.flatten.uniq { |c| c.id }
|
|
||||||
|
|
||||||
commits.sort! do |x, y|
|
|
||||||
y.committed_date <=> x.committed_date
|
|
||||||
end
|
|
||||||
|
|
||||||
commits
|
|
||||||
end
|
|
||||||
|
|
||||||
def commits(repo, ref, path = nil, limit = nil, offset = nil)
|
|
||||||
if path
|
|
||||||
repo.log(ref, path, max_count: limit, skip: offset)
|
|
||||||
elsif limit && offset
|
|
||||||
repo.commits(ref, limit, offset)
|
|
||||||
else
|
|
||||||
repo.commits(ref)
|
|
||||||
end.map{ |c| Commit.new(c) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def commits_between(repo, from, to)
|
|
||||||
repo.commits_between(from, to).map { |c| Commit.new(c) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def compare(project, from, to)
|
|
||||||
result = {
|
|
||||||
commits: [],
|
|
||||||
diffs: [],
|
|
||||||
commit: nil,
|
|
||||||
same: false
|
|
||||||
}
|
|
||||||
|
|
||||||
return result unless from && to
|
|
||||||
|
|
||||||
first = project.repository.commit(to.try(:strip))
|
|
||||||
last = project.repository.commit(from.try(:strip))
|
|
||||||
|
|
||||||
if first && last
|
|
||||||
result[:same] = (first.id == last.id)
|
|
||||||
result[:commits] = project.repo.commits_between(last.id, first.id).map {|c| Commit.new(c)}
|
|
||||||
|
|
||||||
# Dont load diff for 100+ commits
|
|
||||||
result[:diffs] = if result[:commits].size > 100
|
|
||||||
[]
|
|
||||||
else
|
|
||||||
project.repo.diff(last.id, first.id) rescue []
|
|
||||||
end
|
|
||||||
|
|
||||||
result[:commit] = Commit.new(first)
|
|
||||||
end
|
|
||||||
|
|
||||||
result
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(raw_commit, head = nil)
|
attr_accessor :raw
|
||||||
|
|
||||||
|
def initialize(raw_commit)
|
||||||
raise "Nil as raw commit passed" unless raw_commit
|
raise "Nil as raw commit passed" unless raw_commit
|
||||||
|
|
||||||
@commit = raw_commit
|
@raw = raw_commit
|
||||||
@head = head
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def short_id(length = 10)
|
def id
|
||||||
id.to_s[0..length]
|
@raw.id
|
||||||
end
|
end
|
||||||
|
|
||||||
def safe_message
|
# Returns a string describing the commit for use in a link title
|
||||||
@safe_message ||= message
|
|
||||||
end
|
|
||||||
|
|
||||||
def created_at
|
|
||||||
committed_date
|
|
||||||
end
|
|
||||||
|
|
||||||
def author_email
|
|
||||||
author.email
|
|
||||||
end
|
|
||||||
|
|
||||||
def author_name
|
|
||||||
author.name
|
|
||||||
end
|
|
||||||
|
|
||||||
# Was this commit committed by a different person than the original author?
|
|
||||||
def different_committer?
|
|
||||||
author_name != committer_name || author_email != committer_email
|
|
||||||
end
|
|
||||||
|
|
||||||
def committer_name
|
|
||||||
committer.name
|
|
||||||
end
|
|
||||||
|
|
||||||
def committer_email
|
|
||||||
committer.email
|
|
||||||
end
|
|
||||||
|
|
||||||
def prev_commit
|
|
||||||
@prev_commit ||= if parents.present?
|
|
||||||
Commit.new(parents.first)
|
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def prev_commit_id
|
|
||||||
prev_commit.try :id
|
|
||||||
end
|
|
||||||
|
|
||||||
# Shows the diff between the commit's parent and the commit.
|
|
||||||
#
|
#
|
||||||
# Cuts out the header and stats from #to_patch and returns only the diff.
|
# Example
|
||||||
def to_diff
|
#
|
||||||
# see Grit::Commit#show
|
# "Commit: Alex Denisov - Project git clone panel"
|
||||||
patch = to_patch
|
def link_title
|
||||||
|
"Commit: #{author_name} - #{title}"
|
||||||
# discard lines before the diff
|
|
||||||
lines = patch.split("\n")
|
|
||||||
while !lines.first.start_with?("diff --git") do
|
|
||||||
lines.shift
|
|
||||||
end
|
|
||||||
lines.pop if lines.last =~ /^[\d.]+$/ # Git version
|
|
||||||
lines.pop if lines.last == "-- " # end of diff
|
|
||||||
lines.join("\n")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def has_zero_stats?
|
# Returns the commits title.
|
||||||
stats.total.zero?
|
#
|
||||||
rescue
|
# Usually, the commit title is the first line of the commit message.
|
||||||
true
|
# In case this first line is longer than 80 characters, it is cut off
|
||||||
|
# after 70 characters and ellipses (`&hellp;`) are appended.
|
||||||
|
def title
|
||||||
|
title = safe_message
|
||||||
|
|
||||||
|
return no_commit_message if title.blank?
|
||||||
|
|
||||||
|
title_end = title.index(/\n/)
|
||||||
|
if (!title_end && title.length > 80) || (title_end && title_end > 80)
|
||||||
|
title[0..69] << "…".html_safe
|
||||||
|
else
|
||||||
|
title.split(/\n/, 2).first
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns the commits description
|
||||||
|
#
|
||||||
|
# cut off, ellipses (`&hellp;`) are prepended to the commit message.
|
||||||
|
def description
|
||||||
|
description = safe_message
|
||||||
|
|
||||||
|
title_end = description.index(/\n/)
|
||||||
|
if (!title_end && description.length > 80) || (title_end && title_end > 80)
|
||||||
|
"…".html_safe << description[70..-1]
|
||||||
|
else
|
||||||
|
description.split(/\n/, 2)[1].try(:chomp)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def method_missing(m, *args, &block)
|
||||||
|
@raw.send(m, *args, &block)
|
||||||
|
end
|
||||||
|
|
||||||
|
def respond_to?(method)
|
||||||
|
return true if @raw.respond_to?(method)
|
||||||
|
|
||||||
|
super
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -50,7 +50,7 @@ class GollumWiki
|
||||||
# Returns the last 30 Commit objects across the entire
|
# Returns the last 30 Commit objects across the entire
|
||||||
# repository.
|
# repository.
|
||||||
def recent_history
|
def recent_history
|
||||||
Commit.fresh_commits(wiki.repo, 30)
|
Gitlab::Git::Commit.fresh_commits(wiki.repo, 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Finds a page within the repository based on a tile
|
# Finds a page within the repository based on a tile
|
||||||
|
@ -90,13 +90,17 @@ class GollumWiki
|
||||||
private
|
private
|
||||||
|
|
||||||
def create_repo!
|
def create_repo!
|
||||||
if gitlab_shell.add_repository(path_with_namespace)
|
if init_repo(path_with_namespace)
|
||||||
Gollum::Wiki.new(path_to_repo)
|
Gollum::Wiki.new(path_to_repo)
|
||||||
else
|
else
|
||||||
raise CouldNotCreateWikiError
|
raise CouldNotCreateWikiError
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def init_repo(path_with_namespace)
|
||||||
|
gitlab_shell.add_repository(path_with_namespace)
|
||||||
|
end
|
||||||
|
|
||||||
def commit_details(action, message = nil, title = nil)
|
def commit_details(action, message = nil, title = nil)
|
||||||
commit_message = message || default_message(action, title)
|
commit_message = message || default_message(action, title)
|
||||||
|
|
||||||
|
@ -114,5 +118,4 @@ class GollumWiki
|
||||||
def path_to_repo
|
def path_to_repo
|
||||||
@path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git")
|
@path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git")
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -152,7 +152,17 @@ class MergeRequest < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def commits
|
def commits
|
||||||
st_commits || []
|
if st_commits.present?
|
||||||
|
# check if merge request commits are valid
|
||||||
|
if st_commits.first.respond_to?(:short_id)
|
||||||
|
st_commits
|
||||||
|
else
|
||||||
|
# if commits are invalid - simply reload it from repo
|
||||||
|
reloaded_commits
|
||||||
|
end
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def probably_merged?
|
def probably_merged?
|
||||||
|
@ -169,9 +179,8 @@ class MergeRequest < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def unmerged_commits
|
def unmerged_commits
|
||||||
self.project.repo.
|
self.project.repository.
|
||||||
commits_between(self.target_branch, self.source_branch).
|
commits_between(self.target_branch, self.source_branch).
|
||||||
map {|c| Commit.new(c)}.
|
|
||||||
sort_by(&:created_at).
|
sort_by(&:created_at).
|
||||||
reverse
|
reverse
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,7 +8,7 @@ module Network
|
||||||
attr_accessor :time, :spaces, :parent_spaces
|
attr_accessor :time, :spaces, :parent_spaces
|
||||||
|
|
||||||
def initialize(raw_commit, refs)
|
def initialize(raw_commit, refs)
|
||||||
@commit = ::Commit.new(raw_commit)
|
@commit = Gitlab::Git::Commit.new(raw_commit)
|
||||||
@time = -1
|
@time = -1
|
||||||
@spaces = []
|
@spaces = []
|
||||||
@parent_spaces = []
|
@parent_spaces = []
|
||||||
|
|
|
@ -141,13 +141,7 @@ class Project < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def repository
|
def repository
|
||||||
if path
|
@repository ||= Repository.new(path_with_namespace, default_branch)
|
||||||
@repository ||= Repository.new(path_with_namespace, default_branch)
|
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
rescue Grit::NoSuchPathError
|
|
||||||
nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def saved?
|
def saved?
|
||||||
|
@ -332,14 +326,14 @@ class Project < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def valid_repo?
|
def valid_repo?
|
||||||
repo
|
repository.exists?
|
||||||
rescue
|
rescue
|
||||||
errors.add(:path, "Invalid repository path")
|
errors.add(:path, "Invalid repository path")
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def empty_repo?
|
def empty_repo?
|
||||||
!repository || repository.empty?
|
!repository.exists? || repository.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def ensure_satellite_exists
|
def ensure_satellite_exists
|
||||||
|
@ -363,7 +357,7 @@ class Project < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def repo_exists?
|
def repo_exists?
|
||||||
@repo_exists ||= (repository && repository.branches.present?)
|
@repo_exists ||= repository.exists?
|
||||||
rescue
|
rescue
|
||||||
@repo_exists = false
|
@repo_exists = false
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,170 +1,45 @@
|
||||||
class Repository
|
class Repository
|
||||||
include Gitlab::Popen
|
attr_accessor :raw_repository
|
||||||
|
|
||||||
# Repository directory name with namespace direcotry
|
def initialize(path_with_namespace, default_branch)
|
||||||
# Examples:
|
@raw_repository = Gitlab::Git::Repository.new(path_with_namespace, default_branch)
|
||||||
# gitlab/gitolite
|
rescue Gitlab::Git::Repository::NoRepository
|
||||||
# diaspora
|
nil
|
||||||
#
|
|
||||||
attr_accessor :path_with_namespace
|
|
||||||
|
|
||||||
# Grit repo object
|
|
||||||
attr_accessor :repo
|
|
||||||
|
|
||||||
# Default branch in the repository
|
|
||||||
attr_accessor :root_ref
|
|
||||||
|
|
||||||
def initialize(path_with_namespace, root_ref = 'master')
|
|
||||||
@root_ref = root_ref || "master"
|
|
||||||
@path_with_namespace = path_with_namespace
|
|
||||||
|
|
||||||
# Init grit repo object
|
|
||||||
repo
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def raw
|
def exists?
|
||||||
repo
|
raw_repository
|
||||||
end
|
|
||||||
|
|
||||||
def path_to_repo
|
|
||||||
@path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git")
|
|
||||||
end
|
|
||||||
|
|
||||||
def repo
|
|
||||||
@repo ||= Grit::Repo.new(path_to_repo)
|
|
||||||
end
|
|
||||||
|
|
||||||
def commit(commit_id = nil)
|
|
||||||
Commit.find_or_first(repo, commit_id, root_ref)
|
|
||||||
end
|
|
||||||
|
|
||||||
def fresh_commits(n = 10)
|
|
||||||
Commit.fresh_commits(repo, n)
|
|
||||||
end
|
|
||||||
|
|
||||||
def commits_with_refs(n = 20)
|
|
||||||
Commit.commits_with_refs(repo, n)
|
|
||||||
end
|
|
||||||
|
|
||||||
def commits_since(date)
|
|
||||||
Commit.commits_since(repo, date)
|
|
||||||
end
|
|
||||||
|
|
||||||
def commits(ref, path = nil, limit = nil, offset = nil)
|
|
||||||
Commit.commits(repo, ref, path, limit, offset)
|
|
||||||
end
|
|
||||||
|
|
||||||
def last_commit_for(ref, path = nil)
|
|
||||||
commits(ref, path, 1).first
|
|
||||||
end
|
|
||||||
|
|
||||||
def commits_between(from, to)
|
|
||||||
Commit.commits_between(repo, from, to)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns an Array of branch names
|
|
||||||
# sorted by name ASC
|
|
||||||
def branch_names
|
|
||||||
branches.map(&:name)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns an Array of Branches
|
|
||||||
def branches
|
|
||||||
repo.branches.sort_by(&:name)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns an Array of tag names
|
|
||||||
def tag_names
|
|
||||||
repo.tags.collect(&:name).sort.reverse
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns an Array of Tags
|
|
||||||
def tags
|
|
||||||
repo.tags.sort_by(&:name).reverse
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns an Array of branch and tag names
|
|
||||||
def ref_names
|
|
||||||
[branch_names + tag_names].flatten
|
|
||||||
end
|
|
||||||
|
|
||||||
def heads
|
|
||||||
@heads ||= repo.heads
|
|
||||||
end
|
|
||||||
|
|
||||||
def tree(fcommit, path = nil)
|
|
||||||
fcommit = commit if fcommit == :head
|
|
||||||
tree = fcommit.tree
|
|
||||||
path ? (tree / path) : tree
|
|
||||||
end
|
|
||||||
|
|
||||||
def has_commits?
|
|
||||||
!!commit
|
|
||||||
rescue Grit::NoSuchPathError
|
|
||||||
false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def empty?
|
def empty?
|
||||||
!has_commits?
|
raw_repository.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
# Discovers the default branch based on the repository's available branches
|
def commit(id = nil)
|
||||||
#
|
commit = raw_repository.commit(id)
|
||||||
# - If no branches are present, returns nil
|
commit = Commit.new(commit) if commit
|
||||||
# - If one branch is present, returns its name
|
commit
|
||||||
# - If two or more branches are present, returns the one that has a name
|
|
||||||
# matching root_ref (default_branch or 'master' if default_branch is nil)
|
|
||||||
def discover_default_branch
|
|
||||||
if branch_names.length == 0
|
|
||||||
nil
|
|
||||||
elsif branch_names.length == 1
|
|
||||||
branch_names.first
|
|
||||||
else
|
|
||||||
branch_names.select { |v| v == root_ref }.first
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Archive Project to .tar.gz
|
def commits(ref, path = nil, limit = nil, offset = nil)
|
||||||
#
|
commits = raw_repository.commits(ref, path, limit, offset)
|
||||||
# Already packed repo archives stored at
|
commits = Commit.decorate(commits) if commits.present?
|
||||||
# app_root/tmp/repositories/project_name/project_name-commit-id.tag.gz
|
commits
|
||||||
#
|
|
||||||
def archive_repo(ref)
|
|
||||||
ref = ref || self.root_ref
|
|
||||||
commit = self.commit(ref)
|
|
||||||
return nil unless commit
|
|
||||||
|
|
||||||
# Build file path
|
|
||||||
file_name = self.path_with_namespace.gsub("/","_") + "-" + commit.id.to_s + ".tar.gz"
|
|
||||||
storage_path = Rails.root.join("tmp", "repositories")
|
|
||||||
file_path = File.join(storage_path, self.path_with_namespace, file_name)
|
|
||||||
|
|
||||||
# Put files into a directory before archiving
|
|
||||||
prefix = File.basename(self.path_with_namespace) + "/"
|
|
||||||
|
|
||||||
# Create file if not exists
|
|
||||||
unless File.exists?(file_path)
|
|
||||||
FileUtils.mkdir_p File.dirname(file_path)
|
|
||||||
file = self.repo.archive_to_file(ref, prefix, file_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
file_path
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return repo size in megabytes
|
def commits_between(target, source)
|
||||||
# Cached in redis
|
commits = raw_repository.commits_between(target, source)
|
||||||
def size
|
commits = Commit.decorate(commits) if commits.present?
|
||||||
Rails.cache.fetch(cache_key(:size)) do
|
commits
|
||||||
size = popen('du -s', path_to_repo).first.strip.to_i
|
|
||||||
(size.to_f / 1024).round(2)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def expire_cache
|
def method_missing(m, *args, &block)
|
||||||
Rails.cache.delete(cache_key(:size))
|
raw_repository.send(m, *args, &block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def cache_key(type)
|
def respond_to?(method)
|
||||||
"#{type}:#{path_with_namespace}"
|
return true if raw_repository.respond_to?(method)
|
||||||
|
|
||||||
|
super
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,4 +26,12 @@ class Tree
|
||||||
def empty?
|
def empty?
|
||||||
data.blank?
|
data.blank?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def up_dir?
|
||||||
|
path.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def readme
|
||||||
|
@readme ||= contents.find { |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -79,14 +79,14 @@ class WikiPage
|
||||||
def version
|
def version
|
||||||
return nil unless persisted?
|
return nil unless persisted?
|
||||||
|
|
||||||
@version ||= Commit.new(@page.version)
|
@version ||= Commit.new(Gitlab::Git::Commit.new(@page.version))
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns an array of Gitlab Commit instances.
|
# Returns an array of Gitlab Commit instances.
|
||||||
def versions
|
def versions
|
||||||
return [] unless persisted?
|
return [] unless persisted?
|
||||||
|
|
||||||
@page.versions.map { |v| Commit.new(v) }
|
@page.versions.map { |v| Commit.new(Gitlab::Git::Commit.new(v)) }
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the Date that this latest version was
|
# Returns the Date that this latest version was
|
||||||
|
|
|
@ -46,18 +46,21 @@
|
||||||
%span.light ssh:
|
%span.light ssh:
|
||||||
%strong
|
%strong
|
||||||
= link_to @project.ssh_url_to_repo
|
= link_to @project.ssh_url_to_repo
|
||||||
%li
|
- if @project.repository.exists?
|
||||||
%span.light fs:
|
%li
|
||||||
%strong
|
%span.light fs:
|
||||||
= @repository.path_to_repo
|
%strong
|
||||||
|
= @repository.path_to_repo
|
||||||
|
|
||||||
%li
|
%li
|
||||||
%span.light last commit:
|
%span.light last commit:
|
||||||
%strong
|
%strong
|
||||||
- if @repository
|
|
||||||
= last_commit(@project)
|
= last_commit(@project)
|
||||||
- else
|
- else
|
||||||
never
|
%li
|
||||||
|
%span.light repository:
|
||||||
|
%strong.cred
|
||||||
|
does not exist
|
||||||
|
|
||||||
%li
|
%li
|
||||||
%span.light access:
|
%span.light access:
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
%i.icon-angle-right
|
%i.icon-angle-right
|
||||||
= link_to project_tree_path(@project, @ref) do
|
= link_to project_tree_path(@project, @ref) do
|
||||||
= @project.name
|
= @project.name
|
||||||
- @tree.breadcrumbs(6) do |link|
|
- tree_breadcrumbs(@tree, 6) do |link|
|
||||||
\/
|
\/
|
||||||
%li= link
|
%li= link
|
||||||
.clear
|
.clear
|
||||||
|
@ -22,13 +22,13 @@
|
||||||
%table
|
%table
|
||||||
- current_line = 1
|
- current_line = 1
|
||||||
- @blame.each do |commit, lines|
|
- @blame.each do |commit, lines|
|
||||||
- commit = CommitDecorator.decorate(Commit.new(commit))
|
- commit = Commit.new(commit)
|
||||||
%tr
|
%tr
|
||||||
%td.blame-commit
|
%td.blame-commit
|
||||||
%span.commit
|
%span.commit
|
||||||
= link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id"
|
= link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id"
|
||||||
|
|
||||||
= commit.author_link avatar: true, size: 16
|
= commit_author_link(commit, avatar: true, size: 16)
|
||||||
|
|
||||||
= link_to_gfm truncate(commit.title, length: 20), project_commit_path(@project, commit.id), class: "row_title"
|
= link_to_gfm truncate(commit.title, length: 20), project_commit_path(@project, commit.id), class: "row_title"
|
||||||
%td.lines.blame-numbers
|
%td.lines.blame-numbers
|
||||||
|
|
|
@ -24,14 +24,14 @@
|
||||||
.row
|
.row
|
||||||
.span5
|
.span5
|
||||||
.author
|
.author
|
||||||
= @commit.author_link avatar: true, size: 32
|
= commit_author_link(@commit, avatar: true, size: 32)
|
||||||
authored
|
authored
|
||||||
%time{title: @commit.authored_date.stamp("Aug 21, 2011 9:23pm")}
|
%time{title: @commit.authored_date.stamp("Aug 21, 2011 9:23pm")}
|
||||||
#{time_ago_in_words(@commit.authored_date)} ago
|
#{time_ago_in_words(@commit.authored_date)} ago
|
||||||
- if @commit.different_committer?
|
- if @commit.different_committer?
|
||||||
.committer
|
.committer
|
||||||
→
|
→
|
||||||
= @commit.committer_link
|
= commit_committer_link(@commit)
|
||||||
committed
|
committed
|
||||||
%time{title: @commit.committed_date.stamp("Aug 21, 2011 9:23pm")}
|
%time{title: @commit.committed_date.stamp("Aug 21, 2011 9:23pm")}
|
||||||
#{time_ago_in_words(@commit.committed_date)} ago
|
#{time_ago_in_words(@commit.committed_date)} ago
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
%strong= link_to "Browse Code »", project_tree_path(@project, commit), class: "right"
|
%strong= link_to "Browse Code »", project_tree_path(@project, commit), class: "right"
|
||||||
%p
|
%p
|
||||||
= link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id"
|
= link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id"
|
||||||
= commit.author_link avatar: true, size: 24
|
= commit_author_link(commit, avatar: true, size: 24)
|
||||||
|
|
||||||
= link_to_gfm truncate(commit.title, length: 70), project_commit_path(@project, commit.id), class: "row_title"
|
= link_to_gfm truncate(commit.title, length: 70), project_commit_path(@project, commit.id), class: "row_title"
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
- if @path.present?
|
- if @path.present?
|
||||||
%ul.breadcrumb
|
%ul.breadcrumb
|
||||||
= breadcrumbs
|
= commits_breadcrumbs
|
||||||
|
|
||||||
%div{id: dom_id(@project)}
|
%div{id: dom_id(@project)}
|
||||||
#commits-list= render "commits"
|
#commits-list= render "commits"
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
%div.ui-box
|
%div.ui-box
|
||||||
%h5.title
|
%h5.title
|
||||||
Commits (#{@commits.count})
|
Commits (#{@commits.count})
|
||||||
%ul.well-list= render @commits
|
%ul.well-list= render Commit.decorate(@commits)
|
||||||
|
|
||||||
- unless @diffs.empty?
|
- unless @diffs.empty?
|
||||||
%h4 Diff
|
%h4 Diff
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
- commit = CommitDecorator.decorate(commit)
|
|
||||||
%li.commit
|
%li.commit
|
||||||
%p
|
%p
|
||||||
= link_to commit.short_id(8), project_commit_path(project, commit), class: "commit_short_id"
|
= link_to commit.short_id(8), project_commit_path(project, commit), class: "commit_short_id"
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
.form-horizontal= render "shared/clone_panel"
|
.form-horizontal= render "shared/clone_panel"
|
||||||
.span4.pull-right
|
.span4.pull-right
|
||||||
.pull-right
|
.pull-right
|
||||||
- unless @project.empty_repo?
|
- if @project.empty_repo?
|
||||||
- if can? current_user, :download_code, @project
|
- if can? current_user, :download_code, @project
|
||||||
= link_to archive_project_repository_path(@project), class: "btn-small btn grouped" do
|
= link_to archive_project_repository_path(@project), class: "btn-small btn grouped" do
|
||||||
%i.icon-download-alt
|
%i.icon-download-alt
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
- commit = Commit.new(branch.commit)
|
- commit = Commit.new(Gitlab::Git::Commit.new(branch.commit))
|
||||||
- commit = CommitDecorator.decorate(commit)
|
|
||||||
%tr
|
%tr
|
||||||
%td
|
%td
|
||||||
= link_to project_commits_path(@project, branch.name) do
|
= link_to project_commits_path(@project, branch.name) do
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
- commit = update
|
- commit = update
|
||||||
- commit = CommitDecorator.new(commit)
|
|
||||||
%tr
|
%tr
|
||||||
%td
|
%td
|
||||||
= link_to project_commits_path(@project, commit.head.name) do
|
= link_to project_commits_path(@project, commit.head.name) do
|
||||||
|
|
|
@ -7,8 +7,7 @@
|
||||||
%th Last commit
|
%th Last commit
|
||||||
%th
|
%th
|
||||||
- @tags.each do |tag|
|
- @tags.each do |tag|
|
||||||
- commit = Commit.new(tag.commit)
|
- commit = Commit.new(Gitlab::Git::Commit.new(tag.commit))
|
||||||
- commit = CommitDecorator.decorate(commit)
|
|
||||||
%tr
|
%tr
|
||||||
%td
|
%td
|
||||||
%strong
|
%strong
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
%i.icon-angle-right
|
%i.icon-angle-right
|
||||||
= link_to project_tree_path(@project, @ref) do
|
= link_to project_tree_path(@project, @ref) do
|
||||||
= @project.path
|
= @project.path
|
||||||
- tree.breadcrumbs(6) do |title, path|
|
- tree_breadcrumbs(tree, 6) do |title, path|
|
||||||
\/
|
\/
|
||||||
%li
|
%li
|
||||||
- if path
|
- if path
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
%tr.tree-item
|
%tr.tree-item
|
||||||
%td.tree-item-file-name
|
%td.tree-item-file-name
|
||||||
= image_tag "file_empty.png", size: '16x16'
|
= image_tag "file_empty.png", size: '16x16'
|
||||||
= link_to "..", project_tree_path(@project, tree.up_dir_path)
|
= link_to "..", project_tree_path(@project, up_dir_path(tree))
|
||||||
%td
|
%td
|
||||||
%td
|
%td
|
||||||
%td
|
%td
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
%span.tree_author= commit.author_link avatar: true
|
%span.tree_author= commit_author_link(commit, avatar: true)
|
||||||
= link_to_gfm truncate(commit.title, length: 80), project_commit_path(@project, commit.id), class: "tree-commit-link"
|
= link_to_gfm truncate(commit.title, length: 80), project_commit_path(@project, commit.id), class: "tree-commit-link"
|
||||||
|
|
|
@ -14,12 +14,13 @@
|
||||||
%th Format
|
%th Format
|
||||||
%tbody
|
%tbody
|
||||||
- @wiki.versions.each do |version|
|
- @wiki.versions.each do |version|
|
||||||
- commit = CommitDecorator.new(version)
|
- commit = version
|
||||||
%tr
|
%tr
|
||||||
%td
|
%td
|
||||||
= link_to project_wiki_path(@project, @wiki, version_id: commit.id) do
|
= link_to project_wiki_path(@project, @wiki, version_id: commit.id) do
|
||||||
= commit.short_id
|
= commit.short_id
|
||||||
%td= commit.author_link avatar: true, size: 24
|
%td
|
||||||
|
= commit_author_link(commit, avatar: true, size: 24)
|
||||||
%td
|
%td
|
||||||
= commit.title
|
= commit.title
|
||||||
%td
|
%td
|
||||||
|
|
|
@ -21,5 +21,5 @@
|
||||||
= wiki_page.created_at.to_s(:short) do
|
= wiki_page.created_at.to_s(:short) do
|
||||||
(#{time_ago_in_words(wiki_page.created_at)}
|
(#{time_ago_in_words(wiki_page.created_at)}
|
||||||
ago)
|
ago)
|
||||||
- commit = CommitDecorator.decorate(wiki_page.version)
|
%td
|
||||||
%td= commit.author_link avatar: true, size: 24
|
= commit_author_link(wiki_page.version, avatar: true, size: 24)
|
||||||
|
|
|
@ -13,5 +13,4 @@
|
||||||
= preserve do
|
= preserve do
|
||||||
= render_wiki_content(@wiki)
|
= render_wiki_content(@wiki)
|
||||||
|
|
||||||
- commit = CommitDecorator.new(@wiki.version)
|
%p.time Last edited by #{commit_author_link(@wiki.version, avatar: true, size: 16)} #{time_ago_in_words @wiki.created_at} ago
|
||||||
%p.time Last edited by #{commit.author_link(avatar: true, size: 16)} #{time_ago_in_words @wiki.created_at} ago
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ class ProjectBrowseCommits < Spinach::FeatureSteps
|
||||||
end
|
end
|
||||||
|
|
||||||
Then 'I see commits atom feed' do
|
Then 'I see commits atom feed' do
|
||||||
commit = CommitDecorator.decorate(@project.repository.commit)
|
commit = @project.repository.commit
|
||||||
page.response_headers['Content-Type'].should have_content("application/atom+xml")
|
page.response_headers['Content-Type'].should have_content("application/atom+xml")
|
||||||
page.body.should have_selector("title", :text => "Recent commits to #{@project.name}")
|
page.body.should have_selector("title", :text => "Recent commits to #{@project.name}")
|
||||||
page.body.should have_selector("author email", :text => commit.author_email)
|
page.body.should have_selector("author email", :text => commit.author_email)
|
||||||
|
|
|
@ -3,14 +3,14 @@ module SharedProject
|
||||||
|
|
||||||
# Create a project without caring about what it's called
|
# Create a project without caring about what it's called
|
||||||
And "I own a project" do
|
And "I own a project" do
|
||||||
@project = create(:project)
|
@project = create(:project_with_code)
|
||||||
@project.team << [@user, :master]
|
@project.team << [@user, :master]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Create a specific project called "Shop"
|
# Create a specific project called "Shop"
|
||||||
And 'I own project "Shop"' do
|
And 'I own project "Shop"' do
|
||||||
@project = Project.find_by_name "Shop"
|
@project = Project.find_by_name "Shop"
|
||||||
@project ||= create(:project, name: "Shop")
|
@project ||= create(:project_with_code, name: "Shop")
|
||||||
@project.team << [@user, :master]
|
@project.team << [@user, :master]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,7 @@ class Userteams < Spinach::FeatureSteps
|
||||||
team = UserTeam.last
|
team = UserTeam.last
|
||||||
team.projects.each do |project|
|
team.projects.each do |project|
|
||||||
team.members.each do |member|
|
team.members.each do |member|
|
||||||
3.times { project.merge_requests << create(:merge_request, assignee: member) }
|
3.times { create(:merge_request, assignee: member, project: project) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -157,7 +157,7 @@ class Userteams < Spinach::FeatureSteps
|
||||||
team = UserTeam.last
|
team = UserTeam.last
|
||||||
team.projects.each do |project|
|
team.projects.each do |project|
|
||||||
team.members.each do |member|
|
team.members.each do |member|
|
||||||
3.times { project.merge_requests << create(:merge_request, assignee: member) }
|
3.times { create(:merge_request, assignee: member, project: project) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,7 +14,7 @@ require 'spinach/capybara'
|
||||||
require 'sidekiq/testing/inline'
|
require 'sidekiq/testing/inline'
|
||||||
|
|
||||||
|
|
||||||
%w(stubbed_repository valid_commit select2_helper).each do |f|
|
%w(valid_commit select2_helper test_env).each do |f|
|
||||||
require Rails.root.join('spec', 'support', f)
|
require Rails.root.join('spec', 'support', f)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -35,13 +35,8 @@ Capybara.default_wait_time = 10
|
||||||
DatabaseCleaner.strategy = :truncation
|
DatabaseCleaner.strategy = :truncation
|
||||||
|
|
||||||
Spinach.hooks.before_scenario do
|
Spinach.hooks.before_scenario do
|
||||||
# Use tmp dir for FS manipulations
|
TestEnv.init
|
||||||
Gitlab.config.gitlab_shell.stub(repos_path: Rails.root.join('tmp', 'test-git-base-path'))
|
|
||||||
Gitlab::Shell.any_instance.stub(:add_repository) do |path|
|
|
||||||
create_temp_repo("#{Rails.root}/tmp/test-git-base-path/#{path}.git")
|
|
||||||
end
|
|
||||||
FileUtils.rm_rf Gitlab.config.gitlab_shell.repos_path
|
|
||||||
FileUtils.mkdir_p Gitlab.config.gitlab_shell.repos_path
|
|
||||||
DatabaseCleaner.start
|
DatabaseCleaner.start
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -54,9 +49,3 @@ Spinach.hooks.before_run do
|
||||||
|
|
||||||
include FactoryGirl::Syntax::Methods
|
include FactoryGirl::Syntax::Methods
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_temp_repo(path)
|
|
||||||
FileUtils.mkdir_p path
|
|
||||||
command = "git init --quiet --bare #{path};"
|
|
||||||
system(command)
|
|
||||||
end
|
|
||||||
|
|
|
@ -372,7 +372,7 @@ module Gitlab
|
||||||
ref = params[:ref_name] || user_project.try(:default_branch) || 'master'
|
ref = params[:ref_name] || user_project.try(:default_branch) || 'master'
|
||||||
|
|
||||||
commits = user_project.repository.commits(ref, nil, per_page, page * per_page)
|
commits = user_project.repository.commits(ref, nil, per_page, page * per_page)
|
||||||
present CommitDecorator.decorate(commits), with: Entities::RepoCommit
|
present commits, with: Entities::RepoCommit
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get a project snippets
|
# Get a project snippets
|
||||||
|
|
|
@ -85,8 +85,8 @@ module ExtractsPath
|
||||||
# - @id - A string representing the joined ref and path
|
# - @id - A string representing the joined ref and path
|
||||||
# - @ref - A string representing the ref (e.g., the branch, tag, or commit SHA)
|
# - @ref - A string representing the ref (e.g., the branch, tag, or commit SHA)
|
||||||
# - @path - A string representing the filesystem path
|
# - @path - A string representing the filesystem path
|
||||||
# - @commit - A CommitDecorator representing the commit from the given ref
|
# - @commit - A Commit representing the commit from the given ref
|
||||||
# - @tree - A TreeDecorator representing the tree at the given ref/path
|
# - @tree - A Tree representing the tree at the given ref/path
|
||||||
#
|
#
|
||||||
# If the :id parameter appears to be requesting a specific response format,
|
# If the :id parameter appears to be requesting a specific response format,
|
||||||
# that will be handled as well.
|
# that will be handled as well.
|
||||||
|
@ -100,11 +100,9 @@ module ExtractsPath
|
||||||
|
|
||||||
# It is used "@project.repository.commits(@ref, @path, 1, 0)",
|
# It is used "@project.repository.commits(@ref, @path, 1, 0)",
|
||||||
# because "@project.repository.commit(@ref)" returns wrong commit when @ref is tag name.
|
# because "@project.repository.commit(@ref)" returns wrong commit when @ref is tag name.
|
||||||
commits = @project.repository.commits(@ref, @path, 1, 0)
|
@commit = @project.repository.commits(@ref, @path, 1, 0).first
|
||||||
@commit = CommitDecorator.decorate(commits.first)
|
|
||||||
|
|
||||||
@tree = Tree.new(@commit.tree, @ref, @path)
|
@tree = Tree.new(@commit.tree, @ref, @path)
|
||||||
@tree = TreeDecorator.new(@tree)
|
|
||||||
|
|
||||||
raise InvalidPathError if @tree.invalid?
|
raise InvalidPathError if @tree.invalid?
|
||||||
rescue RuntimeError, NoMethodError, InvalidPathError
|
rescue RuntimeError, NoMethodError, InvalidPathError
|
||||||
|
|
22
lib/gitlab/git/blame.rb
Normal file
22
lib/gitlab/git/blame.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
module Gitlab
|
||||||
|
module Git
|
||||||
|
class Blame
|
||||||
|
|
||||||
|
attr_accessor :repository, :sha, :path
|
||||||
|
|
||||||
|
def initialize(repository, sha, path)
|
||||||
|
@repository, @sha, @path = repository, sha, path
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def each
|
||||||
|
raw_blame = Grit::Blob.blame(repository.repo, sha, path)
|
||||||
|
|
||||||
|
raw_blame.each do |commit, lines|
|
||||||
|
commit = Gitlab::Git::Commit.new(commit)
|
||||||
|
yield(commit, lines)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
153
lib/gitlab/git/commit.rb
Normal file
153
lib/gitlab/git/commit.rb
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
# Gitlab::Git::Commit is a wrapper around native Grit::Commit object
|
||||||
|
# We dont want to use grit objects inside app/
|
||||||
|
# It helps us easily migrate to rugged in future
|
||||||
|
module Gitlab
|
||||||
|
module Git
|
||||||
|
class Commit
|
||||||
|
attr_accessor :raw_commit, :head, :refs
|
||||||
|
|
||||||
|
delegate :message, :authored_date, :committed_date, :parents, :sha,
|
||||||
|
:date, :committer, :author, :diffs, :tree, :id, :stats, :to_patch,
|
||||||
|
to: :raw_commit
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def find_or_first(repo, commit_id = nil, root_ref)
|
||||||
|
commit = if commit_id
|
||||||
|
repo.commit(commit_id)
|
||||||
|
else
|
||||||
|
repo.commits(root_ref).first
|
||||||
|
end
|
||||||
|
|
||||||
|
Commit.new(commit) if commit
|
||||||
|
end
|
||||||
|
|
||||||
|
def fresh_commits(repo, n = 10)
|
||||||
|
commits = repo.heads.map do |h|
|
||||||
|
repo.commits(h.name, n).map { |c| Commit.new(c, h) }
|
||||||
|
end.flatten.uniq { |c| c.id }
|
||||||
|
|
||||||
|
commits.sort! do |x, y|
|
||||||
|
y.committed_date <=> x.committed_date
|
||||||
|
end
|
||||||
|
|
||||||
|
commits[0...n]
|
||||||
|
end
|
||||||
|
|
||||||
|
def commits_with_refs(repo, n = 20)
|
||||||
|
commits = repo.branches.map { |ref| Commit.new(ref.commit, ref) }
|
||||||
|
|
||||||
|
commits.sort! do |x, y|
|
||||||
|
y.committed_date <=> x.committed_date
|
||||||
|
end
|
||||||
|
|
||||||
|
commits[0..n]
|
||||||
|
end
|
||||||
|
|
||||||
|
def commits_since(repo, date)
|
||||||
|
commits = repo.heads.map do |h|
|
||||||
|
repo.log(h.name, nil, since: date).each { |c| Commit.new(c, h) }
|
||||||
|
end.flatten.uniq { |c| c.id }
|
||||||
|
|
||||||
|
commits.sort! do |x, y|
|
||||||
|
y.committed_date <=> x.committed_date
|
||||||
|
end
|
||||||
|
|
||||||
|
commits
|
||||||
|
end
|
||||||
|
|
||||||
|
def commits(repo, ref, path = nil, limit = nil, offset = nil)
|
||||||
|
if path
|
||||||
|
repo.log(ref, path, max_count: limit, skip: offset)
|
||||||
|
elsif limit && offset
|
||||||
|
repo.commits(ref, limit, offset)
|
||||||
|
else
|
||||||
|
repo.commits(ref)
|
||||||
|
end.map{ |c| Commit.new(c) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def commits_between(repo, from, to)
|
||||||
|
repo.commits_between(from, to).map { |c| Commit.new(c) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(raw_commit, head = nil)
|
||||||
|
raise "Nil as raw commit passed" unless raw_commit
|
||||||
|
|
||||||
|
@raw_commit = raw_commit
|
||||||
|
@head = head
|
||||||
|
end
|
||||||
|
|
||||||
|
def short_id(length = 10)
|
||||||
|
id.to_s[0..length]
|
||||||
|
end
|
||||||
|
|
||||||
|
def safe_message
|
||||||
|
@safe_message ||= message
|
||||||
|
end
|
||||||
|
|
||||||
|
def created_at
|
||||||
|
committed_date
|
||||||
|
end
|
||||||
|
|
||||||
|
def author_email
|
||||||
|
author.email
|
||||||
|
end
|
||||||
|
|
||||||
|
def author_name
|
||||||
|
author.name
|
||||||
|
end
|
||||||
|
|
||||||
|
# Was this commit committed by a different person than the original author?
|
||||||
|
def different_committer?
|
||||||
|
author_name != committer_name || author_email != committer_email
|
||||||
|
end
|
||||||
|
|
||||||
|
def committer_name
|
||||||
|
committer.name
|
||||||
|
end
|
||||||
|
|
||||||
|
def committer_email
|
||||||
|
committer.email
|
||||||
|
end
|
||||||
|
|
||||||
|
def prev_commit
|
||||||
|
@prev_commit ||= if parents.present?
|
||||||
|
Commit.new(parents.first)
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def prev_commit_id
|
||||||
|
prev_commit.try :id
|
||||||
|
end
|
||||||
|
|
||||||
|
# Shows the diff between the commit's parent and the commit.
|
||||||
|
#
|
||||||
|
# Cuts out the header and stats from #to_patch and returns only the diff.
|
||||||
|
def to_diff
|
||||||
|
# see Grit::Commit#show
|
||||||
|
patch = to_patch
|
||||||
|
|
||||||
|
# discard lines before the diff
|
||||||
|
lines = patch.split("\n")
|
||||||
|
while !lines.first.start_with?("diff --git") do
|
||||||
|
lines.shift
|
||||||
|
end
|
||||||
|
lines.pop if lines.last =~ /^[\d.]+$/ # Git version
|
||||||
|
lines.pop if lines.last == "-- " # end of diff
|
||||||
|
lines.join("\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_zero_stats?
|
||||||
|
stats.total.zero?
|
||||||
|
rescue
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def no_commit_message
|
||||||
|
"--no commit message"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
37
lib/gitlab/git/compare.rb
Normal file
37
lib/gitlab/git/compare.rb
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
module Gitlab
|
||||||
|
module Git
|
||||||
|
class Compare
|
||||||
|
attr_accessor :commits, :commit, :diffs, :same
|
||||||
|
|
||||||
|
def initialize(repository, from, to)
|
||||||
|
@commits, @diffs = [], []
|
||||||
|
@commit = nil
|
||||||
|
@same = false
|
||||||
|
|
||||||
|
return unless from && to
|
||||||
|
|
||||||
|
first = repository.commit(to.try(:strip))
|
||||||
|
last = repository.commit(from.try(:strip))
|
||||||
|
|
||||||
|
return unless first && last
|
||||||
|
|
||||||
|
if first.id == last.id
|
||||||
|
@same = true
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
@commit = Commit.new(first)
|
||||||
|
|
||||||
|
@commits = repository.commits_between(last.id, first.id)
|
||||||
|
@commits = @commits.map { |c| Commit.new(c) }
|
||||||
|
|
||||||
|
@diffs = if @commits.size > 100
|
||||||
|
[]
|
||||||
|
else
|
||||||
|
repository.repo.diff(last.id, first.id) rescue []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
185
lib/gitlab/git/repository.rb
Normal file
185
lib/gitlab/git/repository.rb
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
# Gitlab::Git::Gitlab::Git::Commit is a wrapper around native Grit::Repository object
|
||||||
|
# We dont want to use grit objects inside app/
|
||||||
|
# It helps us easily migrate to rugged in future
|
||||||
|
module Gitlab
|
||||||
|
module Git
|
||||||
|
class Repository
|
||||||
|
include Gitlab::Popen
|
||||||
|
|
||||||
|
class NoRepository < StandardError; end
|
||||||
|
|
||||||
|
# Repository directory name with namespace direcotry
|
||||||
|
# Examples:
|
||||||
|
# gitlab/gitolite
|
||||||
|
# diaspora
|
||||||
|
#
|
||||||
|
attr_accessor :path_with_namespace
|
||||||
|
|
||||||
|
# Grit repo object
|
||||||
|
attr_accessor :repo
|
||||||
|
|
||||||
|
# Default branch in the repository
|
||||||
|
attr_accessor :root_ref
|
||||||
|
|
||||||
|
def initialize(path_with_namespace, root_ref = 'master')
|
||||||
|
@root_ref = root_ref || "master"
|
||||||
|
@path_with_namespace = path_with_namespace
|
||||||
|
|
||||||
|
# Init grit repo object
|
||||||
|
repo
|
||||||
|
end
|
||||||
|
|
||||||
|
def raw
|
||||||
|
repo
|
||||||
|
end
|
||||||
|
|
||||||
|
def path_to_repo
|
||||||
|
@path_to_repo ||= File.join(repos_path, "#{path_with_namespace}.git")
|
||||||
|
end
|
||||||
|
|
||||||
|
def repos_path
|
||||||
|
Gitlab.config.gitlab_shell.repos_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def repo
|
||||||
|
@repo ||= Grit::Repo.new(path_to_repo)
|
||||||
|
rescue Grit::NoSuchPathError
|
||||||
|
raise NoRepository.new('no repository for such path')
|
||||||
|
end
|
||||||
|
|
||||||
|
def commit(commit_id = nil)
|
||||||
|
Gitlab::Git::Commit.find_or_first(repo, commit_id, root_ref)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fresh_commits(n = 10)
|
||||||
|
Gitlab::Git::Commit.fresh_commits(repo, n)
|
||||||
|
end
|
||||||
|
|
||||||
|
def commits_with_refs(n = 20)
|
||||||
|
Gitlab::Git::Commit.commits_with_refs(repo, n)
|
||||||
|
end
|
||||||
|
|
||||||
|
def commits_since(date)
|
||||||
|
Gitlab::Git::Commit.commits_since(repo, date)
|
||||||
|
end
|
||||||
|
|
||||||
|
def commits(ref, path = nil, limit = nil, offset = nil)
|
||||||
|
Gitlab::Git::Commit.commits(repo, ref, path, limit, offset)
|
||||||
|
end
|
||||||
|
|
||||||
|
def last_commit_for(ref, path = nil)
|
||||||
|
commits(ref, path, 1).first
|
||||||
|
end
|
||||||
|
|
||||||
|
def commits_between(from, to)
|
||||||
|
Gitlab::Git::Commit.commits_between(repo, from, to)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns an Array of branch names
|
||||||
|
# sorted by name ASC
|
||||||
|
def branch_names
|
||||||
|
branches.map(&:name)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns an Array of Branches
|
||||||
|
def branches
|
||||||
|
repo.branches.sort_by(&:name)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns an Array of tag names
|
||||||
|
def tag_names
|
||||||
|
repo.tags.collect(&:name).sort.reverse
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns an Array of Tags
|
||||||
|
def tags
|
||||||
|
repo.tags.sort_by(&:name).reverse
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns an Array of branch and tag names
|
||||||
|
def ref_names
|
||||||
|
[branch_names + tag_names].flatten
|
||||||
|
end
|
||||||
|
|
||||||
|
def heads
|
||||||
|
@heads ||= repo.heads
|
||||||
|
end
|
||||||
|
|
||||||
|
def tree(fcommit, path = nil)
|
||||||
|
fcommit = commit if fcommit == :head
|
||||||
|
tree = fcommit.tree
|
||||||
|
path ? (tree / path) : tree
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_commits?
|
||||||
|
!!commit
|
||||||
|
rescue Grit::NoSuchPathError
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def empty?
|
||||||
|
!has_commits?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Discovers the default branch based on the repository's available branches
|
||||||
|
#
|
||||||
|
# - If no branches are present, returns nil
|
||||||
|
# - If one branch is present, returns its name
|
||||||
|
# - If two or more branches are present, returns the one that has a name
|
||||||
|
# matching root_ref (default_branch or 'master' if default_branch is nil)
|
||||||
|
def discover_default_branch
|
||||||
|
if branch_names.length == 0
|
||||||
|
nil
|
||||||
|
elsif branch_names.length == 1
|
||||||
|
branch_names.first
|
||||||
|
else
|
||||||
|
branch_names.select { |v| v == root_ref }.first
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Archive Project to .tar.gz
|
||||||
|
#
|
||||||
|
# Already packed repo archives stored at
|
||||||
|
# app_root/tmp/repositories/project_name/project_name-commit-id.tag.gz
|
||||||
|
#
|
||||||
|
def archive_repo(ref)
|
||||||
|
ref = ref || self.root_ref
|
||||||
|
commit = self.commit(ref)
|
||||||
|
return nil unless commit
|
||||||
|
|
||||||
|
# Build file path
|
||||||
|
file_name = self.path_with_namespace.gsub("/","_") + "-" + commit.id.to_s + ".tar.gz"
|
||||||
|
storage_path = Rails.root.join("tmp", "repositories")
|
||||||
|
file_path = File.join(storage_path, self.path_with_namespace, file_name)
|
||||||
|
|
||||||
|
# Put files into a directory before archiving
|
||||||
|
prefix = File.basename(self.path_with_namespace) + "/"
|
||||||
|
|
||||||
|
# Create file if not exists
|
||||||
|
unless File.exists?(file_path)
|
||||||
|
FileUtils.mkdir_p File.dirname(file_path)
|
||||||
|
file = self.repo.archive_to_file(ref, prefix, file_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
file_path
|
||||||
|
end
|
||||||
|
|
||||||
|
# Return repo size in megabytes
|
||||||
|
# Cached in redis
|
||||||
|
def size
|
||||||
|
Rails.cache.fetch(cache_key(:size)) do
|
||||||
|
size = popen('du -s', path_to_repo).first.strip.to_i
|
||||||
|
(size.to_f / 1024).round(2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def expire_cache
|
||||||
|
Rails.cache.delete(cache_key(:size))
|
||||||
|
end
|
||||||
|
|
||||||
|
def cache_key(type)
|
||||||
|
"#{type}:#{path_with_namespace}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -187,7 +187,7 @@ module Gitlab
|
||||||
|
|
||||||
def reference_commit(identifier)
|
def reference_commit(identifier)
|
||||||
if @project.valid_repo? && commit = @project.repository.commit(identifier)
|
if @project.valid_repo? && commit = @project.repository.commit(identifier)
|
||||||
link_to(identifier, project_commit_url(@project, commit), html_options.merge(title: CommitDecorator.new(commit).link_title, class: "gfm gfm-commit #{html_options[:class]}"))
|
link_to(identifier, project_commit_url(@project, commit), html_options.merge(title: commit.link_title, class: "gfm gfm-commit #{html_options[:class]}"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
6
lib/tasks/cache.rake
Normal file
6
lib/tasks/cache.rake
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
namespace :cache do
|
||||||
|
desc "GITLAB | Clear redis cache"
|
||||||
|
task :clear => :environment do
|
||||||
|
Rails.cache.clear
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,7 +1,7 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe CommitController do
|
describe CommitController do
|
||||||
let(:project) { create(:project) }
|
let(:project) { create(:project_with_code) }
|
||||||
let(:user) { create(:user) }
|
let(:user) { create(:user) }
|
||||||
let(:commit) { project.repository.last_commit_for("master") }
|
let(:commit) { project.repository.last_commit_for("master") }
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe CommitsController do
|
describe CommitsController do
|
||||||
let(:project) { create(:project) }
|
let(:project) { create(:project_with_code) }
|
||||||
let(:user) { create(:user) }
|
let(:user) { create(:user) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe MergeRequestsController do
|
describe MergeRequestsController do
|
||||||
let(:project) { create(:project) }
|
let(:project) { create(:project_with_code) }
|
||||||
let(:user) { create(:user) }
|
let(:user) { create(:user) }
|
||||||
let(:merge_request) { create(:merge_request_with_diffs, project: project, target_branch: "bcf03b5d~3", source_branch: "bcf03b5d") }
|
let(:merge_request) { create(:merge_request_with_diffs, project: project, target_branch: "bcf03b5d~3", source_branch: "bcf03b5d") }
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe TreeController do
|
describe TreeController do
|
||||||
let(:project) { create(:project) }
|
let(:project) { create(:project_with_code) }
|
||||||
let(:user) { create(:user) }
|
let(:user) { create(:user) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
|
|
@ -34,6 +34,10 @@ FactoryGirl.define do
|
||||||
issues_tracker_id { "project_name_in_redmine" }
|
issues_tracker_id { "project_name_in_redmine" }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
factory :project_with_code, parent: :project do
|
||||||
|
path { 'gitlabhq' }
|
||||||
|
end
|
||||||
|
|
||||||
factory :group do
|
factory :group do
|
||||||
sequence(:name) { |n| "group#{n}" }
|
sequence(:name) { |n| "group#{n}" }
|
||||||
path { name.downcase.gsub(/\s/, '_') }
|
path { name.downcase.gsub(/\s/, '_') }
|
||||||
|
@ -73,7 +77,7 @@ FactoryGirl.define do
|
||||||
factory :merge_request do
|
factory :merge_request do
|
||||||
title
|
title
|
||||||
author
|
author
|
||||||
project
|
project factory: :project_with_code
|
||||||
source_branch "master"
|
source_branch "master"
|
||||||
target_branch "stable"
|
target_branch "stable"
|
||||||
|
|
||||||
|
@ -82,9 +86,9 @@ FactoryGirl.define do
|
||||||
target_branch "master" # pretend bcf03b5d~3
|
target_branch "master" # pretend bcf03b5d~3
|
||||||
source_branch "stable" # pretend bcf03b5d
|
source_branch "stable" # pretend bcf03b5d
|
||||||
st_commits do
|
st_commits do
|
||||||
[Commit.new(project.repo.commit('bcf03b5d')),
|
[Commit.new(project.repository.commit('bcf03b5d')),
|
||||||
Commit.new(project.repo.commit('bcf03b5d~1')),
|
Commit.new(project.repository.commit('bcf03b5d~1')),
|
||||||
Commit.new(project.repo.commit('bcf03b5d~2'))]
|
Commit.new(project.repository.commit('bcf03b5d~2'))]
|
||||||
end
|
end
|
||||||
st_diffs do
|
st_diffs do
|
||||||
project.repo.diff("bcf03b5d~3", "bcf03b5d")
|
project.repo.diff("bcf03b5d~3", "bcf03b5d")
|
||||||
|
@ -116,6 +120,7 @@ FactoryGirl.define do
|
||||||
factory :note_on_merge_request_diff, traits: [:on_merge_request, :on_diff]
|
factory :note_on_merge_request_diff, traits: [:on_merge_request, :on_diff]
|
||||||
|
|
||||||
trait :on_commit do
|
trait :on_commit do
|
||||||
|
project factory: :project_with_code
|
||||||
commit_id "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a"
|
commit_id "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a"
|
||||||
noteable_type "Commit"
|
noteable_type "Commit"
|
||||||
end
|
end
|
||||||
|
@ -125,6 +130,7 @@ FactoryGirl.define do
|
||||||
end
|
end
|
||||||
|
|
||||||
trait :on_merge_request do
|
trait :on_merge_request do
|
||||||
|
project factory: :project_with_code
|
||||||
noteable_id 1
|
noteable_id 1
|
||||||
noteable_type "MergeRequest"
|
noteable_type "MergeRequest"
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe "Gitlab Flavored Markdown" do
|
describe "Gitlab Flavored Markdown" do
|
||||||
let(:project) { create(:project) }
|
let(:project) { create(:project_with_code) }
|
||||||
let(:issue) { create(:issue, project: project) }
|
let(:issue) { create(:issue, project: project) }
|
||||||
let(:merge_request) { create(:merge_request, project: project) }
|
let(:merge_request) { create(:merge_request, project: project) }
|
||||||
let(:fred) do
|
let(:fred) do
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe "On a merge request", js: true do
|
describe "On a merge request", js: true do
|
||||||
let!(:project) { create(:project) }
|
let!(:project) { create(:project_with_code) }
|
||||||
let!(:merge_request) { create(:merge_request, project: project) }
|
let!(:merge_request) { create(:merge_request, project: project) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
@ -83,7 +83,7 @@ end
|
||||||
|
|
||||||
|
|
||||||
describe "On a merge request diff", js: true, focus: true do
|
describe "On a merge request diff", js: true, focus: true do
|
||||||
let!(:project) { create(:project) }
|
let!(:project) { create(:project_with_code) }
|
||||||
let!(:merge_request) { create(:merge_request_with_diffs, project: project) }
|
let!(:merge_request) { create(:merge_request_with_diffs, project: project) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
|
|
@ -12,6 +12,7 @@ describe "Profile account page" do
|
||||||
Gitlab.config.gitlab.stub(:signup_enabled).and_return(true)
|
Gitlab.config.gitlab.stub(:signup_enabled).and_return(true)
|
||||||
visit account_profile_path
|
visit account_profile_path
|
||||||
end
|
end
|
||||||
|
|
||||||
it { page.should have_content("Remove account") }
|
it { page.should have_content("Remove account") }
|
||||||
|
|
||||||
it "should delete the account", js: true do
|
it "should delete the account", js: true do
|
||||||
|
|
|
@ -14,7 +14,7 @@ describe "Application access" do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "Project" do
|
describe "Project" do
|
||||||
let(:project) { create(:project) }
|
let(:project) { create(:project_with_code) }
|
||||||
|
|
||||||
let(:master) { create(:user) }
|
let(:master) { create(:user) }
|
||||||
let(:guest) { create(:user) }
|
let(:guest) { create(:user) }
|
||||||
|
|
|
@ -4,10 +4,10 @@ describe GitlabMarkdownHelper do
|
||||||
include ApplicationHelper
|
include ApplicationHelper
|
||||||
include IssuesHelper
|
include IssuesHelper
|
||||||
|
|
||||||
let!(:project) { create(:project) }
|
let!(:project) { create(:project_with_code) }
|
||||||
|
|
||||||
let(:user) { create(:user, username: 'gfm') }
|
let(:user) { create(:user, username: 'gfm') }
|
||||||
let(:commit) { CommitDecorator.decorate(project.repository.commit) }
|
let(:commit) { project.repository.commit }
|
||||||
let(:issue) { create(:issue, project: project) }
|
let(:issue) { create(:issue, project: project) }
|
||||||
let(:merge_request) { create(:merge_request, project: project) }
|
let(:merge_request) { create(:merge_request, project: project) }
|
||||||
let(:snippet) { create(:snippet, project: project) }
|
let(:snippet) { create(:snippet, project: project) }
|
||||||
|
|
49
spec/lib/git/commit_spec.rb
Normal file
49
spec/lib/git/commit_spec.rb
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
require "spec_helper"
|
||||||
|
|
||||||
|
describe Gitlab::Git::Commit do
|
||||||
|
let(:commit) { create(:project_with_code).repository.commit }
|
||||||
|
|
||||||
|
describe "Commit info" do
|
||||||
|
before do
|
||||||
|
@committer = double(
|
||||||
|
email: 'mike@smith.com',
|
||||||
|
name: 'Mike Smith'
|
||||||
|
)
|
||||||
|
|
||||||
|
@author = double(
|
||||||
|
email: 'john@smith.com',
|
||||||
|
name: 'John Smith'
|
||||||
|
)
|
||||||
|
|
||||||
|
@raw_commit = double(
|
||||||
|
id: "bcf03b5de6abcf03b5de6c",
|
||||||
|
author: @author,
|
||||||
|
committer: @committer,
|
||||||
|
committed_date: Date.yesterday,
|
||||||
|
message: 'Refactoring specs'
|
||||||
|
)
|
||||||
|
|
||||||
|
@commit = Gitlab::Git::Commit.new(@raw_commit)
|
||||||
|
end
|
||||||
|
|
||||||
|
it { @commit.short_id.should == "bcf03b5de6a" }
|
||||||
|
it { @commit.safe_message.should == @raw_commit.message }
|
||||||
|
it { @commit.created_at.should == @raw_commit.committed_date }
|
||||||
|
it { @commit.author_email.should == @author.email }
|
||||||
|
it { @commit.author_name.should == @author.name }
|
||||||
|
it { @commit.committer_name.should == @committer.name }
|
||||||
|
it { @commit.committer_email.should == @committer.email }
|
||||||
|
it { @commit.different_committer?.should be_true }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Class methods" do
|
||||||
|
subject { Gitlab::Git::Commit }
|
||||||
|
|
||||||
|
it { should respond_to(:find_or_first) }
|
||||||
|
it { should respond_to(:fresh_commits) }
|
||||||
|
it { should respond_to(:commits_with_refs) }
|
||||||
|
it { should respond_to(:commits_since) }
|
||||||
|
it { should respond_to(:commits_between) }
|
||||||
|
it { should respond_to(:commits) }
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,8 +1,7 @@
|
||||||
require "spec_helper"
|
require "spec_helper"
|
||||||
|
|
||||||
describe Repository do
|
describe Gitlab::Git::Repository do
|
||||||
let(:project) { create(:project) }
|
let(:repository) { Gitlab::Git::Repository.new('gitlabhq', 'master') }
|
||||||
let(:repository) { project.repository }
|
|
||||||
|
|
||||||
describe "Respond to" do
|
describe "Respond to" do
|
||||||
subject { repository }
|
subject { repository }
|
|
@ -5,7 +5,7 @@ describe Notify do
|
||||||
include EmailSpec::Matchers
|
include EmailSpec::Matchers
|
||||||
|
|
||||||
let(:recipient) { create(:user, email: 'recipient@example.com') }
|
let(:recipient) { create(:user, email: 'recipient@example.com') }
|
||||||
let(:project) { create(:project) }
|
let(:project) { create(:project_with_code) }
|
||||||
|
|
||||||
shared_examples 'a multiple recipients email' do
|
shared_examples 'a multiple recipients email' do
|
||||||
it 'is sent to the given recipient' do
|
it 'is sent to the given recipient' do
|
||||||
|
@ -277,14 +277,7 @@ describe Notify do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'on a commit' do
|
describe 'on a commit' do
|
||||||
let(:commit) do
|
let(:commit) { project.repository.commit }
|
||||||
mock(:commit).tap do |commit|
|
|
||||||
commit.stub(:id).and_return('fauxsha1')
|
|
||||||
commit.stub(:project).and_return(project)
|
|
||||||
commit.stub(:short_id).and_return('fauxsha1')
|
|
||||||
commit.stub(:safe_message).and_return('some message')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
before(:each) { note.stub(:noteable).and_return(commit) }
|
before(:each) { note.stub(:noteable).and_return(commit) }
|
||||||
|
|
||||||
|
@ -297,7 +290,7 @@ describe Notify do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'contains a link to the commit' do
|
it 'contains a link to the commit' do
|
||||||
should have_body_text /fauxsha1/
|
should have_body_text commit.short_id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,83 +1,35 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Commit do
|
describe Commit do
|
||||||
let(:commit) { create(:project).repository.commit }
|
let(:commit) { create(:project_with_code).repository.commit }
|
||||||
|
|
||||||
describe CommitDecorator do
|
|
||||||
let(:decorator) { CommitDecorator.new(commit) }
|
|
||||||
|
|
||||||
describe '#title' do
|
describe '#title' do
|
||||||
it "returns no_commit_message when safe_message is blank" do
|
it "returns no_commit_message when safe_message is blank" do
|
||||||
decorator.stub(:safe_message).and_return('')
|
commit.stub(:safe_message).and_return('')
|
||||||
decorator.title.should == "--no commit message"
|
commit.title.should == "--no commit message"
|
||||||
end
|
|
||||||
|
|
||||||
it "truncates a message without a newline at 70 characters" do
|
|
||||||
message = commit.safe_message * 10
|
|
||||||
|
|
||||||
decorator.stub(:safe_message).and_return(message)
|
|
||||||
decorator.title.should == "#{message[0..69]}…"
|
|
||||||
end
|
|
||||||
|
|
||||||
it "truncates a message with a newline before 80 characters at the newline" do
|
|
||||||
message = commit.safe_message.split(" ").first
|
|
||||||
|
|
||||||
decorator.stub(:safe_message).and_return(message + "\n" + message)
|
|
||||||
decorator.title.should == message
|
|
||||||
end
|
|
||||||
|
|
||||||
it "truncates a message with a newline after 80 characters at 70 characters" do
|
|
||||||
message = (commit.safe_message * 10) + "\n"
|
|
||||||
|
|
||||||
decorator.stub(:safe_message).and_return(message)
|
|
||||||
decorator.title.should == "#{message[0..69]}…"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "Commit info" do
|
|
||||||
before do
|
|
||||||
@committer = double(
|
|
||||||
email: 'mike@smith.com',
|
|
||||||
name: 'Mike Smith'
|
|
||||||
)
|
|
||||||
|
|
||||||
@author = double(
|
|
||||||
email: 'john@smith.com',
|
|
||||||
name: 'John Smith'
|
|
||||||
)
|
|
||||||
|
|
||||||
@raw_commit = double(
|
|
||||||
id: "bcf03b5de6abcf03b5de6c",
|
|
||||||
author: @author,
|
|
||||||
committer: @committer,
|
|
||||||
committed_date: Date.yesterday,
|
|
||||||
message: 'Refactoring specs'
|
|
||||||
)
|
|
||||||
|
|
||||||
@commit = Commit.new(@raw_commit)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it { @commit.short_id.should == "bcf03b5de6a" }
|
it "truncates a message without a newline at 70 characters" do
|
||||||
it { @commit.safe_message.should == @raw_commit.message }
|
message = commit.safe_message * 10
|
||||||
it { @commit.created_at.should == @raw_commit.committed_date }
|
|
||||||
it { @commit.author_email.should == @author.email }
|
|
||||||
it { @commit.author_name.should == @author.name }
|
|
||||||
it { @commit.committer_name.should == @committer.name }
|
|
||||||
it { @commit.committer_email.should == @committer.email }
|
|
||||||
it { @commit.different_committer?.should be_true }
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "Class methods" do
|
commit.stub(:safe_message).and_return(message)
|
||||||
subject { Commit }
|
commit.title.should == "#{message[0..69]}…"
|
||||||
|
end
|
||||||
|
|
||||||
it { should respond_to(:find_or_first) }
|
it "truncates a message with a newline before 80 characters at the newline" do
|
||||||
it { should respond_to(:fresh_commits) }
|
message = commit.safe_message.split(" ").first
|
||||||
it { should respond_to(:commits_with_refs) }
|
|
||||||
it { should respond_to(:commits_since) }
|
commit.stub(:safe_message).and_return(message + "\n" + message)
|
||||||
it { should respond_to(:commits_between) }
|
commit.title.should == message
|
||||||
it { should respond_to(:commits) }
|
end
|
||||||
it { should respond_to(:compare) }
|
|
||||||
|
it "truncates a message with a newline after 80 characters at 70 characters" do
|
||||||
|
message = (commit.safe_message * 10) + "\n"
|
||||||
|
|
||||||
|
commit.stub(:safe_message).and_return(message)
|
||||||
|
commit.title.should == "#{message[0..69]}…"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "delegation" do
|
describe "delegation" do
|
||||||
|
|
|
@ -81,7 +81,7 @@ describe GollumWiki do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises CouldNotCreateWikiError if it can't create the wiki repository" do
|
it "raises CouldNotCreateWikiError if it can't create the wiki repository" do
|
||||||
Gitlab::Shell.any_instance.stub(:add_repository).and_return(false)
|
GollumWiki.any_instance.stub(:init_repo).and_return(false)
|
||||||
expect { GollumWiki.new(project, user).wiki }.to raise_exception(GollumWiki::CouldNotCreateWikiError)
|
expect { GollumWiki.new(project, user).wiki }.to raise_exception(GollumWiki::CouldNotCreateWikiError)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -119,7 +119,7 @@ describe Project do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe :update_merge_requests do
|
describe :update_merge_requests do
|
||||||
let(:project) { create(:project) }
|
let(:project) { create(:project_with_code) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
@merge_request = create(:merge_request, project: project)
|
@merge_request = create(:merge_request, project: project)
|
||||||
|
@ -189,10 +189,6 @@ describe Project do
|
||||||
it "should return valid repo" do
|
it "should return valid repo" do
|
||||||
project.repository.should be_kind_of(Repository)
|
project.repository.should be_kind_of(Repository)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should return nil" do
|
|
||||||
Project.new(path: "empty").repository.should be_nil
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe :issue_exists? do
|
describe :issue_exists? do
|
||||||
|
@ -249,7 +245,7 @@ describe Project do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe :open_branches do
|
describe :open_branches do
|
||||||
let(:project) { create(:project) }
|
let(:project) { create(:project_with_code) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
project.protected_branches.create(name: 'master')
|
project.protected_branches.create(name: 'master')
|
||||||
|
|
|
@ -4,7 +4,7 @@ describe Gitlab::API do
|
||||||
include ApiHelpers
|
include ApiHelpers
|
||||||
|
|
||||||
let(:user) { create(:user ) }
|
let(:user) { create(:user ) }
|
||||||
let!(:project) { create(:project, namespace: user.namespace ) }
|
let!(:project) { create(:project_with_code, creator_id: user.id) }
|
||||||
let!(:merge_request) { create(:merge_request, author: user, assignee: user, project: project, title: "Test") }
|
let!(:merge_request) { create(:merge_request, author: user, assignee: user, project: project, title: "Test") }
|
||||||
before { project.team << [user, :reporters] }
|
before { project.team << [user, :reporters] }
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ describe Gitlab::API do
|
||||||
let(:user2) { create(:user) }
|
let(:user2) { create(:user) }
|
||||||
let(:user3) { create(:user) }
|
let(:user3) { create(:user) }
|
||||||
let(:admin) { create(:admin) }
|
let(:admin) { create(:admin) }
|
||||||
let!(:project) { create(:project, namespace: user.namespace ) }
|
let!(:project) { create(:project_with_code, creator_id: user.id) }
|
||||||
let!(:hook) { create(:project_hook, project: project, url: "http://example.com") }
|
let!(:hook) { create(:project_hook, project: project, url: "http://example.com") }
|
||||||
let!(:snippet) { create(:snippet, author: user, project: project, title: 'example') }
|
let!(:snippet) { create(:snippet, author: user, project: project, title: 'example') }
|
||||||
let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) }
|
let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) }
|
||||||
|
|
|
@ -2,7 +2,7 @@ require 'spec_helper'
|
||||||
|
|
||||||
describe GitPushService do
|
describe GitPushService do
|
||||||
let (:user) { create :user }
|
let (:user) { create :user }
|
||||||
let (:project) { create :project }
|
let (:project) { create :project_with_code }
|
||||||
let (:service) { GitPushService.new }
|
let (:service) { GitPushService.new }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
|
|
@ -47,11 +47,7 @@ Spork.prefork do
|
||||||
config.use_transactional_fixtures = false
|
config.use_transactional_fixtures = false
|
||||||
|
|
||||||
config.before do
|
config.before do
|
||||||
# Use tmp dir for FS manipulations
|
TestEnv.init
|
||||||
temp_repos_path = Rails.root.join('tmp', 'test-git-base-path')
|
|
||||||
Gitlab.config.gitlab_shell.stub(repos_path: temp_repos_path)
|
|
||||||
FileUtils.rm_rf temp_repos_path
|
|
||||||
FileUtils.mkdir_p temp_repos_path
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
require "repository"
|
|
||||||
require "project"
|
|
||||||
require "merge_request"
|
|
||||||
require "shell"
|
|
||||||
|
|
||||||
# Stubs out all Git repository access done by models so that specs can run
|
|
||||||
# against fake repositories without Grit complaining that they don't exist.
|
|
||||||
class Project
|
|
||||||
def repository
|
|
||||||
if path == "empty" || !path
|
|
||||||
nil
|
|
||||||
else
|
|
||||||
GitLabTestRepo.new(path_with_namespace)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def satellite
|
|
||||||
FakeSatellite.new
|
|
||||||
end
|
|
||||||
|
|
||||||
class FakeSatellite
|
|
||||||
def exists?
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
def destroy
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
def create
|
|
||||||
true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class MergeRequest
|
|
||||||
def check_if_can_be_merged
|
|
||||||
true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class GitLabTestRepo < Repository
|
|
||||||
def repo
|
|
||||||
@repo ||= Grit::Repo.new(Rails.root.join('tmp', 'repositories', 'gitlabhq'))
|
|
||||||
end
|
|
||||||
|
|
||||||
# patch repo size (in mb)
|
|
||||||
def size
|
|
||||||
12.45
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
module Gitlab
|
|
||||||
class Shell
|
|
||||||
def add_repository name
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
def mv_repository name, new_name
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
def remove_repository name
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_key id, key
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
def remove_key id, key
|
|
||||||
true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
63
spec/support/test_env.rb
Normal file
63
spec/support/test_env.rb
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
module TestEnv
|
||||||
|
extend self
|
||||||
|
|
||||||
|
# Test environment
|
||||||
|
#
|
||||||
|
# all repositories and namespaces stored at
|
||||||
|
# RAILS_APP/tmp/test-git-base-path
|
||||||
|
#
|
||||||
|
# Next shell methods are stubbed and return true
|
||||||
|
# - mv_repository
|
||||||
|
# - remove_repository
|
||||||
|
# - add_key
|
||||||
|
# - remove_key
|
||||||
|
#
|
||||||
|
def init
|
||||||
|
# Use tmp dir for FS manipulations
|
||||||
|
repos_path = Rails.root.join('tmp', 'test-git-base-path')
|
||||||
|
Gitlab.config.gitlab_shell.stub(repos_path: repos_path)
|
||||||
|
|
||||||
|
GollumWiki.any_instance.stub(:init_repo) do |path|
|
||||||
|
create_temp_repo(File.join(repos_path, "#{path}.git"))
|
||||||
|
end
|
||||||
|
|
||||||
|
Gitlab::Shell.any_instance.stub(
|
||||||
|
add_repository: true,
|
||||||
|
mv_repository: true,
|
||||||
|
remove_repository: true,
|
||||||
|
add_key: true,
|
||||||
|
remove_key: true
|
||||||
|
)
|
||||||
|
|
||||||
|
Gitlab::Satellite::Satellite.any_instance.stub(
|
||||||
|
exists?: true,
|
||||||
|
destroy: true,
|
||||||
|
create: true
|
||||||
|
)
|
||||||
|
|
||||||
|
MergeRequest.any_instance.stub(
|
||||||
|
check_if_can_be_merged: true
|
||||||
|
)
|
||||||
|
|
||||||
|
Repository.any_instance.stub(
|
||||||
|
size: 12.45
|
||||||
|
)
|
||||||
|
|
||||||
|
# Remove tmp/test-git-base-path
|
||||||
|
FileUtils.rm_rf Gitlab.config.gitlab_shell.repos_path
|
||||||
|
|
||||||
|
# Recreate tmp/test-git-base-path
|
||||||
|
FileUtils.mkdir_p Gitlab.config.gitlab_shell.repos_path
|
||||||
|
|
||||||
|
# Symlink tmp/repositories/gitlabhq to tmp/test-git-base-path/gitlabhq
|
||||||
|
seed_repo = Rails.root.join('tmp', 'repositories', 'gitlabhq')
|
||||||
|
target_repo = File.join(repos_path, 'gitlabhq.git')
|
||||||
|
system("ln -s #{seed_repo} #{target_repo}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_temp_repo(path)
|
||||||
|
FileUtils.mkdir_p path
|
||||||
|
command = "git init --quiet --bare #{path};"
|
||||||
|
system(command)
|
||||||
|
end
|
||||||
|
end
|
|
@ -9,7 +9,7 @@ describe PostReceive do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "web hook" do
|
context "web hook" do
|
||||||
let(:project) { create(:project) }
|
let(:project) { create(:project_with_code) }
|
||||||
let(:key) { create(:key, user: project.owner) }
|
let(:key) { create(:key, user: project.owner) }
|
||||||
let(:key_id) { key.shell_id }
|
let(:key_id) { key.shell_id }
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue