Commit 1882baa1aaa1c195cce55678b2b8a12e1b59db34

Authored by Dmitriy Zaporozhets
1 parent 8e4625af

Feature: Deploy keys between projects

app/controllers/deploy_keys_controller.rb
@@ -5,7 +5,8 @@ class DeployKeysController < ProjectResourceController @@ -5,7 +5,8 @@ class DeployKeysController < ProjectResourceController
5 before_filter :authorize_admin_project! 5 before_filter :authorize_admin_project!
6 6
7 def index 7 def index
8 - @keys = @project.deploy_keys.all 8 + @enabled_keys = @project.deploy_keys.all
  9 + @available_keys = available_keys - @enabled_keys
9 end 10 end
10 11
11 def show 12 def show
@@ -19,8 +20,9 @@ class DeployKeysController < ProjectResourceController @@ -19,8 +20,9 @@ class DeployKeysController < ProjectResourceController
19 end 20 end
20 21
21 def create 22 def create
22 - @key = @project.deploy_keys.new(params[:key])  
23 - if @key.save 23 + @key = DeployKey.new(params[:deploy_key])
  24 +
  25 + if @key.valid? && @project.deploy_keys << @key
24 redirect_to project_deploy_keys_path(@project) 26 redirect_to project_deploy_keys_path(@project)
25 else 27 else
26 render "new" 28 render "new"
@@ -36,4 +38,22 @@ class DeployKeysController &lt; ProjectResourceController @@ -36,4 +38,22 @@ class DeployKeysController &lt; ProjectResourceController
36 format.js { render nothing: true } 38 format.js { render nothing: true }
37 end 39 end
38 end 40 end
  41 +
  42 + def enable
  43 + project.deploy_keys << available_keys.find(params[:id])
  44 +
  45 + redirect_to project_deploy_keys_path(@project)
  46 + end
  47 +
  48 + def disable
  49 + @project.deploy_keys_projects.where(deploy_key_id: params[:id]).last.destroy
  50 +
  51 + redirect_to project_deploy_keys_path(@project)
  52 + end
  53 +
  54 + protected
  55 +
  56 + def available_keys
  57 + @available_keys ||= DeployKey.in_projects(current_user.owned_projects)
  58 + end
39 end 59 end
app/models/deploy_key.rb
1 class DeployKey < Key 1 class DeployKey < Key
2 has_many :deploy_keys_projects, dependent: :destroy 2 has_many :deploy_keys_projects, dependent: :destroy
3 has_many :projects, through: :deploy_keys_projects 3 has_many :projects, through: :deploy_keys_projects
  4 +
  5 + scope :in_projects, ->(projects) { joins(:deploy_keys_projects).where('deploy_keys_projects.project_id in (?)', projects) }
4 end 6 end
app/models/key.rb
@@ -46,10 +46,6 @@ class Key &lt; ActiveRecord::Base @@ -46,10 +46,6 @@ class Key &lt; ActiveRecord::Base
46 errors.add(:key, "can't be fingerprinted") if $?.exitstatus != 0 46 errors.add(:key, "can't be fingerprinted") if $?.exitstatus != 0
47 end 47 end
48 48
49 - def is_deploy_key  
50 - project.present?  
51 - end  
52 -  
53 # projects that has this key 49 # projects that has this key
54 def projects 50 def projects
55 user.authorized_projects 51 user.authorized_projects
app/models/project.rb
@@ -55,7 +55,6 @@ class Project &lt; ActiveRecord::Base @@ -55,7 +55,6 @@ class Project &lt; ActiveRecord::Base
55 has_many :users_projects, dependent: :destroy 55 has_many :users_projects, dependent: :destroy
56 has_many :notes, dependent: :destroy 56 has_many :notes, dependent: :destroy
57 has_many :snippets, dependent: :destroy 57 has_many :snippets, dependent: :destroy
58 - has_many :deploy_keys, dependent: :destroy, class_name: "Key", foreign_key: "project_id"  
59 has_many :hooks, dependent: :destroy, class_name: "ProjectHook" 58 has_many :hooks, dependent: :destroy, class_name: "ProjectHook"
60 has_many :protected_branches, dependent: :destroy 59 has_many :protected_branches, dependent: :destroy
61 has_many :user_team_project_relationships, dependent: :destroy 60 has_many :user_team_project_relationships, dependent: :destroy
@@ -65,6 +64,9 @@ class Project &lt; ActiveRecord::Base @@ -65,6 +64,9 @@ class Project &lt; ActiveRecord::Base
65 has_many :user_team_user_relationships, through: :user_teams 64 has_many :user_team_user_relationships, through: :user_teams
66 has_many :user_teams_members, through: :user_team_user_relationships 65 has_many :user_teams_members, through: :user_team_user_relationships
67 66
  67 + has_many :deploy_keys_projects, dependent: :destroy
  68 + has_many :deploy_keys, through: :deploy_keys_projects
  69 +
