Commit 37224dc9c1ee80ba9030b616e2bc87bd96919e09

Authored by Dmitriy Zaporozhets
1 parent 3a9e5a93

ProtectedBranches model, Master permission for repo\n Allow push to protected br…

…anch for masters only
app/controllers/protected_branches_controller.rb 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +class ProtectedBranchesController < ApplicationController
  2 + before_filter :project
  3 +
  4 + # Authorize
  5 + before_filter :add_project_abilities
  6 + before_filter :authorize_read_project!
  7 + before_filter :require_non_empty_project
  8 +
  9 + layout "project"
  10 +
  11 + def index
  12 + @branches = @project.protected_branches.all
  13 + @protected_branch = @project.protected_branches.new
  14 + end
  15 +
  16 + def create
  17 + @project.protected_branches.create(params[:protected_branch])
  18 + redirect_to project_protected_branches_path(@project)
  19 + end
  20 +
  21 + def destroy
  22 + end
  23 +end
... ...
app/models/project.rb
... ... @@ -16,6 +16,7 @@ class Project &lt; ActiveRecord::Base
16 16 has_many :snippets, :dependent => :destroy
17 17 has_many :deploy_keys, :dependent => :destroy, :foreign_key => "project_id", :class_name => "Key"
18 18 has_many :web_hooks, :dependent => :destroy
  19 + has_many :protected_branches, :dependent => :destroy
19 20  
20 21 acts_as_taggable
21 22  
... ... @@ -138,6 +139,15 @@ class Project &lt; ActiveRecord::Base
138 139 data
139 140 end
140 141  
  142 + def open_branches
  143 + if protected_branches.empty?
  144 + self.repo.heads
  145 + else
  146 + pnames = protected_branches.map(&:name)
  147 + self.repo.heads.reject { |h| pnames.include?(h.name) }
  148 + end.sort_by(&:name)
  149 + end
  150 +
141 151 def team_member_by_name_or_email(email = nil, name = nil)
142 152 user = users.where("email like ? or name like ?", email, name).first
143 153 users_projects.find_by_user_id(user.id) if user
... ... @@ -210,6 +220,12 @@ class Project &lt; ActiveRecord::Base
210 220 keys.map(&:identifier)
211 221 end
212 222  
  223 + def repository_masters
  224 + keys = Key.joins({:user => :users_projects}).
  225 + where("users_projects.project_id = ? AND users_projects.repo_access = ?", id, Repository::REPO_MASTER)
  226 + keys.map(&:identifier)
  227 + end
  228 +
213 229 def readers
214 230 @readers ||= users_projects.includes(:user).where(:project_access => [PROJECT_R, PROJECT_RW, PROJECT_RWA]).map(&:user)
215 231 end
... ... @@ -235,7 +251,7 @@ class Project &lt; ActiveRecord::Base
235 251 end
236 252  
237 253 def allow_pull_for?(user)
238   - !users_projects.where(:user_id => user.id, :repo_access => [Repository::REPO_R, Repository::REPO_RW]).empty?
  254 + !users_projects.where(:user_id => user.id, :repo_access => [Repository::REPO_R, Repository::REPO_RW, Repository::REPO_MASTER]).empty?
239 255 end
240 256  
241 257 def root_ref
... ... @@ -340,15 +356,18 @@ end
340 356 #
341 357 # Table name: projects
342 358 #
343   -# id :integer not null, primary key
344   -# name :string(255)
345   -# path :string(255)
346   -# description :text
347   -# created_at :datetime
348   -# updated_at :datetime
349   -# private_flag :boolean default(TRUE), not null
350   -# code :string(255)
351   -# owner_id :integer
352   -# default_branch :string(255) default("master"), not null
  359 +# id :integer not null, primary key
  360 +# name :string(255)
  361 +# path :string(255)
  362 +# description :text
  363 +# created_at :datetime
  364 +# updated_at :datetime
  365 +# private_flag :boolean default(TRUE), not null
  366 +# code :string(255)
  367 +# owner_id :integer
  368 +# default_branch :string(255) default("master"), not null
  369 +# issues_enabled :boolean default(TRUE), not null
  370 +# wall_enabled :boolean default(TRUE), not null
  371 +# merge_requests_enabled :boolean default(TRUE), not null
353 372 #
354 373  
... ...
app/models/protected_branch.rb 0 → 100644
... ... @@ -0,0 +1,29 @@
  1 +class ProtectedBranch < ActiveRecord::Base
  2 + belongs_to :project
  3 + validates_presence_of :project_id
  4 + validates_presence_of :name
  5 +
  6 + after_save :update_repository
  7 + after_destroy :update_repository
  8 +
  9 + def update_repository
  10 + Gitlabhq::GitHost.system.new.configure do |c|
  11 + c.update_project(project.path, project)
  12 + end
  13 + end
  14 +
  15 + def commit
  16 + project.commit(self.name)
  17 + end
  18 +end
  19 +# == Schema Information
  20 +#
  21 +# Table name: protected_branches
  22 +#
  23 +# id :integer not null, primary key
  24 +# project_id :integer not null
  25 +# name :string(255) not null
  26 +# created_at :datetime not null
  27 +# updated_at :datetime not null
  28 +#
  29 +
