f51af49676
1. The main implementation is in the `ProtectedBranch` model. The wildcard is converted to a Regex and compared. This has been tested thoroughly. - While `Project#protected_branch?` is the main entry point, `project#open_branches` and `project#developers_can_push_to_protected_branch?` have also been modified to work with wildcard protected branches. - The regex is memoized (within the `ProtectedBranch` instance) 2. Improve the performance of `Project#protected_branch?` - This method is called from `Project#open_branches` once _per branch_ in the project, to check if that branch is protected or not. - Before, `#protected_branch?` was making a database call every time it was invoked (in the above case, that amounts to once per branch), which is expensive. - This commit caches the list of protected branches in memory, which reduces the number of database calls down to 1. - A downside to this approach is that `#protected_branch?` _could_ return a stale value (due to the caching), but this is an acceptable tradeoff. 3. Remove the (now) unused `Project#protected_branch_names` method. - This was previously used to check for protected branch status.
47 lines
1.3 KiB
Ruby
47 lines
1.3 KiB
Ruby
class ProtectedBranch < ActiveRecord::Base
|
|
include Gitlab::ShellAdapter
|
|
|
|
belongs_to :project
|
|
validates :name, presence: true
|
|
validates :project, presence: true
|
|
|
|
def commit
|
|
project.commit(self.name)
|
|
end
|
|
|
|
# Returns all protected branches that match the given branch name.
|
|
# This realizes all records from the scope built up so far, and does
|
|
# _not_ return a relation.
|
|
#
|
|
# This method optionally takes in a list of `protected_branches` to search
|
|
# through, to avoid calling out to the database.
|
|
def self.matching(branch_name, protected_branches: nil)
|
|
(protected_branches || all).select { |protected_branch| protected_branch.matches?(branch_name) }
|
|
end
|
|
|
|
# Checks if the protected branch matches the given branch name.
|
|
def matches?(branch_name)
|
|
return false if self.name.blank?
|
|
|
|
exact_match?(branch_name) || wildcard_match?(branch_name)
|
|
end
|
|
|
|
protected
|
|
|
|
def exact_match?(branch_name)
|
|
self.name == branch_name
|
|
end
|
|
|
|
def wildcard_match?(branch_name)
|
|
wildcard_regex === branch_name
|
|
end
|
|
|
|
def wildcard_regex
|
|
@wildcard_regex ||= begin
|
|
name = self.name.gsub('*', 'STAR_DONT_ESCAPE')
|
|
quoted_name = Regexp.quote(name)
|
|
regex_string = quoted_name.gsub('STAR_DONT_ESCAPE', '.*?')
|
|
/\A#{regex_string}\z/
|
|
end
|
|
end
|
|
end
|