Merge branch 'tsigo-routing_overhaul'

This commit is contained in:
Dmitriy Zaporozhets 2012-09-27 09:56:02 +03:00
commit 19c58becc0
107 changed files with 1753 additions and 655 deletions

View file

@ -57,7 +57,7 @@ gem "seed-fu"
# Markdown to HTML # Markdown to HTML
gem "redcarpet", "~> 2.1.1" gem "redcarpet", "~> 2.1.1"
gem "github-markup", "~> 0.7.4" gem "github-markup", "~> 0.7.4", require: 'github/markup'
# Servers # Servers
gem "thin" gem "thin"

View file

@ -53,7 +53,7 @@ ul.main_menu {
border-left: 0; border-left: 0;
} }
&.current { &.active {
background-color:#D5D5D5; background-color:#D5D5D5;
border-right: 1px solid #BBB; border-right: 1px solid #BBB;
border-left: 1px solid #BBB; border-left: 1px solid #BBB;

View file

@ -2,7 +2,6 @@ class ApplicationController < ActionController::Base
before_filter :authenticate_user! before_filter :authenticate_user!
before_filter :reject_blocked! before_filter :reject_blocked!
before_filter :set_current_user_for_mailer before_filter :set_current_user_for_mailer
before_filter :check_token_auth
before_filter :set_current_user_for_observers before_filter :set_current_user_for_observers
before_filter :dev_tools if Rails.env == 'development' before_filter :dev_tools if Rails.env == 'development'
@ -26,13 +25,6 @@ class ApplicationController < ActionController::Base
protected protected
def check_token_auth
# Redirect to login page if not atom feed
if params[:private_token].present? && params[:format] != 'atom'
redirect_to new_user_session_path
end
end
def reject_blocked! def reject_blocked!
if current_user && current_user.blocked if current_user && current_user.blocked
sign_out current_user sign_out current_user
@ -113,7 +105,7 @@ class ApplicationController < ActionController::Base
end end
def render_404 def render_404
render file: File.join(Rails.root, "public", "404"), layout: false, status: "404" render file: Rails.root.join("public", "404"), layout: false, status: "404"
end end
def require_non_empty_project def require_non_empty_project
@ -126,10 +118,6 @@ class ApplicationController < ActionController::Base
response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT" response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
end end
def render_full_content
@full_content = true
end
def dev_tools def dev_tools
Rack::MiniProfiler.authorize_request Rack::MiniProfiler.authorize_request
end end

View file

@ -0,0 +1,21 @@
# Controller for viewing a file's blame
class BlameController < ApplicationController
include ExtractsPath
layout "project"
before_filter :project
# Authorize
before_filter :add_project_abilities
before_filter :authorize_read_project!
before_filter :authorize_code_access!
before_filter :require_non_empty_project
before_filter :assign_ref_vars
def show
@repo = @project.repo
@blame = Grit::Blob.blame(@repo, @commit.id, @path)
end
end

View file

@ -0,0 +1,37 @@
# Controller for viewing a file's blame
class BlobController < ApplicationController
include ExtractsPath
include Gitlab::Encode
layout "project"
before_filter :project
# Authorize
before_filter :add_project_abilities
before_filter :authorize_read_project!
before_filter :authorize_code_access!
before_filter :require_non_empty_project
before_filter :assign_ref_vars
def show
if @tree.is_blob?
if @tree.text?
encoding = detect_encoding(@tree.data)
mime_type = encoding ? "text/plain; charset=#{encoding}" : "text/plain"
else
mime_type = @tree.mime_type
end
send_data(
@tree.data,
type: mime_type,
disposition: 'inline',
filename: @tree.name
)
else
not_found!
end
end
end

View file

@ -0,0 +1,36 @@
# Controller for a specific Commit
#
# Not to be confused with CommitsController, plural.
class CommitController < ApplicationController
before_filter :project
layout "project"
# Authorize
before_filter :add_project_abilities
before_filter :authorize_read_project!
before_filter :authorize_code_access!
before_filter :require_non_empty_project
def show
result = CommitLoad.new(project, current_user, params).execute
@commit = result[:commit]
git_not_found! unless @commit
@suppress_diff = result[:suppress_diff]
@note = result[:note]
@line_notes = result[:line_notes]
@notes_count = result[:notes_count]
@comments_allowed = true
respond_to do |format|
format.html do
if result[:status] == :huge_commit
render "huge_commit" and return
end
end
format.patch
end
end
end

View file

@ -4,19 +4,19 @@ class CommitsController < ApplicationController
before_filter :project before_filter :project
layout "project" layout "project"
include ExtractsPath
# Authorize # Authorize
before_filter :add_project_abilities before_filter :add_project_abilities
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_code_access! before_filter :authorize_code_access!
before_filter :require_non_empty_project before_filter :require_non_empty_project
before_filter :load_refs, only: :index # load @branch, @tag & @ref
before_filter :render_full_content
def index def show
@repo = project.repo @repo = @project.repo
@limit, @offset = (params[:limit] || 40), (params[:offset] || 0) @limit, @offset = (params[:limit] || 40), (params[:offset] || 0)
@commits = @project.commits(@ref, params[:path], @limit, @offset) @commits = @project.commits(@ref, @path, @limit, @offset)
@commits = CommitDecorator.decorate(@commits) @commits = CommitDecorator.decorate(@commits)
respond_to do |format| respond_to do |format|
@ -25,54 +25,4 @@ class CommitsController < ApplicationController
format.atom { render layout: false } format.atom { render layout: false }
end end
end end
def show
result = CommitLoad.new(project, current_user, params).execute
@commit = result[:commit]
if @commit
@suppress_diff = result[:suppress_diff]
@note = result[:note]
@line_notes = result[:line_notes]
@notes_count = result[:notes_count]
@comments_allowed = true
else
return git_not_found!
end
if result[:status] == :huge_commit
render "huge_commit" and return
end
end
def compare
result = Commit.compare(project, params[:from], params[:to])
@commits = result[:commits]
@commit = result[:commit]
@diffs = result[:diffs]
@refs_are_same = result[:same]
@line_notes = []
@commits = CommitDecorator.decorate(@commits)
end
def patch
@commit = project.commit(params[:id])
send_data(
@commit.to_patch,
type: "text/plain",
disposition: 'attachment',
filename: "#{@commit.id}.patch"
)
end
protected
def load_refs
@ref ||= params[:ref].presence || params[:branch].presence || params[:tag].presence
@ref ||= @ref || @project.try(:default_branch) || 'master'
end
end end

View file

@ -0,0 +1,29 @@
class CompareController < ApplicationController
before_filter :project
layout "project"
# Authorize
before_filter :add_project_abilities
before_filter :authorize_read_project!
before_filter :authorize_code_access!
before_filter :require_non_empty_project
def index
end
def show
result = Commit.compare(project, params[:from], params[:to])
@commits = result[:commits]
@commit = result[:commit]
@diffs = result[:diffs]
@refs_are_same = result[:same]
@line_notes = []
@commits = CommitDecorator.decorate(@commits)
end
def create
redirect_to project_compare_path(@project, params[:from], params[:to])
end
end

View file

@ -7,7 +7,6 @@ class ProtectedBranchesController < ApplicationController
before_filter :require_non_empty_project before_filter :require_non_empty_project
before_filter :authorize_admin_project!, only: [:destroy, :create] before_filter :authorize_admin_project!, only: [:destroy, :create]
before_filter :render_full_content
layout "project" layout "project"

View file

@ -1,5 +1,3 @@
require 'github/markup'
class RefsController < ApplicationController class RefsController < ApplicationController
include Gitlab::Encode include Gitlab::Encode
before_filter :project before_filter :project
@ -11,8 +9,7 @@ class RefsController < ApplicationController
before_filter :require_non_empty_project before_filter :require_non_empty_project
before_filter :ref before_filter :ref
before_filter :define_tree_vars, only: [:tree, :blob, :blame, :logs_tree] before_filter :define_tree_vars, only: [:blob, :logs_tree]
before_filter :render_full_content
layout "project" layout "project"
@ -20,9 +17,9 @@ class RefsController < ApplicationController
respond_to do |format| respond_to do |format|
format.html do format.html do
new_path = if params[:destination] == "tree" new_path = if params[:destination] == "tree"
tree_project_ref_path(@project, params[:ref]) project_tree_path(@project, @ref)
else else
project_commits_path(@project, ref: params[:ref]) project_commits_path(@project, @ref)
end end
redirect_to new_path redirect_to new_path
@ -35,19 +32,6 @@ class RefsController < ApplicationController
end end
end end
#
# Repository preview
#
def tree
respond_to do |format|
format.html
format.js do
# disable cache to allow back button works
no_cache_headers
end
end
end
def logs_tree def logs_tree
contents = @tree.contents contents = @tree.contents
@logs = contents.map do |content| @logs = contents.map do |content|
@ -61,30 +45,6 @@ class RefsController < ApplicationController
end end
end end
def blob
if @tree.is_blob?
if @tree.text?
encoding = detect_encoding(@tree.data)
mime_type = encoding ? "text/plain; charset=#{encoding}" : "text/plain"
else
mime_type = @tree.mime_type
end
send_data(
@tree.data,
type: mime_type,
disposition: 'inline',
filename: @tree.name
)
else
head(404)
end
end
def blame
@blame = Grit::Blob.blame(@repo, @commit.id, params[:path])
end
protected protected
def define_tree_vars def define_tree_vars
@ -95,13 +55,13 @@ class RefsController < ApplicationController
@commit = CommitDecorator.decorate(@commit) @commit = CommitDecorator.decorate(@commit)
@tree = Tree.new(@commit.tree, project, @ref, params[:path]) @tree = Tree.new(@commit.tree, project, @ref, params[:path])
@tree = TreeDecorator.new(@tree) @tree = TreeDecorator.new(@tree)
@hex_path = Digest::SHA1.hexdigest(params[:path] || "/") @hex_path = Digest::SHA1.hexdigest(params[:path] || "")
if params[:path] if params[:path]
@history_path = tree_file_project_ref_path(@project, @ref, params[:path]) @history_path = project_tree_path(@project, File.join(@ref, params[:path]))
@logs_path = logs_file_project_ref_path(@project, @ref, params[:path]) @logs_path = logs_file_project_ref_path(@project, @ref, params[:path])
else else
@history_path = tree_project_ref_path(@project, @ref) @history_path = project_tree_path(@project, @ref)
@logs_path = logs_tree_project_ref_path(@project, @ref) @logs_path = logs_tree_project_ref_path(@project, @ref)
end end
rescue rescue
@ -109,6 +69,6 @@ class RefsController < ApplicationController
end end
def ref def ref
@ref = params[:id] @ref = params[:id] || params[:ref]
end end
end end

View file

@ -6,7 +6,6 @@ class RepositoriesController < ApplicationController
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_code_access! before_filter :authorize_code_access!
before_filter :require_non_empty_project before_filter :require_non_empty_project
before_filter :render_full_content
layout "project" layout "project"
@ -15,11 +14,11 @@ class RepositoriesController < ApplicationController
end end
def branches def branches
@branches = @project.repo.heads.sort_by(&:name) @branches = @project.branches
end end
def tags def tags
@tags = @project.repo.tags.sort_by(&:name).reverse @tags = @project.tags
end end
def archive def archive

View file

@ -55,7 +55,6 @@ class SnippetsController < ApplicationController
def show def show
@note = @project.notes.new(noteable: @snippet) @note = @project.notes.new(noteable: @snippet)
render_full_content
end end
def destroy def destroy

View file

@ -0,0 +1,29 @@
# Controller for viewing a repository's file structure
class TreeController < ApplicationController
include ExtractsPath
layout "project"
before_filter :project
# Authorize
before_filter :add_project_abilities
before_filter :authorize_read_project!
before_filter :authorize_code_access!
before_filter :require_non_empty_project
before_filter :assign_ref_vars
def show
@hex_path = Digest::SHA1.hexdigest(@path)
@history_path = project_tree_path(@project, @id)
@logs_path = logs_file_project_ref_path(@project, @ref, @path)
respond_to do |format|
format.html
# Disable cache so browser history works
format.js { no_cache_headers }
end
end
end

View file

@ -21,7 +21,7 @@ class EventDecorator < ApplicationDecorator
elsif self.merge_request? elsif self.merge_request?
h.project_merge_request_url(self.project, self.merge_request) h.project_merge_request_url(self.project, self.merge_request)
elsif self.push? elsif self.push?
h.project_commits_url(self.project, ref: self.ref_name) h.project_commits_url(self.project, self.ref_name)
end end
end end
end end

View file

@ -15,22 +15,22 @@ class TreeDecorator < ApplicationDecorator
part_path = part if part_path.empty? part_path = part if part_path.empty?
next unless parts.last(2).include?(part) if parts.count > max_links next unless parts.last(2).include?(part) if parts.count > max_links
yield(h.link_to(h.truncate(part, length: 40), h.tree_file_project_ref_path(project, ref, path: part_path), remote: :true)) yield(h.link_to(h.truncate(part, length: 40), h.project_tree_path(project, h.tree_join(ref, part_path)), remote: :true))
end end
end end
end end
def up_dir? def up_dir?
!!path path.present?
end end
def up_dir_path def up_dir_path
file = File.join(path, "..") file = File.join(path, "..")
h.tree_file_project_ref_path(project, ref, file) h.project_tree_path(project, h.tree_join(ref, file))
end end
def history_path def history_path
h.project_commits_path(project, path: path, ref: ref) h.project_commits_path(project, h.tree_join(ref, path))
end end
def mb_size def mb_size

View file

@ -1,6 +1,35 @@
require 'digest/md5' require 'digest/md5'
module ApplicationHelper module ApplicationHelper
# Check if a particular controller is the current one
#
# args - One or more controller names to check
#
# Examples
#
# # On TreeController
# current_controller?(:tree) # => true
# current_controller?(:commits) # => false
# current_controller?(:commits, :tree) # => true
def current_controller?(*args)
args.any? { |v| v.to_s.downcase == controller.controller_name }
end
# Check if a partcular action is the current one
#
# args - One or more action names to check
#
# Examples
#
# # On Projects#new
# current_action?(:new) # => true
# current_action?(:create) # => false
# current_action?(:new, :create) # => true
def current_action?(*args)
args.any? { |v| v.to_s.downcase == action_name }
end
def gravatar_icon(user_email = '', size = 40) def gravatar_icon(user_email = '', size = 40)
if Gitlab.config.disable_gravatar? || user_email.blank? if Gitlab.config.disable_gravatar? || user_email.blank?
'no_avatar.png' 'no_avatar.png'
@ -31,8 +60,8 @@ module ApplicationHelper
def grouped_options_refs(destination = :tree) def grouped_options_refs(destination = :tree)
options = [ options = [
["Branch", @project.repo.heads.map(&:name) ], ["Branch", @project.branch_names ],
[ "Tag", @project.tags ] [ "Tag", @project.tag_names ]
] ]
# If reference is commit id - # If reference is commit id -
@ -58,11 +87,11 @@ module ApplicationHelper
if @project && !@project.new_record? if @project && !@project.new_record?
project_nav = [ project_nav = [
{ label: "#{@project.name} / Issues", url: project_issues_path(@project) }, { label: "#{@project.name} / Issues", url: project_issues_path(@project) },
{ label: "#{@project.name} / Wall", url: wall_project_path(@project) }, { label: "#{@project.name} / Wall", url: wall_project_path(@project) },
{ label: "#{@project.name} / Tree", url: tree_project_ref_path(@project, @project.root_ref) }, { label: "#{@project.name} / Tree", url: project_tree_path(@project, @ref || @project.root_ref) },
{ label: "#{@project.name} / Commits", url: project_commits_path(@project) }, { label: "#{@project.name} / Commits", url: project_commits_path(@project, @ref || @project.root_ref) },
{ label: "#{@project.name} / Team", url: project_team_index_path(@project) } { label: "#{@project.name} / Team", url: project_team_index_path(@project) }
] ]
end end
@ -85,45 +114,6 @@ module ApplicationHelper
event.project.merge_requests_enabled event.project.merge_requests_enabled
end end
def tab_class(tab_key)
active = case tab_key
# Project Area
when :wall; wall_tab?
when :wiki; controller.controller_name == "wikis"
when :issues; issues_tab?
when :network; current_page?(controller: "projects", action: "graph", id: @project)
when :merge_requests; controller.controller_name == "merge_requests"
# Dashboard Area
when :help; controller.controller_name == "help"
when :search; current_page?(search_path)
when :dash_issues; current_page?(dashboard_issues_path)
when :dash_mr; current_page?(dashboard_merge_requests_path)
when :root; current_page?(dashboard_path) || current_page?(root_path)
# Profile Area
when :profile; current_page?(controller: "profile", action: :show)
when :history; current_page?(controller: "profile", action: :history)
when :account; current_page?(controller: "profile", action: :account)
when :token; current_page?(controller: "profile", action: :token)
when :design; current_page?(controller: "profile", action: :design)
when :ssh_keys; controller.controller_name == "keys"
# Admin Area
when :admin_root; controller.controller_name == "dashboard"
when :admin_users; controller.controller_name == 'users'
when :admin_projects; controller.controller_name == "projects"
when :admin_hooks; controller.controller_name == 'hooks'
when :admin_resque; controller.controller_name == 'resque'
when :admin_logs; controller.controller_name == 'logs'
else
false
end
active ? "current" : nil
end
def hexdigest(string) def hexdigest(string)
Digest::SHA1.hexdigest string Digest::SHA1.hexdigest string
end end

View file

@ -1,35 +1,85 @@
module TabHelper module TabHelper
def issues_tab? # Navigation link helper
controller.controller_name == "issues" || controller.controller_name == "milestones" #
end # Returns an `li` element with an 'active' class if the supplied
# controller(s) and/or action(s) currently active. The contents of the
# element is the value passed to the block.
#
# options - The options hash used to determine if the element is "active" (default: {})
# :controller - One or more controller names to check (optional).
# :action - One or more action names to check (optional).
# :path - A shorthand path, such as 'dashboard#index', to check (optional).
# :html_options - Extra options to be passed to the list element (optional).
# block - An optional block that will become the contents of the returned
# `li` element.
#
# When both :controller and :action are specified, BOTH must match in order
# to be marked as active. When only one is given, either can match.
#
# Examples
#
# # Assuming we're on TreeController#show
#
# # Controller matches, but action doesn't
# nav_link(controller: [:tree, :refs], action: :edit) { "Hello" }
# # => '<li>Hello</li>'
#
# # Controller matches
# nav_link(controller: [:tree, :refs]) { "Hello" }
# # => '<li class="active">Hello</li>'
#
# # Shorthand path
# nav_link(path: 'tree#show') { "Hello" }
# # => '<li class="active">Hello</li>'
#
# # Supplying custom options for the list element
# nav_link(controller: :tree, html_options: {class: 'home'}) { "Hello" }
# # => '<li class="home active">Hello</li>'
#
# Returns a list item element String
def nav_link(options = {}, &block)
if path = options.delete(:path)
c, a, _ = path.split('#')
else
c = options.delete(:controller)
a = options.delete(:action)
end
def wall_tab? if c && a
current_page?(controller: "projects", action: "wall", id: @project) # When given both options, make sure BOTH are active
klass = current_controller?(*c) && current_action?(*a) ? 'active' : ''
else
# Otherwise check EITHER option
klass = current_controller?(*c) || current_action?(*a) ? 'active' : ''
end
# Add our custom class into the html_options, which may or may not exist
# and which may or may not already have a :class key
o = options.delete(:html_options) || {}
o[:class] ||= ''
o[:class] += ' ' + klass
o[:class].strip!
if block_given?
content_tag(:li, capture(&block), o)
else
content_tag(:li, nil, o)
end
end end
def project_tab_class def project_tab_class
[:show, :files, :edit, :update].each do |action| [:show, :files, :edit, :update].each do |action|
return "current" if current_page?(controller: "projects", action: action, id: @project) return "active" if current_page?(controller: "projects", action: action, id: @project)
end end
if ['snippets', 'hooks', 'deploy_keys', 'team_members'].include? controller.controller_name if ['snippets', 'hooks', 'deploy_keys', 'team_members'].include? controller.controller_name
"current" "active"
end
end
def tree_tab_class
controller.controller_name == "refs" ? "current" : nil
end
def commit_tab_class
if ['commits', 'repositories', 'protected_branches'].include? controller.controller_name
"current"
end end
end end
def branches_tab_class def branches_tab_class
if current_page?(branches_project_repository_path(@project)) || if current_page?(branches_project_repository_path(@project)) ||
controller.controller_name == "protected_branches" || current_controller?(:protected_branches) ||
current_page?(project_repository_path(@project)) current_page?(project_repository_path(@project))
'active' 'active'
end end

View file

@ -39,4 +39,9 @@ module TreeHelper
def gitlab_markdown?(filename) def gitlab_markdown?(filename)
filename.end_with?(*%w(.mdown .md .markdown)) filename.end_with?(*%w(.mdown .md .markdown))
end end
# Simple shortcut to File.join
def tree_join(*args)
File.join(*args)
end
end end

View file

@ -1,4 +1,4 @@
require File.join(Rails.root, "app/models/commit") require Rails.root.join("app/models/commit")
class MergeRequest < ActiveRecord::Base class MergeRequest < ActiveRecord::Base
include IssueCommonality include IssueCommonality

View file

@ -1,5 +1,5 @@
class Tree class Tree
include Linguist::BlobHelper include Linguist::BlobHelper
attr_accessor :path, :tree, :project, :ref attr_accessor :path, :tree, :project, :ref
delegate :contents, delegate :contents,
@ -14,8 +14,8 @@ class Tree
to: :tree to: :tree
def initialize(raw_tree, project, ref = nil, path = nil) def initialize(raw_tree, project, ref = nil, path = nil)
@project, @ref, @path = project, ref, path, @project, @ref, @path = project, ref, path
@tree = if path @tree = if path.present?
raw_tree / path.dup.force_encoding('ascii-8bit') raw_tree / path.dup.force_encoding('ascii-8bit')
else else
raw_tree raw_tree
@ -26,6 +26,10 @@ class Tree
tree.is_a?(Grit::Blob) tree.is_a?(Grit::Blob)
end end
def invalid?
tree.nil?
end
def empty? def empty?
data.blank? data.blank?
end end

View file

@ -45,8 +45,29 @@ module Repository
File.exists?(hook_file) File.exists?(hook_file)
end end
# Returns an Array of branch names
def branch_names
repo.branches.collect(&:name).sort
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 def tags
repo.tags.map(&:name).sort.reverse repo.tags.sort_by(&:name).reverse
end
# Returns an Array of branch and tag names
def ref_names
[branch_names + tag_names].flatten
end end
def repo def repo
@ -79,14 +100,6 @@ module Repository
@heads ||= repo.heads @heads ||= repo.heads
end end
def branches_names
heads.map(&:name)
end
def ref_names
[branches_names + tags].flatten
end
def tree(fcommit, path = nil) def tree(fcommit, path = nil)
fcommit = commit if fcommit == :head fcommit = commit if fcommit == :head
tree = fcommit.tree tree = fcommit.tree
@ -109,14 +122,12 @@ module Repository
# - If two or more branches are present, returns the one that has a 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) # matching root_ref (default_branch or 'master' if default_branch is nil)
def discover_default_branch def discover_default_branch
branches = heads.collect(&:name) if branch_names.length == 0
if branches.length == 0
nil nil
elsif branches.length == 1 elsif branch_names.length == 1
branches.first branch_names.first
else else
branches.select { |v| v == root_ref }.first branch_names.select { |v| v == root_ref }.first
end end
end end
@ -144,7 +155,7 @@ module Repository
# Build file path # Build file path
file_name = self.code + "-" + commit.id.to_s + ".tar.gz" file_name = self.code + "-" + commit.id.to_s + ".tar.gz"
storage_path = File.join(Rails.root, "tmp", "repositories", self.code) storage_path = Rails.root.join("tmp", "repositories", self.code)
file_path = File.join(storage_path, file_name) file_path = File.join(storage_path, file_name)
# Put files into a directory before archiving # Put files into a directory before archiving

View file

@ -25,6 +25,10 @@ module StaticModel
id id
end end
def new_record?
false
end
def persisted? def persisted?
false false
end end

View file

@ -1,9 +1,8 @@
%ul.nav.nav-tabs %ul.nav.nav-tabs
%li %li
= render partial: 'shared/ref_switcher', locals: {destination: 'tree', path: params[:path]} = render partial: 'shared/ref_switcher', locals: {destination: 'tree', path: params[:path]}
%li{class: "#{'active' if (controller.controller_name == "refs") }"} = nav_link(controller: :refs) do
= link_to tree_project_ref_path(@project, @ref) do = link_to 'Source', project_tree_path(@project, @ref)
Source
%li.right %li.right
.input-prepend.project_clone_holder .input-prepend.project_clone_holder
%button{class: "btn small active", :"data-clone" => @project.ssh_url_to_repo} SSH %button{class: "btn small active", :"data-clone" => @project.ssh_url_to_repo} SSH

View file

@ -4,7 +4,7 @@
%ul.breadcrumb %ul.breadcrumb
%li %li
%span.arrow %span.arrow
= link_to tree_project_ref_path(@project, @ref, path: nil) do = link_to project_tree_path(@project, @ref) do
= @project.name = @project.name
- @tree.breadcrumbs(6) do |link| - @tree.breadcrumbs(6) do |link|
\/ \/
@ -18,9 +18,9 @@
= @tree.name = @tree.name
%small blame %small blame
%span.options %span.options
= link_to "raw", blob_project_ref_path(@project, @ref, path: params[:path]), class: "btn very_small", target: "_blank" = link_to "raw", project_blob_path(@project, @id), class: "btn very_small", target: "_blank"
= link_to "history", project_commits_path(@project, path: params[:path], ref: @ref), class: "btn very_small" = link_to "history", project_commits_path(@project, @id), class: "btn very_small"
= link_to "source", tree_file_project_ref_path(@project, @ref, path: params[:path]), class: "btn very_small" = link_to "source", project_tree_path(@project, @id), class: "btn very_small"
.file_content.blame .file_content.blame
%table %table
- @blame.each do |commit, lines| - @blame.each do |commit, lines|
@ -32,8 +32,8 @@
= commit.author_name = commit.author_name
%td.blame_commit %td.blame_commit
&nbsp; &nbsp;
%code= link_to commit.short_id, project_commit_path(@project, id: commit.id) %code= link_to commit.short_id, project_commit_path(@project, commit)
= link_to_gfm truncate(commit.title, length: 30), project_commit_path(@project, id: commit.id), class: "row_title" rescue "--broken encoding" = link_to_gfm truncate(commit.title, length: 30), project_commit_path(@project, commit), class: "row_title" rescue "--broken encoding"
%td.lines %td.lines
= preserve do = preserve do
%pre %pre

View file

@ -0,0 +1,10 @@
= render "commits/commit_box"
= render "commits/diffs", diffs: @commit.diffs
= render "notes/notes_with_form", tid: @commit.id, tt: "commit"
= render "notes/per_line_form"
:javascript
$(function(){
PerLineNotes.init();
});

View file

@ -0,0 +1 @@
<%= @commit.to_patch %>

View file

@ -1,16 +1,15 @@
%li.commit %li.commit
.browse_code_link_holder .browse_code_link_holder
%p %p
%strong= link_to "Browse Code »", tree_project_ref_path(@project, commit.id), 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, id: commit.id), class: "commit_short_id" = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id"
%strong.commit-author-name= commit.author_name %strong.commit-author-name= commit.author_name
%span.dash &ndash; %span.dash &ndash;
= image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16 = image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16
= link_to_gfm truncate(commit.title, length: 50), project_commit_path(@project, id: commit.id), class: "row_title" = link_to_gfm truncate(commit.title, length: 50), project_commit_path(@project, commit.id), class: "row_title"
%span.committed_ago %span.committed_ago
= time_ago_in_words(commit.committed_date) = time_ago_in_words(commit.committed_date)
ago ago
&nbsp; &nbsp;

View file

@ -5,10 +5,10 @@
%span.btn.disabled.grouped %span.btn.disabled.grouped
%i.icon-comment %i.icon-comment
= @notes_count = @notes_count
= link_to patch_project_commit_path(@project, @commit.id), class: "btn small grouped" do = link_to project_commit_path(@project, @commit, format: :patch), class: "btn small grouped" do
%i.icon-download-alt %i.icon-download-alt
Get Patch Get Patch
= link_to tree_project_ref_path(@project, @commit.id), class: "browse-button primary grouped" do = link_to project_tree_path(@project, @commit), class: "browse-button primary grouped" do
%strong Browse Code » %strong Browse Code »
%h3.commit-title.page_title %h3.commit-title.page_title
= gfm escape_once(@commit.title) = gfm escape_once(@commit.title)

View file

@ -5,7 +5,7 @@
%p To prevent performance issue we rejected diff information. %p To prevent performance issue we rejected diff information.
%p %p
But if you still want to see diff But if you still want to see diff
= link_to "click this link", project_commit_path(@project, @commit.id, force_show_diff: true), class: "dark" = link_to "click this link", project_commit_path(@project, @commit, force_show_diff: true), class: "dark"
%p.cgray %p.cgray
Showing #{pluralize(diffs.count, "changed file")} Showing #{pluralize(diffs.count, "changed file")}
@ -24,7 +24,7 @@
%i.icon-file %i.icon-file
%span{id: "#{diff.old_path}"}= diff.old_path %span{id: "#{diff.old_path}"}= diff.old_path
- else - else
= link_to tree_file_project_ref_path(@project, @commit.id, diff.new_path) do = link_to project_tree_path(@project, tree_join(@commit.id, diff.new_path)) do
%i.icon-file %i.icon-file
%span{id: "#{diff.new_path}"}= diff.new_path %span{id: "#{diff.new_path}"}= diff.new_path
%br/ %br/

View file

@ -1,23 +1,23 @@
%ul.nav.nav-tabs %ul.nav.nav-tabs
%li= render partial: 'shared/ref_switcher', locals: {destination: 'commits'} %li= render partial: 'shared/ref_switcher', locals: {destination: 'commits'}
%li{class: "#{'active' if current_page?(project_commits_path(@project)) }"}
= link_to project_commits_path(@project) do = nav_link(controller: [:commit, :commits]) do
Commits = link_to 'Commits', project_commits_path(@project, @project.root_ref)
%li{class: "#{'active' if current_page?(compare_project_commits_path(@project)) }"} = nav_link(controller: :compare) do
= link_to compare_project_commits_path(@project) do = link_to 'Compare', project_compare_index_path(@project)
Compare
%li{class: "#{branches_tab_class}"} = nav_link(html_options: {class: branches_tab_class}) do
= link_to project_repository_path(@project) do = link_to project_repository_path(@project) do
Branches Branches
%span.badge= @project.repo.branch_count %span.badge= @project.repo.branch_count
%li{class: "#{'active' if current_page?(tags_project_repository_path(@project)) }"} = nav_link(controller: :repositories, action: :tags) do
= link_to tags_project_repository_path(@project) do = link_to tags_project_repository_path(@project) do
Tags Tags
%span.badge= @project.repo.tag_count %span.badge= @project.repo.tag_count
- if current_page?(project_commits_path(@project)) && current_user.private_token - if current_controller?(:commits) && current_user.private_token
%li.right %li.right
%span.rss-icon %span.rss-icon
= link_to project_commits_path(@project, :atom, { private_token: current_user.private_token, ref: @ref }), title: "Feed" do = link_to project_commits_path(@project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Feed" do
= image_tag "rss_ui.png", title: "feed" = image_tag "rss_ui.png", title: "feed"

View file

@ -1,24 +0,0 @@
= render "head"
- if params[:path]
%ul.breadcrumb
%li
%span.arrow
= link_to project_commits_path(@project) do
= @project.name
%span.divider
\/
%li
%a{href: "#"}= params[:path].split("/").join(" / ")
%div{id: dom_id(@project)}
#commits_list= render "commits"
.clear
.loading{ style: "display:none;"}
- if @commits.count == @limit
:javascript
$(function(){
CommitsList.init("#{@ref}", #{@limit});
});

View file

@ -1,8 +1,8 @@
xml.instruct! xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "Recent commits to #{@project.name}:#{@ref}" xml.title "Recent commits to #{@project.name}:#{@ref}"
xml.link :href => project_commits_url(@project, :atom, :ref => @ref), :rel => "self", :type => "application/atom+xml" xml.link :href => project_commits_url(@project, @ref, format: :atom), :rel => "self", :type => "application/atom+xml"
xml.link :href => project_commits_url(@project), :rel => "alternate", :type => "text/html" xml.link :href => project_commits_url(@project, @ref), :rel => "alternate", :type => "text/html"
xml.id project_commits_url(@project) xml.id project_commits_url(@project)
xml.updated @commits.first.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ") if @commits.any? xml.updated @commits.first.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ") if @commits.any?

View file

@ -1,10 +1,24 @@
= render "commits/commit_box" = render "head"
= render "commits/diffs", diffs: @commit.diffs
= render "notes/notes_with_form", tid: @commit.id, tt: "commit"
= render "notes/per_line_form"
- if @path
%ul.breadcrumb
%li
%span.arrow
= link_to project_commits_path(@project) do
= @project.name
%span.divider
\/
%li
%a{href: "#"}= @path.split("/").join(" / ")
%div{id: dom_id(@project)}
#commits_list= render "commits"
.clear
.loading{ style: "display:none;"}
- if @commits.count == @limit
:javascript
$(function(){
CommitsList.init("#{@ref}", #{@limit});
});
:javascript
$(function(){
PerLineNotes.init();
});

View file

@ -1,9 +1,3 @@
= render "head"
%h3.page_title
Compare View
%hr
%div %div
%p.slead %p.slead
Fill input field with commit id like Fill input field with commit id like
@ -14,7 +8,7 @@
%br %br
= form_tag compare_project_commits_path(@project), method: :get do = form_tag project_compare_index_path(@project), method: :post do
.clearfix .clearfix
= text_field_tag :from, params[:from], placeholder: "master", class: "xlarge" = text_field_tag :from, params[:from], placeholder: "master", class: "xlarge"
= "..." = "..."
@ -25,29 +19,14 @@
.actions .actions
= submit_tag "Compare", class: "btn primary wide commits-compare-btn" = submit_tag "Compare", class: "btn primary wide commits-compare-btn"
- if @commits.present?
%div.ui-box
%h5.small Commits (#{@commits.count})
%ul.unstyled= render @commits
- unless @diffs.empty?
%h4 Diff
= render "commits/diffs", diffs: @diffs
:javascript :javascript
$(function() { $(function() {
var availableTags = #{@project.ref_names.to_json}; var availableTags = #{@project.ref_names.to_json};
$("#from").autocomplete({ $("#from, #to").autocomplete({
source: availableTags,
minLength: 1
});
$("#to").autocomplete({
source: availableTags, source: availableTags,
minLength: 1 minLength: 1
}); });
disableButtonIfEmptyField('#to', '.commits-compare-btn'); disableButtonIfEmptyField('#to', '.commits-compare-btn');
}); });

View file

@ -0,0 +1,7 @@
= render "commits/head"
%h3.page_title
Compare View
%hr
= render "form"

View file

@ -0,0 +1,16 @@
= render "commits/head"
%h3.page_title
Compare View
%hr
= render "form"
- if @commits.present?
%div.ui-box
%h5.small Commits (#{@commits.count})
%ul.unstyled= render @commits
- unless @diffs.empty?
%h4 Diff
= render "commits/diffs", diffs: @diffs

View file

@ -1,7 +1,7 @@
- commit = CommitDecorator.decorate(commit) - commit = CommitDecorator.decorate(commit)
%li.commit %li.commit
%p %p
= link_to commit.short_id(8), project_commit_path(project, id: commit.id), class: "commit_short_id" = link_to commit.short_id(8), project_commit_path(project, commit), class: "commit_short_id"
%span= commit.author_name %span= commit.author_name
&ndash; &ndash;
= image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16 = image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16

View file

@ -4,7 +4,7 @@
= image_tag gravatar_icon(event.author_email), class: "avatar" = image_tag gravatar_icon(event.author_email), class: "avatar"
%span You pushed to %span You pushed to
= event.ref_type = event.ref_type
= link_to project_commits_path(event.project, ref: event.ref_name) do = link_to project_commits_path(event.project, event.ref_name) do
%strong= truncate(event.ref_name, length: 28) %strong= truncate(event.ref_name, length: 28)
at at
%strong= link_to event.project.name, event.project %strong= link_to event.project.name, event.project

View file

@ -5,7 +5,7 @@
.event-title .event-title
%strong.author_name #{event.author_name} %strong.author_name #{event.author_name}
%span.event_label.pushed #{event.push_action_name} #{event.ref_type} %span.event_label.pushed #{event.push_action_name} #{event.ref_type}
= link_to project_commits_path(event.project, ref: event.ref_name) do = link_to project_commits_path(event.project, event.ref_name) do
%strong= event.ref_name %strong= event.ref_name
at at
%strong= link_to event.project.name, event.project %strong= link_to event.project.name, event.project
@ -21,6 +21,6 @@
%li.commits-stat %li.commits-stat
- if event.commits_count > 2 - if event.commits_count > 2
%span ... and #{event.commits_count - 2} more commits. %span ... and #{event.commits_count - 2} more commits.
= link_to compare_project_commits_path(event.project, from: event.parent_commit.id, to: event.last_commit.id) do = link_to project_compare_path(event.project, from: event.parent_commit.id, to: event.last_commit.id) do
%strong Compare &rarr; #{event.parent_commit.id[0..7]}...#{event.last_commit.id[0..7]} %strong Compare &rarr; #{event.parent_commit.id[0..7]}...#{event.last_commit.id[0..7]}
.clearfix .clearfix

View file

@ -1,13 +1,10 @@
%ul.nav.nav-tabs %ul.nav.nav-tabs
%li{class: "#{'active' if current_page?(project_issues_path(@project))}"} = nav_link(controller: :issues) do
= link_to project_issues_path(@project), class: "tab" do = link_to 'Browse Issues', project_issues_path(@project), class: "tab"
Browse Issues = nav_link(controller: :milestones) do
%li{class: "#{'active' if current_page?(project_milestones_path(@project))}"} = link_to 'Milestones', project_milestones_path(@project), class: "tab"
= link_to project_milestones_path(@project), class: "tab" do = nav_link(controller: :labels) do
Milestones = link_to 'Labels', project_labels_path(@project), class: "tab"
%li{class: "#{'active' if current_page?(project_labels_path(@project))}"}
= link_to project_labels_path(@project), class: "tab" do
Labels
%li.right %li.right
%span.rss-icon %span.rss-icon
= link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do = link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do

View file

@ -1,19 +0,0 @@
%ul.main_menu
%li.home{class: tab_class(:root)}
= link_to "Home", root_path, title: "Home"
%li{class: tab_class(:dash_issues)}
= link_to dashboard_issues_path do
Issues
%span.count= current_user.assigned_issues.opened.count
%li{class: tab_class(:dash_mr)}
= link_to dashboard_merge_requests_path do
Merge Requests
%span.count= current_user.cared_merge_requests.count
%li{class: tab_class(:search)}
= link_to "Search", search_path
%li{class: tab_class(:help)}
= link_to "Help", help_path

View file

@ -10,8 +10,8 @@
- if controller_name == 'projects' && action_name == 'index' - if controller_name == 'projects' && action_name == 'index'
= auto_discovery_link_tag :atom, projects_url(:atom, private_token: current_user.private_token), title: "Dashboard feed" = auto_discovery_link_tag :atom, projects_url(:atom, private_token: current_user.private_token), title: "Dashboard feed"
- if @project && !@project.new_record? - if @project && !@project.new_record?
- if current_page?(tree_project_ref_path(@project, @project.root_ref)) || current_page?(project_commits_path(@project)) - if current_controller?(:tree, :commits)
= auto_discovery_link_tag(:atom, project_commits_url(@project, :atom, ref: @ref, private_token: current_user.private_token), title: "Recent commits to #{@project.name}:#{@ref}") = auto_discovery_link_tag(:atom, project_commits_url(@project, @ref, format: :atom, private_token: current_user.private_token), title: "Recent commits to #{@project.name}:#{@ref}")
- if request.path == project_issues_path(@project) - if current_controller?(:issues)
= auto_discovery_link_tag(:atom, project_issues_url(@project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues") = auto_discovery_link_tag(:atom, project_issues_url(@project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues")
= csrf_meta_tags = csrf_meta_tags

View file

@ -1,37 +0,0 @@
%ul.main_menu
%li.home{class: project_tab_class}
= link_to @project.code, project_path(@project), title: "Project"
- if @project.repo_exists?
- if can? current_user, :download_code, @project
%li{class: tree_tab_class}
= link_to tree_project_ref_path(@project, @project.root_ref) do
Files
%li{class: commit_tab_class}
= link_to "Commits", project_commits_path(@project)
%li{class: tab_class(:network)}
= link_to "Network", graph_project_path(@project)
- if @project.issues_enabled
%li{class: tab_class(:issues)}
= link_to project_issues_filter_path(@project) do
Issues
%span.count.issue_counter= @project.issues.opened.count
- if @project.repo_exists?
- if @project.merge_requests_enabled
%li{class: tab_class(:merge_requests)}
= link_to project_merge_requests_path(@project) do
Merge Requests
%span.count.merge_counter= @project.merge_requests.opened.count
- if @project.wall_enabled
%li{class: tab_class(:wall)}
= link_to wall_project_path(@project) do
Wall
- if @project.wiki_enabled
%li{class: tab_class(:wiki)}
= link_to project_wiki_path(@project, :index) do
Wiki

View file

@ -6,17 +6,17 @@
= render "layouts/head_panel", title: "Admin area" = render "layouts/head_panel", title: "Admin area"
.container .container
%ul.main_menu %ul.main_menu
%li.home{class: tab_class(:admin_root)} = nav_link(controller: :dashboard, html_options: {class: 'home'}) do
= link_to "Stats", admin_root_path = link_to "Stats", admin_root_path
%li{class: tab_class(:admin_projects)} = nav_link(controller: :projects) do
= link_to "Projects", admin_projects_path = link_to "Projects", admin_projects_path
%li{class: tab_class(:admin_users)} = nav_link(controller: :users) do
= link_to "Users", admin_users_path = link_to "Users", admin_users_path
%li{class: tab_class(:admin_logs)} = nav_link(controller: :logs) do
= link_to "Logs", admin_logs_path = link_to "Logs", admin_logs_path
%li{class: tab_class(:admin_hooks)} = nav_link(controller: :hooks) do
= link_to "Hooks", admin_hooks_path = link_to "Hooks", admin_hooks_path
%li{class: tab_class(:admin_resque)} = nav_link(controller: :resque) do
= link_to "Resque", admin_resque_path = link_to "Resque", admin_resque_path
.content= yield .content= yield

View file

@ -5,6 +5,20 @@
= render "layouts/flash" = render "layouts/flash"
= render "layouts/head_panel", title: "Dashboard" = render "layouts/head_panel", title: "Dashboard"
.container .container
= render partial: "layouts/app_menu" %ul.main_menu
.content = nav_link(path: 'dashboard#index', html_options: {class: 'home'}) do
= yield = link_to "Home", root_path, title: "Home"
= nav_link(path: 'dashboard#issues') do
= link_to dashboard_issues_path do
Issues
%span.count= current_user.assigned_issues.opened.count
= nav_link(path: 'dashboard#merge_requests') do
= link_to dashboard_merge_requests_path do
Merge Requests
%span.count= current_user.cared_merge_requests.count
= nav_link(path: 'search#show') do
= link_to "Search", search_path
= nav_link(path: 'help#index') do
= link_to "Help", help_path
.content= yield

View file

@ -6,23 +6,17 @@
= render "layouts/head_panel", title: "Profile" = render "layouts/head_panel", title: "Profile"
.container .container
%ul.main_menu %ul.main_menu
%li.home{class: tab_class(:profile)} = nav_link(path: 'profile#show', html_options: {class: 'home'}) do
= link_to "Profile", profile_path = link_to "Profile", profile_path
= nav_link(path: 'profile#account') do
%li{class: tab_class(:account)}
= link_to "Account", profile_account_path = link_to "Account", profile_account_path
= nav_link(controller: :keys) do
%li{class: tab_class(:ssh_keys)}
= link_to keys_path do = link_to keys_path do
SSH Keys SSH Keys
%span.count= current_user.keys.count %span.count= current_user.keys.count
= nav_link(path: 'profile#design') do
%li{class: tab_class(:design)}
= link_to "Design", profile_design_path = link_to "Design", profile_design_path
= nav_link(path: 'profile#history') do
%li{class: tab_class(:history)}
= link_to "History", profile_history_path = link_to "History", profile_history_path
.content= yield
.content
= yield

View file

@ -5,7 +5,37 @@
= render "layouts/flash" = render "layouts/flash"
= render "layouts/head_panel", title: @project.name = render "layouts/head_panel", title: @project.name
.container .container
= render partial: "layouts/project_menu" %ul.main_menu
.content = nav_link(html_options: {class: "home #{project_tab_class}"}) do
= yield = link_to @project.code, project_path(@project), title: "Project"
- if @project.repo_exists?
- if can? current_user, :download_code, @project
= nav_link(controller: %w(tree blob blame)) do
= link_to 'Files', project_tree_path(@project, @ref || @project.root_ref)
= nav_link(controller: %w(commit commits compare repositories protected_branches)) do
= link_to "Commits", project_commits_path(@project, @ref || @project.root_ref)
= nav_link(path: 'projects#graph') do
= link_to "Network", graph_project_path(@project)
- if @project.issues_enabled
= nav_link(controller: %w(issues milestones labels)) do
= link_to project_issues_filter_path(@project) do
Issues
%span.count.issue_counter= @project.issues.opened.count
- if @project.repo_exists? && @project.merge_requests_enabled
= nav_link(controller: :merge_requests) do
= link_to project_merge_requests_path(@project) do
Merge Requests
%span.count.merge_counter= @project.merge_requests.opened.count
- if @project.wall_enabled
= nav_link(path: 'projects#wall') do
= link_to 'Wall', wall_project_path(@project)
- if @project.wiki_enabled
= nav_link(controller: :wikis) do
= link_to 'Wiki', project_wiki_path(@project, :index)
.content= yield

View file

@ -1,29 +1,27 @@
%ul.nav.nav-tabs %ul.nav.nav-tabs
%li{ class: "#{'active' if current_page?(project_path(@project)) }" } = nav_link(path: 'projects#show') do
= link_to project_path(@project), class: "activities-tab tab" do = link_to project_path(@project), class: "activities-tab tab" do
%i.icon-home %i.icon-home
Show Show
%li{ class: " #{'active' if (controller.controller_name == "team_members") || current_page?(project_team_index_path(@project)) }" } = nav_link(controller: :team_members) do
= link_to project_team_index_path(@project), class: "team-tab tab" do = link_to project_team_index_path(@project), class: "team-tab tab" do
%i.icon-user %i.icon-user
Team Team
%li{ class: "#{'active' if current_page?(files_project_path(@project)) }" } = nav_link(path: 'projects#files') do
= link_to files_project_path(@project), class: "files-tab tab " do = link_to 'Attachments', files_project_path(@project), class: "files-tab tab"
Attachments = nav_link(controller: :snippets) do
%li{ class: " #{'active' if (controller.controller_name == "snippets") }" } = link_to 'Snippets', project_snippets_path(@project), class: "snippets-tab tab"
= link_to project_snippets_path(@project), class: "snippets-tab tab" do
Snippets
- if can? current_user, :admin_project, @project - if can? current_user, :admin_project, @project
%li.right{class: "#{'active' if controller.controller_name == "deploy_keys"}"} = nav_link(controller: :deploy_keys, html_options: {class: 'right'}) do
= link_to project_deploy_keys_path(@project) do = link_to project_deploy_keys_path(@project) do
%span %span
Deploy Keys Deploy Keys
%li.right{class: "#{'active' if controller.controller_name == "hooks" }"} = nav_link(controller: :hooks, html_options: {class: 'right'}) do
= link_to project_hooks_path(@project) do = link_to project_hooks_path(@project) do
%span %span
Hooks Hooks
%li.right{ class: "#{'active' if current_page?(edit_project_path(@project)) }" } = nav_link(path: 'projects#edit', html_options: {class: 'right'}) do
= link_to edit_project_path(@project), class: "stat-tab tab " do = link_to edit_project_path(@project), class: "stat-tab tab " do
%i.icon-edit %i.icon-edit
Edit Edit

View file

@ -34,7 +34,7 @@
- @branches.each do |branch| - @branches.each do |branch|
%tr %tr
%td %td
= link_to project_commits_path(@project, ref: branch.name) do = link_to project_commits_path(@project, branch.name) do
%strong= branch.name %strong= branch.name
- if branch.name == @project.root_ref - if branch.name == @project.root_ref
%span.label default %span.label default

View file

@ -6,4 +6,4 @@
:plain :plain
var row = $("table.table_#{@hex_path} tr.file_#{hexdigest(file_name)}"); var row = $("table.table_#{@hex_path} tr.file_#{hexdigest(file_name)}");
row.find("td.tree_time_ago").html('#{escape_javascript(time_ago_in_words(content_commit.committed_date))} ago'); row.find("td.tree_time_ago").html('#{escape_javascript(time_ago_in_words(content_commit.committed_date))} ago');
row.find("td.tree_commit").html('#{escape_javascript(render("tree_commit", tm: tm, content_commit: content_commit))}'); row.find("td.tree_commit").html('#{escape_javascript(render("tree/tree_commit", tm: tm, content_commit: content_commit))}');

View file

@ -1,7 +0,0 @@
= render "head"
#tree-holder= render partial: "tree", locals: {repo: @repo, commit: @commit, tree: @tree}
:javascript
$(function() {
Tree.init();
});

View file

@ -2,12 +2,12 @@
- commit = CommitDecorator.decorate(commit) - commit = CommitDecorator.decorate(commit)
%tr %tr
%td %td
= link_to project_commits_path(@project, ref: branch.name) do = link_to project_commits_path(@project, branch.name) do
%strong= truncate(branch.name, length: 60) %strong= truncate(branch.name, length: 60)
- if branch.name == @project.root_ref - if branch.name == @project.root_ref
%span.label default %span.label default
%td %td
= link_to project_commit_path(@project, id: commit.id) do = link_to project_commit_path(@project, commit) do
%code= commit.short_id %code= commit.short_id
= image_tag gravatar_icon(commit.author_email), class: "", width: 16 = image_tag gravatar_icon(commit.author_email), class: "", width: 16

View file

@ -1,11 +1,8 @@
= render "commits/head" = render "commits/head"
%ul.nav.nav-pills %ul.nav.nav-pills
%li{class: ("active" if current_page?(project_repository_path(@project)))} = nav_link(path: 'repositories#show') do
= link_to project_repository_path(@project) do = link_to 'Recent', project_repository_path(@project)
Recent = nav_link(path: 'protected_branches#index') do
%li{class: ("active" if current_page?(project_protected_branches_path(@project)))} = link_to 'Protected', project_protected_branches_path(@project)
= link_to project_protected_branches_path(@project) do = nav_link(path: 'repositories#branches') do
Protected = link_to 'All', branches_project_repository_path(@project)
%li{class: ("active" if current_page?(branches_project_repository_path(@project)))}
= link_to branches_project_repository_path(@project) do
All

View file

@ -2,7 +2,7 @@
- commit = CommitDecorator.new(commit) - commit = CommitDecorator.new(commit)
%tr %tr
%td %td
= link_to project_commits_path(@project, ref: commit.head.name) do = link_to project_commits_path(@project, commit.head.name) do
%strong %strong
= commit.head.name = commit.head.name
- if commit.head.name == @project.root_ref - if commit.head.name == @project.root_ref

View file

@ -12,7 +12,7 @@
- commit = CommitDecorator.decorate(commit) - commit = CommitDecorator.decorate(commit)
%tr %tr
%td %td
%strong= link_to tag.name, project_commits_path(@project, ref: tag.name), class: "" %strong= link_to tag.name, project_commits_path(@project, tag.name), class: ""
%td %td
= link_to project_commit_path(@project, commit.id) do = link_to project_commit_path(@project, commit.id) do
%code= commit.short_id %code= commit.short_id

View file

@ -1,5 +1,5 @@
= form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form" do = form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form" do
= select_tag "ref", grouped_options_refs, class: "project-refs-select chosen" = select_tag "ref", grouped_options_refs, class: "project-refs-select chosen"
= hidden_field_tag :destination, destination = hidden_field_tag :destination, destination
- if respond_to?(:path) - if defined?(path)
= hidden_field_tag :path, path = hidden_field_tag :path, path

View file

@ -0,0 +1,10 @@
%ul.nav.nav-tabs
%li
= render partial: 'shared/ref_switcher', locals: {destination: 'tree', path: @path}
= nav_link(controller: :tree) do
= link_to 'Source', project_tree_path(@project, @ref)
%li.right
.input-prepend.project_clone_holder
%button{class: "btn small active", :"data-clone" => @project.ssh_url_to_repo} SSH
%button{class: "btn small", :"data-clone" => @project.http_url_to_repo} HTTP
= text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select span5"

View file

@ -1,7 +1,7 @@
%ul.breadcrumb %ul.breadcrumb
%li %li
%span.arrow %span.arrow
= link_to tree_project_ref_path(@project, @ref, path: nil), remote: true do = link_to project_tree_path(@project, @ref), remote: true do
= @project.name = @project.name
- tree.breadcrumbs(6) do |link| - tree.breadcrumbs(6) do |link|
\/ \/
@ -10,7 +10,7 @@
%div.tree_progress %div.tree_progress
#tree-content-holder #tree-content-holder
- if tree.is_blob? - if tree.is_blob?
= render partial: "refs/tree_file", locals: { name: tree.name, content: tree.data, file: tree } = render partial: "tree/tree_file", locals: { name: tree.name, content: tree.data, file: tree }
- else - else
- contents = tree.contents - contents = tree.contents
%table#tree-slider{class: "table_#{@hex_path}" } %table#tree-slider{class: "table_#{@hex_path}" }
@ -31,11 +31,11 @@
- index = 0 - index = 0
- contents.select{ |i| i.is_a?(Grit::Tree)}.each do |content| - contents.select{ |i| i.is_a?(Grit::Tree)}.each do |content|
= render partial: "refs/tree_item", locals: { content: content, index: (index += 1) } = render partial: "tree/tree_item", locals: { content: content, index: (index += 1) }
- contents.select{ |i| i.is_a?(Grit::Blob)}.each do |content| - contents.select{ |i| i.is_a?(Grit::Blob)}.each do |content|
= render partial: "refs/tree_item", locals: { content: content, index: (index += 1) } = render partial: "tree/tree_item", locals: { content: content, index: (index += 1) }
- contents.select{ |i| i.is_a?(Grit::Submodule)}.each do |content| - contents.select{ |i| i.is_a?(Grit::Submodule)}.each do |content|
= render partial: "refs/submodule_item", locals: { content: content, index: (index += 1) } = render partial: "tree/submodule_item", locals: { content: content, index: (index += 1) }
- if content = contents.select{ |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i }.first - if content = contents.select{ |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i }.first
.file_holder#README .file_holder#README

View file

@ -5,9 +5,9 @@
= name.force_encoding('utf-8') = name.force_encoding('utf-8')
%small #{file.mode} %small #{file.mode}
%span.options %span.options
= link_to "raw", blob_project_ref_path(@project, @ref, path: params[:path]), class: "btn very_small", target: "_blank" = link_to "raw", project_blob_path(@project, @id), class: "btn very_small", target: "_blank"
= link_to "history", project_commits_path(@project, path: params[:path], ref: @ref), class: "btn very_small" = link_to "history", project_commits_path(@project, @id), class: "btn very_small"
= link_to "blame", blame_file_project_ref_path(@project, @ref, path: params[:path]), class: "btn very_small" = link_to "blame", project_blame_path(@project, @id), class: "btn very_small"
- if file.text? - if file.text?
- if gitlab_markdown?(name) - if gitlab_markdown?(name)
.file_content.wiki .file_content.wiki
@ -32,7 +32,7 @@
- else - else
.file_content.blob_file .file_content.blob_file
%center %center
= link_to blob_project_ref_path(@project, @ref, path: params[:path]) do = link_to project_blob_path(@project, @id) do
%div.padded %div.padded
%br %br
= image_tag "download.png", width: 64 = image_tag "download.png", width: 64

View file

@ -1,8 +1,8 @@
- file = tree_full_path(content) - file = tree_full_path(content)
%tr{ class: "tree-item #{tree_hex_class(content)}", url: tree_file_project_ref_path(@project, @ref, file) } %tr{ class: "tree-item #{tree_hex_class(content)}", url: project_tree_path(@project, tree_join(@id, file)) }
%td.tree-item-file-name %td.tree-item-file-name
= tree_icon(content) = tree_icon(content)
%strong= link_to truncate(content.name, length: 40), tree_file_project_ref_path(@project, @ref || @commit.id, file), remote: :true %strong= link_to truncate(content.name, length: 40), project_tree_path(@project, tree_join(@id || @commit.id, file)), remote: :true
%td.tree_time_ago.cgray %td.tree_time_ago.cgray
- if index == 1 - if index == 1
%span.log_loading %span.log_loading

View file

@ -0,0 +1,7 @@
= render "head"
#tree-holder= render partial: "tree", locals: {commit: @commit, tree: @tree}
:javascript
$(function() {
Tree.init();
});

View file

@ -1,8 +1,8 @@
:plain :plain
// Load Files list // Load Files list
$("#tree-holder").html("#{escape_javascript(render(partial: "tree", locals: {repo: @repo, commit: @commit, tree: @tree}))}"); $("#tree-holder").html("#{escape_javascript(render(partial: "tree", locals: {commit: @commit, tree: @tree}))}");
$("#tree-content-holder").show("slide", { direction: "right" }, 150); $("#tree-content-holder").show("slide", { direction: "right" }, 150);
$('.project-refs-form #path').val("#{params[:path]}"); $('.project-refs-form #path').val("#{@path}");
// Load last commit log for each file in tree // Load last commit log for each file in tree
$('#tree-slider').waitForImages(function() { $('#tree-slider').waitForImages(function() {

View file

@ -112,7 +112,7 @@ class Settings < Settingslogic
def backup_path def backup_path
t = app['backup_path'] || "backups/" t = app['backup_path'] || "backups/"
t = /^\//.match(t) ? t : File.join(Rails.root + t) t = /^\//.match(t) ? t : Rails.root .join(t)
t t
end end

View file

@ -8,3 +8,24 @@
# inflect.irregular 'person', 'people' # inflect.irregular 'person', 'people'
# inflect.uncountable %w( fish sheep ) # inflect.uncountable %w( fish sheep )
# end # end
# Mark "commits" as uncountable.
#
# Without this change, the routes
#
# resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/}
# resources :commits, only: [:show], constraints: {id: /.+/}
#
# would generate identical route helper methods (`project_commit_path`), resulting
# in one of them not getting a helper method at all.
#
# After this change, the helper methods are:
#
# project_commit_path(@project, @project.commit)
# # => "/gitlabhq/commit/bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a
#
# project_commits_path(@project, 'stable/README.md')
# # => "/gitlabhq/commits/stable/README.md"
ActiveSupport::Inflector.inflections do |inflect|
inflect.uncountable %w(commits)
end

View file

@ -3,3 +3,5 @@
# Add new mime types for use in respond_to blocks: # Add new mime types for use in respond_to blocks:
# Mime::Type.register "text/richtext", :rtf # Mime::Type.register "text/richtext", :rtf
# Mime::Type.register_alias "text/html", :iphone # Mime::Type.register_alias "text/html", :iphone
Mime::Type.register_alias 'text/plain', :patch

View file

@ -122,38 +122,14 @@ Gitlab::Application.routes.draw do
end end
member do member do
get "tree", constraints: { id: /[a-zA-Z.\/0-9_\-]+/ } # tree viewer logs
get "logs_tree", constraints: { id: /[a-zA-Z.\/0-9_\-]+/ } get "logs_tree", constraints: { id: /[a-zA-Z.\/0-9_\-]+/ }
get "blob",
constraints: {
id: /[a-zA-Z.0-9\/_\-]+/,
path: /.*/
}
# tree viewer
get "tree/:path" => "refs#tree",
as: :tree_file,
constraints: {
id: /[a-zA-Z.0-9\/_\-]+/,
path: /.*/
}
# tree viewer
get "logs_tree/:path" => "refs#logs_tree", get "logs_tree/:path" => "refs#logs_tree",
as: :logs_file, as: :logs_file,
constraints: { constraints: {
id: /[a-zA-Z.0-9\/_\-]+/, id: /[a-zA-Z.0-9\/_\-]+/,
path: /.*/ path: /.*/
} }
# blame
get "blame/:path" => "refs#blame",
as: :blame_file,
constraints: {
id: /[a-zA-Z.0-9\/_\-]+/,
path: /.*/
}
end end
end end
@ -182,27 +158,27 @@ Gitlab::Application.routes.draw do
get :test get :test
end end
end end
resources :commits do
collection do
get :compare
end
member do resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/}
get :patch resources :commits, only: [:show], constraints: {id: /.+/}
end resources :compare, only: [:index, :create]
end resources :blame, only: [:show], constraints: {id: /.+/}
resources :blob, only: [:show], constraints: {id: /.+/}
resources :tree, only: [:show], constraints: {id: /.+/}
match "/compare/:from...:to" => "compare#show", as: "compare", constraints: {from: /.+/, to: /.+/}
resources :team, controller: 'team_members', only: [:index] resources :team, controller: 'team_members', only: [:index]
resources :team_members resources :team_members
resources :milestones resources :milestones
resources :labels, only: [:index] resources :labels, only: [:index]
resources :issues do resources :issues do
collection do collection do
post :sort post :sort
post :bulk_update post :bulk_update
get :search get :search
end end
end end
resources :notes, only: [:index, :create, :destroy] do resources :notes, only: [:index, :create, :destroy] do
collection do collection do
post :preview post :preview

View file

@ -3,13 +3,13 @@ require 'fileutils'
print "Unpacking seed repository..." print "Unpacking seed repository..."
SEED_REPO = 'seed_project.tar.gz' SEED_REPO = 'seed_project.tar.gz'
REPO_PATH = File.join(Rails.root, 'tmp', 'repositories') REPO_PATH = Rails.root.join('tmp', 'repositories')
# Make whatever directories we need to make # Make whatever directories we need to make
FileUtils.mkdir_p(REPO_PATH) FileUtils.mkdir_p(REPO_PATH)
# Copy the archive to the repo path # Copy the archive to the repo path
FileUtils.cp(File.join(Rails.root, 'spec', SEED_REPO), REPO_PATH) FileUtils.cp(Rails.root.join('spec', SEED_REPO), REPO_PATH)
# chdir to the repo path # chdir to the repo path
FileUtils.cd(REPO_PATH) do FileUtils.cd(REPO_PATH) do

View file

@ -0,0 +1,33 @@
Feature: Admin active tab
Background:
Given I sign in as an admin
Scenario: On Admin Home
Given I visit admin page
Then the active main tab should be Home
And no other main tabs should be active
Scenario: On Admin Projects
Given I visit admin projects page
Then the active main tab should be Projects
And no other main tabs should be active
Scenario: On Admin Users
Given I visit admin users page
Then the active main tab should be Users
And no other main tabs should be active
Scenario: On Admin Logs
Given I visit admin logs page
Then the active main tab should be Logs
And no other main tabs should be active
Scenario: On Admin Hooks
Given I visit admin hooks page
Then the active main tab should be Hooks
And no other main tabs should be active
Scenario: On Admin Resque
Given I visit admin Resque page
Then the active main tab should be Resque
And no other main tabs should be active

View file

@ -0,0 +1,28 @@
Feature: Dashboard active tab
Background:
Given I sign in as a user
Scenario: On Dashboard Home
Given I visit dashboard page
Then the active main tab should be Home
And no other main tabs should be active
Scenario: On Dashboard Issues
Given I visit dashboard issues page
Then the active main tab should be Issues
And no other main tabs should be active
Scenario: On Dashboard Merge Requests
Given I visit dashboard merge requests page
Then the active main tab should be Merge Requests
And no other main tabs should be active
Scenario: On Dashboard Search
Given I visit dashboard search page
Then the active main tab should be Search
And no other main tabs should be active
Scenario: On Dashboard Help
Given I visit dashboard help page
Then the active main tab should be Help
And no other main tabs should be active

View file

@ -0,0 +1,28 @@
Feature: Profile active tab
Background:
Given I sign in as a user
Scenario: On Profile Home
Given I visit profile page
Then the active main tab should be Home
And no other main tabs should be active
Scenario: On Profile Account
Given I visit profile account page
Then the active main tab should be Account
And no other main tabs should be active
Scenario: On Profile SSH Keys
Given I visit profile SSH keys page
Then the active main tab should be SSH Keys
And no other main tabs should be active
Scenario: On Profile Design
Given I visit profile design page
Then the active main tab should be Design
And no other main tabs should be active
Scenario: On Profile History
Given I visit profile history page
Then the active main tab should be History
And no other main tabs should be active

View file

@ -0,0 +1,147 @@
Feature: Project active tab
Background:
Given I sign in as a user
And I own a project
# Main Tabs
Scenario: On Project Home
Given I visit my project's home page
Then the active main tab should be Home
And no other main tabs should be active
Scenario: On Project Files
Given I visit my project's files page
Then the active main tab should be Files
And no other main tabs should be active
Scenario: On Project Commits
Given I visit my project's commits page
Then the active main tab should be Commits
And no other main tabs should be active
Scenario: On Project Network
Given I visit my project's network page
Then the active main tab should be Network
And no other main tabs should be active
Scenario: On Project Issues
Given I visit my project's issues page
Then the active main tab should be Issues
And no other main tabs should be active
Scenario: On Project Merge Requests
Given I visit my project's merge requests page
Then the active main tab should be Merge Requests
And no other main tabs should be active
Scenario: On Project Wall
Given I visit my project's wall page
Then the active main tab should be Wall
And no other main tabs should be active
Scenario: On Project Wiki
Given I visit my project's wiki page
Then the active main tab should be Wiki
And no other main tabs should be active
# Sub Tabs: Home
Scenario: On Project Home/Show
Given I visit my project's home page
Then the active sub tab should be Show
And no other sub tabs should be active
And the active main tab should be Home
Scenario: On Project Home/Team
Given I visit my project's home page
And I click the "Team" tab
Then the active sub tab should be Team
And no other sub tabs should be active
And the active main tab should be Home
Scenario: On Project Home/Attachments
Given I visit my project's home page
And I click the "Attachments" tab
Then the active sub tab should be Attachments
And no other sub tabs should be active
And the active main tab should be Home
Scenario: On Project Home/Snippets
Given I visit my project's home page
And I click the "Snippets" tab
Then the active sub tab should be Snippets
And no other sub tabs should be active
And the active main tab should be Home
Scenario: On Project Home/Edit
Given I visit my project's home page
And I click the "Edit" tab
Then the active sub tab should be Edit
And no other sub tabs should be active
And the active main tab should be Home
Scenario: On Project Home/Hooks
Given I visit my project's home page
And I click the "Hooks" tab
Then the active sub tab should be Hooks
And no other sub tabs should be active
And the active main tab should be Home
Scenario: On Project Home/Deploy Keys
Given I visit my project's home page
And I click the "Deploy Keys" tab
Then the active sub tab should be Deploy Keys
And no other sub tabs should be active
And the active main tab should be Home
# Sub Tabs: Commits
Scenario: On Project Commits/Commits
Given I visit my project's commits page
Then the active sub tab should be Commits
And no other sub tabs should be active
And the active main tab should be Commits
Scenario: On Project Commits/Compare
Given I visit my project's commits page
And I click the "Compare" tab
Then the active sub tab should be Compare
And no other sub tabs should be active
And the active main tab should be Commits
Scenario: On Project Commits/Branches
Given I visit my project's commits page
And I click the "Branches" tab
Then the active sub tab should be Branches
And no other sub tabs should be active
And the active main tab should be Commits
Scenario: On Project Commits/Tags
Given I visit my project's commits page
And I click the "Tags" tab
Then the active sub tab should be Tags
And no other sub tabs should be active
And the active main tab should be Commits
# Sub Tabs: Issues
Scenario: On Project Issues/Browse
Given I visit my project's issues page
Then the active sub tab should be Browse Issues
And no other sub tabs should be active
And the active main tab should be Issues
Scenario: On Project Issues/Milestones
Given I visit my project's issues page
And I click the "Milestones" tab
Then the active sub tab should be Milestones
And no other sub tabs should be active
And the active main tab should be Issues
Scenario: On Project Issues/Labels
Given I visit my project's issues page
And I click the "Labels" tab
Then the active sub tab should be Labels
And no other sub tabs should be active
And the active main tab should be Issues

View file

@ -1,8 +1,8 @@
Feature: Project Browse commits Feature: Project Browse commits
Background: Background:
Given I sign in as a user Given I sign in as a user
And I own project "Shop" And I own a project
Given I visit project commits page And I visit my project's commits page
Scenario: I browse commits list for master branch Scenario: I browse commits list for master branch
Then I see project commits Then I see project commits
@ -18,4 +18,4 @@ Feature: Project Browse commits
Scenario: I compare refs Scenario: I compare refs
Given I visit compare refs page Given I visit compare refs page
And I fill compare fields with refs And I fill compare fields with refs
And I see compared refs Then I see compared refs

View file

@ -0,0 +1,29 @@
class AdminActiveTab < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
include SharedActiveTab
Then 'the active main tab should be Home' do
ensure_active_main_tab('Stats')
end
Then 'the active main tab should be Projects' do
ensure_active_main_tab('Projects')
end
Then 'the active main tab should be Users' do
ensure_active_main_tab('Users')
end
Then 'the active main tab should be Logs' do
ensure_active_main_tab('Logs')
end
Then 'the active main tab should be Hooks' do
ensure_active_main_tab('Hooks')
end
Then 'the active main tab should be Resque' do
ensure_active_main_tab('Resque')
end
end

View file

@ -0,0 +1,25 @@
class DashboardActiveTab < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
include SharedActiveTab
Then 'the active main tab should be Home' do
ensure_active_main_tab('Home')
end
Then 'the active main tab should be Issues' do
ensure_active_main_tab('Issues')
end
Then 'the active main tab should be Merge Requests' do
ensure_active_main_tab('Merge Requests')
end
Then 'the active main tab should be Search' do
ensure_active_main_tab('Search')
end
Then 'the active main tab should be Help' do
ensure_active_main_tab('Help')
end
end

View file

@ -0,0 +1,25 @@
class ProfileActiveTab < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
include SharedActiveTab
Then 'the active main tab should be Home' do
ensure_active_main_tab('Profile')
end
Then 'the active main tab should be Account' do
ensure_active_main_tab('Account')
end
Then 'the active main tab should be SSH Keys' do
ensure_active_main_tab('SSH Keys')
end
Then 'the active main tab should be Design' do
ensure_active_main_tab('Design')
end
Then 'the active main tab should be History' do
ensure_active_main_tab('History')
end
end

View file

@ -0,0 +1,146 @@
class ProjectActiveTab < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
include SharedProject
include SharedActiveTab
# Main Tabs
Then 'the active main tab should be Home' do
ensure_active_main_tab(@project.name)
end
Then 'the active main tab should be Files' do
ensure_active_main_tab('Files')
end
Then 'the active main tab should be Commits' do
ensure_active_main_tab('Commits')
end
Then 'the active main tab should be Network' do
ensure_active_main_tab('Network')
end
Then 'the active main tab should be Issues' do
ensure_active_main_tab('Issues')
end
Then 'the active main tab should be Merge Requests' do
ensure_active_main_tab('Merge Requests')
end
Then 'the active main tab should be Wall' do
ensure_active_main_tab('Wall')
end
Then 'the active main tab should be Wiki' do
ensure_active_main_tab('Wiki')
end
# Sub Tabs: Home
Given 'I click the "Team" tab' do
click_link('Team')
end
Given 'I click the "Attachments" tab' do
click_link('Attachments')
end
Given 'I click the "Snippets" tab' do
click_link('Snippets')
end
Given 'I click the "Edit" tab' do
click_link('Edit')
end
Given 'I click the "Hooks" tab' do
click_link('Hooks')
end
Given 'I click the "Deploy Keys" tab' do
click_link('Deploy Keys')
end
Then 'the active sub tab should be Show' do
ensure_active_sub_tab('Show')
end
Then 'the active sub tab should be Team' do
ensure_active_sub_tab('Team')
end
Then 'the active sub tab should be Attachments' do
ensure_active_sub_tab('Attachments')
end
Then 'the active sub tab should be Snippets' do
ensure_active_sub_tab('Snippets')
end
Then 'the active sub tab should be Edit' do
ensure_active_sub_tab('Edit')
end
Then 'the active sub tab should be Hooks' do
ensure_active_sub_tab('Hooks')
end
Then 'the active sub tab should be Deploy Keys' do
ensure_active_sub_tab('Deploy Keys')
end
# Sub Tabs: Commits
Given 'I click the "Compare" tab' do
click_link('Compare')
end
Given 'I click the "Branches" tab' do
click_link('Branches')
end
Given 'I click the "Tags" tab' do
click_link('Tags')
end
Then 'the active sub tab should be Commits' do
ensure_active_sub_tab('Commits')
end
Then 'the active sub tab should be Compare' do
ensure_active_sub_tab('Compare')
end
Then 'the active sub tab should be Branches' do
ensure_active_sub_tab('Branches')
end
Then 'the active sub tab should be Tags' do
ensure_active_sub_tab('Tags')
end
# Sub Tabs: Issues
Given 'I click the "Milestones" tab' do
click_link('Milestones')
end
Given 'I click the "Labels" tab' do
click_link('Labels')
end
Then 'the active sub tab should be Browse Issues' do
ensure_active_sub_tab('Browse Issues')
end
Then 'the active sub tab should be Milestones' do
ensure_active_sub_tab('Milestones')
end
Then 'the active sub tab should be Labels' do
ensure_active_sub_tab('Labels')
end
end

View file

@ -4,8 +4,6 @@ class ProjectBrowseCommits < Spinach::FeatureSteps
include SharedPaths include SharedPaths
Then 'I see project commits' do Then 'I see project commits' do
current_path.should == project_commits_path(@project)
commit = @project.commit commit = @project.commit
page.should have_content(@project.name) page.should have_content(@project.name)
page.should have_content(commit.message) page.should have_content(commit.message)
@ -34,14 +32,14 @@ class ProjectBrowseCommits < Spinach::FeatureSteps
end end
And 'I fill compare fields with refs' do And 'I fill compare fields with refs' do
fill_in "from", :with => "master" fill_in "from", with: "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a"
fill_in "to", :with => "stable" fill_in "to", with: "8716fc78f3c65bbf7bcf7b574febd583bc5d2812"
click_button "Compare" click_button "Compare"
end end
And 'I see compared refs' do Then 'I see compared refs' do
page.should have_content "Commits (27)"
page.should have_content "Compare View" page.should have_content "Compare View"
page.should have_content "Showing 73 changed files" page.should have_content "Commits (1)"
page.should have_content "Showing 2 changed files"
end end
end end

View file

@ -10,7 +10,7 @@ class ProjectBrowseFiles < Spinach::FeatureSteps
end end
Then 'I should see files from repository for "8470d70"' do Then 'I should see files from repository for "8470d70"' do
current_path.should == tree_project_ref_path(@project, "8470d70") current_path.should == project_tree_path(@project, "8470d70")
page.should have_content "app" page.should have_content "app"
page.should have_content "History" page.should have_content "History"
page.should have_content "Gemfile" page.should have_content "Gemfile"

View file

@ -0,0 +1,19 @@
module SharedActiveTab
include Spinach::DSL
def ensure_active_main_tab(content)
page.find('ul.main_menu li.active').should have_content(content)
end
def ensure_active_sub_tab(content)
page.find('div.content ul.nav-tabs li.active').should have_content(content)
end
And 'no other main tabs should be active' do
page.should have_selector('ul.main_menu li.active', count: 1)
end
And 'no other sub tabs should be active' do
page.should have_selector('div.content ul.nav-tabs li.active', count: 1)
end
end

View file

@ -7,4 +7,8 @@ module SharedAuthentication
Given 'I sign in as a user' do Given 'I sign in as a user' do
login_as :user login_as :user
end end
Given 'I sign in as an admin' do
login_as :admin
end
end end

View file

@ -1,22 +1,38 @@
module SharedPaths module SharedPaths
include Spinach::DSL include Spinach::DSL
And 'I visit dashboard search page' do When 'I visit new project page' do
visit search_path visit new_project_path
end end
And 'I visit dashboard merge requests page' do # ----------------------------------------
visit dashboard_merge_requests_path # Dashboard
# ----------------------------------------
Given 'I visit dashboard page' do
visit dashboard_path
end end
And 'I visit dashboard issues page' do Given 'I visit dashboard issues page' do
visit dashboard_issues_path visit dashboard_issues_path
end end
When 'I visit dashboard page' do Given 'I visit dashboard merge requests page' do
visit dashboard_path visit dashboard_merge_requests_path
end end
Given 'I visit dashboard search page' do
visit search_path
end
Given 'I visit dashboard help page' do
visit help_path
end
# ----------------------------------------
# Profile
# ----------------------------------------
Given 'I visit profile page' do Given 'I visit profile page' do
visit profile_path visit profile_path
end end
@ -25,14 +41,94 @@ module SharedPaths
visit profile_account_path visit profile_account_path
end end
Given 'I visit profile SSH keys page' do
visit keys_path
end
Given 'I visit profile design page' do
visit profile_design_path
end
Given 'I visit profile history page' do
visit profile_history_path
end
Given 'I visit profile token page' do Given 'I visit profile token page' do
visit profile_token_path visit profile_token_path
end end
When 'I visit new project page' do # ----------------------------------------
visit new_project_path # Admin
# ----------------------------------------
Given 'I visit admin page' do
visit admin_root_path
end end
Given 'I visit admin projects page' do
visit admin_projects_path
end
Given 'I visit admin users page' do
visit admin_users_path
end
Given 'I visit admin logs page' do
visit admin_logs_path
end
Given 'I visit admin hooks page' do
visit admin_hooks_path
end
Given 'I visit admin Resque page' do
visit admin_resque_path
end
# ----------------------------------------
# Generic Project
# ----------------------------------------
Given "I visit my project's home page" do
visit project_path(@project)
end
Given "I visit my project's files page" do
visit project_tree_path(@project, @project.root_ref)
end
Given "I visit my project's commits page" do
visit project_commits_path(@project, @project.root_ref, {limit: 5})
end
Given "I visit my project's network page" do
# Stub out find_all to speed this up (10 commits vs. 650)
commits = Grit::Commit.find_all(@project.repo, nil, {max_count: 10})
Grit::Commit.stub(:find_all).and_return(commits)
visit graph_project_path(@project)
end
Given "I visit my project's issues page" do
visit project_issues_path(@project)
end
Given "I visit my project's merge requests page" do
visit project_merge_requests_path(@project)
end
Given "I visit my project's wall page" do
visit wall_project_path(@project)
end
Given "I visit my project's wiki page" do
visit project_wiki_path(@project, :index)
end
# ----------------------------------------
# "Shop" Project
# ----------------------------------------
And 'I visit project "Shop" page' do And 'I visit project "Shop" page' do
project = Project.find_by_name("Shop") project = Project.find_by_name("Shop")
visit project_path(project) visit project_path(project)
@ -43,23 +139,27 @@ module SharedPaths
end end
Given 'I visit compare refs page' do Given 'I visit compare refs page' do
visit compare_project_commits_path(@project) visit project_compare_index_path(@project)
end end
Given 'I visit project commits page' do Given 'I visit project commits page' do
visit project_commits_path(@project) visit project_commits_path(@project, @project.root_ref, {limit: 5})
end
Given 'I visit project commits page for stable branch' do
visit project_commits_path(@project, 'stable', {limit: 5})
end end
Given 'I visit project source page' do Given 'I visit project source page' do
visit tree_project_ref_path(@project, @project.root_ref) visit project_tree_path(@project, @project.root_ref)
end end
Given 'I visit blob file from repo' do Given 'I visit blob file from repo' do
visit tree_project_ref_path(@project, ValidCommit::ID, :path => ValidCommit::BLOB_FILE_PATH) visit project_tree_path(@project, File.join(ValidCommit::ID, ValidCommit::BLOB_FILE_PATH))
end end
Given 'I visit project source page for "8470d70"' do Given 'I visit project source page for "8470d70"' do
visit tree_project_ref_path(@project, "8470d70") visit project_tree_path(@project, "8470d70")
end end
Given 'I visit project tags page' do Given 'I visit project tags page' do

View file

@ -1,6 +1,13 @@
module SharedProject module SharedProject
include Spinach::DSL include Spinach::DSL
# Create a project without caring about what it's called
And "I own a project" do
@project = create(:project)
@project.add_access(@user, :admin)
end
# Create a specific project called "Shop"
And 'I own project "Shop"' do And 'I own project "Shop"' do
@project = Factory :project, :name => "Shop" @project = Factory :project, :name => "Shop"
@project.add_access(@user, :admin) @project.add_access(@user, :admin)

View file

@ -23,5 +23,7 @@ Spinach.hooks.after_scenario { DatabaseCleaner.clean }
Spinach.hooks.before_run do Spinach.hooks.before_run do
RSpec::Mocks::setup self RSpec::Mocks::setup self
include FactoryGirl::Syntax::Methods
stub_gitolite! stub_gitolite!
end end

114
lib/extracts_path.rb Normal file
View file

@ -0,0 +1,114 @@
# Module providing methods for dealing with separating a tree-ish string and a
# file path string when combined in a request parameter
module ExtractsPath
extend ActiveSupport::Concern
# Raised when given an invalid file path
class InvalidPathError < StandardError; end
included do
if respond_to?(:before_filter)
before_filter :assign_ref_vars, only: [:show]
end
end
# Given a string containing both a Git tree-ish, such as a branch or tag, and
# a filesystem path joined by forward slashes, attempts to separate the two.
#
# Expects a @project instance variable to contain the active project. This is
# used to check the input against a list of valid repository refs.
#
# Examples
#
# # No @project available
# extract_ref('master')
# # => ['', '']
#
# extract_ref('master')
# # => ['master', '']
#
# extract_ref("f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG")
# # => ['f4b14494ef6abf3d144c28e4af0c20143383e062', 'CHANGELOG']
#
# extract_ref("v2.0.0/README.md")
# # => ['v2.0.0', 'README.md']
#
# extract_ref('issues/1234/app/models/project.rb')
# # => ['issues/1234', 'app/models/project.rb']
#
# # Given an invalid branch, we fall back to just splitting on the first slash
# extract_ref('non/existent/branch/README.md')
# # => ['non', 'existent/branch/README.md']
#
# Returns an Array where the first value is the tree-ish and the second is the
# path
def extract_ref(input)
pair = ['', '']
return pair unless @project
if input.match(/^([[:alnum:]]{40})(.+)/)
# If the ref appears to be a SHA, we're done, just split the string
pair = $~.captures
else
# Otherwise, attempt to detect the ref using a list of the project's
# branches and tags
# Append a trailing slash if we only get a ref and no file path
id = input
id += '/' unless id.include?('/')
valid_refs = @project.branches + @project.tags
valid_refs.select! { |v| id.start_with?("#{v}/") }
if valid_refs.length != 1
# No exact ref match, so just try our best
pair = id.match(/([^\/]+)(.*)/).captures
else
# Partition the string into the ref and the path, ignoring the empty first value
pair = id.partition(valid_refs.first)[1..-1]
end
end
# Remove leading slash from path
pair[1].gsub!(/^\//, '')
pair
end
# Assigns common instance variables for views working with Git tree-ish objects
#
# Assignments are:
#
# - @id - A string representing the joined ref and path
# - @ref - A string representing the ref (e.g., the branch, tag, or commit SHA)
# - @path - A string representing the filesystem path
# - @commit - A CommitDecorator representing the commit from the given ref
# - @tree - A TreeDecorator representing the tree at the given ref/path
#
# If the :id parameter appears to be requesting a specific response format,
# that will be handled as well.
#
# Automatically renders `not_found!` if a valid tree path could not be
# resolved (e.g., when a user inserts an invalid path or ref).
def assign_ref_vars
# Handle formats embedded in the id
if params[:id].ends_with?('.atom')
params[:id].gsub!(/\.atom$/, '')
request.format = :atom
end
@ref, @path = extract_ref(params[:id])
@id = File.join(@ref, @path)
@commit = CommitDecorator.decorate(@project.commit(@ref))
@tree = Tree.new(@commit.tree, @project, @ref, @path)
@tree = TreeDecorator.new(@tree)
raise InvalidPathError if @tree.invalid?
rescue NoMethodError, InvalidPathError
not_found!
end
end

View file

@ -10,7 +10,7 @@ module Gitlab
attr_reader :config_tmp_dir, :ga_repo, :conf attr_reader :config_tmp_dir, :ga_repo, :conf
def config_tmp_dir def config_tmp_dir
@config_tmp_dir ||= File.join(Rails.root, 'tmp',"gitlabhq-gitolite-#{Time.now.to_i}") @config_tmp_dir ||= Rails.root.join('tmp',"gitlabhq-gitolite-#{Time.now.to_i}")
end end
def ga_repo def ga_repo
@ -19,7 +19,7 @@ module Gitlab
def apply def apply
Timeout::timeout(30) do Timeout::timeout(30) do
File.open(File.join(Rails.root, 'tmp', "gitlabhq-gitolite.lock"), "w+") do |f| File.open(Rails.root.join('tmp', "gitlabhq-gitolite.lock"), "w+") do |f|
begin begin
# Set exclusive lock # Set exclusive lock
# to prevent race condition # to prevent race condition

View file

@ -15,7 +15,7 @@ module Gitlab
end end
def self.build def self.build
new(File.join(Rails.root, "log", file_name)) new(Rails.root.join("log", file_name))
end end
end end
end end

View file

@ -174,7 +174,7 @@ module Gitlab
def reference_commit(identifier) def reference_commit(identifier)
if commit = @project.commit(identifier) if commit = @project.commit(identifier)
link_to(identifier, project_commit_path(@project, id: commit.id), html_options.merge(title: CommitDecorator.new(commit).link_title, class: "gfm gfm-commit #{html_options[:class]}")) link_to(identifier, project_commit_path(@project, commit), html_options.merge(title: CommitDecorator.new(commit).link_title, class: "gfm gfm-commit #{html_options[:class]}"))
end end
end end
end end

View file

@ -28,7 +28,7 @@ module Gitlab
def process def process
Grit::Git.with_timeout(30.seconds) do Grit::Git.with_timeout(30.seconds) do
lock_file = File.join(Rails.root, "tmp", "merge_repo_#{project.path}.lock") lock_file = Rails.root.join("tmp", "merge_repo_#{project.path}.lock")
File.open(lock_file, "w+") do |f| File.open(lock_file, "w+") do |f|
f.flock(File::LOCK_EX) f.flock(File::LOCK_EX)

View file

@ -14,7 +14,7 @@ module Gitlab
end end
def path def path
File.join(Rails.root, "tmp", "repo_satellites", project.path) Rails.root.join("tmp", "repo_satellites", project.path)
end end
def exists? def exists?

View file

@ -0,0 +1,22 @@
require 'spec_helper'
describe CommitsController do
let(:project) { create(:project) }
let(:user) { create(:user) }
before do
sign_in(user)
project.add_access(user, :read, :admin)
end
describe "GET show" do
context "as atom feed" do
it "should render as atom" do
get :show, project_id: project.code, id: "master.atom"
response.should be_success
response.content_type.should == 'application/atom+xml'
end
end
end
end

View file

@ -0,0 +1,43 @@
require 'spec_helper'
describe TreeController do
let(:project) { create(:project) }
let(:user) { create(:user) }
before do
sign_in(user)
project.add_access(user, :read, :admin)
project.stub(:branches).and_return(['master', 'foo/bar/baz'])
project.stub(:tags).and_return(['v1.0.0', 'v2.0.0'])
controller.instance_variable_set(:@project, project)
end
describe "GET show" do
# Make sure any errors accessing the tree in our views bubble up to this spec
render_views
before { get :show, project_id: project.code, id: id }
context "valid branch, no path" do
let(:id) { 'master' }
it { should respond_with(:success) }
end
context "valid branch, valid path" do
let(:id) { 'master/README.md' }
it { should respond_with(:success) }
end
context "valid branch, invalid path" do
let(:id) { 'master/invalid-path.rb' }
it { should respond_with(:not_found) }
end
context "invalid branch, valid path" do
let(:id) { 'invalid-branch/README.md' }
it { should respond_with(:not_found) }
end
end
end

View file

@ -42,8 +42,8 @@ FactoryGirl.define do
factory :project do factory :project do
sequence(:name) { |n| "project#{n}" } sequence(:name) { |n| "project#{n}" }
path { name } path { name.downcase.gsub(/\s/, '_') }
code { name } code { name.downcase.gsub(/\s/, '_') }
owner owner
end end

View file

@ -1,6 +1,44 @@
require 'spec_helper' require 'spec_helper'
describe ApplicationHelper do describe ApplicationHelper do
describe 'current_controller?' do
before do
controller.stub!(:controller_name).and_return('foo')
end
it "returns true when controller matches argument" do
current_controller?(:foo).should be_true
end
it "returns false when controller does not match argument" do
current_controller?(:bar).should_not be_true
end
it "should take any number of arguments" do
current_controller?(:baz, :bar).should_not be_true
current_controller?(:baz, :bar, :foo).should be_true
end
end
describe 'current_action?' do
before do
stub!(:action_name).and_return('foo')
end
it "returns true when action matches argument" do
current_action?(:foo).should be_true
end
it "returns false when action does not match argument" do
current_action?(:bar).should_not be_true
end
it "should take any number of arguments" do
current_action?(:baz, :bar).should_not be_true
current_action?(:baz, :bar, :foo).should be_true
end
end
describe "gravatar_icon" do describe "gravatar_icon" do
let(:user_email) { 'user@email.com' } let(:user_email) { 'user@email.com' }

View file

@ -0,0 +1,44 @@
require 'spec_helper'
describe TabHelper do
include ApplicationHelper
describe 'nav_link' do
before do
controller.stub!(:controller_name).and_return('foo')
stub!(:action_name).and_return('foo')
end
it "captures block output" do
nav_link { "Testing Blocks" }.should match(/Testing Blocks/)
end
it "performs checks on the current controller" do
nav_link(controller: :foo).should match(/<li class="active">/)
nav_link(controller: :bar).should_not match(/active/)
nav_link(controller: [:foo, :bar]).should match(/active/)
end
it "performs checks on the current action" do
nav_link(action: :foo).should match(/<li class="active">/)
nav_link(action: :bar).should_not match(/active/)
nav_link(action: [:foo, :bar]).should match(/active/)
end
it "performs checks on both controller and action when both are present" do
nav_link(controller: :bar, action: :foo).should_not match(/active/)
nav_link(controller: :foo, action: :bar).should_not match(/active/)
nav_link(controller: :foo, action: :foo).should match(/active/)
end
it "accepts a path shorthand" do
nav_link(path: 'foo#bar').should_not match(/active/)
nav_link(path: 'foo#foo').should match(/active/)
end
it "passes extra html options to the list element" do
nav_link(action: :foo, html_options: {class: 'home'}).should match(/<li class="home active">/)
nav_link(html_options: {class: 'active'}).should match(/<li class="active">/)
end
end
end

View file

@ -0,0 +1,58 @@
require 'spec_helper'
describe ExtractsPath do
include ExtractsPath
let(:project) { double('project') }
before do
@project = project
project.stub(:branches).and_return(['master', 'foo/bar/baz'])
project.stub(:tags).and_return(['v1.0.0', 'v2.0.0'])
end
describe '#extract_ref' do
it "returns an empty pair when no @project is set" do
@project = nil
extract_ref('master/CHANGELOG').should == ['', '']
end
context "without a path" do
it "extracts a valid branch" do
extract_ref('master').should == ['master', '']
end
it "extracts a valid tag" do
extract_ref('v2.0.0').should == ['v2.0.0', '']
end
it "extracts a valid commit ref without a path" do
extract_ref('f4b14494ef6abf3d144c28e4af0c20143383e062').should ==
['f4b14494ef6abf3d144c28e4af0c20143383e062', '']
end
it "falls back to a primitive split for an invalid ref" do
extract_ref('stable').should == ['stable', '']
end
end
context "with a path" do
it "extracts a valid branch" do
extract_ref('foo/bar/baz/CHANGELOG').should == ['foo/bar/baz', 'CHANGELOG']
end
it "extracts a valid tag" do
extract_ref('v2.0.0/CHANGELOG').should == ['v2.0.0', 'CHANGELOG']
end
it "extracts a valid commit SHA" do
extract_ref('f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG').should ==
['f4b14494ef6abf3d144c28e4af0c20143383e062', 'CHANGELOG']
end
it "falls back to a primitive split for an invalid ref" do
extract_ref('stable/CHANGELOG').should == ['stable', 'CHANGELOG']
end
end
end
end

View file

@ -0,0 +1,58 @@
require 'spec_helper'
describe ExtractsPath do
include ExtractsPath
let(:project) { double('project') }
before do
@project = project
project.stub(:branches).and_return(['master', 'foo/bar/baz'])
project.stub(:tags).and_return(['v1.0.0', 'v2.0.0'])
end
describe '#extract_ref' do
it "returns an empty pair when no @project is set" do
@project = nil
extract_ref('master/CHANGELOG').should == ['', '']
end
context "without a path" do
it "extracts a valid branch" do
extract_ref('master').should == ['master', '']
end
it "extracts a valid tag" do
extract_ref('v2.0.0').should == ['v2.0.0', '']
end
it "extracts a valid commit ref without a path" do
extract_ref('f4b14494ef6abf3d144c28e4af0c20143383e062').should ==
['f4b14494ef6abf3d144c28e4af0c20143383e062', '']
end
it "falls back to a primitive split for an invalid ref" do
extract_ref('stable').should == ['stable', '']
end
end
context "with a path" do
it "extracts a valid branch" do
extract_ref('foo/bar/baz/CHANGELOG').should == ['foo/bar/baz', 'CHANGELOG']
end
it "extracts a valid tag" do
extract_ref('v2.0.0/CHANGELOG').should == ['v2.0.0', 'CHANGELOG']
end
it "extracts a valid commit SHA" do
extract_ref('f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG').should ==
['f4b14494ef6abf3d144c28e4af0c20143383e062', 'CHANGELOG']
end
it "falls back to a primitive split for an invalid ref" do
extract_ref('stable/CHANGELOG').should == ['stable', 'CHANGELOG']
end
end
end
end

View file

@ -125,7 +125,7 @@ describe Project do
it "should return path to repo" do it "should return path to repo" do
project = Project.new(path: "somewhere") project = Project.new(path: "somewhere")
project.path_to_repo.should == File.join(Rails.root, "tmp", "repositories", "somewhere") project.path_to_repo.should == Rails.root.join("tmp", "repositories", "somewhere")
end end
it "returns the full web URL for this repo" do it "returns the full web URL for this repo" do

Some files were not shown because too many files have changed in this diff Show more