68 delegate :name, to: :owner, allow_nil: true, prefix: true 70 delegate :name, to: :owner, allow_nil: true, prefix: true
69 71
70 # Validations 72 # Validations
app/models/user.rb
@@ -89,7 +89,7 @@ class User &lt; ActiveRecord::Base @@ -89,7 +89,7 @@ class User &lt; ActiveRecord::Base
89 89
90 has_many :personal_projects, through: :namespace, source: :projects 90 has_many :personal_projects, through: :namespace, source: :projects
91 has_many :projects, through: :users_projects 91 has_many :projects, through: :users_projects
92 - has_many :own_projects, foreign_key: :creator_id 92 + has_many :own_projects, foreign_key: :creator_id, class_name: 'Project'
93 has_many :owned_projects, through: :namespaces, source: :projects 93 has_many :owned_projects, through: :namespaces, source: :projects
94 94
95 # 95 #
app/views/deploy_keys/_deploy_key.html.haml 0 → 100644
@@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
  1 +%li
  2 + .pull-right
  3 + - if @available_keys.include?(deploy_key)
  4 + = link_to enable_project_deploy_key_path(@project, deploy_key), class: 'btn btn-small', method: :put do
  5 + %i.icon-plus
  6 + Enable
  7 + - else
  8 + - if deploy_key.projects.count > 1
  9 + = link_to disable_project_deploy_key_path(@project, deploy_key), class: 'btn btn-small', method: :put do
  10 + %i.icon-off
  11 + Disable
  12 + - else
  13 + = link_to 'Remove', project_deploy_key_path(@project, deploy_key), confirm: 'Are you sure?', method: :delete, class: "btn btn-remove delete-key btn-small pull-right"
  14 +
  15 +
  16 + = link_to project_deploy_key_path(@project, deploy_key) do
  17 + %i.icon-key
  18 + %strong= deploy_key.title
  19 +
  20 + %p.light.prepend-top-10
  21 + - deploy_key.projects.map(&:name_with_namespace).each do |project_name|
  22 + %span.label= project_name
  23 + %small.pull-right
  24 + Created #{time_ago_in_words(deploy_key.created_at)} ago
  25 +
app/views/deploy_keys/_form.html.haml
@@ -18,6 +18,6 @@ @@ -18,6 +18,6 @@
18 = link_to "here", help_ssh_path 18 = link_to "here", help_ssh_path
19 19
20 .actions 20 .actions
21 - = f.submit 'Save', class: "btn-save btn" 21 + = f.submit 'Create', class: "btn-create btn"
22 = link_to "Cancel", project_deploy_keys_path(@project), class: "btn btn-cancel" 22 = link_to "Cancel", project_deploy_keys_path(@project), class: "btn btn-cancel"
23 23
app/views/deploy_keys/_show.html.haml
@@ -1,12 +0,0 @@ @@ -1,12 +0,0 @@
1 -%tr  
2 - %td  
3 - %a{href: project_deploy_key_path(key.project, key)}  
4 - %strong= key.title  
5 - %td  
6 - %span.update-author  
7 - Added  
8 - = time_ago_in_words(key.created_at)  
9 - ago  
10 - %td  
11 - = link_to 'Remove', project_deploy_key_path(key.project, key), confirm: 'Are you sure?', method: :delete, class: "btn btn-remove delete-key btn-small pull-right"  
12 -  
app/views/deploy_keys/index.html.haml
1 = render "projects/settings_nav" 1 = render "projects/settings_nav"
2 2
3 %p.slead 3 %p.slead
4 - Deploy keys allow read-only access to repository. They can be used for CI, staging or production servers. A deploy key can be added to only one project. If you need to add the same key to multiple projects you can create a deploy user and add that user to multiple projects. 4 + Deploy keys allow read-only access to repository. They can be used for CI, staging or production servers
5 5
6 - - if can? current_user, :admin_project, @project  
7 - = link_to new_project_deploy_key_path(@project), class: "btn btn-small", title: "New Deploy Key" do  
8 - Add Deploy Key  
9 -- if @keys.any?  
10 - %table  
11 - %thead  
12 - %tr  
13 - %th Keys  
14 - %th  
15 - %th  
16 - - @keys.each do |key|  
17 - = render(partial: 'show', locals: {key: key}) 6 +%p
  7 + You can create a deploy key or add existing one
  8 + = link_to new_project_deploy_key_path(@project), class: "btn btn-primary pull-right", title: "New Deploy Key" do
  9 + %i.icon-plus
  10 + New Deploy Key
  11 +
  12 +%hr.clearfix
  13 +
  14 +.row
  15 + .span6.enabled-keys
  16 + %h5.cgreen
  17 + Enabled deploy keys
  18 + %small for this project
  19 + %ul.bordered-list
  20 + = render @enabled_keys
  21 + .span6.available-keys
  22 + %h5
  23 + Available deploy keys
  24 + %small from projects you are able to manage
  25 + %ul.bordered-list
  26 + = render @available_keys
