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

protected_branch.rb « models « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 40a1a4392dd3a376916b4bfc90966c8707c1bc99 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# frozen_string_literal: true

class ProtectedBranch < ApplicationRecord
  include ProtectedRef
  include Gitlab::SQL::Pattern
  include FromUnion
  include EachBatch
  include Presentable

  belongs_to :group, foreign_key: :namespace_id, touch: true, inverse_of: :protected_branches

  validate :validate_either_project_or_top_group
  validates :name, presence: true
  validates :name, uniqueness: { scope: [:project_id, :namespace_id] }, if: :name_changed?

  scope :requiring_code_owner_approval, -> { where(code_owner_approval_required: true) }
  scope :allowing_force_push, -> { where(allow_force_push: true) }
  scope :sorted_by_name, -> { order(name: :asc) }
  scope :sorted_by_namespace_and_name, -> { order(:namespace_id, :name) }

  scope :for_group, ->(group) { where(group: group) }

  protected_ref_access_levels :merge, :push

  def self.get_ids_by_name(name)
    where(name: name).pluck(:id)
  end

  def self.protected_ref_accessible_to?(ref, user, project:, action:, protected_refs: nil)
    if project.empty_repo?
      member_access = project.team.max_member_access(user.id)

      # Admins are always allowed to create the default branch
      return true if user.admin? || user.can?(:admin_project, project)

      # Developers can push if it is allowed by default branch protection settings
      if member_access == Gitlab::Access::DEVELOPER && project.initial_push_to_default_branch_allowed_for_developer?
        return true
      end
    end

    super
  end

  # Check if branch name is marked as protected in the system
  def self.protected?(project, ref_name)
    return true if project.empty_repo? && project.default_branch_protected?
    return false if ref_name.blank?

    ProtectedBranches::CacheService.new(project).fetch(ref_name) do # rubocop: disable CodeReuse/ServiceClass
      self.matching(ref_name, protected_refs: protected_refs(project)).present?
    end
  end

  def self.allow_force_push?(project, ref_name)
    if allow_protected_branches_for_group?(project.group)
      protected_branches = project.all_protected_branches.matching(ref_name)

      project_protected_branches, group_protected_branches = protected_branches.partition(&:project_id)

      # Group owner can be able to enforce the settings
      return group_protected_branches.any?(&:allow_force_push) if group_protected_branches.present?
      return project_protected_branches.any?(&:allow_force_push) if project_protected_branches.present?

      false
    else
      project.protected_branches.allowing_force_push.matching(ref_name).any?
    end
  end

  def self.allow_protected_branches_for_group?(group)
    Feature.enabled?(:group_protected_branches, group) || Feature.enabled?(:allow_protected_branches_for_group, group)
  end

  def self.any_protected?(project, ref_names)
    protected_refs(project).any? do |protected_ref|
      ref_names.any? do |ref_name|
        protected_ref.matches?(ref_name)
      end
    end
  end

  def self.protected_refs(project)
    project.all_protected_branches
  end

  # overridden in EE
  def self.branch_requires_code_owner_approval?(project, branch_name)
    false
  end

  def self.by_name(query)
    return none if query.blank?

    where(fuzzy_arel_match(:name, query.downcase))
  end

  def allow_multiple?(type)
    type == :push
  end

  def self.downcase_humanized_name
    name.underscore.humanize.downcase
  end

  def default_branch?
    name == project.default_branch
  end

  def group_level?
    entity.is_a?(Group)
  end

  def project_level?
    entity.is_a?(Project)
  end

  def entity
    group || project
  end

  private

  def validate_either_project_or_top_group
    if !project && !group
      errors.add(:base, _('must be associated with a Group or a Project'))
    elsif project && group
      errors.add(:base, _('cannot be associated with both a Group and a Project'))
    elsif group && group.subgroup?
      errors.add(:base, _('cannot be associated with a subgroup'))
    end
  end
end

ProtectedBranch.prepend_mod_with('ProtectedBranch')