... ...
app/models/repository.rb
... ... @@ -4,6 +4,7 @@ class Repository
4 4 REPO_N = 0
5 5 REPO_R = 1
6 6 REPO_RW = 2
  7 + REPO_MASTER = 3
7 8  
8 9 attr_accessor :project
9 10  
... ... @@ -15,7 +16,8 @@ class Repository
15 16 {
16 17 "Denied" => REPO_N,
17 18 "Pull" => REPO_R,
18   - "Pull & Push" => REPO_RW
  19 + "Pull & Push" => REPO_RW,
  20 + "Master" => REPO_MASTER
19 21 }
20 22 end
21 23  
... ...
app/views/protected_branches/index.html.haml 0 → 100644
... ... @@ -0,0 +1,39 @@
  1 += render "repositories/branches_head"
  2 +
  3 += form_for [@project, @protected_branch] do |f|
  4 + -if @protected_branch.errors.any?
  5 + .alert-message.block-message.error
  6 + %ul
  7 + - @protected_branch.errors.full_messages.each do |msg|
  8 + %li= msg
  9 +
  10 + .clearfix
  11 + = f.label :name
  12 + .input= f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , { :include_blank => "Select branch" }, { :style => "width:300px" })
  13 + .actions
  14 + = f.submit 'Add', :class => "primary btn"
  15 +
  16 +
  17 +- unless @branches.empty?
  18 + %table
  19 + %thead
  20 + %tr
  21 + %th Name
  22 + %th Last commit
  23 + %tbody
  24 + - @branches.each do |branch|
  25 + %tr
  26 + %td
  27 + = link_to project_commits_path(@project, :ref => branch.name) do
  28 + %strong= branch.name
  29 + - if branch.name == @project.root_ref
  30 + %span.label default
  31 + %td
  32 + = link_to project_commits_path(@project, branch.commit.id) do
  33 + = truncate branch.commit.id.to_s, :length => 10
  34 + = time_ago_in_words(branch.commit.committed_date)
  35 + ago
  36 +
  37 +
  38 +:javascript
  39 + $('select#protected_branch_name').chosen();
... ...
app/views/repositories/_branches_head.html.haml 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 += render "repositories/head"
  2 +%ul.pills
  3 + %li{:class => ("active" if current_page?(branches_project_repository_path(@project)))}
  4 + = link_to branches_project_repository_path(@project) do
  5 + All
  6 + %li{:class => ("active" if current_page?(project_protected_branches_path(@project)))}
  7 + = link_to project_protected_branches_path(@project) do
  8 + Protected
  9 +
... ...
app/views/repositories/_head.html.haml
... ... @@ -3,7 +3,7 @@
3 3 = link_to project_repository_path(@project) do
4 4 %span
5 5 Activities
6   - %li{:class => "#{'active' if current_page?(branches_project_repository_path(@project)) }"}
  6 + %li{:class => "#{'active' if current_page?(branches_project_repository_path(@project)) || current_page?(project_protected_branches_path(@project)) }"}
7 7 = link_to branches_project_repository_path(@project) do
8 8 %span
9 9 Branches
... ...
app/views/repositories/branches.html.haml
1   -= render "head"
  1 += render "repositories/branches_head"
2 2 - unless @branches.empty?
3 3 %table
4 4 %thead
... ...
config/routes.rb
... ... @@ -62,6 +62,7 @@ Gitlab::Application.routes.draw do
62 62 end
63 63  
64 64 resources :deploy_keys
  65 + resources :protected_branches, :only => [:index, :create, :destroy]
65 66  
66 67 resources :refs, :only => [], :path => "/" do
67 68 collection do
... ...
db/migrate/20120215182305_create_protected_branches.rb 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +class CreateProtectedBranches < ActiveRecord::Migration
  2 + def change
  3 + create_table :protected_branches do |t|
  4 + t.integer :project_id, :null => false
  5 + t.string :name, :null => false
  6 +
  7 + t.timestamps
  8 + end
  9 + end
  10 +end
... ...
db/schema.rb
... ... @@ -11,7 +11,19 @@
11 11 #
12 12 # It's strongly recommended to check this file into your version control system.
13 13  
14   -ActiveRecord::Schema.define(:version => 20120206170141) do
  14 +ActiveRecord::Schema.define(:version => 20120215182305) do
  15 +
  16 + create_table "features", :force => true do |t|
  17 + t.string "name"
  18 + t.string "branch_name"
  19 + t.integer "assignee_id"
  20 + t.integer "author_id"
  21 + t.integer "project_id"
  22 + t.datetime "created_at"
  23 + t.datetime "updated_at"
  24 + t.string "version"
  25 + t.integer "status", :default => 0, :null => false
  26 + end
