Commit ae997cdf authored by mo khan's avatar mo khan Committed by Mike Kozono
Browse files

Refresh license compliance checks

When a new software license policy is created,
this will refresh the license check approval rules associated
with each open merge request for the project that the
software license policy was created for.
parent 94c34351
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -116,3 +116,4 @@
  - [incident_management, 2]
  - [jira_connect, 1]
  - [update_external_pull_requests, 3]
  - [refresh_license_compliance_checks, 2]
+21 −0
Original line number Diff line number Diff line
@@ -55,6 +55,10 @@ class ApprovalMergeRequestRule < ApplicationRecord
  # To be removed with https://gitlab.com/gitlab-org/gitlab-ee/issues/11834
  scope :code_owner, -> { where(code_owner: true).or(where(rule_type: :code_owner)) }
  scope :security_report, -> { report_approver.where(report_type: :security) }
  scope :license_compliance, -> { report_approver.where(report_type: :license_management) }
  scope :with_head_pipeline, -> { includes(merge_request: [:head_pipeline]) }
  scope :open_merge_requests, -> { merge(MergeRequest.opened) }
  scope :for_checks_that_can_be_refreshed, -> { license_compliance.open_merge_requests.with_head_pipeline }

  def self.find_or_create_code_owner_rule(merge_request, pattern)
    merge_request.approval_rules.code_owner.where(name: pattern).first_or_create do |rule|
@@ -114,6 +118,12 @@ def sync_approved_approvers
    self.approved_approver_ids = merge_request.approvals.map(&:user_id) & approvers.map(&:id)
  end

  def refresh_required_approvals!(project_approval_rule)
    return unless report_approver?

    refresh_license_management_approvals(project_approval_rule) if license_management?
  end

  private

  def validate_approval_project_rule
@@ -122,4 +132,15 @@ def validate_approval_project_rule

    errors.add(:approval_project_rule, 'must be for the same project')
  end

  def refresh_license_management_approvals(project_approval_rule)
    license_report = merge_request.head_pipeline&.license_management_report
    return if license_report.blank?

    if license_report.violates?(project.software_license_policies)
      update!(approvals_required: project_approval_rule.approvals_required)
    else
      update!(approvals_required: 0)
    end
  end
end
+1 −0
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ module Project
      has_many :approver_users, through: :approvers, source: :user
      has_many :approver_groups, as: :target, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
      has_many :approval_rules, class_name: 'ApprovalProjectRule'
      has_many :approval_merge_request_rules, through: :merge_requests, source: :approval_rules
      has_many :audit_events, as: :entity
      has_many :designs, inverse_of: :project, class_name: 'DesignManagement::Design'
      has_many :path_locks
+7 −0
Original line number Diff line number Diff line
@@ -8,4 +8,11 @@ class SoftwareLicense < ApplicationRecord
  validates :name, presence: true

  scope :ordered, -> { order(:name) }

  def self.create_policy_for!(project:, name:, approval_status:)
    project.software_license_policies.create!(
      approval_status: approval_status,
      software_license: safe_find_or_create_by!(name: name)
    )
  end
end
+16 −26
Original line number Diff line number Diff line
@@ -7,37 +7,27 @@ def initialize(project, user, params)
      super(project, user, params.with_indifferent_access)
    end

    # Returns the created managed license.
    # rubocop: disable CodeReuse/ActiveRecord
    def execute
      return error("", 403) unless can?(@current_user, :admin_software_license_policy, @project)

      # Load or create the software license
      name = params.delete(:name)

      software_license = SoftwareLicense.transaction do
        SoftwareLicense.transaction(requires_new: true) do
          SoftwareLicense.find_or_create_by(name: name)
        end
      rescue ActiveRecord::RecordNotUnique
        retry
      end

      # Add the software license to params
      params[:software_license] = software_license

      begin
        software_license_policy = @project.software_license_policies.create(params)
      rescue ArgumentError => ex
        return error(ex.message, 400)
      success(software_license_policy: create_software_license_policy)
    rescue ActiveRecord::RecordInvalid => exception
      error(exception.record.errors.full_messages, 400)
    rescue ArgumentError => exception
      log_error(exception.message)
      error(exception.message, 400)
    end

      if software_license_policy.errors.any?
        return error(software_license_policy.errors.full_messages.join("\n"), 400)
      end
    private

      success(software_license_policy: software_license_policy)
    def create_software_license_policy
      policy = SoftwareLicense.create_policy_for!(
        project: project,
        name: params[:name],
        approval_status: params[:approval_status]
      )
      RefreshLicenseComplianceChecksWorker.perform_async(project.id)
      policy
    end
    # rubocop: enable CodeReuse/ActiveRecord
  end
end
Loading