Commit f5551efdfd71c6aedb609093374a6c4dbed6a78b

Authored by Dmitriy Zaporozhets
1 parent 70bf7f6e

Rewrite and improve git backend logic. Fix project movind. Raise exception to pr…

…event unexpected issues
app/controllers/admin/groups_controller.rb
@@ -22,6 +22,7 @@ class Admin::GroupsController < AdminController @@ -22,6 +22,7 @@ class Admin::GroupsController < AdminController
22 22
23 def create 23 def create
24 @group = Group.new(params[:group]) 24 @group = Group.new(params[:group])
  25 + @group.path = @group.name.dup.parameterize if @group.name
25 @group.owner = current_user 26 @group.owner = current_user
26 27
27 if @group.save 28 if @group.save
app/controllers/projects_controller.rb
@@ -34,11 +34,16 @@ class ProjectsController < ProjectResourceController @@ -34,11 +34,16 @@ class ProjectsController < ProjectResourceController
34 end 34 end
35 35
36 def update 36 def update
37 - namespace_id = params[:project].delete(:namespace_id)  
38 -  
39 - if namespace_id.present? and namespace_id.to_i != project.namespace_id  
40 - namespace = Namespace.find(namespace_id)  
41 - project.transfer(namespace) 37 + if params[:project].has_key?(:namespace_id)
  38 + namespace_id = params[:project].delete(:namespace_id)
  39 + if namespace_id == Namespace.global_id and project.namespace.present?
  40 + # Transfer to global namespace from anyone
  41 + project.transfer(nil)
  42 + elsif namespace_id.present? and namespace_id.to_i != project.namespace_id
  43 + # Transfer to someone namespace
  44 + namespace = Namespace.find(namespace_id)
  45 + project.transfer(namespace)
  46 + end
42 end 47 end
43 48
44 respond_to do |format| 49 respond_to do |format|
app/helpers/application_helper.rb
@@ -84,6 +84,7 @@ module ApplicationHelper @@ -84,6 +84,7 @@ module ApplicationHelper
84 end 84 end
85 85
86 options = [ 86 options = [
  87 + ["Global", [['/', Namespace.global_id]] ],
87 ["Groups", groups.map {|g| [g.human_name, g.id]} ], 88 ["Groups", groups.map {|g| [g.human_name, g.id]} ],
88 [ "Users", users.map {|u| [u.human_name, u.id]} ] 89 [ "Users", users.map {|u| [u.human_name, u.id]} ]
89 ] 90 ]
app/models/namespace.rb
@@ -35,6 +35,10 @@ class Namespace < ActiveRecord::Base @@ -35,6 +35,10 @@ class Namespace < ActiveRecord::Base
35 where("name LIKE :query OR path LIKE :query", query: "%#{query}%") 35 where("name LIKE :query OR path LIKE :query", query: "%#{query}%")
36 end 36 end
37 37
  38 + def self.global_id
  39 + 'GLN'
  40 + end
  41 +
38 def to_param 42 def to_param
39 path 43 path
40 end 44 end
@@ -51,6 +55,9 @@ class Namespace < ActiveRecord::Base @@ -51,6 +55,9 @@ class Namespace < ActiveRecord::Base
51 def move_dir 55 def move_dir
52 old_path = File.join(Gitlab.config.git_base_path, path_was) 56 old_path = File.join(Gitlab.config.git_base_path, path_was)
53 new_path = File.join(Gitlab.config.git_base_path, path) 57 new_path = File.join(Gitlab.config.git_base_path, path)
  58 + if File.exists?(new_path)
  59 + raise "Already exists"
  60 + end
54 system("mv #{old_path} #{new_path}") 61 system("mv #{old_path} #{new_path}")
55 end 62 end
56 63
app/models/project.rb
@@ -111,12 +111,14 @@ class Project < ActiveRecord::Base @@ -111,12 +111,14 @@ class Project < ActiveRecord::Base
111 111
112 # Apply namespace if user has access to it 112 # Apply namespace if user has access to it
113 # else fallback to user namespace 113 # else fallback to user namespace
114 - project.namespace_id = user.namespace_id  
115 -  
116 - if namespace_id  
117 - group = Group.find_by_id(namespace_id)  
118 - if user.can? :manage_group, group  
119 - project.namespace_id = namespace_id 114 + if namespace_id != Namespace.global_id
  115 + project.namespace_id = user.namespace_id
  116 +
  117 + if namespace_id
  118 + group = Group.find_by_id(namespace_id)
  119 + if user.can? :manage_group, group
  120 + project.namespace_id = namespace_id
  121 + end