15 27  
16 28 create_table "issues", :force => true do |t|
17 29 t.string "title"
... ... @@ -82,6 +94,13 @@ ActiveRecord::Schema.define(:version =&gt; 20120206170141) do
82 94 t.boolean "merge_requests_enabled", :default => true, :null => false
83 95 end
84 96  
  97 + create_table "protected_branches", :force => true do |t|
  98 + t.integer "project_id", :null => false
  99 + t.string "name", :null => false
  100 + t.datetime "created_at", :null => false
  101 + t.datetime "updated_at", :null => false
  102 + end
  103 +
85 104 create_table "snippets", :force => true do |t|
86 105 t.string "title"
87 106 t.text "content"
... ...
lib/gitlabhq/gitolite.rb
... ... @@ -64,21 +64,9 @@ module Gitlabhq
64 64 def update_project(repo_name, project)
65 65 ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite'))
66 66 conf = ga_repo.config
67   -
68   - repo = if conf.has_repo?(repo_name)
69   - conf.get_repo(repo_name)
70   - else
71   - ::Gitolite::Config::Repo.new(repo_name)
72   - end
73   -
74   - name_readers = project.repository_readers
75   - name_writers = project.repository_writers
76   -
77   - repo.clean_permissions
78   - repo.add_permission("R", "", name_readers) unless name_readers.blank?
79   - repo.add_permission("RW+", "", name_writers) unless name_writers.blank?
  67 + repo = update_project_config(project, conf)
80 68 conf.add_repo(repo, true)
81   -
  69 +
82 70 ga_repo.save
83 71 end
84 72  
... ... @@ -89,25 +77,43 @@ module Gitlabhq
89 77 conf = ga_repo.config
90 78  
91 79 projects.each do |project|
92   - repo_name = project.path
93   -
94   - repo = if conf.has_repo?(repo_name)
95   - conf.get_repo(repo_name)
96   - else
97   - ::Gitolite::Config::Repo.new(repo_name)
98   - end
99   -
100   - name_readers = project.repository_readers
101   - name_writers = project.repository_writers
102   -
103   - repo.clean_permissions
104   - repo.add_permission("R", "", name_readers) unless name_readers.blank?
105   - repo.add_permission("RW+", "", name_writers) unless name_writers.blank?
  80 + repo = update_project_config(project, conf)
106 81 conf.add_repo(repo, true)
107 82 end
108 83  
109 84 ga_repo.save
110 85 end
111 86  
  87 + def update_project_config(project, conf)
  88 + repo_name = project.path
  89 +
  90 + repo = if conf.has_repo?(repo_name)
  91 + conf.get_repo(repo_name)
  92 + else
  93 + ::Gitolite::Config::Repo.new(repo_name)
  94 + end
  95 +
  96 + name_readers = project.repository_readers
  97 + name_writers = project.repository_writers
  98 + name_masters = project.repository_masters
  99 +
  100 + pr_br = project.protected_branches.map(&:name).join(" ")
  101 +
  102 + repo.clean_permissions
  103 +
  104 + # Deny access to protected branches for writers
  105 + unless name_writers.blank? || pr_br.blank?
  106 + repo.add_permission("-", pr_br, name_writers)
  107 + end
  108 +
  109 + # Add read permissions
  110 + repo.add_permission("R", "", name_readers) unless name_readers.blank?
  111 +
  112 + # Add write permissions
  113 + repo.add_permission("RW+", "", name_writers) unless name_writers.blank?
  114 + repo.add_permission("RW+", "", name_masters) unless name_masters.blank?
  115 +
  116 + repo
  117 + end
112 118 end
113 119 end
... ...
spec/models/project_spec.rb
... ... @@ -290,15 +290,18 @@ end
290 290 #
291 291 # Table name: projects
292 292 #
293   -# id :integer not null, primary key
294   -# name :string(255)
295   -# path :string(255)
296   -# description :text
297   -# created_at :datetime
298   -# updated_at :datetime
299   -# private_flag :boolean default(TRUE), not null
300   -# code :string(255)
301   -# owner_id :integer
302   -# default_branch :string(255) default("master"), not null
  293 +# id :integer not null, primary key
  294 +# name :string(255)
  295 +# path :string(255)
  296 +# description :text
  297 +# created_at :datetime
  298 +# updated_at :datetime
  299 +# private_flag :boolean default(TRUE), not null
  300 +# code :string(255)
  301 +# owner_id :integer
  302 +# default_branch :string(255) default("master"), not null
  303 +# issues_enabled :boolean default(TRUE), not null
  304 +# wall_enabled :boolean default(TRUE), not null
  305 +# merge_requests_enabled :boolean default(TRUE), not null
303 306 #
304 307  
... ...
spec/models/protected_branch_spec.rb 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +# == Schema Information
  2 +#
  3 +# Table name: protected_branches
  4 +#
  5 +# id :integer not null, primary key
  6 +# project_id :integer not null
  7 +# name :string(255) not null
  8 +# created_at :datetime not null
  9 +# updated_at :datetime not null
  10 +#
  11 +
  12 +require 'spec_helper'
  13 +
  14 +describe ProtectedBranch do
  15 + pending "add some examples to (or delete) #{__FILE__}"
  16 +end
... ...