From aad6ceaef9ccfba8e058012a0877b80c103a3838 Mon Sep 17 00:00:00 2001
From: Marco Wessel <marco@poop.nl>
Date: Sun, 25 Jan 2015 16:33:54 +0100
Subject: [PATCH] Allow configuring protection of the default branch upon first
 push

---
 CHANGELOG                                     |  2 +-
 .../admin/application_settings_controller.rb  |  1 +
 app/models/application_setting.rb             |  2 ++
 app/services/git_push_service.rb              | 10 ++++++++--
 .../application_settings/_form.html.haml      |  4 ++++
 config/initializers/1_settings.rb             |  1 +
 ...0_add_default_branch_protection_setting.rb |  5 +++++
 db/schema.rb                                  |  3 ++-
 lib/gitlab/access.rb                          | 16 ++++++++++++++++
 lib/gitlab/current_settings.rb                |  1 +
 spec/models/application_setting_spec.rb       | 19 ++++++++++---------
 spec/services/git_push_service_spec.rb        |  2 +-
 12 files changed, 52 insertions(+), 14 deletions(-)
 create mode 100644 db/migrate/20150125163100_add_default_branch_protection_setting.rb

diff --git a/CHANGELOG b/CHANGELOG
index dd9b13ceac2..26cef6c6c1e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -28,7 +28,7 @@ v 7.8.0
   - 
   - 
   - 
-  - 
+  - Allow configuring protection of the default branch upon first push (Marco Wessel)
   - 
   - 
   - 
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index a937f484877..7458542fc73 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -22,6 +22,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
   def application_setting_params
     params.require(:application_setting).permit(
       :default_projects_limit,
+      :default_branch_protection,
       :signup_enabled,
       :signin_enabled,
       :gravatar_enabled,
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 45ae79a75cc..3285a1a248e 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -4,6 +4,7 @@
 #
 #  id                     :integer          not null, primary key
 #  default_projects_limit :integer
+#  default_branch_protection :integer
 #  signup_enabled         :boolean
 #  signin_enabled         :boolean
 #  gravatar_enabled       :boolean
@@ -25,6 +26,7 @@ class ApplicationSetting < ActiveRecord::Base
   def self.create_from_defaults
     create(
       default_projects_limit: Settings.gitlab['default_projects_limit'],
+      default_branch_protection: Settings.gitlab['default_branch_protection'],
       signup_enabled: Settings.gitlab['signup_enabled'],
       signin_enabled: Settings.gitlab['signin_enabled'],
       gravatar_enabled: Settings.gravatar['enabled'],
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index 872b886c575..b45ca0a5e6b 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -1,5 +1,7 @@
 class GitPushService
   attr_accessor :project, :user, :push_data, :push_commits
+  include Gitlab::CurrentSettings
+  include Gitlab::Access
 
   # This method will be called after each git update
   # and only if the provided user and project is present in GitLab.
@@ -29,8 +31,12 @@ class GitPushService
         if is_default_branch?(ref)
           # Initial push to the default branch. Take the full history of that branch as "newly pushed".
           @push_commits = project.repository.commits(newrev)
-          # Default branch is protected by default
-          project.protected_branches.create({ name: project.default_branch })
+
+          # Set protection on the default branch if configured
+          if (current_application_settings.default_branch_protection != PROTECTION_NONE)
+	          developers_can_push = current_application_settings.default_branch_protection == PROTECTION_DEV_CAN_PUSH ? true : false
+            project.protected_branches.create({ name: project.default_branch, developers_can_push: developers_can_push })
+          end
         else
           # Use the pushed commits that aren't reachable by the default branch
           # as a heuristic. This may include more commits than are actually pushed, but
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index 9423a207068..bf0ee49d2f4 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -25,6 +25,10 @@
       = f.label :default_projects_limit, class: 'control-label'
       .col-sm-10
         = f.number_field :default_projects_limit, class: 'form-control'
+    .form-group
+      = f.label :default_branch_protection, class: 'control-label'
+      .col-sm-10
+        = f.select :default_branch_protection, options_for_select(Gitlab::Access.protection_options, @application_setting.default_branch_protection), {}, class: 'form-control'
     .form-group
       = f.label :home_page_url, class: 'control-label'
       .col-sm-10
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 1ec842761ff..2c8441ece08 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -87,6 +87,7 @@ Settings['issues_tracker']  ||= {}
 #
 Settings['gitlab'] ||= Settingslogic.new({})
 Settings.gitlab['default_projects_limit'] ||= 10
+Settings.gitlab['default_branch_protection'] ||= 2
 Settings.gitlab['default_can_create_group'] = true if Settings.gitlab['default_can_create_group'].nil?
 Settings.gitlab['default_theme'] = Gitlab::Theme::MARS if Settings.gitlab['default_theme'].nil?
 Settings.gitlab['host']       ||= 'localhost'
diff --git a/db/migrate/20150125163100_add_default_branch_protection_setting.rb b/db/migrate/20150125163100_add_default_branch_protection_setting.rb
new file mode 100644
index 00000000000..5020daf55f3
--- /dev/null
+++ b/db/migrate/20150125163100_add_default_branch_protection_setting.rb
@@ -0,0 +1,5 @@
+class AddDefaultBranchProtectionSetting < ActiveRecord::Migration
+  def change
+    add_column :application_settings, :default_branch_protection, :integer, :default => 2
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 29466f048eb..124023545f9 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,13 +11,14 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 20150116234544) do
+ActiveRecord::Schema.define(version: 20150125163100) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
 
   create_table "application_settings", force: true do |t|
     t.integer  "default_projects_limit"
+    t.integer  "default_branch_protection"
     t.boolean  "signup_enabled"
     t.boolean  "signin_enabled"
     t.boolean  "gravatar_enabled"
diff --git a/lib/gitlab/access.rb b/lib/gitlab/access.rb
index 411b2b9a3cc..ad05bfadafe 100644
--- a/lib/gitlab/access.rb
+++ b/lib/gitlab/access.rb
@@ -11,6 +11,11 @@ module Gitlab
     MASTER    = 40
     OWNER     = 50
 
+    # Branch protection settings
+    PROTECTION_NONE         = 0
+    PROTECTION_DEV_CAN_PUSH = 1
+    PROTECTION_FULL         = 2
+
     class << self
       def values
         options.values
@@ -43,6 +48,17 @@ module Gitlab
           master:    MASTER,
         }
       end