120 end 122 end
121 end 123 end
122 124
@@ -254,12 +256,16 @@ class Project < ActiveRecord::Base @@ -254,12 +256,16 @@ class Project < ActiveRecord::Base
254 old_dir = old_namespace.try(:path) || '' 256 old_dir = old_namespace.try(:path) || ''
255 new_dir = new_namespace.try(:path) || '' 257 new_dir = new_namespace.try(:path) || ''
256 258
257 - old_repo = File.join(old_dir, self.path)  
258 -  
259 - git_host.move_repository(old_repo, self.path_with_namespace, self) 259 + old_repo = if old_dir.present?
  260 + File.join(old_dir, self.path)
  261 + else
  262 + self.path
  263 + end
260 264
261 Gitlab::ProjectMover.new(self, old_dir, new_dir).execute 265 Gitlab::ProjectMover.new(self, old_dir, new_dir).execute
262 266
  267 + git_host.move_repository(old_repo, self.path_with_namespace, self)
  268 +
263 save! 269 save!
264 end 270 end
265 end 271 end
app/roles/repository.rb
@@ -83,7 +83,7 @@ module Repository @@ -83,7 +83,7 @@ module Repository
83 end 83 end
84 84
85 def path_to_repo 85 def path_to_repo
86 - File.join(Gitlab.config.git_base_path, namespace_dir, "#{path}.git") 86 + File.join(Gitlab.config.git_base_path, "#{path_with_namespace}.git")
87 end 87 end
88 88
89 def namespace_dir 89 def namespace_dir
@@ -165,7 +165,7 @@ module Repository @@ -165,7 +165,7 @@ module Repository
165 165
166 # Build file path 166 # Build file path
167 file_name = self.path + "-" + commit.id.to_s + ".tar.gz" 167 file_name = self.path + "-" + commit.id.to_s + ".tar.gz"
168 - storage_path = Rails.root.join("tmp", "repositories", self.path) 168 + storage_path = Rails.root.join("tmp", "repositories", self.path_with_namespace)
169 file_path = File.join(storage_path, file_name) 169 file_path = File.join(storage_path, file_name)
170 170
171 # Put files into a directory before archiving 171 # Put files into a directory before archiving
app/views/admin/dashboard/index.html.haml
@@ -28,6 +28,8 @@ @@ -28,6 +28,8 @@
28 %h1= Project.count 28 %h1= Project.count
29 %hr 29 %hr
30 = link_to 'New Project', new_project_path, class: "btn small" 30 = link_to 'New Project', new_project_path, class: "btn small"
  31 +  
  32 + = link_to 'New Group', new_admin_group_path, class: "btn small"
31 .span4 33 .span4
32 .ui-box 34 .ui-box
33 %h5 Users 35 %h5 Users
@@ -44,7 +46,7 @@ @@ -44,7 +46,7 @@
44 %hr 46 %hr
45 - @projects.each do |project| 47 - @projects.each do |project|
46 %p 48 %p
47 - = link_to project.name, [:admin, project] 49 + = link_to project.name_with_namespace, [:admin, project]
48 .span6 50 .span6
49 %h3 Latest users 51 %h3 Latest users
50 %hr 52 %hr
app/views/admin/groups/new.html.haml
1 %h3.page_title New Group 1 %h3.page_title New Group
2 -%br  
3 -= render 'form' 2 +%hr
  3 += form_for [:admin, @group] do |f|
  4 + - if @group.errors.any?
  5 + .alert-message.block-message.error
  6 + %span= @group.errors.full_messages.first
  7 + .clearfix
  8 + = f.label :name do
  9 + Group name is
  10 + .input
  11 + = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left"
  12 +  
  13 + = f.submit 'Create group', class: "btn primary"
  14 + %hr
  15 + .padded
  16 + %ul
  17 + %li Group is kind of directory for several projects
  18 + %li All created groups are private
  19 + %li People within a group see only projects they have access to
  20 + %li All projects of group will be stored in group directory
  21 + %li You will be able to move existing projects into group
