Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorDuana Saskia <starkcoffee@users.noreply.github.com>2018-06-07 10:35:17 +0300
committerDuana Saskia <starkcoffee@users.noreply.github.com>2018-08-13 14:20:58 +0300
commitece6a1ea6ecffdbde5ff7d663f1ad1eb74f78aa6 (patch)
tree288e34ff932b6c84e1a1c5ead26cbd8f80ea12f5 /app
parent07356866b2ce85f4d724c96f14e129fbe6a56963 (diff)
Filter project hooks by branch
Allow specificying a branch filter for a project hook and only trigger a project hook if either the branch filter is blank or the branch matches. Only supported for push_events for now.
Diffstat (limited to 'app')
-rw-r--r--app/controllers/projects/hooks_controller.rb1
-rw-r--r--app/models/hooks/active_hook_filter.rb38
-rw-r--r--app/models/hooks/web_hook.rb1
-rw-r--r--app/models/project.rb3
-rw-r--r--app/validators/branch_filter_validator.rb34
-rw-r--r--app/views/shared/web_hooks/_form.html.haml1
6 files changed, 76 insertions, 2 deletions
diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb
index 2da2aad9b33..bbf8c7d5cbc 100644
--- a/app/controllers/projects/hooks_controller.rb
+++ b/app/controllers/projects/hooks_controller.rb
@@ -66,6 +66,7 @@ class Projects::HooksController < Projects::ApplicationController
:enable_ssl_verification,
:token,
:url,
+ :push_events_branch_filter,
*ProjectHook.triggers.values
)
end
diff --git a/app/models/hooks/active_hook_filter.rb b/app/models/hooks/active_hook_filter.rb
new file mode 100644
index 00000000000..611af971163
--- /dev/null
+++ b/app/models/hooks/active_hook_filter.rb
@@ -0,0 +1,38 @@
+class ActiveHookFilter
+ def initialize(hook)
+ @hook = hook
+ end
+
+ def matches?(hooks_scope, data)
+ return true if hooks_scope != :push_hooks
+ return true if @hook.push_events_branch_filter.blank?
+
+ branch_name = Gitlab::Git.branch_name(data[:ref])
+ exact_match?(branch_name) || wildcard_match?(branch_name)
+ end
+
+ private
+
+ def exact_match?(branch_name)
+ @hook.push_events_branch_filter == branch_name
+ end
+
+ def wildcard_match?(branch_name)
+ return false unless wildcard?
+
+ wildcard_regex === branch_name
+ end
+
+ def wildcard_regex
+ @wildcard_regex ||= begin
+ name = @hook.push_events_branch_filter.gsub('*', 'STAR_DONT_ESCAPE')
+ quoted_name = Regexp.quote(name)
+ regex_string = quoted_name.gsub('STAR_DONT_ESCAPE', '.*?')
+ /\A#{regex_string}\z/
+ end
+ end
+
+ def wildcard?
+ @hook.push_events_branch_filter && @hook.push_events_branch_filter.include?('*')
+ end
+end
diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb
index f18aadefa5c..20f15c15277 100644
--- a/app/models/hooks/web_hook.rb
+++ b/app/models/hooks/web_hook.rb
@@ -9,6 +9,7 @@ class WebHook < ActiveRecord::Base
allow_local_network: lambda(&:allow_local_requests?) }
validates :token, format: { without: /\n/ }
+ validates :push_events_branch_filter, branch_filter: true
def execute(data, hook_name)
WebHookService.new(self, data, hook_name).execute
diff --git a/app/models/project.rb b/app/models/project.rb
index 7735f23cb9e..72a53e1a50d 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -1163,10 +1163,9 @@ class Project < ActiveRecord::Base
def execute_hooks(data, hooks_scope = :push_hooks)
run_after_commit_or_now do
- hooks.hooks_for(hooks_scope).each do |hook|
+ hooks.hooks_for(hooks_scope).select {|hook| ActiveHookFilter.new(hook).matches?(hooks_scope, data)}.each do |hook|
hook.async_execute(data, hooks_scope.to_s)
end
-
SystemHooksService.new.execute_hooks(data, hooks_scope)
end
end
diff --git a/app/validators/branch_filter_validator.rb b/app/validators/branch_filter_validator.rb
new file mode 100644
index 00000000000..0965be3d101
--- /dev/null
+++ b/app/validators/branch_filter_validator.rb
@@ -0,0 +1,34 @@
+# BranchFilterValidator
+#
+# Custom validator for branch names. Squishes whitespace and ignores empty
+# string. This only checks that a string is a valid git branch name. It does
+# not check whether a branch already exists.
+#
+# Example:
+#
+# class Webhook < ActiveRecord::Base
+# validates :push_events_branch_filter, branch_name: true
+# end
+#
+class BranchFilterValidator < ActiveModel::EachValidator
+ def validate_each(record, attribute, value)
+ value.squish! unless value.nil?
+
+ if value.present?
+ value_without_wildcards = value.tr('*', 'x')
+ unless Gitlab::GitRefValidator.validate(value_without_wildcards)
+ record.errors[attribute] << "is not a valid branch name"
+ end
+
+ unless value.length <= 4000
+ record.errors[attribute] << "is longer than the allowed length of 4000 characters."
+ end
+ end
+ end
+
+ private
+
+ def contains_wildcard?(value)
+ value.include?('*')
+ end
+end
diff --git a/app/views/shared/web_hooks/_form.html.haml b/app/views/shared/web_hooks/_form.html.haml
index 07ebb8680d2..9c5b9593bba 100644
--- a/app/views/shared/web_hooks/_form.html.haml
+++ b/app/views/shared/web_hooks/_form.html.haml
@@ -17,6 +17,7 @@
%strong Push events
%p.light.ml-1
This URL will be triggered by a push to the repository
+ = form.text_field :push_events_branch_filter, class: 'form-control', placeholder: 'Branch name or wildcard pattern to trigger on (leave blank for all)'
%li
= form.check_box :tag_push_events, class: 'form-check-input'
= form.label :tag_push_events, class: 'list-label form-check-label ml-1' do