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.

Gemfile
... ... @@ -57,7 +57,7 @@ gem "seed-fu"
57 57  
58 58 # Markdown to HTML
59 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 62 # Servers
63 63 gem "thin"
... ...
app/assets/stylesheets/gitlab_bootstrap/files.scss
... ... @@ -68,10 +68,22 @@
68 68 * Blame file
69 69 */
70 70 &.blame {
  71 + table {
  72 + border:none;
  73 + box-shadow:none;
  74 + margin:0;
  75 + }
71 76 tr {
72 77 border-bottom: 1px solid #eee;
73 78 }
74 79 td {
  80 + &:first-child {
  81 + border-left:none;
  82 + }
  83 + &:last-child {
  84 + border-right:none;
  85 + }
  86 + background:#fff;
75 87 padding:5px;
76 88 }
77 89 .author,
... ...
app/assets/stylesheets/sections/nav.scss
... ... @@ -53,7 +53,7 @@ ul.main_menu {
53 53 border-left: 0;
54 54 }
55 55  
56   - &.current {
  56 + &.active {
57 57 background-color:#D5D5D5;
58 58 border-right: 1px solid #BBB;
59 59 border-left: 1px solid #BBB;
... ...
app/controllers/application_controller.rb
... ... @@ -2,7 +2,6 @@ class ApplicationController < ActionController::Base
2 2 before_filter :authenticate_user!
3 3 before_filter :reject_blocked!
4 4 before_filter :set_current_user_for_mailer
5   - before_filter :check_token_auth
6 5 before_filter :set_current_user_for_observers
7 6 before_filter :dev_tools if Rails.env == 'development'
8 7  
... ... @@ -24,13 +23,6 @@ class ApplicationController < ActionController::Base
24 23  
25 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 26 def reject_blocked!
35 27 if current_user && current_user.blocked
36 28 sign_out current_user
... ... @@ -103,7 +95,7 @@ class ApplicationController < ActionController::Base
103 95 end
104 96  
105 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 99 end
108 100  
109 101 def require_non_empty_project
... ... @@ -116,10 +108,6 @@ class ApplicationController < ActionController::Base
116 108 response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
117 109 end
118 110  
119   - def render_full_content
120   - @full_content = true
121   - end
122   -
123 111 def dev_tools
124 112 Rack::MiniProfiler.authorize_request
125 113 end
... ...
app/controllers/blame_controller.rb 0 → 100644
... ... @@ -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 @@
  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 @@
  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 1 require "base64"
2 2  
3 3 class CommitsController < ProjectController
  4 + include ExtractsPath
  5 +
4 6 # Authorize
5 7 before_filter :authorize_read_project!
6 8 before_filter :authorize_code_access!
7 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 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 16 @commits = CommitDecorator.decorate(@commits)
17 17  
18 18 respond_to do |format|
... ... @@ -21,54 +21,4 @@ class CommitsController &lt; ProjectController
21 21 format.atom { render layout: false }
22 22 end
23 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 24 end
... ...
app/controllers/compare_controller.rb 0 → 100644
... ... @@ -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 4 before_filter :require_non_empty_project
5 5  
6 6 before_filter :authorize_admin_project!, only: [:destroy, :create]
7   - before_filter :render_full_content
8 7  
9 8 def index
10 9 @branches = @project.protected_branches.all
... ...
app/controllers/refs_controller.rb
1   -require 'github/markup'
2   -
3 1 class RefsController < ProjectController
4 2 include Gitlab::Encode
5 3  
... ... @@ -9,21 +7,20 @@ class RefsController &lt; ProjectController
9 7 before_filter :require_non_empty_project
10 8  
11 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 12 def switch
16 13 respond_to do |format|
17 14 format.html do
18 15 new_path = if params[:destination] == "tree"
19   - tree_project_ref_path(@project, params[:ref])
  16 + project_tree_path(@project, @ref)
20 17 else
21   - project_commits_path(@project, ref: params[:ref])
  18 + project_commits_path(@project, @ref)
22 19 end
23 20  
24   - redirect_to new_path
  21 + redirect_to new_path
25 22 end
26   - format.js do
  23 + format.js do
27 24 @ref = params[:ref]
28 25 define_tree_vars
29 26 render "tree"
... ... @@ -31,19 +28,6 @@ class RefsController &lt; ProjectController
31 28 end
32 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 31 def logs_tree
48 32 contents = @tree.contents
49 33 @logs = contents.map do |content|
... ... @@ -51,36 +35,12 @@ class RefsController &lt; ProjectController
51 35 last_commit = @project.commits(@commit.id, file, 1).last
52 36 last_commit = CommitDecorator.decorate(last_commit)
53 37 {
54   - file_name: content.name,
  38 + file_name: content.name,
55 39 commit: last_commit
56 40 }
57 41 end
58 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 44 protected
85 45  
86 46 def define_tree_vars
... ... @@ -91,20 +51,20 @@ class RefsController &lt; ProjectController
91 51 @commit = CommitDecorator.decorate(@commit)
92 52 @tree = Tree.new(@commit.tree, project, @ref, params[:path])
93 53 @tree = TreeDecorator.new(@tree)
94   - @hex_path = Digest::SHA1.hexdigest(params[:path] || "/")
  54 + @hex_path = Digest::SHA1.hexdigest(params[:path] || "")
95 55  
96 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 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 62 end
103 63 rescue
104 64 return render_404
105 65 end
106   -
  66 +
107 67 def ref
108   - @ref = params[:id]
  68 + @ref = params[:id] || params[:ref]
109 69 end
110 70 end
... ...
app/controllers/repositories_controller.rb
... ... @@ -3,18 +3,17 @@ class RepositoriesController &lt; ProjectController
3 3 before_filter :authorize_read_project!
4 4 before_filter :authorize_code_access!
5 5 before_filter :require_non_empty_project
6   - before_filter :render_full_content
7 6  
8 7 def show
9 8 @activities = @project.commits_with_refs(20)
10 9 end
11 10  
12 11 def branches
13   - @branches = @project.repo.heads.sort_by(&:name)
  12 + @branches = @project.branches
14 13 end
15 14  
16 15 def tags
17   - @tags = @project.repo.tags.sort_by(&:name).reverse
  16 + @tags = @project.tags
18 17 end
19 18  
20 19 def archive
... ...
app/controllers/snippets_controller.rb
... ... @@ -50,7 +50,6 @@ class SnippetsController &lt; ProjectController
50 50  
51 51 def show
52 52 @note = @project.notes.new(noteable: @snippet)
53   - render_full_content
54 53 end
55 54  
56 55 def destroy
... ...
app/controllers/tree_controller.rb 0 → 100644
... ... @@ -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 21 elsif self.merge_request?
22 22 h.project_merge_request_url(self.project, self.merge_request)
23 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 25 end
26 26 end
27 27 end
... ...
app/decorators/tree_decorator.rb
... ... @@ -6,7 +6,7 @@ class TreeDecorator &lt; ApplicationDecorator
6 6 part_path = ""
7 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 11 yield(h.link_to("..", "#", remote: :true)) if parts.count > max_links
12 12  
... ... @@ -15,29 +15,29 @@ class TreeDecorator &lt; ApplicationDecorator
15 15 part_path = part if part_path.empty?
16 16  
17 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 19 end
20 20 end
21 21 end
22 22  
23 23 def up_dir?
24   - !!path
  24 + path.present?
25 25 end
26 26  
27 27 def up_dir_path
28 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 30 end
31 31  
32 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 34 end
35 35  
36 36 def mb_size
37 37 size = (tree.size / 1024)
38 38 if size < 1024
39   - "#{size} KB"
40   - else
  39 + "#{size} KB"
  40 + else
41 41 "#{size/1024} MB"
42 42 end
43 43 end
... ...
app/helpers/application_helper.rb
1 1 require 'digest/md5'
  2 +
2 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 33 def gravatar_icon(user_email = '', size = 40)
5 34 if Gitlab.config.disable_gravatar? || user_email.blank?
6 35 'no_avatar.png'
... ... @@ -31,8 +60,8 @@ module ApplicationHelper
31 60  
32 61 def grouped_options_refs(destination = :tree)
33 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 67 # If reference is commit id -
... ... @@ -58,11 +87,11 @@ module ApplicationHelper
58 87  
59 88 if @project && !@project.new_record?
60 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 96 end
68 97  
... ... @@ -85,45 +114,6 @@ module ApplicationHelper
85 114 event.project.merge_requests_enabled
86 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 117 def hexdigest(string)
128 118 Digest::SHA1.hexdigest string
129 119 end
... ...
app/helpers/tab_helper.rb
1 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 68 end
9 69  
10 70 def project_tab_class
11 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 73 end
14 74  
15 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 77 end
28 78 end
29 79  
30 80 def branches_tab_class
31 81 if current_page?(branches_project_repository_path(@project)) ||
32   - controller.controller_name == "protected_branches" ||
  82 + current_controller?(:protected_branches) ||
33 83 current_page?(project_repository_path(@project))
34 84 'active'
35 85 end
... ...
app/helpers/tree_helper.rb
... ... @@ -39,4 +39,9 @@ module TreeHelper
39 39 def gitlab_markdown?(filename)
40 40 filename.end_with?(*%w(.mdown .md .markdown))
41 41 end
  42 +
  43 + # Simple shortcut to File.join
  44 + def tree_join(*args)
  45 + File.join(*args)
  46 + end
42 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 3 class MergeRequest < ActiveRecord::Base
4 4 include IssueCommonality
... ...
app/models/tree.rb
1 1 class Tree
2   - include Linguist::BlobHelper
  2 + include Linguist::BlobHelper
3 3 attr_accessor :path, :tree, :project, :ref
4 4  
5 5 delegate :contents,
... ... @@ -14,8 +14,8 @@ class Tree
14 14 to: :tree
15 15  
16 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 19 raw_tree / path.dup.force_encoding('ascii-8bit')
20 20 else
21 21 raw_tree
... ... @@ -26,6 +26,10 @@ class Tree
26 26 tree.is_a?(Grit::Blob)
27 27 end
28 28  
  29 + def invalid?
  30 + tree.nil?
  31 + end
  32 +
29 33 def empty?
30 34 data.blank?
31 35 end
... ...
app/roles/repository.rb
... ... @@ -45,8 +45,29 @@ module Repository
45 45 File.exists?(hook_file)
46 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 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 71 end
51 72  
52 73 def repo
... ... @@ -79,14 +100,6 @@ module Repository
79 100 @heads ||= repo.heads
80 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 103 def tree(fcommit, path = nil)
91 104 fcommit = commit if fcommit == :head
92 105 tree = fcommit.tree
... ... @@ -109,14 +122,12 @@ module Repository
109 122 # - If two or more branches are present, returns the one that has a name
110 123 # matching root_ref (default_branch or 'master' if default_branch is nil)
111 124 def discover_default_branch
112   - branches = heads.collect(&:name)
113   -
114   - if branches.length == 0
  125 + if branch_names.length == 0
115 126 nil
116   - elsif branches.length == 1
117   - branches.first
  127 + elsif branch_names.length == 1
  128 + branch_names.first
118 129 else
119   - branches.select { |v| v == root_ref }.first
  130 + branch_names.select { |v| v == root_ref }.first
120 131 end
121 132 end
122 133  
... ... @@ -144,7 +155,7 @@ module Repository
144 155  
145 156 # Build file path
146 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 159 file_path = File.join(storage_path, file_name)
149 160  
150 161 # Put files into a directory before archiving
... ...
app/roles/static_model.rb
... ... @@ -25,6 +25,10 @@ module StaticModel
25 25 id
26 26 end
27 27  
  28 + def new_record?
  29 + false
  30 + end
  31 +
28 32 def persisted?
29 33 false
30 34 end
... ...
app/views/blame/_head.html.haml 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  1 +<%= @commit.to_patch %>
... ...
app/views/commits/_commit.html.haml
1 1 %li.commit
2 2 .browse_code_link_holder
3 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 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 7 %strong.commit-author-name= commit.author_name
8 8 %span.dash &ndash;
9 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 12 %span.committed_ago
13 13 = time_ago_in_words(commit.committed_date)
14 14 ago
15 15 &nbsp;
16   -
... ...
app/views/commits/_commit_box.html.haml
... ... @@ -5,10 +5,10 @@
5 5 %span.btn.disabled.grouped
6 6 %i.icon-comment
7 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 9 %i.icon-download-alt
10 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 12 %strong Browse Code »
13 13 %h3.commit-title.page_title
14 14 = gfm escape_once(@commit.title)
... ...
app/views/commits/_diffs.html.haml
... ... @@ -5,7 +5,7 @@
5 5 %p To prevent performance issue we rejected diff information.
6 6 %p
7 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 10 %p.cgray
11 11 Showing #{pluralize(diffs.count, "changed file")}
... ... @@ -24,7 +24,7 @@
24 24 %i.icon-file
25 25 %span{id: "#{diff.old_path}"}= diff.old_path
26 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 28 %i.icon-file
29 29 %span{id: "#{diff.new_path}"}= diff.new_path
30 30 %br/
... ...
app/views/commits/_head.html.haml
1 1 %ul.nav.nav-tabs
2 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 10 = link_to project_repository_path(@project) do
11 11 Branches
12 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 15 = link_to tags_project_repository_path(@project) do
16 16 Tags
17 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 20 %li.right
21 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 23 = image_tag "rss_ui.png", title: "feed"
... ...
app/views/commits/compare.html.haml
... ... @@ -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   -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   -= 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   -: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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 1 - commit = CommitDecorator.decorate(commit)
2 2 %li.commit
3 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 5 %span= commit.author_name
6 6 &ndash;
7 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 4 = image_tag gravatar_icon(event.author_email), class: "avatar"
5 5 %span You pushed to
6 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 8 %strong= truncate(event.ref_name, length: 28)
9 9 at
10 10 %strong= link_to event.project.name, event.project
... ...
app/views/events/_event_push.html.haml
... ... @@ -5,7 +5,7 @@
5 5 .event-title
6 6 %strong.author_name #{event.author_name}
7 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 9 %strong= event.ref_name
10 10 at
11 11 %strong= link_to event.project.name, event.project
... ... @@ -21,6 +21,6 @@
21 21 %li.commits-stat
22 22 - if event.commits_count > 2
23 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 25 %strong Compare &rarr; #{event.parent_commit.id[0..7]}...#{event.last_commit.id[0..7]}
26 26 .clearfix
... ...
app/views/issues/_head.html.haml
1 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 8 %li.right
12 9 %span.rss-icon
13 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   -%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 10 - if controller_name == 'projects' && action_name == 'index'
11 11 = auto_discovery_link_tag :atom, projects_url(:atom, private_token: current_user.private_token), title: "Dashboard feed"
12 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 16 = auto_discovery_link_tag(:atom, project_issues_url(@project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues")
17 17 = csrf_meta_tags
... ...
app/views/layouts/_project_menu.html.haml
... ... @@ -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 6 = render "layouts/head_panel", title: "Admin area"
7 7 .container
8 8 %ul.main_menu
9   - %li.home{class: tab_class(:admin_root)}
  9 + = nav_link(controller: :dashboard, html_options: {class: 'home'}) do
10 10 = link_to "Stats", admin_root_path
11   - %li{class: tab_class(:admin_projects)}
  11 + = nav_link(controller: :projects) do
12 12 = link_to "Projects", admin_projects_path
13   - %li{class: tab_class(:admin_users)}
  13 + = nav_link(controller: :users) do
14 14 = link_to "Users", admin_users_path
15   - %li{class: tab_class(:admin_logs)}
  15 + = nav_link(controller: :logs) do
16 16 = link_to "Logs", admin_logs_path
17   - %li{class: tab_class(:admin_hooks)}
  17 + = nav_link(controller: :hooks) do
18 18 = link_to "Hooks", admin_hooks_path
19   - %li{class: tab_class(:admin_resque)}
  19 + = nav_link(controller: :resque) do
20 20 = link_to "Resque", admin_resque_path
21 21  
22 22 .content= yield
... ...
app/views/layouts/application.html.haml
... ... @@ -5,6 +5,20 @@
5 5 = render "layouts/flash"
6 6 = render "layouts/head_panel", title: "Dashboard"
7 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 6 = render "layouts/head_panel", title: "Profile"
7 7 .container
8 8 %ul.main_menu
9   - %li.home{class: tab_class(:profile)}
  9 + = nav_link(path: 'profile#show', html_options: {class: 'home'}) do
10 10 = link_to "Profile", profile_path
11   -
12   - %li{class: tab_class(:account)}
  11 + = nav_link(path: 'profile#account') do
13 12 = link_to "Account", profile_account_path
14   -
15   - %li{class: tab_class(:ssh_keys)}
  13 + = nav_link(controller: :keys) do
16 14 = link_to keys_path do
17 15 SSH Keys
18 16 %span.count= current_user.keys.count
19   -
20   - %li{class: tab_class(:design)}
  17 + = nav_link(path: 'profile#design') do
21 18 = link_to "Design", profile_design_path
22   -
23   - %li{class: tab_class(:history)}
  19 + = nav_link(path: 'profile#history') do
24 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 5 = render "layouts/flash"
6 6 = render "layouts/head_panel", title: @project.name
7 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 1 %ul.nav.nav-tabs
2   - %li{ class: "#{'active' if current_page?(project_path(@project)) }" }
  2 + = nav_link(path: 'projects#show') do
3 3 = link_to project_path(@project), class: "activities-tab tab" do
4 4 %i.icon-home
5 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 7 = link_to project_team_index_path(@project), class: "team-tab tab" do
8 8 %i.icon-user
9 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 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 17 = link_to project_deploy_keys_path(@project) do
20 18 %span
21 19 Deploy Keys
22   - %li.right{class: "#{'active' if controller.controller_name == "hooks" }"}
  20 + = nav_link(controller: :hooks, html_options: {class: 'right'}) do
23 21 = link_to project_hooks_path(@project) do
24 22 %span
25 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 25 = link_to edit_project_path(@project), class: "stat-tab tab " do
28 26 %i.icon-edit
29 27 Edit
... ...
app/views/protected_branches/index.html.haml
... ... @@ -34,7 +34,7 @@
34 34 - @branches.each do |branch|
35 35 %tr
36 36 %td
37   - = link_to project_commits_path(@project, ref: branch.name) do
  37 + = link_to project_commits_path(@project, branch.name) do
38 38 %strong= branch.name
39 39 - if branch.name == @project.root_ref
40 40 %span.label default
... ...
app/views/refs/_head.html.haml
... ... @@ -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   -- 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   -%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   -- 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   -.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   -- 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   -= 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 6 :plain
7 7 var row = $("table.table_#{@hex_path} tr.file_#{hexdigest(file_name)}");
8 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   -= 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   -: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 2 - commit = CommitDecorator.decorate(commit)
3 3 %tr
4 4 %td
5   - = link_to project_commits_path(@project, ref: branch.name) do
  5 + = link_to project_commits_path(@project, branch.name) do
6 6 %strong= truncate(branch.name, length: 60)
7 7 - if branch.name == @project.root_ref
8 8 %span.label default
9 9 %td
10   - = link_to project_commit_path(@project, id: commit.id) do
  10 + = link_to project_commit_path(@project, commit) do
11 11 %code= commit.short_id
12 12  
13 13 = image_tag gravatar_icon(commit.author_email), class: "", width: 16
... ...
app/views/repositories/_branches_head.html.haml
1 1 = render "commits/head"
2 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 2 - commit = CommitDecorator.new(commit)
3 3 %tr
4 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 6 %strong
7 7 = commit.head.name
8 8 - if commit.head.name == @project.root_ref
... ...
app/views/repositories/tags.html.haml
... ... @@ -12,7 +12,7 @@
12 12 - commit = CommitDecorator.decorate(commit)
13 13 %tr
14 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 16 %td
17 17 = link_to project_commit_path(@project, commit.id) do
18 18 %code= commit.short_id
... ...
app/views/shared/_ref_switcher.html.haml
1 1 = form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form" do
2 2 = select_tag "ref", grouped_options_refs, class: "project-refs-select chosen"
3 3 = hidden_field_tag :destination, destination
4   - - if respond_to?(:path)
  4 + - if defined?(path)
5 5 = hidden_field_tag :path, path
... ...
app/views/tree/_head.html.haml 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 112  
113 113 def backup_path
114 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 116 t
117 117 end
118 118  
... ...
config/initializers/inflections.rb
... ... @@ -8,3 +8,24 @@
8 8 # inflect.irregular 'person', 'people'
9 9 # inflect.uncountable %w( fish sheep )
10 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 # Add new mime types for use in respond_to blocks:
4 4 # Mime::Type.register "text/richtext", :rtf
5 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 122 end
123 123  
124 124 member do
125   - get "tree", constraints: { id: /[a-zA-Z.\/0-9_\-]+/ }
  125 + # tree viewer logs
126 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 127 get "logs_tree/:path" => "refs#logs_tree",
144 128 as: :logs_file,
145 129 constraints: {
146 130 id: /[a-zA-Z.0-9\/_\-]+/,
147 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 133 end
158 134 end
159 135  
... ... @@ -182,27 +158,27 @@ Gitlab::Application.routes.draw do
182 158 get :test
183 159 end
184 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 170 resources :team, controller: 'team_members', only: [:index]
195 171 resources :team_members
196 172 resources :milestones
197 173 resources :labels, only: [:index]
198 174 resources :issues do
199   -
200 175 collection do
201 176 post :sort
202 177 post :bulk_update
203 178 get :search
204 179 end
205 180 end
  181 +
206 182 resources :notes, only: [:index, :create, :destroy] do
207 183 collection do
208 184 post :preview
... ...
db/fixtures/test/001_repo.rb
... ... @@ -3,13 +3,13 @@ require &#39;fileutils&#39;
3 3 print "Unpacking seed repository..."
4 4  
5 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 8 # Make whatever directories we need to make
9 9 FileUtils.mkdir_p(REPO_PATH)
10 10  
11 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 14 # chdir to the repo path
15 15 FileUtils.cd(REPO_PATH) do
... ...
features/admin/active_tab.feature 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 1 Feature: Project Browse commits
2 2 Background:
3 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 7 Scenario: I browse commits list for master branch
8 8 Then I see project commits
... ... @@ -18,4 +18,4 @@ Feature: Project Browse commits
18 18 Scenario: I compare refs
19 19 Given I visit compare refs page
20 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 @@
  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 @@
  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 @@
  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 @@
  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 4 include SharedPaths
5 5  
6 6 Then 'I see project commits' do
7   - current_path.should == project_commits_path(@project)
8   -
9 7 commit = @project.commit
10 8 page.should have_content(@project.name)
11 9 page.should have_content(commit.message)
... ... @@ -34,14 +32,14 @@ class ProjectBrowseCommits &lt; Spinach::FeatureSteps
34 32 end
35 33  
36 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 37 click_button "Compare"
40 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 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 44 end
47 45 end
... ...
features/steps/project/project_browse_files.rb
... ... @@ -10,7 +10,7 @@ class ProjectBrowseFiles &lt; Spinach::FeatureSteps
10 10 end
11 11  
12 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 14 page.should have_content "app"
15 15 page.should have_content "History"
16 16 page.should have_content "Gemfile"
... ...
features/steps/shared/active_tab.rb 0 → 100644
... ... @@ -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 7 Given 'I sign in as a user' do
8 8 login_as :user
9 9 end
  10 +
  11 + Given 'I sign in as an admin' do
  12 + login_as :admin
  13 + end
10 14 end
... ...
features/steps/shared/paths.rb
1 1 module SharedPaths
2 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 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 14 end
11 15  
12   - And 'I visit dashboard issues page' do
  16 + Given 'I visit dashboard issues page' do
13 17 visit dashboard_issues_path
14 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 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 36 Given 'I visit profile page' do
21 37 visit profile_path
22 38 end
... ... @@ -25,14 +41,94 @@ module SharedPaths
25 41 visit profile_account_path
26 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 56 Given 'I visit profile token page' do
29 57 visit profile_token_path
30 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 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 132 And 'I visit project "Shop" page' do
37 133 project = Project.find_by_name("Shop")
38 134 visit project_path(project)
... ... @@ -43,23 +139,27 @@ module SharedPaths
43 139 end
44 140  
45 141 Given 'I visit compare refs page' do
46   - visit compare_project_commits_path(@project)
  142 + visit project_compare_index_path(@project)
47 143 end
48 144  
49 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 151 end
52 152  
53 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 155 end
56 156  
57 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 159 end
60 160  
61 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 163 end
64 164  
65 165 Given 'I visit project tags page' do
... ...
features/steps/shared/project.rb
1 1 module SharedProject
2 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 11 And 'I own project "Shop"' do
5 12 @project = Factory :project, :name => "Shop"
6 13 @project.add_access(@user, :admin)
... ...
features/support/env.rb
... ... @@ -23,5 +23,7 @@ Spinach.hooks.after_scenario { DatabaseCleaner.clean }
23 23 Spinach.hooks.before_run do
24 24 RSpec::Mocks::setup self
25 25  
  26 + include FactoryGirl::Syntax::Methods
  27 +
26 28 stub_gitolite!
27 29 end
... ...
lib/extracts_path.rb 0 → 100644
... ... @@ -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 10 attr_reader :config_tmp_dir, :ga_repo, :conf
11 11  
12 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 14 end
15 15  
16 16 def ga_repo
... ... @@ -19,7 +19,7 @@ module Gitlab
19 19  
20 20 def apply
21 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 23 begin
24 24 # Set exclusive lock
25 25 # to prevent race condition
... ...