app/views/admin/groups/show.html.haml
@@ -22,7 +22,7 @@ @@ -22,7 +22,7 @@
22 %b 22 %b
23 Path: 23 Path:
24 %td 24 %td
25 - = @group.path 25 + %span.monospace= File.join(Gitlab.config.git_base_path, @group.path)
26 %tr 26 %tr
27 %td 27 %td
28 %b 28 %b
@@ -43,10 +43,14 @@ @@ -43,10 +43,14 @@
43 = link_to 'Remove from group', remove_project_admin_group_path(@group, project_id: project.id), confirm: 'Are you sure?', method: :delete, class: "btn danger small" 43 = link_to 'Remove from group', remove_project_admin_group_path(@group, project_id: project.id), confirm: 'Are you sure?', method: :delete, class: "btn danger small"
44 .clearfix 44 .clearfix
45 45
46 -%br  
47 -%h3 Add new project  
48 -%br 46 +
49 = form_tag project_update_admin_group_path(@group), class: "bulk_import", method: :put do 47 = form_tag project_update_admin_group_path(@group), class: "bulk_import", method: :put do
50 - = select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5'  
51 - .form-actions  
52 - = submit_tag 'Add', class: "btn primary" 48 + %fieldset
  49 + %legend Move projects to group
  50 + .clearfix
  51 + = label_tag :project_ids do
  52 + Projects
  53 + .input
  54 + = select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5'
  55 + .form-actions
  56 + = submit_tag 'Add', class: "btn primary"
app/views/admin/users/_form.html.haml
@@ -6,52 +6,42 @@ @@ -6,52 +6,42 @@
6 - @admin_user.errors.full_messages.each do |msg| 6 - @admin_user.errors.full_messages.each do |msg|
7 %li= msg 7 %li= msg
8 8
9 - .row  
10 - .span7  
11 - .ui-box  
12 - %br  
13 - .clearfix  
14 - = f.label :name  
15 - .input  
16 - = f.text_field :name  
17 - %span.help-inline * required  
18 - .clearfix  
19 - = f.label :username  
20 - .input  
21 - = f.text_field :username  
22 - %span.help-inline * required  
23 - .clearfix  
24 - = f.label :email  
25 - .input  
26 - = f.text_field :email  
27 - %span.help-inline * required  
28 - %hr  
29 - -if f.object.new_record?  
30 - .clearfix  
31 - = f.label :force_random_password do  
32 - %span Generate random password  
33 - .input= f.check_box :force_random_password, {}, true, nil 9 + %fieldset
  10 + %legend Account
  11 + .clearfix
  12 + = f.label :name
  13 + .input
  14 + = f.text_field :name, required: true
  15 + %span.help-inline * required
  16 + .clearfix
  17 + = f.label :username
  18 + .input
  19 + = f.text_field :username, required: true
  20 + %span.help-inline * required
  21 + .clearfix
  22 + = f.label :email
  23 + .input
  24 + = f.text_field :email, required: true
  25 + %span.help-inline * required
34 26
35 - %div.password-fields  
36 - .clearfix  
37 - = f.label :password  
38 - .input= f.password_field :password, disabled: f.object.force_random_password  
39 - .clearfix  
40 - = f.label :password_confirmation  
41 - .input= f.password_field :password_confirmation, disabled: f.object.force_random_password  
42 - %hr  
43 - .clearfix  
44 - = f.label :skype  
45 - .input= f.text_field :skype  
46 - .clearfix  
47 - = f.label :linkedin  
48 - .input= f.text_field :linkedin  
49 - .clearfix  
50 - = f.label :twitter  
51 - .input= f.text_field :twitter  
52 - .span5  
53 - .ui-box  
54 - %br 27 + %fieldset
  28 + %legend Password
  29 + .clearfix
  30 + = f.label :password
  31 + .input= f.password_field :password, disabled: f.object.force_random_password
  32 + .clearfix
  33 + = f.label :password_confirmation
  34 + .input= f.password_field :password_confirmation, disabled: f.object.force_random_password
  35 + -if f.object.new_record?
  36 + .clearfix
  37 + = f.label :force_random_password do
  38 + %span Generate random password
  39 + .input= f.check_box :force_random_password, {}, true, nil
  40 +
  41 + %fieldset
  42 + %legend Access
  43 + .row
  44 + .span8
