Commit e563e948bb907a26c4a170eaec0f3976fdf11d74

Authored by Cyril
2 parents bdf317ad a8870e87

Merge branch 'master' into simplify_controllers2

Conflicts:
	app/controllers/commits_controller.rb
	app/controllers/refs_controller.rb
Showing 119 changed files with 1992 additions and 882 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 119 files displayed.

@@ -57,7 +57,7 @@ gem "seed-fu" @@ -57,7 +57,7 @@ gem "seed-fu"
57 57
58 # Markdown to HTML 58 # Markdown to HTML
59 gem "redcarpet", "~> 2.1.1" 59 gem "redcarpet", "~> 2.1.1"
60 -gem "github-markup", "~> 0.7.4" 60 +gem "github-markup", "~> 0.7.4", require: 'github/markup'
61 61
62 # Servers 62 # Servers
63 gem "thin" 63 gem "thin"
app/assets/stylesheets/gitlab_bootstrap/files.scss
@@ -68,10 +68,22 @@ @@ -68,10 +68,22 @@
68 * Blame file 68 * Blame file
69 */ 69 */
70 &.blame { 70 &.blame {
  71 + table {
  72 + border:none;
  73 + box-shadow:none;
  74 + margin:0;
  75 + }
71 tr { 76 tr {
72 border-bottom: 1px solid #eee; 77 border-bottom: 1px solid #eee;
73 } 78 }
74 td { 79 td {
  80 + &:first-child {
  81 + border-left:none;
  82 + }
  83 + &:last-child {
  84 + border-right:none;
  85 + }
  86 + background:#fff;
75 padding:5px; 87 padding:5px;
76 } 88 }
77 .author, 89 .author,
app/assets/stylesheets/sections/nav.scss
@@ -53,7 +53,7 @@ ul.main_menu { @@ -53,7 +53,7 @@ ul.main_menu {
53 border-left: 0; 53 border-left: 0;
54 } 54 }
55 55
56 - &.current { 56 + &.active {
57 background-color:#D5D5D5; 57 background-color:#D5D5D5;
58 border-right: 1px solid #BBB; 58 border-right: 1px solid #BBB;
59 border-left: 1px solid #BBB; 59 border-left: 1px solid #BBB;
app/controllers/application_controller.rb
@@ -2,7 +2,6 @@ class ApplicationController < ActionController::Base @@ -2,7 +2,6 @@ class ApplicationController < ActionController::Base
2 before_filter :authenticate_user! 2 before_filter :authenticate_user!
3 before_filter :reject_blocked! 3 before_filter :reject_blocked!
4 before_filter :set_current_user_for_mailer 4 before_filter :set_current_user_for_mailer
5 - before_filter :check_token_auth  
6 before_filter :set_current_user_for_observers 5 before_filter :set_current_user_for_observers
7 before_filter :dev_tools if Rails.env == 'development' 6 before_filter :dev_tools if Rails.env == 'development'
8 7
@@ -24,13 +23,6 @@ class ApplicationController < ActionController::Base @@ -24,13 +23,6 @@ class ApplicationController < ActionController::Base
24 23
25 protected 24 protected
26 25
27 - def check_token_auth  
28 - # Redirect to login page if not atom feed  
29 - if params[:private_token].present? && params[:format] != 'atom'  
30 - redirect_to new_user_session_path  
31 - end  
32 - end  
33 -  
34 def reject_blocked! 26 def reject_blocked!
35 if current_user && current_user.blocked 27 if current_user && current_user.blocked
36 sign_out current_user 28 sign_out current_user
@@ -103,7 +95,7 @@ class ApplicationController < ActionController::Base @@ -103,7 +95,7 @@ class ApplicationController < ActionController::Base
103 end 95 end
104 96
105 def render_404 97 def render_404
106 - render file: File.join(Rails.root, "public", "404"), layout: false, status: "404" 98 + render file: Rails.root.join("public", "404"), layout: false, status: "404"
107 end 99 end
108 100
109 def require_non_empty_project 101 def require_non_empty_project
@@ -116,10 +108,6 @@ class ApplicationController < ActionController::Base @@ -116,10 +108,6 @@ class ApplicationController < ActionController::Base
116 response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT" 108 response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
117 end 109 end
118 110
119 - def render_full_content  
120 - @full_content = true  
121 - end  
122 -  
123 def dev_tools 111 def dev_tools
124 Rack::MiniProfiler.authorize_request 112 Rack::MiniProfiler.authorize_request
125 end 113 end
app/controllers/blame_controller.rb 0 → 100644
@@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
  1 +# Controller for viewing a file's blame
  2 +class BlameController < ApplicationController
  3 + include ExtractsPath
  4 +
  5 + layout "project"
  6 +
  7 + before_filter :project
  8 +
  9 + # Authorize
  10 + before_filter :add_project_abilities
  11 + before_filter :authorize_read_project!
  12 + before_filter :authorize_code_access!
  13 + before_filter :require_non_empty_project
  14 +
  15 + before_filter :assign_ref_vars
  16 +
  17 + def show
  18 + @repo = @project.repo
  19 + @blame = Grit::Blob.blame(@repo, @commit.id, @path)
  20 + end
  21 +end
app/controllers/blob_controller.rb 0 → 100644
@@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
  1 +# Controller for viewing a file's blame
  2 +class BlobController < ApplicationController
  3 + include ExtractsPath
  4 + include Gitlab::Encode
  5 +
  6 + layout "project"
  7 +
  8 + before_filter :project
  9 +
  10 + # Authorize
  11 + before_filter :add_project_abilities
  12 + before_filter :authorize_read_project!
  13 + before_filter :authorize_code_access!
  14 + before_filter :require_non_empty_project
  15 +
  16 + before_filter :assign_ref_vars
  17 +
  18 + def show
  19 + if @tree.is_blob?
  20 + if @tree.text?
  21 + encoding = detect_encoding(@tree.data)
  22 + mime_type = encoding ? "text/plain; charset=#{encoding}" : "text/plain"
  23 + else
  24 + mime_type = @tree.mime_type
  25 + end
  26 +
  27 + send_data(
  28 + @tree.data,
  29 + type: mime_type,
  30 + disposition: 'inline',
  31 + filename: @tree.name
  32 + )
  33 + else
  34 + not_found!
  35 + end
  36 + end
  37 +end
app/controllers/commit_controller.rb 0 → 100644
@@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
  1 +# Controller for a specific Commit
  2 +#
  3 +# Not to be confused with CommitsController, plural.
  4 +class CommitController < ApplicationController
  5 + before_filter :project
  6 + layout "project"
  7 +
  8 + # Authorize
  9 + before_filter :add_project_abilities
  10 + before_filter :authorize_read_project!
  11 + before_filter :authorize_code_access!
  12 + before_filter :require_non_empty_project
  13 +
  14 + def show
  15 + result = CommitLoad.new(project, current_user, params).execute
  16 +
  17 + @commit = result[:commit]
  18 + git_not_found! unless @commit
  19 +
  20 + @suppress_diff = result[:suppress_diff]
  21 + @note = result[:note]
  22 + @line_notes = result[:line_notes]
  23 + @notes_count = result[:notes_count]
  24 + @comments_allowed = true
  25 +
  26 + respond_to do |format|
  27 + format.html do
  28 + if result[:status] == :huge_commit
  29 + render "huge_commit" and return
  30 + end
  31 + end
  32 +
  33 + format.patch
  34 + end
  35 + end
  36 +end
app/controllers/commits_controller.rb
1 require "base64" 1 require "base64"
2 2
3 class CommitsController < ProjectController 3 class CommitsController < ProjectController
  4 + include ExtractsPath
  5 +
4 # Authorize 6 # Authorize
5 before_filter :authorize_read_project! 7 before_filter :authorize_read_project!
6 before_filter :authorize_code_access! 8 before_filter :authorize_code_access!
7 before_filter :require_non_empty_project 9 before_filter :require_non_empty_project
8 - before_filter :load_refs, only: :index # load @branch, @tag & @ref  
9 - before_filter :render_full_content  
10 10
11 - def index  
12 - @repo = project.repo 11 + def show
  12 + @repo = @project.repo
13 @limit, @offset = (params[:limit] || 40), (params[:offset] || 0) 13 @limit, @offset = (params[:limit] || 40), (params[:offset] || 0)
14 14
15 - @commits = @project.commits(@ref, params[:path], @limit, @offset) 15 + @commits = @project.commits(@ref, @path, @limit, @offset)
16 @commits = CommitDecorator.decorate(@commits) 16 @commits = CommitDecorator.decorate(@commits)
17 17
18 respond_to do |format| 18 respond_to do |format|
@@ -21,54 +21,4 @@ class CommitsController &lt; ProjectController @@ -21,54 +21,4 @@ class CommitsController &lt; ProjectController
21 format.atom { render layout: false } 21 format.atom { render layout: false }
22 end 22 end
23 end 23 end
24 -  
25 - def show  
26 - result = CommitLoad.new(project, current_user, params).execute  
27 -  
28 - @commit = result[:commit]  
29 -  
30 - if @commit  
31 - @suppress_diff = result[:suppress_diff]  
32 - @note = result[:note]  
33 - @line_notes = result[:line_notes]  
34 - @notes_count = result[:notes_count]  
35 - @comments_allowed = true  
36 - else  
37 - return git_not_found!  
38 - end  
39 -  
40 - if result[:status] == :huge_commit  
41 - render "huge_commit" and return  
42 - end  
43 - end  
44 -  
45 - def compare  
46 - result = Commit.compare(project, params[:from], params[:to])  
47 -  
48 - @commits = result[:commits]  
49 - @commit = result[:commit]  
50 - @diffs = result[:diffs]  
51 - @refs_are_same = result[:same]  
52 - @line_notes = []  
53 -  
54 - @commits = CommitDecorator.decorate(@commits)  
55 - end  
56 -  
57 - def patch  
58 - @commit = project.commit(params[:id])  
59 -  
60 - send_data(  
61 - @commit.to_patch,  
62 - type: "text/plain",  
63 - disposition: 'attachment',  
64 - filename: "#{@commit.id}.patch"  
65 - )  
66 - end  
67 -  
68 - protected  
69 -  
70 - def load_refs  
71 - @ref ||= params[:ref].presence || params[:branch].presence || params[:tag].presence  
72 - @ref ||= @ref || @project.try(:default_branch) || 'master'  
73 - end  
74 end 24 end
app/controllers/compare_controller.rb 0 → 100644
@@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
  1 +class CompareController < ApplicationController
  2 + before_filter :project
  3 + layout "project"
  4 +
  5 + # Authorize
  6 + before_filter :add_project_abilities
  7 + before_filter :authorize_read_project!
  8 + before_filter :authorize_code_access!
  9 + before_filter :require_non_empty_project
  10 +
  11 + def index
  12 + end
  13 +
  14 + def show
  15 + result = Commit.compare(project, params[:from], params[:to])
  16 +
  17 + @commits = result[:commits]
  18 + @commit = result[:commit]
  19 + @diffs = result[:diffs]
  20 + @refs_are_same = result[:same]
  21 + @line_notes = []
  22 +
  23 + @commits = CommitDecorator.decorate(@commits)
  24 + end
  25 +
  26 + def create
  27 + redirect_to project_compare_path(@project, params[:from], params[:to])
  28 + end
  29 +end
app/controllers/protected_branches_controller.rb
@@ -4,7 +4,6 @@ class ProtectedBranchesController &lt; ProjectController @@ -4,7 +4,6 @@ class ProtectedBranchesController &lt; ProjectController
4 before_filter :require_non_empty_project 4 before_filter :require_non_empty_project
5 5
6 before_filter :authorize_admin_project!, only: [:destroy, :create] 6 before_filter :authorize_admin_project!, only: [:destroy, :create]
7 - before_filter :render_full_content  
8 7
9 def index 8 def index
10 @branches = @project.protected_branches.all 9 @branches = @project.protected_branches.all
app/controllers/refs_controller.rb
1 -require 'github/markup'  
2 -  
3 class RefsController < ProjectController 1 class RefsController < ProjectController
4 include Gitlab::Encode 2 include Gitlab::Encode
5 3
@@ -9,21 +7,20 @@ class RefsController &lt; ProjectController @@ -9,21 +7,20 @@ class RefsController &lt; ProjectController
9 before_filter :require_non_empty_project 7 before_filter :require_non_empty_project
10 8
11 before_filter :ref 9 before_filter :ref
12 - before_filter :define_tree_vars, only: [:tree, :blob, :blame, :logs_tree]  
13 - before_filter :render_full_content 10 + before_filter :define_tree_vars, only: [:blob, :logs_tree]
14 11
15 def switch 12 def switch
16 respond_to do |format| 13 respond_to do |format|
17 format.html do 14 format.html do
18 new_path = if params[:destination] == "tree" 15 new_path = if params[:destination] == "tree"
19 - tree_project_ref_path(@project, params[:ref]) 16 + project_tree_path(@project, @ref)
20 else 17 else
21 - project_commits_path(@project, ref: params[:ref]) 18 + project_commits_path(@project, @ref)
22 end 19 end
23 20
24 - redirect_to new_path 21 + redirect_to new_path
25 end 22 end
26 - format.js do 23 + format.js do
27 @ref = params[:ref] 24 @ref = params[:ref]
28 define_tree_vars 25 define_tree_vars
29 render "tree" 26 render "tree"
@@ -31,19 +28,6 @@ class RefsController &lt; ProjectController @@ -31,19 +28,6 @@ class RefsController &lt; ProjectController
31 end 28 end
32 end 29 end
33 30
34 - #  
35 - # Repository preview  
36 - #  
37 - def tree  
38 - respond_to do |format|  
39 - format.html  
40 - format.js do  
41 - # disable cache to allow back button works  
42 - no_cache_headers  
43 - end  
44 - end  
45 - end  
46 -  
47 def logs_tree 31 def logs_tree
48 contents = @tree.contents 32 contents = @tree.contents
49 @logs = contents.map do |content| 33 @logs = contents.map do |content|
@@ -51,36 +35,12 @@ class RefsController &lt; ProjectController @@ -51,36 +35,12 @@ class RefsController &lt; ProjectController
51 last_commit = @project.commits(@commit.id, file, 1).last 35 last_commit = @project.commits(@commit.id, file, 1).last
52 last_commit = CommitDecorator.decorate(last_commit) 36 last_commit = CommitDecorator.decorate(last_commit)
53 { 37 {
54 - file_name: content.name, 38 + file_name: content.name,
55 commit: last_commit 39 commit: last_commit
56 } 40 }
57 end 41 end
58 end 42 end
59 43
60 - def blob  
61 - if @tree.is_blob?  
62 - if @tree.text?  
63 - encoding = detect_encoding(@tree.data)  
64 - mime_type = encoding ? "text/plain; charset=#{encoding}" : "text/plain"  
65 - else  
66 - mime_type = @tree.mime_type  
67 - end  
68 -  
69 - send_data(  
70 - @tree.data,  
71 - type: mime_type,  
72 - disposition: 'inline',  
73 - filename: @tree.name  
74 - )  
75 - else  
76 - head(404)  
77 - end  
78 - end  
79 -  
80 - def blame  
81 - @blame = Grit::Blob.blame(@repo, @commit.id, params[:path])  
82 - end  
83 -  
84 protected 44 protected
85 45
86 def define_tree_vars 46 def define_tree_vars
@@ -91,20 +51,20 @@ class RefsController &lt; ProjectController @@ -91,20 +51,20 @@ class RefsController &lt; ProjectController
91 @commit = CommitDecorator.decorate(@commit) 51 @commit = CommitDecorator.decorate(@commit)
92 @tree = Tree.new(@commit.tree, project, @ref, params[:path]) 52 @tree = Tree.new(@commit.tree, project, @ref, params[:path])
93 @tree = TreeDecorator.new(@tree) 53 @tree = TreeDecorator.new(@tree)
94 - @hex_path = Digest::SHA1.hexdigest(params[:path] || "/") 54 + @hex_path = Digest::SHA1.hexdigest(params[:path] || "")
95 55
96 if params[:path] 56 if params[:path]
97 - @history_path = tree_file_project_ref_path(@project, @ref, params[:path])  
98 - @logs_path = logs_file_project_ref_path(@project, @ref, params[:path]) 57 + @history_path = project_tree_path(@project, File.join(@ref, params[:path]))
  58 + @logs_path = logs_file_project_ref_path(@project, @ref, params[:path])
99 else 59 else
100 - @history_path = tree_project_ref_path(@project, @ref)  
101 - @logs_path = logs_tree_project_ref_path(@project, @ref) 60 + @history_path = project_tree_path(@project, @ref)
  61 + @logs_path = logs_tree_project_ref_path(@project, @ref)
102 end 62 end
103 rescue 63 rescue
104 return render_404 64 return render_404
105 end 65 end
106 - 66 +
107 def ref 67 def ref
108 - @ref = params[:id] 68 + @ref = params[:id] || params[:ref]
109 end 69 end
110 end 70 end
app/controllers/repositories_controller.rb
@@ -3,18 +3,17 @@ class RepositoriesController &lt; ProjectController @@ -3,18 +3,17 @@ class RepositoriesController &lt; ProjectController
3 before_filter :authorize_read_project! 3 before_filter :authorize_read_project!
4 before_filter :authorize_code_access! 4 before_filter :authorize_code_access!
5 before_filter :require_non_empty_project 5 before_filter :require_non_empty_project
6 - before_filter :render_full_content  
7 6
8 def show 7 def show
9 @activities = @project.commits_with_refs(20) 8 @activities = @project.commits_with_refs(20)
10 end 9 end
11 10
12 def branches 11 def branches
13 - @branches = @project.repo.heads.sort_by(&:name) 12 + @branches = @project.branches
14 end 13 end
15 14
16 def tags 15 def tags
17 - @tags = @project.repo.tags.sort_by(&:name).reverse 16 + @tags = @project.tags
18 end 17 end
19 18
20 def archive 19 def archive
app/controllers/snippets_controller.rb
@@ -50,7 +50,6 @@ class SnippetsController &lt; ProjectController @@ -50,7 +50,6 @@ class SnippetsController &lt; ProjectController
50 50
51 def show 51 def show
52 @note = @project.notes.new(noteable: @snippet) 52 @note = @project.notes.new(noteable: @snippet)
53 - render_full_content  
54 end 53 end
55 54
56 def destroy 55 def destroy
app/controllers/tree_controller.rb 0 → 100644
@@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
  1 +# Controller for viewing a repository's file structure
  2 +class TreeController < ApplicationController
  3 + include ExtractsPath
  4 +
  5 + layout "project"
  6 +
  7 + before_filter :project
  8 +
  9 + # Authorize
  10 + before_filter :add_project_abilities
  11 + before_filter :authorize_read_project!
  12 + before_filter :authorize_code_access!
  13 + before_filter :require_non_empty_project
  14 +
  15 + before_filter :assign_ref_vars
  16 +
  17 + def show
  18 + @hex_path = Digest::SHA1.hexdigest(@path)
  19 +
  20 + @history_path = project_tree_path(@project, @id)
  21 + @logs_path = logs_file_project_ref_path(@project, @ref, @path)
  22 +
  23 + respond_to do |format|
  24 + format.html
  25 + # Disable cache so browser history works
  26 + format.js { no_cache_headers }
  27 + end
  28 + end
  29 +end
app/decorators/event_decorator.rb
@@ -21,7 +21,7 @@ class EventDecorator &lt; ApplicationDecorator @@ -21,7 +21,7 @@ class EventDecorator &lt; ApplicationDecorator
21 elsif self.merge_request? 21 elsif self.merge_request?
22 h.project_merge_request_url(self.project, self.merge_request) 22 h.project_merge_request_url(self.project, self.merge_request)
23 elsif self.push? 23 elsif self.push?
24 - h.project_commits_url(self.project, ref: self.ref_name) 24 + h.project_commits_url(self.project, self.ref_name)
25 end 25 end
26 end 26 end
27 end 27 end
app/decorators/tree_decorator.rb
@@ -6,7 +6,7 @@ class TreeDecorator &lt; ApplicationDecorator @@ -6,7 +6,7 @@ class TreeDecorator &lt; ApplicationDecorator
6 part_path = "" 6 part_path = ""
7 parts = path.split("\/") 7 parts = path.split("\/")
8 8
9 - #parts = parts[0...-1] if is_blob? 9 + #parts = parts[0...-1] if is_blob?
10 10
11 yield(h.link_to("..", "#", remote: :true)) if parts.count > max_links 11 yield(h.link_to("..", "#", remote: :true)) if parts.count > max_links
12 12
@@ -15,29 +15,29 @@ class TreeDecorator &lt; ApplicationDecorator @@ -15,29 +15,29 @@ class TreeDecorator &lt; ApplicationDecorator
15 part_path = part if part_path.empty? 15 part_path = part if part_path.empty?
16 16
17 next unless parts.last(2).include?(part) if parts.count > max_links 17 next unless parts.last(2).include?(part) if parts.count > max_links
18 - yield(h.link_to(h.truncate(part, length: 40), h.tree_file_project_ref_path(project, ref, path: part_path), remote: :true)) 18 + yield(h.link_to(h.truncate(part, length: 40), h.project_tree_path(project, h.tree_join(ref, part_path)), remote: :true))
19 end 19 end
20 end 20 end
21 end 21 end
22 22
23 def up_dir? 23 def up_dir?
24 - !!path 24 + path.present?
25 end 25 end
26 26
27 def up_dir_path 27 def up_dir_path
28 file = File.join(path, "..") 28 file = File.join(path, "..")
29 - h.tree_file_project_ref_path(project, ref, file) 29 + h.project_tree_path(project, h.tree_join(ref, file))
30 end 30 end
31 31
32 def history_path 32 def history_path
33 - h.project_commits_path(project, path: path, ref: ref) 33 + h.project_commits_path(project, h.tree_join(ref, path))
34 end 34 end
35 35
36 def mb_size 36 def mb_size
37 size = (tree.size / 1024) 37 size = (tree.size / 1024)
38 if size < 1024 38 if size < 1024
39 - "#{size} KB"  
40 - else 39 + "#{size} KB"
  40 + else
41 "#{size/1024} MB" 41 "#{size/1024} MB"
42 end 42 end
43 end 43 end
app/helpers/application_helper.rb
1 require 'digest/md5' 1 require 'digest/md5'
  2 +
2 module ApplicationHelper 3 module ApplicationHelper
3 4
  5 + # Check if a particular controller is the current one
  6 + #
  7 + # args - One or more controller names to check
  8 + #
  9 + # Examples
  10 + #
  11 + # # On TreeController
  12 + # current_controller?(:tree) # => true
  13 + # current_controller?(:commits) # => false
  14 + # current_controller?(:commits, :tree) # => true
  15 + def current_controller?(*args)
  16 + args.any? { |v| v.to_s.downcase == controller.controller_name }
  17 + end
  18 +
  19 + # Check if a partcular action is the current one
  20 + #
  21 + # args - One or more action names to check
  22 + #
  23 + # Examples
  24 + #
  25 + # # On Projects#new
  26 + # current_action?(:new) # => true
  27 + # current_action?(:create) # => false
  28 + # current_action?(:new, :create) # => true
  29 + def current_action?(*args)
  30 + args.any? { |v| v.to_s.downcase == action_name }
  31 + end
  32 +
4 def gravatar_icon(user_email = '', size = 40) 33 def gravatar_icon(user_email = '', size = 40)
5 if Gitlab.config.disable_gravatar? || user_email.blank? 34 if Gitlab.config.disable_gravatar? || user_email.blank?
6 'no_avatar.png' 35 'no_avatar.png'
@@ -31,8 +60,8 @@ module ApplicationHelper @@ -31,8 +60,8 @@ module ApplicationHelper
31 60
32 def grouped_options_refs(destination = :tree) 61 def grouped_options_refs(destination = :tree)
33 options = [ 62 options = [
34 - ["Branch", @project.repo.heads.map(&:name) ],  
35 - [ "Tag", @project.tags ] 63 + ["Branch", @project.branch_names ],
  64 + [ "Tag", @project.tag_names ]
36 ] 65 ]
37 66
38 # If reference is commit id - 67 # If reference is commit id -
@@ -58,11 +87,11 @@ module ApplicationHelper @@ -58,11 +87,11 @@ module ApplicationHelper
58 87
59 if @project && !@project.new_record? 88 if @project && !@project.new_record?
60 project_nav = [ 89 project_nav = [
61 - { label: "#{@project.name} / Issues", url: project_issues_path(@project) },  
62 - { label: "#{@project.name} / Wall", url: wall_project_path(@project) },  
63 - { label: "#{@project.name} / Tree", url: tree_project_ref_path(@project, @project.root_ref) },  
64 - { label: "#{@project.name} / Commits", url: project_commits_path(@project) },  
65 - { label: "#{@project.name} / Team", url: project_team_index_path(@project) } 90 + { label: "#{@project.name} / Issues", url: project_issues_path(@project) },
  91 + { label: "#{@project.name} / Wall", url: wall_project_path(@project) },
  92 + { label: "#{@project.name} / Tree", url: project_tree_path(@project, @ref || @project.root_ref) },
  93 + { label: "#{@project.name} / Commits", url: project_commits_path(@project, @ref || @project.root_ref) },
  94 + { label: "#{@project.name} / Team", url: project_team_index_path(@project) }
66 ] 95 ]
67 end 96 end
68 97
@@ -85,45 +114,6 @@ module ApplicationHelper @@ -85,45 +114,6 @@ module ApplicationHelper
85 event.project.merge_requests_enabled 114 event.project.merge_requests_enabled
86 end 115 end
87 116
88 - def tab_class(tab_key)  
89 - active = case tab_key  
90 -  
91 - # Project Area  
92 - when :wall; wall_tab?  
93 - when :wiki; controller.controller_name == "wikis"  
94 - when :issues; issues_tab?  
95 - when :network; current_page?(controller: "projects", action: "graph", id: @project)  
96 - when :merge_requests; controller.controller_name == "merge_requests"  
97 -  
98 - # Dashboard Area  
99 - when :help; controller.controller_name == "help"  
100 - when :search; current_page?(search_path)  
101 - when :dash_issues; current_page?(dashboard_issues_path)  
102 - when :dash_mr; current_page?(dashboard_merge_requests_path)  
103 - when :root; current_page?(dashboard_path) || current_page?(root_path)  
104 -  
105 - # Profile Area  
106 - when :profile; current_page?(controller: "profile", action: :show)  
107 - when :history; current_page?(controller: "profile", action: :history)  
108 - when :account; current_page?(controller: "profile", action: :account)  
109 - when :token; current_page?(controller: "profile", action: :token)  
110 - when :design; current_page?(controller: "profile", action: :design)  
111 - when :ssh_keys; controller.controller_name == "keys"  
112 -  
113 - # Admin Area  
114 - when :admin_root; controller.controller_name == "dashboard"  
115 - when :admin_users; controller.controller_name == 'users'  
116 - when :admin_projects; controller.controller_name == "projects"  
117 - when :admin_hooks; controller.controller_name == 'hooks'  
118 - when :admin_resque; controller.controller_name == 'resque'  
119 - when :admin_logs; controller.controller_name == 'logs'  
120 -  
121 - else  
122 - false  
123 - end  
124 - active ? "current" : nil  
125 - end  
126 -  
127 def hexdigest(string) 117 def hexdigest(string)
128 Digest::SHA1.hexdigest string 118 Digest::SHA1.hexdigest string
129 end 119 end
app/helpers/tab_helper.rb
1 module TabHelper 1 module TabHelper
2 - def issues_tab?  
3 - controller.controller_name == "issues" || controller.controller_name == "milestones"  
4 - end 2 + # Navigation link helper
  3 + #
  4 + # Returns an `li` element with an 'active' class if the supplied
  5 + # controller(s) and/or action(s) currently active. The contents of the
  6 + # element is the value passed to the block.
  7 + #
  8 + # options - The options hash used to determine if the element is "active" (default: {})
  9 + # :controller - One or more controller names to check (optional).
  10 + # :action - One or more action names to check (optional).
  11 + # :path - A shorthand path, such as 'dashboard#index', to check (optional).
  12 + # :html_options - Extra options to be passed to the list element (optional).
  13 + # block - An optional block that will become the contents of the returned
  14 + # `li` element.
  15 + #
  16 + # When both :controller and :action are specified, BOTH must match in order
  17 + # to be marked as active. When only one is given, either can match.
  18 + #
  19 + # Examples
  20 + #
  21 + # # Assuming we're on TreeController#show
  22 + #
  23 + # # Controller matches, but action doesn't
  24 + # nav_link(controller: [:tree, :refs], action: :edit) { "Hello" }
  25 + # # => '<li>Hello</li>'
  26 + #
  27 + # # Controller matches
  28 + # nav_link(controller: [:tree, :refs]) { "Hello" }
  29 + # # => '<li class="active">Hello</li>'
  30 + #
  31 + # # Shorthand path
  32 + # nav_link(path: 'tree#show') { "Hello" }
  33 + # # => '<li class="active">Hello</li>'
  34 + #
  35 + # # Supplying custom options for the list element
  36 + # nav_link(controller: :tree, html_options: {class: 'home'}) { "Hello" }
  37 + # # => '<li class="home active">Hello</li>'
  38 + #
  39 + # Returns a list item element String
  40 + def nav_link(options = {}, &block)
  41 + if path = options.delete(:path)
  42 + c, a, _ = path.split('#')
  43 + else
  44 + c = options.delete(:controller)
  45 + a = options.delete(:action)
  46 + end
  47 +
  48 + if c && a
  49 + # When given both options, make sure BOTH are active
  50 + klass = current_controller?(*c) && current_action?(*a) ? 'active' : ''
  51 + else
  52 + # Otherwise check EITHER option
  53 + klass = current_controller?(*c) || current_action?(*a) ? 'active' : ''
  54 + end
  55 +
  56 + # Add our custom class into the html_options, which may or may not exist
  57 + # and which may or may not already have a :class key
  58 + o = options.delete(:html_options) || {}
  59 + o[:class] ||= ''
  60 + o[:class] += ' ' + klass
  61 + o[:class].strip!
5 62
6 - def wall_tab?  
7 - current_page?(controller: "projects", action: "wall", id: @project) 63 + if block_given?
  64 + content_tag(:li, capture(&block), o)
  65 + else
  66 + content_tag(:li, nil, o)
  67 + end
8 end 68 end
9 69
10 def project_tab_class 70 def project_tab_class
11 [:show, :files, :edit, :update].each do |action| 71 [:show, :files, :edit, :update].each do |action|
12 - return "current" if current_page?(controller: "projects", action: action, id: @project) 72 + return "active" if current_page?(controller: "projects", action: action, id: @project)
13 end 73 end
14 74
15 if ['snippets', 'hooks', 'deploy_keys', 'team_members'].include? controller.controller_name 75 if ['snippets', 'hooks', 'deploy_keys', 'team_members'].include? controller.controller_name
16 - "current"  
17 - end  
18 - end  
19 -  
20 - def tree_tab_class  
21 - controller.controller_name == "refs" ? "current" : nil  
22 - end  
23 -  
24 - def commit_tab_class  
25 - if ['commits', 'repositories', 'protected_branches'].include? controller.controller_name  
26 - "current" 76 + "active"
27 end 77 end
28 end 78 end
29 79
30 def branches_tab_class 80 def branches_tab_class
31 if current_page?(branches_project_repository_path(@project)) || 81 if current_page?(branches_project_repository_path(@project)) ||
32 - controller.controller_name == "protected_branches" || 82 + current_controller?(:protected_branches) ||
33 current_page?(project_repository_path(@project)) 83 current_page?(project_repository_path(@project))
34 'active' 84 'active'
35 end 85 end
app/helpers/tree_helper.rb
@@ -39,4 +39,9 @@ module TreeHelper @@ -39,4 +39,9 @@ module TreeHelper
39 def gitlab_markdown?(filename) 39 def gitlab_markdown?(filename)
40 filename.end_with?(*%w(.mdown .md .markdown)) 40 filename.end_with?(*%w(.mdown .md .markdown))
41 end 41 end
  42 +
  43 + # Simple shortcut to File.join
  44 + def tree_join(*args)
  45 + File.join(*args)
  46 + end
42 end 47 end
app/models/merge_request.rb
1 -require File.join(Rails.root, "app/models/commit") 1 +require Rails.root.join("app/models/commit")
2 2
3 class MergeRequest < ActiveRecord::Base 3 class MergeRequest < ActiveRecord::Base
4 include IssueCommonality 4 include IssueCommonality
app/models/tree.rb
1 class Tree 1 class Tree
2 - include Linguist::BlobHelper 2 + include Linguist::BlobHelper
3 attr_accessor :path, :tree, :project, :ref 3 attr_accessor :path, :tree, :project, :ref
4 4
5 delegate :contents, 5 delegate :contents,
@@ -14,8 +14,8 @@ class Tree @@ -14,8 +14,8 @@ class Tree
14 to: :tree 14 to: :tree
15 15
16 def initialize(raw_tree, project, ref = nil, path = nil) 16 def initialize(raw_tree, project, ref = nil, path = nil)
17 - @project, @ref, @path = project, ref, path,  
18 - @tree = if path 17 + @project, @ref, @path = project, ref, path
  18 + @tree = if path.present?
19 raw_tree / path.dup.force_encoding('ascii-8bit') 19 raw_tree / path.dup.force_encoding('ascii-8bit')
20 else 20 else
21 raw_tree 21 raw_tree
@@ -26,6 +26,10 @@ class Tree @@ -26,6 +26,10 @@ class Tree
26 tree.is_a?(Grit::Blob) 26 tree.is_a?(Grit::Blob)
27 end 27 end
28 28
  29 + def invalid?
  30 + tree.nil?
  31 + end
  32 +
29 def empty? 33 def empty?
30 data.blank? 34 data.blank?
31 end 35 end
app/roles/repository.rb
@@ -45,8 +45,29 @@ module Repository @@ -45,8 +45,29 @@ module Repository
45 File.exists?(hook_file) 45 File.exists?(hook_file)
46 end 46 end
47 47
  48 + # Returns an Array of branch names
  49 + def branch_names
  50 + repo.branches.collect(&:name).sort
  51 + end
  52 +
  53 + # Returns an Array of Branches
  54 + def branches
  55 + repo.branches.sort_by(&:name)
  56 + end
  57 +
  58 + # Returns an Array of tag names
  59 + def tag_names
  60 + repo.tags.collect(&:name).sort.reverse
  61 + end
  62 +
  63 + # Returns an Array of Tags
48 def tags 64 def tags
49 - repo.tags.map(&:name).sort.reverse 65 + repo.tags.sort_by(&:name).reverse
  66 + end
  67 +
  68 + # Returns an Array of branch and tag names
  69 + def ref_names
  70 + [branch_names + tag_names].flatten
50 end 71 end
51 72
52 def repo 73 def repo
@@ -79,14 +100,6 @@ module Repository @@ -79,14 +100,6 @@ module Repository
79 @heads ||= repo.heads 100 @heads ||= repo.heads
80 end 101 end
81 102
82 - def branches_names  
83 - heads.map(&:name)  
84 - end  
85 -  
86 - def ref_names  
87 - [branches_names + tags].flatten  
88 - end  
89 -  
90 def tree(fcommit, path = nil) 103 def tree(fcommit, path = nil)
91 fcommit = commit if fcommit == :head 104 fcommit = commit if fcommit == :head
92 tree = fcommit.tree 105 tree = fcommit.tree
@@ -109,14 +122,12 @@ module Repository @@ -109,14 +122,12 @@ module Repository
109 # - If two or more branches are present, returns the one that has a name 122 # - If two or more branches are present, returns the one that has a name
110 # matching root_ref (default_branch or 'master' if default_branch is nil) 123 # matching root_ref (default_branch or 'master' if default_branch is nil)
111 def discover_default_branch 124 def discover_default_branch
112 - branches = heads.collect(&:name)  
113 -  
114 - if branches.length == 0 125 + if branch_names.length == 0
115 nil 126 nil
116 - elsif branches.length == 1  
117 - branches.first 127 + elsif branch_names.length == 1
  128 + branch_names.first
118 else 129 else
119 - branches.select { |v| v == root_ref }.first 130 + branch_names.select { |v| v == root_ref }.first
120 end 131 end
121 end 132 end
122 133
@@ -144,7 +155,7 @@ module Repository @@ -144,7 +155,7 @@ module Repository
144 155
145 # Build file path 156 # Build file path
146 file_name = self.code + "-" + commit.id.to_s + ".tar.gz" 157 file_name = self.code + "-" + commit.id.to_s + ".tar.gz"
147 - storage_path = File.join(Rails.root, "tmp", "repositories", self.code) 158 + storage_path = Rails.root.join("tmp", "repositories", self.code)
148 file_path = File.join(storage_path, file_name) 159 file_path = File.join(storage_path, file_name)
149 160
150 # Put files into a directory before archiving 161 # Put files into a directory before archiving
app/roles/static_model.rb
@@ -25,6 +25,10 @@ module StaticModel @@ -25,6 +25,10 @@ module StaticModel
25 id 25 id
26 end 26 end
27 27
  28 + def new_record?
  29 + false
  30 + end
  31 +
28 def persisted? 32 def persisted?
29 false 33 false
30 end 34 end
app/views/blame/_head.html.haml 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +%ul.nav.nav-tabs
  2 + %li
  3 + = render partial: 'shared/ref_switcher', locals: {destination: 'tree', path: params[:path]}
  4 + = nav_link(controller: :refs) do
  5 + = link_to 'Source', project_tree_path(@project, @ref)
  6 + %li.right
  7 + .input-prepend.project_clone_holder
  8 + %button{class: "btn small active", :"data-clone" => @project.ssh_url_to_repo} SSH
  9 + %button{class: "btn small", :"data-clone" => @project.http_url_to_repo} HTTP
  10 + = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select span5"
app/views/blame/show.html.haml 0 → 100644
@@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
  1 += render "head"
  2 +
  3 +#tree-holder
  4 + %ul.breadcrumb
  5 + %li
  6 + %span.arrow
  7 + = link_to project_tree_path(@project, @ref) do
  8 + = @project.name
  9 + - @tree.breadcrumbs(6) do |link|
  10 + \/
  11 + %li= link
  12 + .clear
  13 +
  14 + .file_holder
  15 + .file_title
  16 + %i.icon-file
  17 + %span.file_name
  18 + = @tree.name
  19 + %small blame
  20 + %span.options
  21 + = link_to "raw", project_blob_path(@project, @id), class: "btn very_small", target: "_blank"
  22 + = link_to "history", project_commits_path(@project, @id), class: "btn very_small"
  23 + = link_to "source", project_tree_path(@project, @id), class: "btn very_small"
  24 + .file_content.blame
  25 + %table
  26 + - @blame.each do |commit, lines|
  27 + - commit = Commit.new(commit)
  28 + - commit = CommitDecorator.decorate(commit)
  29 + %tr
  30 + %td.author
  31 + = image_tag gravatar_icon(commit.author_email, 16)
  32 + = commit.author_name
  33 + %td.blame_commit
  34 + &nbsp;
  35 + %code= link_to commit.short_id, project_commit_path(@project, commit)
  36 + = link_to_gfm truncate(commit.title, length: 30), project_commit_path(@project, commit), class: "row_title" rescue "--broken encoding"
  37 + %td.lines
  38 + = preserve do
  39 + %pre
  40 + = Gitlab::Encode.utf8 lines.join("\n")
app/views/commit/show.html.haml 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 += render "commits/commit_box"
  2 += render "commits/diffs", diffs: @commit.diffs
  3 += render "notes/notes_with_form", tid: @commit.id, tt: "commit"
  4 += render "notes/per_line_form"
  5 +
  6 +
  7 +:javascript
  8 + $(function(){
  9 + PerLineNotes.init();
  10 + });
app/views/commit/show.patch.erb 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +<%= @commit.to_patch %>
app/views/commits/_commit.html.haml
1 %li.commit 1 %li.commit
2 .browse_code_link_holder 2 .browse_code_link_holder
3 %p 3 %p
4 - %strong= link_to "Browse Code »", tree_project_ref_path(@project, commit.id), class: "right" 4 + %strong= link_to "Browse Code »", project_tree_path(@project, commit), class: "right"
5 %p 5 %p
6 - = link_to commit.short_id(8), project_commit_path(@project, id: commit.id), class: "commit_short_id" 6 + = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id"
7 %strong.commit-author-name= commit.author_name 7 %strong.commit-author-name= commit.author_name
8 %span.dash &ndash; 8 %span.dash &ndash;
9 = image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16 9 = image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16
10 - = link_to_gfm truncate(commit.title, length: 50), project_commit_path(@project, id: commit.id), class: "row_title" 10 + = link_to_gfm truncate(commit.title, length: 50), project_commit_path(@project, commit.id), class: "row_title"
11 11
12 %span.committed_ago 12 %span.committed_ago
13 = time_ago_in_words(commit.committed_date) 13 = time_ago_in_words(commit.committed_date)
14 ago 14 ago
15 &nbsp; 15 &nbsp;
16 -  
app/views/commits/_commit_box.html.haml
@@ -5,10 +5,10 @@ @@ -5,10 +5,10 @@
5 %span.btn.disabled.grouped 5 %span.btn.disabled.grouped
6 %i.icon-comment 6 %i.icon-comment
7 = @notes_count 7 = @notes_count
8 - = link_to patch_project_commit_path(@project, @commit.id), class: "btn small grouped" do 8 + = link_to project_commit_path(@project, @commit, format: :patch), class: "btn small grouped" do
9 %i.icon-download-alt 9 %i.icon-download-alt
10 Get Patch 10 Get Patch
11 - = link_to tree_project_ref_path(@project, @commit.id), class: "browse-button primary grouped" do 11 + = link_to project_tree_path(@project, @commit), class: "browse-button primary grouped" do
12 %strong Browse Code » 12 %strong Browse Code »
13 %h3.commit-title.page_title 13 %h3.commit-title.page_title
14 = gfm escape_once(@commit.title) 14 = gfm escape_once(@commit.title)
app/views/commits/_diffs.html.haml
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 %p To prevent performance issue we rejected diff information. 5 %p To prevent performance issue we rejected diff information.
6 %p 6 %p
7 But if you still want to see diff 7 But if you still want to see diff
8 - = link_to "click this link", project_commit_path(@project, @commit.id, force_show_diff: true), class: "dark" 8 + = link_to "click this link", project_commit_path(@project, @commit, force_show_diff: true), class: "dark"
9 9
10 %p.cgray 10 %p.cgray
11 Showing #{pluralize(diffs.count, "changed file")} 11 Showing #{pluralize(diffs.count, "changed file")}
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 %i.icon-file 24 %i.icon-file
25 %span{id: "#{diff.old_path}"}= diff.old_path 25 %span{id: "#{diff.old_path}"}= diff.old_path
26 - else 26 - else
27 - = link_to tree_file_project_ref_path(@project, @commit.id, diff.new_path) do 27 + = link_to project_tree_path(@project, tree_join(@commit.id, diff.new_path)) do
28 %i.icon-file 28 %i.icon-file
29 %span{id: "#{diff.new_path}"}= diff.new_path 29 %span{id: "#{diff.new_path}"}= diff.new_path
30 %br/ 30 %br/
app/views/commits/_head.html.haml
1 %ul.nav.nav-tabs 1 %ul.nav.nav-tabs
2 %li= render partial: 'shared/ref_switcher', locals: {destination: 'commits'} 2 %li= render partial: 'shared/ref_switcher', locals: {destination: 'commits'}
3 - %li{class: "#{'active' if current_page?(project_commits_path(@project)) }"}  
4 - = link_to project_commits_path(@project) do  
5 - Commits  
6 - %li{class: "#{'active' if current_page?(compare_project_commits_path(@project)) }"}  
7 - = link_to compare_project_commits_path(@project) do  
8 - Compare  
9 - %li{class: "#{branches_tab_class}"} 3 +
  4 + = nav_link(controller: [:commit, :commits]) do
  5 + = link_to 'Commits', project_commits_path(@project, @project.root_ref)
  6 + = nav_link(controller: :compare) do
  7 + = link_to 'Compare', project_compare_index_path(@project)
  8 +
  9 + = nav_link(html_options: {class: branches_tab_class}) do
10 = link_to project_repository_path(@project) do 10 = link_to project_repository_path(@project) do
11 Branches 11 Branches
12 %span.badge= @project.repo.branch_count 12 %span.badge= @project.repo.branch_count
13 13
14 - %li{class: "#{'active' if current_page?(tags_project_repository_path(@project)) }"} 14 + = nav_link(controller: :repositories, action: :tags) do
15 = link_to tags_project_repository_path(@project) do 15 = link_to tags_project_repository_path(@project) do
16 Tags 16 Tags
17 %span.badge= @project.repo.tag_count 17 %span.badge= @project.repo.tag_count
18 18
19 - - if current_page?(project_commits_path(@project)) && current_user.private_token 19 + - if current_controller?(:commits) && current_user.private_token
20 %li.right 20 %li.right
21 %span.rss-icon 21 %span.rss-icon
22 - = link_to project_commits_path(@project, :atom, { private_token: current_user.private_token, ref: @ref }), title: "Feed" do 22 + = link_to project_commits_path(@project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Feed" do
23 = image_tag "rss_ui.png", title: "feed" 23 = image_tag "rss_ui.png", title: "feed"
app/views/commits/compare.html.haml
@@ -1,53 +0,0 @@ @@ -1,53 +0,0 @@
1 -= render "head"  
2 -  
3 -%h3.page_title  
4 - Compare View  
5 -%hr  
6 -  
7 -%div  
8 - %p.slead  
9 - Fill input field with commit id like  
10 - %code.label_branch 4eedf23  
11 - or branch/tag name like  
12 - %code.label_branch master  
13 - and press compare button for commits list, code diff.  
14 -  
15 - %br  
16 -  
17 - = form_tag compare_project_commits_path(@project), method: :get do  
18 - .clearfix  
19 - = text_field_tag :from, params[:from], placeholder: "master", class: "xlarge"  
20 - = "..."  
21 - = text_field_tag :to, params[:to], placeholder: "aa8b4ef", class: "xlarge"  
22 - - if @refs_are_same  
23 - .alert  
24 - %span Refs are the same  
25 - .actions  
26 - = submit_tag "Compare", class: "btn primary wide commits-compare-btn"  
27 -  
28 -- if @commits.present?  
29 - %div.ui-box  
30 - %h5.small Commits (#{@commits.count})  
31 - %ul.unstyled= render @commits  
32 -  
33 - - unless @diffs.empty?  
34 - %h4 Diff  
35 - = render "commits/diffs", diffs: @diffs  
36 -  
37 -:javascript  
38 - $(function() {  
39 - var availableTags = #{@project.ref_names.to_json};  
40 -  
41 - $("#from").autocomplete({  
42 - source: availableTags,  
43 - minLength: 1  
44 - });  
45 -  
46 - $("#to").autocomplete({  
47 - source: availableTags,  
48 - minLength: 1  
49 - });  
50 -  
51 - disableButtonIfEmptyField('#to', '.commits-compare-btn');  
52 - });  
53 -  
app/views/commits/index.atom.builder
@@ -1,23 +0,0 @@ @@ -1,23 +0,0 @@
1 -xml.instruct!  
2 -xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do  
3 - xml.title "Recent commits to #{@project.name}:#{@ref}"  
4 - xml.link :href => project_commits_url(@project, :atom, :ref => @ref), :rel => "self", :type => "application/atom+xml"  
5 - xml.link :href => project_commits_url(@project), :rel => "alternate", :type => "text/html"  
6 - xml.id project_commits_url(@project)  
7 - xml.updated @commits.first.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ") if @commits.any?  
8 -  
9 - @commits.each do |commit|  
10 - xml.entry do  
11 - xml.id project_commit_url(@project, :id => commit.id)  
12 - xml.link :href => project_commit_url(@project, :id => commit.id)  
13 - xml.title truncate(commit.title, :length => 80)  
14 - xml.updated commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")  
15 - xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(commit.author_email)  
16 - xml.author do |author|  
17 - xml.name commit.author_name  
18 - xml.email commit.author_email  
19 - end  
20 - xml.summary gfm(commit.description)  
21 - end  
22 - end  
23 -end  
app/views/commits/index.html.haml
@@ -1,24 +0,0 @@ @@ -1,24 +0,0 @@
1 -= render "head"  
2 -  
3 -- if params[:path]  
4 - %ul.breadcrumb  
5 - %li  
6 - %span.arrow  
7 - = link_to project_commits_path(@project) do  
8 - = @project.name  
9 - %span.divider  
10 - \/  
11 - %li  
12 - %a{href: "#"}= params[:path].split("/").join(" / ")  
13 -  
14 -%div{id: dom_id(@project)}  
15 - #commits_list= render "commits"  
16 -.clear  
17 -.loading{ style: "display:none;"}  
18 -  
19 -- if @commits.count == @limit  
20 - :javascript  
21 - $(function(){  
22 - CommitsList.init("#{@ref}", #{@limit});  
23 - });  
24 -  
app/views/commits/index.js.haml
@@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
1 -:plain  
2 - CommitsList.append(#{@commits.count}, "#{escape_javascript(render(partial: 'commits/commits'))}");  
3 -  
app/views/commits/show.atom.builder 0 → 100644
@@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
  1 +xml.instruct!
  2 +xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
  3 + xml.title "Recent commits to #{@project.name}:#{@ref}"
  4 + xml.link :href => project_commits_url(@project, @ref, format: :atom), :rel => "self", :type => "application/atom+xml"
  5 + xml.link :href => project_commits_url(@project, @ref), :rel => "alternate", :type => "text/html"
  6 + xml.id project_commits_url(@project)
  7 + xml.updated @commits.first.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ") if @commits.any?
  8 +
  9 + @commits.each do |commit|
  10 + xml.entry do
  11 + xml.id project_commit_url(@project, :id => commit.id)
  12 + xml.link :href => project_commit_url(@project, :id => commit.id)
  13 + xml.title truncate(commit.title, :length => 80)
  14 + xml.updated commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")
  15 + xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(commit.author_email)
  16 + xml.author do |author|
  17 + xml.name commit.author_name
  18 + xml.email commit.author_email
  19 + end
  20 + xml.summary gfm(commit.description)
  21 + end
  22 + end
  23 +end
app/views/commits/show.html.haml
1 -= render "commits/commit_box"  
2 -= render "commits/diffs", diffs: @commit.diffs  
3 -= render "notes/notes_with_form", tid: @commit.id, tt: "commit"  
4 -= render "notes/per_line_form" 1 += render "head"
5 2
  3 +- if @path.present?
  4 + %ul.breadcrumb
  5 + %li
  6 + %span.arrow
  7 + = link_to project_commits_path(@project) do
  8 + = @project.name
  9 + %span.divider
  10 + \/
  11 + %li
  12 + %a{href: "#"}= @path.split("/").join(" / ")
  13 +
  14 +%div{id: dom_id(@project)}
  15 + #commits_list= render "commits"
  16 +.clear
  17 +.loading{ style: "display:none;"}
  18 +
  19 +- if @commits.count == @limit
  20 + :javascript
  21 + $(function(){
  22 + CommitsList.init("#{@ref}", #{@limit});
  23 + });
6 24
7 -:javascript  
8 - $(function(){  
9 - PerLineNotes.init();  
10 - });  
app/views/commits/show.js.haml 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +:plain
  2 + CommitsList.append(#{@commits.count}, "#{escape_javascript(render(partial: 'commits/commits'))}");
  3 +
app/views/compare/_form.html.haml 0 → 100644
@@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
  1 +%div
  2 + %p.slead
  3 + Fill input field with commit id like
  4 + %code.label_branch 4eedf23
  5 + or branch/tag name like
  6 + %code.label_branch master
  7 + and press compare button for commits list, code diff.
  8 +
  9 + %br
  10 +
  11 + = form_tag project_compare_index_path(@project), method: :post do
  12 + .clearfix
  13 + = text_field_tag :from, params[:from], placeholder: "master", class: "xlarge"
  14 + = "..."
  15 + = text_field_tag :to, params[:to], placeholder: "aa8b4ef", class: "xlarge"
  16 + - if @refs_are_same
  17 + .alert
  18 + %span Refs are the same
  19 + .actions
  20 + = submit_tag "Compare", class: "btn primary wide commits-compare-btn"
  21 +
  22 +:javascript
  23 + $(function() {
  24 + var availableTags = #{@project.ref_names.to_json};
  25 +
  26 + $("#from, #to").autocomplete({
  27 + source: availableTags,
  28 + minLength: 1
  29 + });
  30 +
  31 + disableButtonIfEmptyField('#to', '.commits-compare-btn');
  32 + });
app/views/compare/index.html.haml 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 += render "commits/head"
  2 +
  3 +%h3.page_title
  4 + Compare View
  5 +%hr
  6 +
  7 += render "form"
app/views/compare/show.html.haml 0 → 100644
@@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
  1 += render "commits/head"
  2 +
  3 +%h3.page_title
  4 + Compare View
  5 +%hr
  6 +
  7 += render "form"
  8 +
  9 +- if @commits.present?
  10 + %div.ui-box
  11 + %h5.small Commits (#{@commits.count})
  12 + %ul.unstyled= render @commits
  13 +
  14 + - unless @diffs.empty?
  15 + %h4 Diff
  16 + = render "commits/diffs", diffs: @diffs
app/views/events/_commit.html.haml
1 - commit = CommitDecorator.decorate(commit) 1 - commit = CommitDecorator.decorate(commit)
2 %li.commit 2 %li.commit
3 %p 3 %p
4 - = link_to commit.short_id(8), project_commit_path(project, id: commit.id), class: "commit_short_id" 4 + = link_to commit.short_id(8), project_commit_path(project, commit), class: "commit_short_id"
5 %span= commit.author_name 5 %span= commit.author_name
6 &ndash; 6 &ndash;
7 = image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16 7 = image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16
app/views/events/_event_last_push.html.haml
@@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
4 = image_tag gravatar_icon(event.author_email), class: "avatar" 4 = image_tag gravatar_icon(event.author_email), class: "avatar"
5 %span You pushed to 5 %span You pushed to
6 = event.ref_type 6 = event.ref_type
7 - = link_to project_commits_path(event.project, ref: event.ref_name) do 7 + = link_to project_commits_path(event.project, event.ref_name) do
8 %strong= truncate(event.ref_name, length: 28) 8 %strong= truncate(event.ref_name, length: 28)
9 at 9 at
10 %strong= link_to event.project.name, event.project 10 %strong= link_to event.project.name, event.project
app/views/events/_event_push.html.haml
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 .event-title 5 .event-title
6 %strong.author_name #{event.author_name} 6 %strong.author_name #{event.author_name}
7 %span.event_label.pushed #{event.push_action_name} #{event.ref_type} 7 %span.event_label.pushed #{event.push_action_name} #{event.ref_type}
8 - = link_to project_commits_path(event.project, ref: event.ref_name) do 8 + = link_to project_commits_path(event.project, event.ref_name) do
9 %strong= event.ref_name 9 %strong= event.ref_name
10 at 10 at
11 %strong= link_to event.project.name, event.project 11 %strong= link_to event.project.name, event.project
@@ -21,6 +21,6 @@ @@ -21,6 +21,6 @@
21 %li.commits-stat 21 %li.commits-stat
22 - if event.commits_count > 2 22 - if event.commits_count > 2
23 %span ... and #{event.commits_count - 2} more commits. 23 %span ... and #{event.commits_count - 2} more commits.
24 - = link_to compare_project_commits_path(event.project, from: event.parent_commit.id, to: event.last_commit.id) do 24 + = link_to project_compare_path(event.project, from: event.parent_commit.id, to: event.last_commit.id) do
25 %strong Compare &rarr; #{event.parent_commit.id[0..7]}...#{event.last_commit.id[0..7]} 25 %strong Compare &rarr; #{event.parent_commit.id[0..7]}...#{event.last_commit.id[0..7]}
26 .clearfix 26 .clearfix
app/views/issues/_head.html.haml
1 %ul.nav.nav-tabs 1 %ul.nav.nav-tabs
2 - %li{class: "#{'active' if current_page?(project_issues_path(@project))}"}  
3 - = link_to project_issues_path(@project), class: "tab" do  
4 - Browse Issues  
5 - %li{class: "#{'active' if current_page?(project_milestones_path(@project))}"}  
6 - = link_to project_milestones_path(@project), class: "tab" do  
7 - Milestones  
8 - %li{class: "#{'active' if current_page?(project_labels_path(@project))}"}  
9 - = link_to project_labels_path(@project), class: "tab" do  
10 - Labels 2 + = nav_link(controller: :issues) do
  3 + = link_to 'Browse Issues', project_issues_path(@project), class: "tab"
  4 + = nav_link(controller: :milestones) do
  5 + = link_to 'Milestones', project_milestones_path(@project), class: "tab"
  6 + = nav_link(controller: :labels) do
  7 + = link_to 'Labels', project_labels_path(@project), class: "tab"
11 %li.right 8 %li.right
12 %span.rss-icon 9 %span.rss-icon
13 = link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do 10 = link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do
app/views/layouts/_app_menu.html.haml
@@ -1,19 +0,0 @@ @@ -1,19 +0,0 @@
1 -%ul.main_menu  
2 - %li.home{class: tab_class(:root)}  
3 - = link_to "Home", root_path, title: "Home"  
4 -  
5 - %li{class: tab_class(:dash_issues)}  
6 - = link_to dashboard_issues_path do  
7 - Issues  
8 - %span.count= current_user.assigned_issues.opened.count  
9 -  
10 - %li{class: tab_class(:dash_mr)}  
11 - = link_to dashboard_merge_requests_path do  
12 - Merge Requests  
13 - %span.count= current_user.cared_merge_requests.count  
14 -  
15 - %li{class: tab_class(:search)}  
16 - = link_to "Search", search_path  
17 -  
18 - %li{class: tab_class(:help)}  
19 - = link_to "Help", help_path  
app/views/layouts/_head.html.haml
@@ -10,8 +10,8 @@ @@ -10,8 +10,8 @@
10 - if controller_name == 'projects' && action_name == 'index' 10 - if controller_name == 'projects' && action_name == 'index'
11 = auto_discovery_link_tag :atom, projects_url(:atom, private_token: current_user.private_token), title: "Dashboard feed" 11 = auto_discovery_link_tag :atom, projects_url(:atom, private_token: current_user.private_token), title: "Dashboard feed"
12 - if @project && !@project.new_record? 12 - if @project && !@project.new_record?
13 - - if current_page?(tree_project_ref_path(@project, @project.root_ref)) || current_page?(project_commits_path(@project))  
14 - = 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}")  
15 - - if request.path == project_issues_path(@project) 13 + - if current_controller?(:tree, :commits)
  14 + = 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}")
  15 + - if current_controller?(:issues)
16 = auto_discovery_link_tag(:atom, project_issues_url(@project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues") 16 = auto_discovery_link_tag(:atom, project_issues_url(@project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues")
17 = csrf_meta_tags 17 = csrf_meta_tags
app/views/layouts/_project_menu.html.haml
@@ -1,37 +0,0 @@ @@ -1,37 +0,0 @@
1 -%ul.main_menu  
2 - %li.home{class: project_tab_class}  
3 - = link_to @project.code, project_path(@project), title: "Project"  
4 -  
5 - - if @project.repo_exists?  
6 - - if can? current_user, :download_code, @project  
7 - %li{class: tree_tab_class}  
8 - = link_to tree_project_ref_path(@project, @project.root_ref) do  
9 - Files  
10 - %li{class: commit_tab_class}  
11 - = link_to "Commits", project_commits_path(@project)  
12 -  
13 - %li{class: tab_class(:network)}  
14 - = link_to "Network", graph_project_path(@project)  
15 -  
16 - - if @project.issues_enabled  
17 - %li{class: tab_class(:issues)}  
18 - = link_to project_issues_filter_path(@project) do  
19 - Issues  
20 - %span.count.issue_counter= @project.issues.opened.count  
21 -  
22 - - if @project.repo_exists?  
23 - - if @project.merge_requests_enabled  
24 - %li{class: tab_class(:merge_requests)}  
25 - = link_to project_merge_requests_path(@project) do  
26 - Merge Requests  
27 - %span.count.merge_counter= @project.merge_requests.opened.count  
28 -  
29 - - if @project.wall_enabled  
30 - %li{class: tab_class(:wall)}  
31 - = link_to wall_project_path(@project) do  
32 - Wall  
33 -  
34 - - if @project.wiki_enabled  
35 - %li{class: tab_class(:wiki)}  
36 - = link_to project_wiki_path(@project, :index) do  
37 - Wiki  
app/views/layouts/admin.html.haml
@@ -6,17 +6,17 @@ @@ -6,17 +6,17 @@
6 = render "layouts/head_panel", title: "Admin area" 6 = render "layouts/head_panel", title: "Admin area"
7 .container 7 .container
8 %ul.main_menu 8 %ul.main_menu
9 - %li.home{class: tab_class(:admin_root)} 9 + = nav_link(controller: :dashboard, html_options: {class: 'home'}) do
10 = link_to "Stats", admin_root_path 10 = link_to "Stats", admin_root_path
11 - %li{class: tab_class(:admin_projects)} 11 + = nav_link(controller: :projects) do
12 = link_to "Projects", admin_projects_path 12 = link_to "Projects", admin_projects_path
13 - %li{class: tab_class(:admin_users)} 13 + = nav_link(controller: :users) do
14 = link_to "Users", admin_users_path 14 = link_to "Users", admin_users_path
15 - %li{class: tab_class(:admin_logs)} 15 + = nav_link(controller: :logs) do
16 = link_to "Logs", admin_logs_path 16 = link_to "Logs", admin_logs_path
17 - %li{class: tab_class(:admin_hooks)} 17 + = nav_link(controller: :hooks) do
18 = link_to "Hooks", admin_hooks_path 18 = link_to "Hooks", admin_hooks_path
19 - %li{class: tab_class(:admin_resque)} 19 + = nav_link(controller: :resque) do
20 = link_to "Resque", admin_resque_path 20 = link_to "Resque", admin_resque_path
21 21
22 .content= yield 22 .content= yield
app/views/layouts/application.html.haml
@@ -5,6 +5,20 @@ @@ -5,6 +5,20 @@
5 = render "layouts/flash" 5 = render "layouts/flash"
6 = render "layouts/head_panel", title: "Dashboard" 6 = render "layouts/head_panel", title: "Dashboard"
7 .container 7 .container
8 - = render partial: "layouts/app_menu"  
9 - .content  
10 - = yield 8 + %ul.main_menu
  9 + = nav_link(path: 'dashboard#index', html_options: {class: 'home'}) do
  10 + = link_to "Home", root_path, title: "Home"
  11 + = nav_link(path: 'dashboard#issues') do
  12 + = link_to dashboard_issues_path do
  13 + Issues
  14 + %span.count= current_user.assigned_issues.opened.count
  15 + = nav_link(path: 'dashboard#merge_requests') do
  16 + = link_to dashboard_merge_requests_path do
  17 + Merge Requests
  18 + %span.count= current_user.cared_merge_requests.count
  19 + = nav_link(path: 'search#show') do
  20 + = link_to "Search", search_path
  21 + = nav_link(path: 'help#index') do
  22 + = link_to "Help", help_path
  23 +
  24 + .content= yield
app/views/layouts/profile.html.haml
@@ -6,23 +6,17 @@ @@ -6,23 +6,17 @@
6 = render "layouts/head_panel", title: "Profile" 6 = render "layouts/head_panel", title: "Profile"
7 .container 7 .container
8 %ul.main_menu 8 %ul.main_menu
9 - %li.home{class: tab_class(:profile)} 9 + = nav_link(path: 'profile#show', html_options: {class: 'home'}) do
10 = link_to "Profile", profile_path 10 = link_to "Profile", profile_path
11 -  
12 - %li{class: tab_class(:account)} 11 + = nav_link(path: 'profile#account') do
13 = link_to "Account", profile_account_path 12 = link_to "Account", profile_account_path
14 -  
15 - %li{class: tab_class(:ssh_keys)} 13 + = nav_link(controller: :keys) do
16 = link_to keys_path do 14 = link_to keys_path do
17 SSH Keys 15 SSH Keys
18 %span.count= current_user.keys.count 16 %span.count= current_user.keys.count
19 -  
20 - %li{class: tab_class(:design)} 17 + = nav_link(path: 'profile#design') do
21 = link_to "Design", profile_design_path 18 = link_to "Design", profile_design_path
22 -  
23 - %li{class: tab_class(:history)} 19 + = nav_link(path: 'profile#history') do
24 = link_to "History", profile_history_path 20 = link_to "History", profile_history_path
25 21
26 -  
27 - .content  
28 - = yield 22 + .content= yield
app/views/layouts/project.html.haml
@@ -5,7 +5,37 @@ @@ -5,7 +5,37 @@
5 = render "layouts/flash" 5 = render "layouts/flash"
6 = render "layouts/head_panel", title: @project.name 6 = render "layouts/head_panel", title: @project.name
7 .container 7 .container
8 - = render partial: "layouts/project_menu"  
9 - .content  
10 - = yield 8 + %ul.main_menu
  9 + = nav_link(html_options: {class: "home #{project_tab_class}"}) do
  10 + = link_to @project.code, project_path(@project), title: "Project"
11 11
  12 + - if @project.repo_exists?
  13 + - if can? current_user, :download_code, @project
  14 + = nav_link(controller: %w(tree blob blame)) do
  15 + = link_to 'Files', project_tree_path(@project, @ref || @project.root_ref)
  16 + = nav_link(controller: %w(commit commits compare repositories protected_branches)) do
  17 + = link_to "Commits", project_commits_path(@project, @ref || @project.root_ref)
  18 + = nav_link(path: 'projects#graph') do
  19 + = link_to "Network", graph_project_path(@project)
  20 +
  21 + - if @project.issues_enabled
  22 + = nav_link(controller: %w(issues milestones labels)) do
  23 + = link_to project_issues_filter_path(@project) do
  24 + Issues
  25 + %span.count.issue_counter= @project.issues.opened.count
  26 +
  27 + - if @project.repo_exists? && @project.merge_requests_enabled
  28 + = nav_link(controller: :merge_requests) do
  29 + = link_to project_merge_requests_path(@project) do
  30 + Merge Requests
  31 + %span.count.merge_counter= @project.merge_requests.opened.count
  32 +
  33 + - if @project.wall_enabled
  34 + = nav_link(path: 'projects#wall') do
  35 + = link_to 'Wall', wall_project_path(@project)
  36 +
  37 + - if @project.wiki_enabled
  38 + = nav_link(controller: :wikis) do
  39 + = link_to 'Wiki', project_wiki_path(@project, :index)
  40 +
  41 + .content= yield
app/views/projects/_project_head.html.haml
1 %ul.nav.nav-tabs 1 %ul.nav.nav-tabs
2 - %li{ class: "#{'active' if current_page?(project_path(@project)) }" } 2 + = nav_link(path: 'projects#show') do
3 = link_to project_path(@project), class: "activities-tab tab" do 3 = link_to project_path(@project), class: "activities-tab tab" do
4 %i.icon-home 4 %i.icon-home
5 Show 5 Show
6 - %li{ class: " #{'active' if (controller.controller_name == "team_members") || current_page?(project_team_index_path(@project)) }" } 6 + = nav_link(controller: :team_members) do
7 = link_to project_team_index_path(@project), class: "team-tab tab" do 7 = link_to project_team_index_path(@project), class: "team-tab tab" do
8 %i.icon-user 8 %i.icon-user
9 Team 9 Team
10 - %li{ class: "#{'active' if current_page?(files_project_path(@project)) }" }  
11 - = link_to files_project_path(@project), class: "files-tab tab " do  
12 - Attachments  
13 - %li{ class: " #{'active' if (controller.controller_name == "snippets") }" }  
14 - = link_to project_snippets_path(@project), class: "snippets-tab tab" do  
15 - Snippets 10 + = nav_link(path: 'projects#files') do
  11 + = link_to 'Attachments', files_project_path(@project), class: "files-tab tab"
  12 + = nav_link(controller: :snippets) do
  13 + = link_to 'Snippets', project_snippets_path(@project), class: "snippets-tab tab"
16 14
17 - if can? current_user, :admin_project, @project 15 - if can? current_user, :admin_project, @project
18 - %li.right{class: "#{'active' if controller.controller_name == "deploy_keys"}"} 16 + = nav_link(controller: :deploy_keys, html_options: {class: 'right'}) do
19 = link_to project_deploy_keys_path(@project) do 17 = link_to project_deploy_keys_path(@project) do
20 %span 18 %span
21 Deploy Keys 19 Deploy Keys
22 - %li.right{class: "#{'active' if controller.controller_name == "hooks" }"} 20 + = nav_link(controller: :hooks, html_options: {class: 'right'}) do
23 = link_to project_hooks_path(@project) do 21 = link_to project_hooks_path(@project) do
24 %span 22 %span
25 Hooks 23 Hooks
26 - %li.right{ class: "#{'active' if current_page?(edit_project_path(@project)) }" } 24 + = nav_link(path: 'projects#edit', html_options: {class: 'right'}) do
27 = link_to edit_project_path(@project), class: "stat-tab tab " do 25 = link_to edit_project_path(@project), class: "stat-tab tab " do
28 %i.icon-edit 26 %i.icon-edit
29 Edit 27 Edit
app/views/protected_branches/index.html.haml
@@ -34,7 +34,7 @@ @@ -34,7 +34,7 @@
34 - @branches.each do |branch| 34 - @branches.each do |branch|
35 %tr 35 %tr
36 %td 36 %td
37 - = link_to project_commits_path(@project, ref: branch.name) do 37 + = link_to project_commits_path(@project, branch.name) do
38 %strong= branch.name 38 %strong= branch.name
39 - if branch.name == @project.root_ref 39 - if branch.name == @project.root_ref
40 %span.label default 40 %span.label default
app/views/refs/_head.html.haml
@@ -1,11 +0,0 @@ @@ -1,11 +0,0 @@
1 -%ul.nav.nav-tabs  
2 - %li  
3 - = render partial: 'shared/ref_switcher', locals: {destination: 'tree', path: params[:path]}  
4 - %li{class: "#{'active' if (controller.controller_name == "refs") }"}  
5 - = link_to tree_project_ref_path(@project, @ref) do  
6 - Source  
7 - %li.right  
8 - .input-prepend.project_clone_holder  
9 - %button{class: "btn small active", :"data-clone" => @project.ssh_url_to_repo} SSH  
10 - %button{class: "btn small", :"data-clone" => @project.http_url_to_repo} HTTP  
11 - = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select span5"  
app/views/refs/_submodule_item.html.haml
@@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
1 -- url = content.url(@ref) rescue nil  
2 -- name = content.basename  
3 -- return unless url  
4 -%tr{ class: "tree-item", url: url }  
5 - %td.tree-item-file-name  
6 - = image_tag "submodule.png"  
7 - %strong= truncate(name, length: 40)  
8 - %td  
9 - %code= content.id[0..10]  
10 - %td  
11 - = link_to truncate(url, length: 40), url  
12 -  
13 -  
app/views/refs/_tree.html.haml
@@ -1,70 +0,0 @@ @@ -1,70 +0,0 @@
1 -%ul.breadcrumb  
2 - %li  
3 - %span.arrow  
4 - = link_to tree_project_ref_path(@project, @ref, path: nil), remote: true do  
5 - = @project.name  
6 - - tree.breadcrumbs(6) do |link|  
7 - \/  
8 - %li= link  
9 -.clear  
10 -%div.tree_progress  
11 -#tree-content-holder  
12 - - if tree.is_blob?  
13 - = render partial: "refs/tree_file", locals: { name: tree.name, content: tree.data, file: tree }  
14 - - else  
15 - - contents = tree.contents  
16 - %table#tree-slider{class: "table_#{@hex_path}" }  
17 - %thead  
18 - %th Name  
19 - %th Last Update  
20 - %th  
21 - Last commit  
22 - = link_to "History", tree.history_path, class: "right"  
23 -  
24 - - if tree.up_dir?  
25 - %tr{ class: "tree-item", url: tree.up_dir_path }  
26 - %td.tree-item-file-name  
27 - = image_tag "file_empty.png"  
28 - = link_to "..", tree.up_dir_path, remote: :true  
29 - %td  
30 - %td  
31 -  
32 - - index = 0  
33 - - contents.select{ |i| i.is_a?(Grit::Tree)}.each do |content|  
34 - = render partial: "refs/tree_item", locals: { content: content, index: (index += 1) }  
35 - - contents.select{ |i| i.is_a?(Grit::Blob)}.each do |content|  
36 - = render partial: "refs/tree_item", locals: { content: content, index: (index += 1) }  
37 - - contents.select{ |i| i.is_a?(Grit::Submodule)}.each do |content|  
38 - = render partial: "refs/submodule_item", locals: { content: content, index: (index += 1) }  
39 -  
40 - - if content = contents.select{ |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i }.first  
41 - .file_holder#README  
42 - .file_title  
43 - %i.icon-file  
44 - = content.name  
45 - .file_content.wiki  
46 - - if gitlab_markdown?(content.name)  
47 - = preserve do  
48 - = markdown(content.data)  
49 - - else  
50 - = raw GitHub::Markup.render(content.name, content.data)  
51 -  
52 -:javascript  
53 - $(function(){  
54 - history.pushState({ path: this.path }, '', "#{@history_path}");  
55 - });  
56 -  
57 -- unless tree.is_blob?  
58 - :javascript  
59 - // Load last commit log for each file in tree  
60 - $(window).load(function(){  
61 - ajaxGet('#{@logs_path}');  
62 - });  
63 -  
64 -- if params[:path] && request.xhr?  
65 - :javascript  
66 - $(window).unbind('popstate');  
67 - $(window).bind('popstate', function() {  
68 - if(location.pathname.search("tree") != -1) {  
69 - $.ajax({type: "GET", url: location.pathname, dataType: "script"})}  
70 - else { location.href = location.pathname;}});  
app/views/refs/_tree_commit.html.haml
@@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
1 -- if tm  
2 - = link_to "[#{tm.user_name}]", project_team_member_path(@project, tm)  
3 -= link_to_gfm truncate(content_commit.title, length: tm ? 30 : 50), project_commit_path(@project, content_commit.id), class: "tree-commit-link"  
app/views/refs/_tree_file.html.haml
@@ -1,40 +0,0 @@ @@ -1,40 +0,0 @@
1 -.file_holder  
2 - .file_title  
3 - %i.icon-file  
4 - %span.file_name  
5 - = name.force_encoding('utf-8')  
6 - %small #{file.mode}  
7 - %span.options  
8 - = link_to "raw", blob_project_ref_path(@project, @ref, path: params[:path]), class: "btn very_small", target: "_blank"  
9 - = link_to "history", project_commits_path(@project, path: params[:path], ref: @ref), class: "btn very_small"  
10 - = link_to "blame", blame_file_project_ref_path(@project, @ref, path: params[:path]), class: "btn very_small"  
11 - - if file.text?  
12 - - if gitlab_markdown?(name)  
13 - .file_content.wiki  
14 - = preserve do  
15 - = markdown(file.data)  
16 - - elsif markup?(name)  
17 - .file_content.wiki  
18 - = raw GitHub::Markup.render(name, file.data)  
19 - - else  
20 - .file_content.code  
21 - - unless file.empty?  
22 - %div{class: current_user.dark_scheme ? "black" : "white"}  
23 - = preserve do  
24 - = raw file.colorize(options: { linenos: 'True'})  
25 - - else  
26 - %h4.nothing_here_message Empty file  
27 -  
28 - - elsif file.image?  
29 - .file_content.image_file  
30 - %img{ src: "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"}  
31 -  
32 - - else  
33 - .file_content.blob_file  
34 - %center  
35 - = link_to blob_project_ref_path(@project, @ref, path: params[:path]) do  
36 - %div.padded  
37 - %br  
38 - = image_tag "download.png", width: 64  
39 - %h3  
40 - Download (#{file.mb_size})  
app/views/refs/_tree_item.html.haml
@@ -1,11 +0,0 @@ @@ -1,11 +0,0 @@
1 -- file = tree_full_path(content)  
2 -%tr{ class: "tree-item #{tree_hex_class(content)}", url: tree_file_project_ref_path(@project, @ref, file) }  
3 - %td.tree-item-file-name  
4 - = tree_icon(content)  
5 - %strong= link_to truncate(content.name, length: 40), tree_file_project_ref_path(@project, @ref || @commit.id, file), remote: :true  
6 - %td.tree_time_ago.cgray  
7 - - if index == 1  
8 - %span.log_loading  
9 - Loading commit data..  
10 - = image_tag "ajax_loader_tree.gif", width: 14  
11 - %td.tree_commit  
app/views/refs/blame.html.haml
@@ -1,40 +0,0 @@ @@ -1,40 +0,0 @@
1 -= render "head"  
2 -  
3 -#tree-holder  
4 - %ul.breadcrumb  
5 - %li  
6 - %span.arrow  
7 - = link_to tree_project_ref_path(@project, @ref, path: nil) do  
8 - = @project.name  
9 - - @tree.breadcrumbs(6) do |link|  
10 - \/  
11 - %li= link  
12 - .clear  
13 -  
14 - .file_holder  
15 - .file_title  
16 - %i.icon-file  
17 - %span.file_name  
18 - = @tree.name  
19 - %small blame  
20 - %span.options  
21 - = link_to "raw", blob_project_ref_path(@project, @ref, path: params[:path]), class: "btn very_small", target: "_blank"  
22 - = link_to "history", project_commits_path(@project, path: params[:path], ref: @ref), class: "btn very_small"  
23 - = link_to "source", tree_file_project_ref_path(@project, @ref, path: params[:path]), class: "btn very_small"  
24 - .file_content.blame  
25 - %table  
26 - - @blame.each do |commit, lines|  
27 - - commit = Commit.new(commit)  
28 - - commit = CommitDecorator.decorate(commit)  
29 - %tr  
30 - %td.author  
31 - = image_tag gravatar_icon(commit.author_email, 16)  
32 - = commit.author_name  
33 - %td.blame_commit  
34 - &nbsp;  
35 - %code= link_to commit.short_id, project_commit_path(@project, id: commit.id)  
36 - = link_to_gfm truncate(commit.title, length: 30), project_commit_path(@project, id: commit.id), class: "row_title" rescue "--broken encoding"  
37 - %td.lines  
38 - = preserve do  
39 - %pre  
40 - = Gitlab::Encode.utf8 lines.join("\n")  
app/views/refs/logs_tree.js.haml
@@ -6,4 +6,4 @@ @@ -6,4 +6,4 @@
6 :plain 6 :plain
7 var row = $("table.table_#{@hex_path} tr.file_#{hexdigest(file_name)}"); 7 var row = $("table.table_#{@hex_path} tr.file_#{hexdigest(file_name)}");
8 row.find("td.tree_time_ago").html('#{escape_javascript(time_ago_in_words(content_commit.committed_date))} ago'); 8 row.find("td.tree_time_ago").html('#{escape_javascript(time_ago_in_words(content_commit.committed_date))} ago');
9 - row.find("td.tree_commit").html('#{escape_javascript(render("tree_commit", tm: tm, content_commit: content_commit))}'); 9 + row.find("td.tree_commit").html('#{escape_javascript(render("tree/tree_commit", tm: tm, content_commit: content_commit))}');
app/views/refs/tree.html.haml
@@ -1,7 +0,0 @@ @@ -1,7 +0,0 @@
1 -= render "head"  
2 -#tree-holder= render partial: "tree", locals: {repo: @repo, commit: @commit, tree: @tree}  
3 -  
4 -:javascript  
5 - $(function() {  
6 - Tree.init();  
7 - });  
app/views/refs/tree.js.haml
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -:plain  
2 - // Load Files list  
3 - $("#tree-holder").html("#{escape_javascript(render(partial: "tree", locals: {repo: @repo, commit: @commit, tree: @tree}))}");  
4 - $("#tree-content-holder").show("slide", { direction: "right" }, 150);  
5 - $('.project-refs-form #path').val("#{params[:path]}");  
6 -  
7 - // Load last commit log for each file in tree  
8 - $('#tree-slider').waitForImages(function() {  
9 - ajaxGet('#{@logs_path}');  
10 - });  
app/views/repositories/_branch.html.haml
@@ -2,12 +2,12 @@ @@ -2,12 +2,12 @@
2 - commit = CommitDecorator.decorate(commit) 2 - commit = CommitDecorator.decorate(commit)
3 %tr 3 %tr
4 %td 4 %td
5 - = link_to project_commits_path(@project, ref: branch.name) do 5 + = link_to project_commits_path(@project, branch.name) do
6 %strong= truncate(branch.name, length: 60) 6 %strong= truncate(branch.name, length: 60)
7 - if branch.name == @project.root_ref 7 - if branch.name == @project.root_ref
8 %span.label default 8 %span.label default
9 %td 9 %td
10 - = link_to project_commit_path(@project, id: commit.id) do 10 + = link_to project_commit_path(@project, commit) do
11 %code= commit.short_id 11 %code= commit.short_id
12 12
13 = image_tag gravatar_icon(commit.author_email), class: "", width: 16 13 = image_tag gravatar_icon(commit.author_email), class: "", width: 16
app/views/repositories/_branches_head.html.haml
1 = render "commits/head" 1 = render "commits/head"
2 %ul.nav.nav-pills 2 %ul.nav.nav-pills
3 - %li{class: ("active" if current_page?(project_repository_path(@project)))}  
4 - = link_to project_repository_path(@project) do  
5 - Recent  
6 - %li{class: ("active" if current_page?(project_protected_branches_path(@project)))}  
7 - = link_to project_protected_branches_path(@project) do  
8 - Protected  
9 - %li{class: ("active" if current_page?(branches_project_repository_path(@project)))}  
10 - = link_to branches_project_repository_path(@project) do  
11 - All 3 + = nav_link(path: 'repositories#show') do
  4 + = link_to 'Recent', project_repository_path(@project)
  5 + = nav_link(path: 'protected_branches#index') do
  6 + = link_to 'Protected', project_protected_branches_path(@project)
  7 + = nav_link(path: 'repositories#branches') do
  8 + = link_to 'All', branches_project_repository_path(@project)
app/views/repositories/_feed.html.haml
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 - commit = CommitDecorator.new(commit) 2 - commit = CommitDecorator.new(commit)
3 %tr 3 %tr
4 %td 4 %td
5 - = link_to project_commits_path(@project, ref: commit.head.name) do 5 + = link_to project_commits_path(@project, commit.head.name) do
6 %strong 6 %strong
7 = commit.head.name 7 = commit.head.name
8 - if commit.head.name == @project.root_ref 8 - if commit.head.name == @project.root_ref
app/views/repositories/tags.html.haml
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@
12 - commit = CommitDecorator.decorate(commit) 12 - commit = CommitDecorator.decorate(commit)
13 %tr 13 %tr
14 %td 14 %td
15 - %strong= link_to tag.name, project_commits_path(@project, ref: tag.name), class: "" 15 + %strong= link_to tag.name, project_commits_path(@project, tag.name), class: ""
16 %td 16 %td
17 = link_to project_commit_path(@project, commit.id) do 17 = link_to project_commit_path(@project, commit.id) do
18 %code= commit.short_id 18 %code= commit.short_id
app/views/shared/_ref_switcher.html.haml
1 = form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form" do 1 = form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form" do
2 = select_tag "ref", grouped_options_refs, class: "project-refs-select chosen" 2 = select_tag "ref", grouped_options_refs, class: "project-refs-select chosen"
3 = hidden_field_tag :destination, destination 3 = hidden_field_tag :destination, destination
4 - - if respond_to?(:path) 4 + - if defined?(path)
5 = hidden_field_tag :path, path 5 = hidden_field_tag :path, path
app/views/tree/_head.html.haml 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +%ul.nav.nav-tabs
  2 + %li
  3 + = render partial: 'shared/ref_switcher', locals: {destination: 'tree', path: @path}
  4 + = nav_link(controller: :tree) do
  5 + = link_to 'Source', project_tree_path(@project, @ref)
  6 + %li.right
  7 + .input-prepend.project_clone_holder
  8 + %button{class: "btn small active", :"data-clone" => @project.ssh_url_to_repo} SSH
  9 + %button{class: "btn small", :"data-clone" => @project.http_url_to_repo} HTTP
  10 + = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select span5"
app/views/tree/_submodule_item.html.haml 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +- url = content.url(@ref) rescue nil
  2 +- name = content.basename
  3 +- return unless url
  4 +%tr{ class: "tree-item", url: url }
  5 + %td.tree-item-file-name
  6 + = image_tag "submodule.png"
  7 + %strong= truncate(name, length: 40)
  8 + %td
  9 + %code= content.id[0..10]
  10 + %td
  11 + = link_to truncate(url, length: 40), url
  12 +
  13 +
app/views/tree/_tree.html.haml 0 → 100644
@@ -0,0 +1,70 @@ @@ -0,0 +1,70 @@
  1 +%ul.breadcrumb
  2 + %li
  3 + %span.arrow
  4 + = link_to project_tree_path(@project, @ref), remote: true do
  5 + = @project.name
  6 + - tree.breadcrumbs(6) do |link|
  7 + \/
  8 + %li= link
  9 +.clear
  10 +%div.tree_progress
  11 +#tree-content-holder
  12 + - if tree.is_blob?
  13 + = render partial: "tree/tree_file", locals: { name: tree.name, content: tree.data, file: tree }
  14 + - else
  15 + - contents = tree.contents
  16 + %table#tree-slider{class: "table_#{@hex_path}" }
  17 + %thead
  18 + %th Name
  19 + %th Last Update
  20 + %th
  21 + Last commit
  22 + = link_to "History", tree.history_path, class: "right"
  23 +
  24 + - if tree.up_dir?
  25 + %tr{ class: "tree-item", url: tree.up_dir_path }
  26 + %td.tree-item-file-name
  27 + = image_tag "file_empty.png"
  28 + = link_to "..", tree.up_dir_path, remote: :true
  29 + %td
  30 + %td
  31 +
  32 + - index = 0
  33 + - contents.select{ |i| i.is_a?(Grit::Tree)}.each do |content|
  34 + = render partial: "tree/tree_item", locals: { content: content, index: (index += 1) }
  35 + - contents.select{ |i| i.is_a?(Grit::Blob)}.each do |content|
  36 + = render partial: "tree/tree_item", locals: { content: content, index: (index += 1) }
  37 + - contents.select{ |i| i.is_a?(Grit::Submodule)}.each do |content|
  38 + = render partial: "tree/submodule_item", locals: { content: content, index: (index += 1) }
  39 +
  40 + - if content = contents.select{ |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i }.first
  41 + .file_holder#README
  42 + .file_title
  43 + %i.icon-file
  44 + = content.name
  45 + .file_content.wiki
  46 + - if gitlab_markdown?(content.name)
  47 + = preserve do
  48 + = markdown(content.data)
  49 + - else
  50 + = raw GitHub::Markup.render(content.name, content.data)
  51 +
  52 +:javascript
  53 + $(function(){
  54 + history.pushState({ path: this.path }, '', "#{@history_path}");
  55 + });
  56 +
  57 +- unless tree.is_blob?
  58 + :javascript
  59 + // Load last commit log for each file in tree
  60 + $(window).load(function(){
  61 + ajaxGet('#{@logs_path}');
  62 + });
  63 +
  64 +- if params[:path] && request.xhr?
  65 + :javascript
  66 + $(window).unbind('popstate');
  67 + $(window).bind('popstate', function() {
  68 + if(location.pathname.search("tree") != -1) {
  69 + $.ajax({type: "GET", url: location.pathname, dataType: "script"})}
  70 + else { location.href = location.pathname;}});
app/views/tree/_tree_commit.html.haml 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +- if tm
  2 + = link_to "[#{tm.user_name}]", project_team_member_path(@project, tm)
  3 += link_to_gfm truncate(content_commit.title, length: tm ? 30 : 50), project_commit_path(@project, content_commit.id), class: "tree-commit-link"
app/views/tree/_tree_file.html.haml 0 → 100644
@@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
  1 +.file_holder
  2 + .file_title
  3 + %i.icon-file
  4 + %span.file_name
  5 + = name.force_encoding('utf-8')
  6 + %small #{file.mode}
  7 + %span.options
  8 + = link_to "raw", project_blob_path(@project, @id), class: "btn very_small", target: "_blank"
  9 + = link_to "history", project_commits_path(@project, @id), class: "btn very_small"
  10 + = link_to "blame", project_blame_path(@project, @id), class: "btn very_small"
  11 + - if file.text?
  12 + - if gitlab_markdown?(name)
  13 + .file_content.wiki
  14 + = preserve do
  15 + = markdown(file.data)
  16 + - elsif markup?(name)
  17 + .file_content.wiki
  18 + = raw GitHub::Markup.render(name, file.data)
  19 + - else
  20 + .file_content.code
  21 + - unless file.empty?
  22 + %div{class: current_user.dark_scheme ? "black" : "white"}
  23 + = preserve do
  24 + = raw file.colorize(options: { linenos: 'True'})
  25 + - else
  26 + %h4.nothing_here_message Empty file
  27 +
  28 + - elsif file.image?
  29 + .file_content.image_file
  30 + %img{ src: "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"}
  31 +
  32 + - else
  33 + .file_content.blob_file
  34 + %center
  35 + = link_to project_blob_path(@project, @id) do
  36 + %div.padded
  37 + %br
  38 + = image_tag "download.png", width: 64
  39 + %h3
  40 + Download (#{file.mb_size})
app/views/tree/_tree_item.html.haml 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +- file = tree_full_path(content)
  2 +%tr{ class: "tree-item #{tree_hex_class(content)}", url: project_tree_path(@project, tree_join(@id, file)) }
  3 + %td.tree-item-file-name
  4 + = tree_icon(content)
  5 + %strong= link_to truncate(content.name, length: 40), project_tree_path(@project, tree_join(@id || @commit.id, file)), remote: :true
  6 + %td.tree_time_ago.cgray
  7 + - if index == 1
  8 + %span.log_loading
  9 + Loading commit data..
  10 + = image_tag "ajax_loader_tree.gif", width: 14
  11 + %td.tree_commit
app/views/tree/show.html.haml 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 += render "head"
  2 +#tree-holder= render partial: "tree", locals: {commit: @commit, tree: @tree}
  3 +
  4 +:javascript
  5 + $(function() {
  6 + Tree.init();
  7 + });
app/views/tree/show.js.haml 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +:plain
  2 + // Load Files list
  3 + $("#tree-holder").html("#{escape_javascript(render(partial: "tree", locals: {commit: @commit, tree: @tree}))}");
  4 + $("#tree-content-holder").show("slide", { direction: "right" }, 150);
  5 + $('.project-refs-form #path').val("#{@path}");
  6 +
  7 + // Load last commit log for each file in tree
  8 + $('#tree-slider').waitForImages(function() {
  9 + ajaxGet('#{@logs_path}');
  10 + });
config/initializers/1_settings.rb
@@ -112,7 +112,7 @@ class Settings &lt; Settingslogic @@ -112,7 +112,7 @@ class Settings &lt; Settingslogic
112 112
113 def backup_path 113 def backup_path
114 t = app['backup_path'] || "backups/" 114 t = app['backup_path'] || "backups/"
115 - t = /^\//.match(t) ? t : File.join(Rails.root + t) 115 + t = /^\//.match(t) ? t : Rails.root .join(t)
116 t 116 t
117 end 117 end
118 118
config/initializers/inflections.rb
@@ -8,3 +8,24 @@ @@ -8,3 +8,24 @@
8 # inflect.irregular 'person', 'people' 8 # inflect.irregular 'person', 'people'
9 # inflect.uncountable %w( fish sheep ) 9 # inflect.uncountable %w( fish sheep )
10 # end 10 # end
  11 +
  12 +# Mark "commits" as uncountable.
  13 +#
  14 +# Without this change, the routes
  15 +#
  16 +# resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/}
  17 +# resources :commits, only: [:show], constraints: {id: /.+/}
  18 +#
  19 +# would generate identical route helper methods (`project_commit_path`), resulting
  20 +# in one of them not getting a helper method at all.
  21 +#
  22 +# After this change, the helper methods are:
  23 +#
  24 +# project_commit_path(@project, @project.commit)
  25 +# # => "/gitlabhq/commit/bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a
  26 +#
  27 +# project_commits_path(@project, 'stable/README.md')
  28 +# # => "/gitlabhq/commits/stable/README.md"
  29 +ActiveSupport::Inflector.inflections do |inflect|
  30 + inflect.uncountable %w(commits)
  31 +end
config/initializers/mime_types.rb
@@ -3,3 +3,5 @@ @@ -3,3 +3,5 @@
3 # Add new mime types for use in respond_to blocks: 3 # Add new mime types for use in respond_to blocks:
4 # Mime::Type.register "text/richtext", :rtf 4 # Mime::Type.register "text/richtext", :rtf
5 # Mime::Type.register_alias "text/html", :iphone 5 # Mime::Type.register_alias "text/html", :iphone
  6 +
  7 +Mime::Type.register_alias 'text/plain', :patch
config/routes.rb
@@ -122,38 +122,14 @@ Gitlab::Application.routes.draw do @@ -122,38 +122,14 @@ Gitlab::Application.routes.draw do
122 end 122 end
123 123
124 member do 124 member do
125 - get "tree", constraints: { id: /[a-zA-Z.\/0-9_\-]+/ } 125 + # tree viewer logs
126 get "logs_tree", constraints: { id: /[a-zA-Z.\/0-9_\-]+/ } 126 get "logs_tree", constraints: { id: /[a-zA-Z.\/0-9_\-]+/ }
127 -  
128 - get "blob",  
129 - constraints: {  
130 - id: /[a-zA-Z.0-9\/_\-]+/,  
131 - path: /.*/  
132 - }  
133 -  
134 - # tree viewer  
135 - get "tree/:path" => "refs#tree",  
136 - as: :tree_file,  
137 - constraints: {  
138 - id: /[a-zA-Z.0-9\/_\-]+/,  
139 - path: /.*/  
140 - }  
141 -  
142 - # tree viewer  
143 get "logs_tree/:path" => "refs#logs_tree", 127 get "logs_tree/:path" => "refs#logs_tree",
144 as: :logs_file, 128 as: :logs_file,
145 constraints: { 129 constraints: {
146 id: /[a-zA-Z.0-9\/_\-]+/, 130 id: /[a-zA-Z.0-9\/_\-]+/,
147 path: /.*/ 131 path: /.*/
148 } 132 }
149 -  
150 - # blame  
151 - get "blame/:path" => "refs#blame",  
152 - as: :blame_file,  
153 - constraints: {  
154 - id: /[a-zA-Z.0-9\/_\-]+/,  
155 - path: /.*/  
156 - }  
157 end 133 end
158 end 134 end
159 135
@@ -182,27 +158,27 @@ Gitlab::Application.routes.draw do @@ -182,27 +158,27 @@ Gitlab::Application.routes.draw do
182 get :test 158 get :test
183 end 159 end
184 end 160 end
185 - resources :commits do  
186 - collection do  
187 - get :compare  
188 - end  
189 161
190 - member do  
191 - get :patch  
192 - end  
193 - end 162 + resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/}
  163 + resources :commits, only: [:show], constraints: {id: /.+/}
  164 + resources :compare, only: [:index, :create]
  165 + resources :blame, only: [:show], constraints: {id: /.+/}
  166 + resources :blob, only: [:show], constraints: {id: /.+/}
  167 + resources :tree, only: [:show], constraints: {id: /.+/}
  168 + match "/compare/:from...:to" => "compare#show", as: "compare", constraints: {from: /.+/, to: /.+/}
  169 +
194 resources :team, controller: 'team_members', only: [:index] 170 resources :team, controller: 'team_members', only: [:index]
195 resources :team_members 171 resources :team_members
196 resources :milestones 172 resources :milestones
197 resources :labels, only: [:index] 173 resources :labels, only: [:index]
198 resources :issues do 174 resources :issues do
199 -  
200 collection do 175 collection do
201 post :sort 176 post :sort
202 post :bulk_update 177 post :bulk_update
203 get :search 178 get :search
204 end 179 end
205 end 180 end
  181 +
206 resources :notes, only: [:index, :create, :destroy] do 182 resources :notes, only: [:index, :create, :destroy] do
207 collection do 183 collection do
208 post :preview 184 post :preview
db/fixtures/test/001_repo.rb
@@ -3,13 +3,13 @@ require &#39;fileutils&#39; @@ -3,13 +3,13 @@ require &#39;fileutils&#39;
3 print "Unpacking seed repository..." 3 print "Unpacking seed repository..."
4 4
5 SEED_REPO = 'seed_project.tar.gz' 5 SEED_REPO = 'seed_project.tar.gz'
6 -REPO_PATH = File.join(Rails.root, 'tmp', 'repositories') 6 +REPO_PATH = Rails.root.join('tmp', 'repositories')
7 7
8 # Make whatever directories we need to make 8 # Make whatever directories we need to make
9 FileUtils.mkdir_p(REPO_PATH) 9 FileUtils.mkdir_p(REPO_PATH)
10 10
11 # Copy the archive to the repo path 11 # Copy the archive to the repo path
12 -FileUtils.cp(File.join(Rails.root, 'spec', SEED_REPO), REPO_PATH) 12 +FileUtils.cp(Rails.root.join('spec', SEED_REPO), REPO_PATH)
13 13
14 # chdir to the repo path 14 # chdir to the repo path
15 FileUtils.cd(REPO_PATH) do 15 FileUtils.cd(REPO_PATH) do
features/admin/active_tab.feature 0 → 100644
@@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
  1 +Feature: Admin active tab
  2 + Background:
  3 + Given I sign in as an admin
  4 +
  5 + Scenario: On Admin Home
  6 + Given I visit admin page
  7 + Then the active main tab should be Home
  8 + And no other main tabs should be active
  9 +
  10 + Scenario: On Admin Projects
  11 + Given I visit admin projects page
  12 + Then the active main tab should be Projects
  13 + And no other main tabs should be active
  14 +
  15 + Scenario: On Admin Users
  16 + Given I visit admin users page
  17 + Then the active main tab should be Users
  18 + And no other main tabs should be active
  19 +
  20 + Scenario: On Admin Logs
  21 + Given I visit admin logs page
  22 + Then the active main tab should be Logs
  23 + And no other main tabs should be active
  24 +
  25 + Scenario: On Admin Hooks
  26 + Given I visit admin hooks page
  27 + Then the active main tab should be Hooks
  28 + And no other main tabs should be active
  29 +
  30 + Scenario: On Admin Resque
  31 + Given I visit admin Resque page
  32 + Then the active main tab should be Resque
  33 + And no other main tabs should be active
features/dashboard/active_tab.feature 0 → 100644
@@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
  1 +Feature: Dashboard active tab
  2 + Background:
  3 + Given I sign in as a user
  4 +
  5 + Scenario: On Dashboard Home
  6 + Given I visit dashboard page
  7 + Then the active main tab should be Home
  8 + And no other main tabs should be active
  9 +
  10 + Scenario: On Dashboard Issues
  11 + Given I visit dashboard issues page
  12 + Then the active main tab should be Issues
  13 + And no other main tabs should be active
  14 +
  15 + Scenario: On Dashboard Merge Requests
  16 + Given I visit dashboard merge requests page
  17 + Then the active main tab should be Merge Requests
  18 + And no other main tabs should be active
  19 +
  20 + Scenario: On Dashboard Search
  21 + Given I visit dashboard search page
  22 + Then the active main tab should be Search
  23 + And no other main tabs should be active
  24 +
  25 + Scenario: On Dashboard Help
  26 + Given I visit dashboard help page
  27 + Then the active main tab should be Help
  28 + And no other main tabs should be active
features/profile/active_tab.feature 0 → 100644
@@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
  1 +Feature: Profile active tab
  2 + Background:
  3 + Given I sign in as a user
  4 +
  5 + Scenario: On Profile Home
  6 + Given I visit profile page
  7 + Then the active main tab should be Home
  8 + And no other main tabs should be active
  9 +
  10 + Scenario: On Profile Account
  11 + Given I visit profile account page
  12 + Then the active main tab should be Account
  13 + And no other main tabs should be active
  14 +
  15 + Scenario: On Profile SSH Keys
  16 + Given I visit profile SSH keys page
  17 + Then the active main tab should be SSH Keys
  18 + And no other main tabs should be active
  19 +
  20 + Scenario: On Profile Design
  21 + Given I visit profile design page
  22 + Then the active main tab should be Design
  23 + And no other main tabs should be active
  24 +
  25 + Scenario: On Profile History
  26 + Given I visit profile history page
  27 + Then the active main tab should be History
  28 + And no other main tabs should be active
features/project/active_tab.feature 0 → 100644
@@ -0,0 +1,147 @@ @@ -0,0 +1,147 @@
  1 +Feature: Project active tab
  2 + Background:
  3 + Given I sign in as a user
  4 + And I own a project
  5 +
  6 + # Main Tabs
  7 +
  8 + Scenario: On Project Home
  9 + Given I visit my project's home page
  10 + Then the active main tab should be Home
  11 + And no other main tabs should be active
  12 +
  13 + Scenario: On Project Files
  14 + Given I visit my project's files page
  15 + Then the active main tab should be Files
  16 + And no other main tabs should be active
  17 +
  18 + Scenario: On Project Commits
  19 + Given I visit my project's commits page
  20 + Then the active main tab should be Commits
  21 + And no other main tabs should be active
  22 +
  23 + Scenario: On Project Network
  24 + Given I visit my project's network page
  25 + Then the active main tab should be Network
  26 + And no other main tabs should be active
  27 +
  28 + Scenario: On Project Issues
  29 + Given I visit my project's issues page
  30 + Then the active main tab should be Issues
  31 + And no other main tabs should be active
  32 +
  33 + Scenario: On Project Merge Requests
  34 + Given I visit my project's merge requests page
  35 + Then the active main tab should be Merge Requests
  36 + And no other main tabs should be active
  37 +
  38 + Scenario: On Project Wall
  39 + Given I visit my project's wall page
  40 + Then the active main tab should be Wall
  41 + And no other main tabs should be active
  42 +
  43 + Scenario: On Project Wiki
  44 + Given I visit my project's wiki page
  45 + Then the active main tab should be Wiki
  46 + And no other main tabs should be active
  47 +
  48 + # Sub Tabs: Home
  49 +
  50 + Scenario: On Project Home/Show
  51 + Given I visit my project's home page
  52 + Then the active sub tab should be Show
  53 + And no other sub tabs should be active
  54 + And the active main tab should be Home
  55 +
  56 + Scenario: On Project Home/Team
  57 + Given I visit my project's home page
  58 + And I click the "Team" tab
  59 + Then the active sub tab should be Team
  60 + And no other sub tabs should be active
  61 + And the active main tab should be Home
  62 +
  63 + Scenario: On Project Home/Attachments
  64 + Given I visit my project's home page
  65 + And I click the "Attachments" tab
  66 + Then the active sub tab should be Attachments
  67 + And no other sub tabs should be active
  68 + And the active main tab should be Home
  69 +
  70 + Scenario: On Project Home/Snippets
  71 + Given I visit my project's home page
  72 + And I click the "Snippets" tab
  73 + Then the active sub tab should be Snippets
  74 + And no other sub tabs should be active
  75 + And the active main tab should be Home
  76 +
  77 + Scenario: On Project Home/Edit
  78 + Given I visit my project's home page
  79 + And I click the "Edit" tab
  80 + Then the active sub tab should be Edit
  81 + And no other sub tabs should be active
  82 + And the active main tab should be Home
  83 +
  84 + Scenario: On Project Home/Hooks
  85 + Given I visit my project's home page
  86 + And I click the "Hooks" tab
  87 + Then the active sub tab should be Hooks
  88 + And no other sub tabs should be active
  89 + And the active main tab should be Home
  90 +
  91 + Scenario: On Project Home/Deploy Keys
  92 + Given I visit my project's home page
  93 + And I click the "Deploy Keys" tab
  94 + Then the active sub tab should be Deploy Keys
  95 + And no other sub tabs should be active
  96 + And the active main tab should be Home
  97 +
  98 + # Sub Tabs: Commits
  99 +
  100 + Scenario: On Project Commits/Commits
  101 + Given I visit my project's commits page
  102 + Then the active sub tab should be Commits
  103 + And no other sub tabs should be active
  104 + And the active main tab should be Commits
  105 +
  106 + Scenario: On Project Commits/Compare
  107 + Given I visit my project's commits page
  108 + And I click the "Compare" tab
  109 + Then the active sub tab should be Compare
  110 + And no other sub tabs should be active
  111 + And the active main tab should be Commits
  112 +
  113 + Scenario: On Project Commits/Branches
  114 + Given I visit my project's commits page
  115 + And I click the "Branches" tab
  116 + Then the active sub tab should be Branches
  117 + And no other sub tabs should be active
  118 + And the active main tab should be Commits
  119 +
  120 + Scenario: On Project Commits/Tags
  121 + Given I visit my project's commits page
  122 + And I click the "Tags" tab
  123 + Then the active sub tab should be Tags
  124 + And no other sub tabs should be active
  125 + And the active main tab should be Commits
  126 +
  127 + # Sub Tabs: Issues
  128 +
  129 + Scenario: On Project Issues/Browse
  130 + Given I visit my project's issues page
  131 + Then the active sub tab should be Browse Issues
  132 + And no other sub tabs should be active
  133 + And the active main tab should be Issues
  134 +
  135 + Scenario: On Project Issues/Milestones
  136 + Given I visit my project's issues page
  137 + And I click the "Milestones" tab
  138 + Then the active sub tab should be Milestones
  139 + And no other sub tabs should be active
  140 + And the active main tab should be Issues
  141 +
  142 + Scenario: On Project Issues/Labels
  143 + Given I visit my project's issues page
  144 + And I click the "Labels" tab
  145 + Then the active sub tab should be Labels
  146 + And no other sub tabs should be active
  147 + And the active main tab should be Issues
features/project/commits/commits.feature
1 Feature: Project Browse commits 1 Feature: Project Browse commits
2 Background: 2 Background:
3 Given I sign in as a user 3 Given I sign in as a user
4 - And I own project "Shop"  
5 - Given I visit project commits page 4 + And I own a project
  5 + And I visit my project's commits page
6 6
7 Scenario: I browse commits list for master branch 7 Scenario: I browse commits list for master branch
8 Then I see project commits 8 Then I see project commits
@@ -18,4 +18,4 @@ Feature: Project Browse commits @@ -18,4 +18,4 @@ Feature: Project Browse commits
18 Scenario: I compare refs 18 Scenario: I compare refs
19 Given I visit compare refs page 19 Given I visit compare refs page
20 And I fill compare fields with refs 20 And I fill compare fields with refs
21 - And I see compared refs 21 + Then I see compared refs
features/steps/admin/admin_active_tab.rb 0 → 100644
@@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
  1 +class AdminActiveTab < Spinach::FeatureSteps
  2 + include SharedAuthentication
  3 + include SharedPaths
  4 + include SharedActiveTab
  5 +
  6 + Then 'the active main tab should be Home' do
  7 + ensure_active_main_tab('Stats')
  8 + end
  9 +
  10 + Then 'the active main tab should be Projects' do
  11 + ensure_active_main_tab('Projects')
  12 + end
  13 +
  14 + Then 'the active main tab should be Users' do
  15 + ensure_active_main_tab('Users')
  16 + end
  17 +
  18 + Then 'the active main tab should be Logs' do
  19 + ensure_active_main_tab('Logs')
  20 + end
  21 +
  22 + Then 'the active main tab should be Hooks' do
  23 + ensure_active_main_tab('Hooks')
  24 + end
  25 +
  26 + Then 'the active main tab should be Resque' do
  27 + ensure_active_main_tab('Resque')
  28 + end
  29 +end
features/steps/dashboard/dashboard_active_tab.rb 0 → 100644
@@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
  1 +class DashboardActiveTab < Spinach::FeatureSteps
  2 + include SharedAuthentication
  3 + include SharedPaths
  4 + include SharedActiveTab
  5 +
  6 + Then 'the active main tab should be Home' do
  7 + ensure_active_main_tab('Home')
  8 + end
  9 +
  10 + Then 'the active main tab should be Issues' do
  11 + ensure_active_main_tab('Issues')
  12 + end
  13 +
  14 + Then 'the active main tab should be Merge Requests' do
  15 + ensure_active_main_tab('Merge Requests')
  16 + end
  17 +
  18 + Then 'the active main tab should be Search' do
  19 + ensure_active_main_tab('Search')
  20 + end
  21 +
  22 + Then 'the active main tab should be Help' do
  23 + ensure_active_main_tab('Help')
  24 + end
  25 +end
features/steps/profile/profile_active_tab.rb 0 → 100644
@@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
  1 +class ProfileActiveTab < Spinach::FeatureSteps
  2 + include SharedAuthentication
  3 + include SharedPaths
  4 + include SharedActiveTab
  5 +
  6 + Then 'the active main tab should be Home' do
  7 + ensure_active_main_tab('Profile')
  8 + end
  9 +
  10 + Then 'the active main tab should be Account' do
  11 + ensure_active_main_tab('Account')
  12 + end
  13 +
  14 + Then 'the active main tab should be SSH Keys' do
  15 + ensure_active_main_tab('SSH Keys')
  16 + end
  17 +
  18 + Then 'the active main tab should be Design' do
  19 + ensure_active_main_tab('Design')
  20 + end
  21 +
  22 + Then 'the active main tab should be History' do
  23 + ensure_active_main_tab('History')
  24 + end
  25 +end
features/steps/project/project_active_tab.rb 0 → 100644
@@ -0,0 +1,146 @@ @@ -0,0 +1,146 @@
  1 +class ProjectActiveTab < Spinach::FeatureSteps
  2 + include SharedAuthentication
  3 + include SharedPaths
  4 + include SharedProject
  5 + include SharedActiveTab
  6 +
  7 + # Main Tabs
  8 +
  9 + Then 'the active main tab should be Home' do
  10 + ensure_active_main_tab(@project.name)
  11 + end
  12 +
  13 + Then 'the active main tab should be Files' do
  14 + ensure_active_main_tab('Files')
  15 + end
  16 +
  17 + Then 'the active main tab should be Commits' do
  18 + ensure_active_main_tab('Commits')
  19 + end
  20 +
  21 + Then 'the active main tab should be Network' do
  22 + ensure_active_main_tab('Network')
  23 + end
  24 +
  25 + Then 'the active main tab should be Issues' do
  26 + ensure_active_main_tab('Issues')
  27 + end
  28 +
  29 + Then 'the active main tab should be Merge Requests' do
  30 + ensure_active_main_tab('Merge Requests')
  31 + end
  32 +
  33 + Then 'the active main tab should be Wall' do
  34 + ensure_active_main_tab('Wall')
  35 + end
  36 +
  37 + Then 'the active main tab should be Wiki' do
  38 + ensure_active_main_tab('Wiki')
  39 + end
  40 +
  41 + # Sub Tabs: Home
  42 +
  43 + Given 'I click the "Team" tab' do
  44 + click_link('Team')
  45 + end
  46 +
  47 + Given 'I click the "Attachments" tab' do
  48 + click_link('Attachments')
  49 + end
  50 +
  51 + Given 'I click the "Snippets" tab' do
  52 + click_link('Snippets')
  53 + end
  54 +
  55 + Given 'I click the "Edit" tab' do
  56 + click_link('Edit')
  57 + end
  58 +
  59 + Given 'I click the "Hooks" tab' do
  60 + click_link('Hooks')
  61 + end
  62 +
  63 + Given 'I click the "Deploy Keys" tab' do
  64 + click_link('Deploy Keys')
  65 + end
  66 +
  67 + Then 'the active sub tab should be Show' do
  68 + ensure_active_sub_tab('Show')
  69 + end
  70 +
  71 + Then 'the active sub tab should be Team' do
  72 + ensure_active_sub_tab('Team')
  73 + end
  74 +
  75 + Then 'the active sub tab should be Attachments' do
  76 + ensure_active_sub_tab('Attachments')
  77 + end
  78 +
  79 + Then 'the active sub tab should be Snippets' do
  80 + ensure_active_sub_tab('Snippets')
  81 + end
  82 +
  83 + Then 'the active sub tab should be Edit' do
  84 + ensure_active_sub_tab('Edit')
  85 + end
  86 +
  87 + Then 'the active sub tab should be Hooks' do
  88 + ensure_active_sub_tab('Hooks')
  89 + end
  90 +
  91 + Then 'the active sub tab should be Deploy Keys' do
  92 + ensure_active_sub_tab('Deploy Keys')
  93 + end
  94 +
  95 + # Sub Tabs: Commits
  96 +
  97 + Given 'I click the "Compare" tab' do
  98 + click_link('Compare')
  99 + end
  100 +
  101 + Given 'I click the "Branches" tab' do
  102 + click_link('Branches')
  103 + end
  104 +
  105 + Given 'I click the "Tags" tab' do
  106 + click_link('Tags')
  107 + end
  108 +
  109 + Then 'the active sub tab should be Commits' do
  110 + ensure_active_sub_tab('Commits')
  111 + end
  112 +
  113 + Then 'the active sub tab should be Compare' do
  114 + ensure_active_sub_tab('Compare')
  115 + end
  116 +
  117 + Then 'the active sub tab should be Branches' do
  118 + ensure_active_sub_tab('Branches')
  119 + end
  120 +
  121 + Then 'the active sub tab should be Tags' do
  122 + ensure_active_sub_tab('Tags')
  123 + end
  124 +
  125 + # Sub Tabs: Issues
  126 +
  127 + Given 'I click the "Milestones" tab' do
  128 + click_link('Milestones')
  129 + end
  130 +
  131 + Given 'I click the "Labels" tab' do
  132 + click_link('Labels')
  133 + end
  134 +
  135 + Then 'the active sub tab should be Browse Issues' do
  136 + ensure_active_sub_tab('Browse Issues')
  137 + end
  138 +
  139 + Then 'the active sub tab should be Milestones' do
  140 + ensure_active_sub_tab('Milestones')
  141 + end
  142 +
  143 + Then 'the active sub tab should be Labels' do
  144 + ensure_active_sub_tab('Labels')
  145 + end
  146 +end
features/steps/project/project_browse_commits.rb
@@ -4,8 +4,6 @@ class ProjectBrowseCommits &lt; Spinach::FeatureSteps @@ -4,8 +4,6 @@ class ProjectBrowseCommits &lt; Spinach::FeatureSteps
4 include SharedPaths 4 include SharedPaths
5 5
6 Then 'I see project commits' do 6 Then 'I see project commits' do
7 - current_path.should == project_commits_path(@project)  
8 -  
9 commit = @project.commit 7 commit = @project.commit
10 page.should have_content(@project.name) 8 page.should have_content(@project.name)
11 page.should have_content(commit.message) 9 page.should have_content(commit.message)
@@ -34,14 +32,14 @@ class ProjectBrowseCommits &lt; Spinach::FeatureSteps @@ -34,14 +32,14 @@ class ProjectBrowseCommits &lt; Spinach::FeatureSteps
34 end 32 end
35 33
36 And 'I fill compare fields with refs' do 34 And 'I fill compare fields with refs' do
37 - fill_in "from", :with => "master"  
38 - fill_in "to", :with => "stable" 35 + fill_in "from", with: "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a"
  36 + fill_in "to", with: "8716fc78f3c65bbf7bcf7b574febd583bc5d2812"
39 click_button "Compare" 37 click_button "Compare"
40 end 38 end
41 39
42 - And 'I see compared refs' do  
43 - page.should have_content "Commits (27)" 40 + Then 'I see compared refs' do
44 page.should have_content "Compare View" 41 page.should have_content "Compare View"
45 - page.should have_content "Showing 73 changed files" 42 + page.should have_content "Commits (1)"
  43 + page.should have_content "Showing 2 changed files"
46 end 44 end
47 end 45 end
features/steps/project/project_browse_files.rb
@@ -10,7 +10,7 @@ class ProjectBrowseFiles &lt; Spinach::FeatureSteps @@ -10,7 +10,7 @@ class ProjectBrowseFiles &lt; Spinach::FeatureSteps
10 end 10 end
11 11
12 Then 'I should see files from repository for "8470d70"' do 12 Then 'I should see files from repository for "8470d70"' do
13 - current_path.should == tree_project_ref_path(@project, "8470d70") 13 + current_path.should == project_tree_path(@project, "8470d70")
14 page.should have_content "app" 14 page.should have_content "app"
15 page.should have_content "History" 15 page.should have_content "History"
16 page.should have_content "Gemfile" 16 page.should have_content "Gemfile"
features/steps/shared/active_tab.rb 0 → 100644
@@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
  1 +module SharedActiveTab
  2 + include Spinach::DSL
  3 +
  4 + def ensure_active_main_tab(content)
  5 + page.find('ul.main_menu li.active').should have_content(content)
  6 + end
  7 +
  8 + def ensure_active_sub_tab(content)
  9 + page.find('div.content ul.nav-tabs li.active').should have_content(content)
  10 + end
  11 +
  12 + And 'no other main tabs should be active' do
  13 + page.should have_selector('ul.main_menu li.active', count: 1)
  14 + end
  15 +
  16 + And 'no other sub tabs should be active' do
  17 + page.should have_selector('div.content ul.nav-tabs li.active', count: 1)
  18 + end
  19 +end
features/steps/shared/authentication.rb
@@ -7,4 +7,8 @@ module SharedAuthentication @@ -7,4 +7,8 @@ module SharedAuthentication
7 Given 'I sign in as a user' do 7 Given 'I sign in as a user' do
8 login_as :user 8 login_as :user
9 end 9 end
  10 +
  11 + Given 'I sign in as an admin' do
  12 + login_as :admin
  13 + end
10 end 14 end
features/steps/shared/paths.rb
1 module SharedPaths 1 module SharedPaths
2 include Spinach::DSL 2 include Spinach::DSL
3 3
4 - And 'I visit dashboard search page' do  
5 - visit search_path 4 + When 'I visit new project page' do
  5 + visit new_project_path
6 end 6 end
7 7
8 - And 'I visit dashboard merge requests page' do  
9 - visit dashboard_merge_requests_path 8 + # ----------------------------------------
  9 + # Dashboard
  10 + # ----------------------------------------
  11 +
  12 + Given 'I visit dashboard page' do
  13 + visit dashboard_path
10 end 14 end
11 15
12 - And 'I visit dashboard issues page' do 16 + Given 'I visit dashboard issues page' do
13 visit dashboard_issues_path 17 visit dashboard_issues_path
14 end 18 end
15 19
16 - When 'I visit dashboard page' do  
17 - visit dashboard_path 20 + Given 'I visit dashboard merge requests page' do
  21 + visit dashboard_merge_requests_path
  22 + end
  23 +
  24 + Given 'I visit dashboard search page' do
  25 + visit search_path
18 end 26 end
19 27
  28 + Given 'I visit dashboard help page' do
  29 + visit help_path
  30 + end
  31 +
  32 + # ----------------------------------------
  33 + # Profile
  34 + # ----------------------------------------
  35 +
20 Given 'I visit profile page' do 36 Given 'I visit profile page' do
21 visit profile_path 37 visit profile_path
22 end 38 end
@@ -25,14 +41,94 @@ module SharedPaths @@ -25,14 +41,94 @@ module SharedPaths
25 visit profile_account_path 41 visit profile_account_path
26 end 42 end
27 43
  44 + Given 'I visit profile SSH keys page' do
  45 + visit keys_path
  46 + end
  47 +
  48 + Given 'I visit profile design page' do
  49 + visit profile_design_path
  50 + end
  51 +
  52 + Given 'I visit profile history page' do
  53 + visit profile_history_path
  54 + end
  55 +
28 Given 'I visit profile token page' do 56 Given 'I visit profile token page' do
29 visit profile_token_path 57 visit profile_token_path
30 end 58 end
31 59
32 - When 'I visit new project page' do  
33 - visit new_project_path 60 + # ----------------------------------------
  61 + # Admin
  62 + # ----------------------------------------
  63 +
  64 + Given 'I visit admin page' do
  65 + visit admin_root_path
  66 + end
  67 +
  68 + Given 'I visit admin projects page' do
  69 + visit admin_projects_path
34 end 70 end
35 71
  72 + Given 'I visit admin users page' do
  73 + visit admin_users_path
  74 + end
  75 +
  76 + Given 'I visit admin logs page' do
  77 + visit admin_logs_path
  78 + end
  79 +
  80 + Given 'I visit admin hooks page' do
  81 + visit admin_hooks_path
  82 + end
  83 +
  84 + Given 'I visit admin Resque page' do
  85 + visit admin_resque_path
  86 + end
  87 +
  88 + # ----------------------------------------
  89 + # Generic Project
  90 + # ----------------------------------------
  91 +
  92 + Given "I visit my project's home page" do
  93 + visit project_path(@project)
  94 + end
  95 +
  96 + Given "I visit my project's files page" do
  97 + visit project_tree_path(@project, @project.root_ref)
  98 + end
  99 +
  100 + Given "I visit my project's commits page" do
  101 + visit project_commits_path(@project, @project.root_ref, {limit: 5})
  102 + end
  103 +
  104 + Given "I visit my project's network page" do
  105 + # Stub out find_all to speed this up (10 commits vs. 650)
  106 + commits = Grit::Commit.find_all(@project.repo, nil, {max_count: 10})
  107 + Grit::Commit.stub(:find_all).and_return(commits)
  108 +
  109 + visit graph_project_path(@project)
  110 + end
  111 +
  112 + Given "I visit my project's issues page" do
  113 + visit project_issues_path(@project)
  114 + end
  115 +
  116 + Given "I visit my project's merge requests page" do
  117 + visit project_merge_requests_path(@project)
  118 + end
  119 +
  120 + Given "I visit my project's wall page" do
  121 + visit wall_project_path(@project)
  122 + end
  123 +
  124 + Given "I visit my project's wiki page" do
  125 + visit project_wiki_path(@project, :index)
  126 + end
  127 +
  128 + # ----------------------------------------
  129 + # "Shop" Project
  130 + # ----------------------------------------
  131 +
36 And 'I visit project "Shop" page' do 132 And 'I visit project "Shop" page' do
37 project = Project.find_by_name("Shop") 133 project = Project.find_by_name("Shop")
38 visit project_path(project) 134 visit project_path(project)
@@ -43,23 +139,27 @@ module SharedPaths @@ -43,23 +139,27 @@ module SharedPaths
43 end 139 end
44 140
45 Given 'I visit compare refs page' do 141 Given 'I visit compare refs page' do
46 - visit compare_project_commits_path(@project) 142 + visit project_compare_index_path(@project)
47 end 143 end
48 144
49 Given 'I visit project commits page' do 145 Given 'I visit project commits page' do
50 - visit project_commits_path(@project) 146 + visit project_commits_path(@project, @project.root_ref, {limit: 5})
  147 + end
  148 +
  149 + Given 'I visit project commits page for stable branch' do
  150 + visit project_commits_path(@project, 'stable', {limit: 5})
51 end 151 end
52 152
53 Given 'I visit project source page' do 153 Given 'I visit project source page' do
54 - visit tree_project_ref_path(@project, @project.root_ref) 154 + visit project_tree_path(@project, @project.root_ref)
55 end 155 end
56 156
57 Given 'I visit blob file from repo' do 157 Given 'I visit blob file from repo' do
58 - visit tree_project_ref_path(@project, ValidCommit::ID, :path => ValidCommit::BLOB_FILE_PATH) 158 + visit project_tree_path(@project, File.join(ValidCommit::ID, ValidCommit::BLOB_FILE_PATH))
59 end 159 end
60 160
61 Given 'I visit project source page for "8470d70"' do 161 Given 'I visit project source page for "8470d70"' do
62 - visit tree_project_ref_path(@project, "8470d70") 162 + visit project_tree_path(@project, "8470d70")
63 end 163 end
64 164
65 Given 'I visit project tags page' do 165 Given 'I visit project tags page' do
features/steps/shared/project.rb
1 module SharedProject 1 module SharedProject
2 include Spinach::DSL 2 include Spinach::DSL
3 3
  4 + # Create a project without caring about what it's called
  5 + And "I own a project" do
  6 + @project = create(:project)
  7 + @project.add_access(@user, :admin)
  8 + end
  9 +
  10 + # Create a specific project called "Shop"
4 And 'I own project "Shop"' do 11 And 'I own project "Shop"' do
5 @project = Factory :project, :name => "Shop" 12 @project = Factory :project, :name => "Shop"
6 @project.add_access(@user, :admin) 13 @project.add_access(@user, :admin)
features/support/env.rb
@@ -23,5 +23,7 @@ Spinach.hooks.after_scenario { DatabaseCleaner.clean } @@ -23,5 +23,7 @@ Spinach.hooks.after_scenario { DatabaseCleaner.clean }
23 Spinach.hooks.before_run do 23 Spinach.hooks.before_run do
24 RSpec::Mocks::setup self 24 RSpec::Mocks::setup self
25 25
  26 + include FactoryGirl::Syntax::Methods
  27 +
26 stub_gitolite! 28 stub_gitolite!
27 end 29 end
lib/extracts_path.rb 0 → 100644
@@ -0,0 +1,114 @@ @@ -0,0 +1,114 @@
  1 +# Module providing methods for dealing with separating a tree-ish string and a
  2 +# file path string when combined in a request parameter
  3 +module ExtractsPath
  4 + extend ActiveSupport::Concern
  5 +
  6 + # Raised when given an invalid file path
  7 + class InvalidPathError < StandardError; end
  8 +
  9 + included do
  10 + if respond_to?(:before_filter)
  11 + before_filter :assign_ref_vars, only: [:show]
  12 + end
  13 + end
  14 +
  15 + # Given a string containing both a Git tree-ish, such as a branch or tag, and
  16 + # a filesystem path joined by forward slashes, attempts to separate the two.
  17 + #
  18 + # Expects a @project instance variable to contain the active project. This is
  19 + # used to check the input against a list of valid repository refs.
  20 + #
  21 + # Examples
  22 + #
  23 + # # No @project available
  24 + # extract_ref('master')
  25 + # # => ['', '']
  26 + #
  27 + # extract_ref('master')
  28 + # # => ['master', '']
  29 + #
  30 + # extract_ref("f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG")
  31 + # # => ['f4b14494ef6abf3d144c28e4af0c20143383e062', 'CHANGELOG']
  32 + #
  33 + # extract_ref("v2.0.0/README.md")
  34 + # # => ['v2.0.0', 'README.md']
  35 + #
  36 + # extract_ref('issues/1234/app/models/project.rb')
  37 + # # => ['issues/1234', 'app/models/project.rb']
  38 + #
  39 + # # Given an invalid branch, we fall back to just splitting on the first slash
  40 + # extract_ref('non/existent/branch/README.md')
  41 + # # => ['non', 'existent/branch/README.md']
  42 + #
  43 + # Returns an Array where the first value is the tree-ish and the second is the
  44 + # path
  45 + def extract_ref(input)
  46 + pair = ['', '']
  47 +
  48 + return pair unless @project
  49 +
  50 + if input.match(/^([[:alnum:]]{40})(.+)/)
  51 + # If the ref appears to be a SHA, we're done, just split the string
  52 + pair = $~.captures
  53 + else
  54 + # Otherwise, attempt to detect the ref using a list of the project's
  55 + # branches and tags
  56 +
  57 + # Append a trailing slash if we only get a ref and no file path
  58 + id = input
  59 + id += '/' unless id.include?('/')
  60 +
  61 + valid_refs = @project.branches + @project.tags
  62 + valid_refs.select! { |v| id.start_with?("#{v}/") }
  63 +
  64 + if valid_refs.length != 1
  65 + # No exact ref match, so just try our best
  66 + pair = id.match(/([^\/]+)(.*)/).captures
  67 + else
  68 + # Partition the string into the ref and the path, ignoring the empty first value
  69 + pair = id.partition(valid_refs.first)[1..-1]
  70 + end
  71 + end
  72 +
  73 + # Remove leading slash from path
  74 + pair[1].gsub!(/^\//, '')
  75 +
  76 + pair
  77 + end
  78 +
  79 + # Assigns common instance variables for views working with Git tree-ish objects
  80 + #
  81 + # Assignments are:
  82 + #
  83 + # - @id - A string representing the joined ref and path
  84 + # - @ref - A string representing the ref (e.g., the branch, tag, or commit SHA)
  85 + # - @path - A string representing the filesystem path
  86 + # - @commit - A CommitDecorator representing the commit from the given ref
  87 + # - @tree - A TreeDecorator representing the tree at the given ref/path
  88 + #
  89 + # If the :id parameter appears to be requesting a specific response format,
  90 + # that will be handled as well.
  91 + #
  92 + # Automatically renders `not_found!` if a valid tree path could not be
  93 + # resolved (e.g., when a user inserts an invalid path or ref).
  94 + def assign_ref_vars
  95 + # Handle formats embedded in the id
  96 + if params[:id].ends_with?('.atom')
  97 + params[:id].gsub!(/\.atom$/, '')
  98 + request.format = :atom
  99 + end
  100 +
  101 + @ref, @path = extract_ref(params[:id])
  102 +
  103 + @id = File.join(@ref, @path)
  104 +
  105 + @commit = CommitDecorator.decorate(@project.commit(@ref))
  106 +
  107 + @tree = Tree.new(@commit.tree, @project, @ref, @path)
  108 + @tree = TreeDecorator.new(@tree)
  109 +
  110 + raise InvalidPathError if @tree.invalid?
  111 + rescue NoMethodError, InvalidPathError
  112 + not_found!
  113 + end
  114 +end
lib/gitlab/backend/gitolite_config.rb
@@ -10,7 +10,7 @@ module Gitlab @@ -10,7 +10,7 @@ module Gitlab
10 attr_reader :config_tmp_dir, :ga_repo, :conf 10 attr_reader :config_tmp_dir, :ga_repo, :conf
11 11
12 def config_tmp_dir 12 def config_tmp_dir
13 - @config_tmp_dir ||= File.join(Rails.root, 'tmp',"gitlabhq-gitolite-#{Time.now.to_i}") 13 + @config_tmp_dir ||= Rails.root.join('tmp',"gitlabhq-gitolite-#{Time.now.to_i}")
14 end 14 end
15 15
16 def ga_repo 16 def ga_repo
@@ -19,7 +19,7 @@ module Gitlab @@ -19,7 +19,7 @@ module Gitlab
19 19
20 def apply 20 def apply
21 Timeout::timeout(30) do 21 Timeout::timeout(30) do
22 - File.open(File.join(Rails.root, 'tmp', "gitlabhq-gitolite.lock"), "w+") do |f| 22 + File.open(Rails.root.join('tmp', "gitlabhq-gitolite.lock"), "w+") do |f|
23 begin 23 begin
24 # Set exclusive lock 24 # Set exclusive lock
25 # to prevent race condition 25 # to prevent race condition