app/views/deploy_keys/show.html.haml
@@ -12,4 +12,4 @@ @@ -12,4 +12,4 @@
12 %hr 12 %hr
13 %pre= @key.key 13 %pre= @key.key
14 .pull-right 14 .pull-right
15 - = link_to 'Remove', project_deploy_key_path(@key.project, @key), confirm: 'Are you sure?', method: :delete, class: "btn-remove btn delete-key" 15 + = link_to 'Remove', project_deploy_key_path(@project, @key), confirm: 'Are you sure?', method: :delete, class: "btn-remove btn delete-key"
app/views/refs/logs_tree.js.haml
1 -- @logs.each do |content_data| 1 +- @logs.each do |content_data|
2 - file_name = content_data[:file_name] 2 - file_name = content_data[:file_name]
3 - commit = content_data[:commit] 3 - commit = content_data[:commit]
4 4
config/routes.rb
@@ -215,7 +215,13 @@ Gitlab::Application.routes.draw do @@ -215,7 +215,13 @@ Gitlab::Application.routes.draw do
215 end 215 end
216 end 216 end
217 217
218 - resources :deploy_keys 218 + resources :deploy_keys do
  219 + member do
  220 + put :enable
  221 + put :disable
  222 + end
  223 + end
  224 +
219 resources :protected_branches, only: [:index, :create, :destroy] 225 resources :protected_branches, only: [:index, :create, :destroy]
220 226
221 resources :refs, only: [] do 227 resources :refs, only: [] do
spec/features/projects_deploy_keys_spec.rb
@@ -1,67 +0,0 @@ @@ -1,67 +0,0 @@
1 -require 'spec_helper'  
2 -  
3 -describe "Projects", "DeployKeys" do  
4 - let(:project) { create(:project) }  
5 -  
6 - before do  
7 - login_as :user  
8 - project.team << [@user, :master]  
9 - end  
10 -  
11 - describe "GET /keys" do  
12 - before do  
13 - @key = create(:key, project: project)  
14 - visit project_deploy_keys_path(project)  
15 - end  
16 -  
17 - subject { page }  
18 -  
19 - it { should have_content(@key.title) }  
20 -  
21 - describe "Destroy" do  
22 - before { visit project_deploy_key_path(project, @key) }  
23 -  
24 - it "should remove entry" do  
25 - expect {  
26 - click_link "Remove"  
27 - }.to change { project.deploy_keys.count }.by(-1)  
28 - end  
29 - end  
30 - end  
31 -  
32 - describe "New key" do  
33 - before do  
34 - visit project_deploy_keys_path(project)  
35 - click_link "New Deploy Key"  
36 - end  
37 -  
38 - it "should open new key popup" do  
39 - page.should have_content("New Deploy key")  
40 - end  
41 -  
42 - describe "fill in" do  
43 - before do  
44 - fill_in "key_title", with: "laptop"  
45 - fill_in "key_key", with: "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAzrEJUIR6Y03TCE9rIJ+GqTBvgb8t1jI9h5UBzCLuK4VawOmkLornPqLDrGbm6tcwM/wBrrLvVOqi2HwmkKEIecVO0a64A4rIYScVsXIniHRS6w5twyn1MD3sIbN+socBDcaldECQa2u1dI3tnNVcs8wi77fiRe7RSxePsJceGoheRQgC8AZ510UdIlO+9rjIHUdVN7LLyz512auAfYsgx1OfablkQ/XJcdEwDNgi9imI6nAXhmoKUm1IPLT2yKajTIC64AjLOnE0YyCh6+7RFMpiMyu1qiOCpdjYwTgBRiciNRZCH8xIedyCoAmiUgkUT40XYHwLuwiPJICpkAzp7Q== user@laptop"  
46 - end  
47 -  
48 - it { expect { click_button "Save" }.to change {Key.count}.by(1) }  
49 -  
50 - it "should add new key to table" do  
51 - click_button "Save"  
52 -  
53 - page.should have_content "laptop"  
54 - end  
55 - end  
56 - end  
57 -  
58 - describe "Show page" do  
59 - before do  
60 - @key = create(:key, project: project)  
61 - visit project_deploy_key_path(project, @key)  
62 - end  
63 -  
64 - it { page.should have_content @key.title }  
65 - it { page.should have_content @key.key[0..10] }  
66 - end  
67 -end