55 .clearfix 45 .clearfix
56 = f.label :projects_limit 46 = f.label :projects_limit
57 .input= f.number_field :projects_limit 47 .input= f.number_field :projects_limit
@@ -60,23 +50,27 @@ @@ -60,23 +50,27 @@
60 = f.label :admin do 50 = f.label :admin do
61 %strong.cred Administrator 51 %strong.cred Administrator
62 .input= f.check_box :admin 52 .input= f.check_box :admin
  53 + .span4
63 - unless @admin_user.new_record? 54 - unless @admin_user.new_record?
64 - %hr  
65 - .padded.cred 55 + .alert.alert-error
66 - if @admin_user.blocked 56 - if @admin_user.blocked
67 - %span  
68 - This user is blocked and is not able to login to GitLab  
69 - .clearfix  
70 - = link_to 'Unblock User', unblock_admin_user_path(@admin_user), method: :put, class: "btn small right" 57 + %p This user is blocked and is not able to login to GitLab
  58 + = link_to 'Unblock User', unblock_admin_user_path(@admin_user), method: :put, class: "btn small"
71 - else 59 - else
72 - %span  
73 - Blocked users will be removed from all projects & will not be able to login to GitLab.  
74 - .clearfix  
75 - = link_to 'Block User', block_admin_user_path(@admin_user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small right danger" 60 + %p Blocked users will be removed from all projects & will not be able to login to GitLab.
  61 + = link_to 'Block User', block_admin_user_path(@admin_user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small danger"
  62 + %fieldset
  63 + %legend Profile
  64 + .clearfix
  65 + = f.label :skype
  66 + .input= f.text_field :skype
  67 + .clearfix
  68 + = f.label :linkedin
  69 + .input= f.text_field :linkedin
  70 + .clearfix
  71 + = f.label :twitter
  72 + .input= f.text_field :twitter
76 73
77 - .row  
78 - .span6  
79 - .span6  
80 .actions 74 .actions
81 = f.submit 'Save', class: "btn save-btn" 75 = f.submit 'Save', class: "btn save-btn"
82 - if @admin_user.new_record? 76 - if @admin_user.new_record?
app/views/admin/users/edit.html.haml
1 -%h3.page_title #{@admin_user.name} → Edit user 1 +%h3.page_title
  2 + #{@admin_user.name} →
  3 + %i.icon-edit
  4 + Edit user
2 %hr 5 %hr
3 = render 'form' 6 = render 'form'
app/views/admin/users/new.html.haml
1 -%h3.page_title New user  
2 -%br 1 +%h3.page_title
  2 + %i.icon-plus
  3 + New user
  4 +%hr
3 = render 'form' 5 = render 'form'
app/views/dashboard/issues.atom.builder
1 xml.instruct! 1 xml.instruct!
2 xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do 2 xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
3 - xml.title "#{@user.name} issues"  
4 - xml.link :href => dashboard_issues_url(:atom, :private_token => @user.private_token), :rel => "self", :type => "application/atom+xml"  
5 - xml.link :href => dashboard_issues_url(:private_token => @user.private_token), :rel => "alternate", :type => "text/html"  
6 - xml.id dashboard_issues_url(:private_token => @user.private_token) 3 + xml.title "#{current_user.name} issues"
  4 + xml.link :href => dashboard_issues_url(:atom, :private_token => current_user.private_token), :rel => "self", :type => "application/atom+xml"
  5 + xml.link :href => dashboard_issues_url(:private_token => current_user.private_token), :rel => "alternate", :type => "text/html"
  6 + xml.id dashboard_issues_url(:private_token => current_user.private_token)
7 xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any? 7 xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any?
8 8
9 @issues.each do |issue| 9 @issues.each do |issue|
app/views/events/_event.html.haml
1 - if event.allowed? 1 - if event.allowed?
2 %div.event-item 2 %div.event-item
3 = event_image(event) 3 = event_image(event)
4 - = image_tag gravatar_icon(event.author_email), class: "avatar" 4 + = image_tag gravatar_icon(event.author_email), class: "avatar s24"
5 5
6 - if event.push? 6 - if event.push?
7 = render "events/event/push", event: event 7 = render "events/event/push", event: event
app/views/layouts/notify.html.haml
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 %td{style: "font-size: 0px;", width: "20"} 20 %td{style: "font-size: 0px;", width: "20"}
21 21
22 %td{align: "left", style: "padding: 18px 0 10px;", width: "580"} 22 %td{align: "left", style: "padding: 18px 0 10px;", width: "580"}
23 - %h1{style: "color: #BBBBBB; font: normal 32px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 40px;"} 23 + %h1{style: "color: #BBBBBB; font: normal 22px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 32px;"}
24 GITLAB 24 GITLAB
25 - if @project 25 - if @project
26 | #{@project.name} 26 | #{@project.name}
app/views/search/show.html.haml
@@ -23,7 +23,7 @@ @@ -23,7 +23,7 @@
23 %tr 23 %tr
24 %td 24 %td
25 = link_to project do 25 = link_to project do
26 - %strong.term= project.name 26 + %strong.term= project.name_with_namespace
27 %small.cgray 27 %small.cgray
28 last activity at 28 last activity at
29 = project.last_activity_date.stamp("Aug 25, 2011") 29 = project.last_activity_date.stamp("Aug 25, 2011")
app/views/shared/_no_ssh.html.haml
1 - if current_user.require_ssh_key? 1 - if current_user.require_ssh_key?
2 %p.error_message 2 %p.error_message
3 - You won't be able to pull or push project code until you #{link_to 'add an SSH key', new_key_path} to your profile 3 + You won't be able to pull or push project code via SSH until you #{link_to 'add an SSH key', new_key_path} to your profile
lib/gitlab/backend/gitolite.rb
@@ -23,7 +23,7 @@ module Gitlab @@ -23,7 +23,7 @@ module Gitlab
23 end 23 end
24 24
25 def update_repository project 25 def update_repository project
26 - config.update_project!(project.path, project) 26 + config.update_project!(project)
27 end 27 end
28 28
29 def move_repository(old_repo, new_repo, project) 29 def move_repository(old_repo, new_repo, project)
lib/gitlab/backend/gitolite_config.rb
@@ -109,18 +109,18 @@ module Gitlab @@ -109,18 +109,18 @@ module Gitlab
109 end 109 end
110 110
111 # update or create 111 # update or create
112 - def update_project(repo_name, project) 112 + def update_project(project)
113 repo = update_project_config(project, conf) 113 repo = update_project_config(project, conf)
114 conf.add_repo(repo, true) 114 conf.add_repo(repo, true)
115 end 115 end
116 116
117 - def update_project!(repo_name, project) 117 + def update_project!( project)
118 apply do |config| 118 apply do |config|
119 - config.update_project(repo_name, project) 119 + config.update_project(project)
120 end 120 end
121 end 121 end
122 122
123 - # Updates many projects and uses project.path as the repo path 123 + # Updates many projects and uses project.path_with_namespace as the repo path
124 # An order of magnitude faster than update_project 124 # An order of magnitude faster than update_project
125 def update_projects(projects) 125 def update_projects(projects)
126 projects.each do |project| 126 projects.each do |project|
lib/gitlab/project_mover.rb
@@ -21,6 +21,10 @@ module Gitlab @@ -21,6 +21,10 @@ module Gitlab
21 old_path = File.join(Gitlab.config.git_base_path, old_dir, "#{project.path}.git") 21 old_path = File.join(Gitlab.config.git_base_path, old_dir, "#{project.path}.git")
22 new_path = File.join(new_dir_path, "#{project.path}.git") 22 new_path = File.join(new_dir_path, "#{project.path}.git")
23 23
  24 + if File.exists? new_path
  25 + raise ProjectMoveError.new("Destination #{new_path} already exists")
  26 + end
  27 +
24 if system("mv #{old_path} #{new_path}") 28 if system("mv #{old_path} #{new_path}")
25 log_info "Project #{project.name} was moved from #{old_path} to #{new_path}" 29 log_info "Project #{project.name} was moved from #{old_path} to #{new_path}"
26 true 30 true