+
+      def protection_options
+       {
+          "None"                          => PROTECTION_NONE,
+          "Protect, developers can push"  => PROTECTION_DEV_CAN_PUSH,
+          "Full protection"               => PROTECTION_FULL,
+       }
+      end
+      def protection_values
+        protection_options.values
+      end
     end
 
     def human_access
diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb
index 2c5660df373..75afc024a62 100644
--- a/lib/gitlab/current_settings.rb
+++ b/lib/gitlab/current_settings.rb
@@ -12,6 +12,7 @@ module Gitlab
     def fake_application_settings
       OpenStruct.new(
         default_projects_limit: Settings.gitlab['default_projects_limit'],
+	default_branch_protection: Settings.gitlab['default_branch_protection'],
         signup_enabled: Settings.gitlab['signup_enabled'],
         signin_enabled: Settings.gitlab['signin_enabled'],
         gravatar_enabled: Settings.gravatar['enabled'],
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index 1723eba9ec3..ac68e3d925f 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -2,15 +2,16 @@
 #
 # Table name: application_settings
 #
-#  id                     :integer          not null, primary key
-#  default_projects_limit :integer
-#  signup_enabled         :boolean
-#  signin_enabled         :boolean
-#  gravatar_enabled       :boolean
-#  sign_in_text           :text
-#  created_at             :datetime
-#  updated_at             :datetime
-#  home_page_url          :string(255)
+#  id                         :integer          not null, primary key
+#  default_projects_limit     :integer
+#  default_branch_protection  :interger
+#  signup_enabled             :boolean
+#  signin_enabled             :boolean
+#  gravatar_enabled           :boolean
+#  sign_in_text               :text
+#  created_at                 :datetime
+#  updated_at                 :datetime
+#  home_page_url              :string(255)
 #
 
 require 'spec_helper'
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index 19b442573f4..02c8133d2c6 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -106,7 +106,7 @@ describe GitPushService do
       it "when pushing a branch for the first time" do
         project.should_receive(:execute_hooks)
         project.default_branch.should == "master"
-        project.protected_branches.should_receive(:create).with({ name: "master" })
+        project.protected_branches.should_receive(:create).with({ name: "master", developers_can_push: false })
         service.execute(project, user, @blankrev, 'newrev', 'refs/heads/master')
       end
 
-- 
GitLab