Commit 37224dc9c1ee80ba9030b616e2bc87bd96919e09
1 parent
3a9e5a93
Exists in
master
and in
4 other branches
ProtectedBranches model, Master permission for repo\n Allow push to protected br…
…anch for masters only
Showing
14 changed files
with
229 additions
and
53 deletions
Show diff stats
... | ... | @@ -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 < 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 < 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 < 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 < 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 | ... | ... |
... | ... | @@ -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 | ... | ... |
... | ... | @@ -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(); | ... | ... |
... | ... | @@ -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
config/routes.rb
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 => 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 | ... | ... |
... | ... | @@ -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 | ... | ... |