diff options
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/analytics/cycle_analytics.rb | 9 | ||||
-rw-r--r-- | app/models/analytics/cycle_analytics/project_stage.rb | 9 | ||||
-rw-r--r-- | app/models/application_setting.rb | 5 | ||||
-rw-r--r-- | app/models/application_setting_implementation.rb | 4 | ||||
-rw-r--r-- | app/models/clusters/applications/cert_manager.rb | 8 | ||||
-rw-r--r-- | app/models/clusters/applications/knative.rb | 12 | ||||
-rw-r--r-- | app/models/clusters/applications/prometheus.rb | 4 | ||||
-rw-r--r-- | app/models/commit_status.rb | 21 | ||||
-rw-r--r-- | app/models/concerns/has_status.rb | 5 | ||||
-rw-r--r-- | app/models/merge_request.rb | 13 | ||||
-rw-r--r-- | app/models/namespace.rb | 7 | ||||
-rw-r--r-- | app/models/notification_recipient.rb | 8 | ||||
-rw-r--r-- | app/models/project.rb | 16 | ||||
-rw-r--r-- | app/models/project_services/emails_on_push_service.rb | 1 | ||||
-rw-r--r-- | app/models/project_services/slash_commands_service.rb | 2 |
15 files changed, 100 insertions, 24 deletions
diff --git a/app/models/analytics/cycle_analytics.rb b/app/models/analytics/cycle_analytics.rb new file mode 100644 index 00000000000..626fc91cc41 --- /dev/null +++ b/app/models/analytics/cycle_analytics.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Analytics + module CycleAnalytics + def self.table_name_prefix + 'analytics_cycle_analytics_' + end + end +end diff --git a/app/models/analytics/cycle_analytics/project_stage.rb b/app/models/analytics/cycle_analytics/project_stage.rb new file mode 100644 index 00000000000..88c8cb40ccb --- /dev/null +++ b/app/models/analytics/cycle_analytics/project_stage.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Analytics + module CycleAnalytics + class ProjectStage < ApplicationRecord + belongs_to :project + end + end +end diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index cb6346421ec..2a99c6e5c59 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -99,6 +99,11 @@ class ApplicationSetting < ApplicationRecord presence: true, if: :plantuml_enabled + validates :snowplow_collector_hostname, + presence: true, + hostname: true, + if: :snowplow_enabled + validates :max_attachment_size, presence: true, numericality: { only_integer: true, greater_than: 0 } diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb index b7a4d7aa803..55ac1e129cf 100644 --- a/app/models/application_setting_implementation.rb +++ b/app/models/application_setting_implementation.rb @@ -97,6 +97,10 @@ module ApplicationSettingImplementation usage_stats_set_by_user_id: nil, diff_max_patch_bytes: Gitlab::Git::Diff::DEFAULT_MAX_PATCH_BYTES, commit_email_hostname: default_commit_email_hostname, + snowplow_collector_hostname: nil, + snowplow_cookie_domain: nil, + snowplow_enabled: false, + snowplow_site_id: nil, protected_ci_variables: false, local_markdown_version: 0, outbound_local_requests_whitelist: [], diff --git a/app/models/clusters/applications/cert_manager.rb b/app/models/clusters/applications/cert_manager.rb index 2fc1b67dfd2..6bd7473c8ff 100644 --- a/app/models/clusters/applications/cert_manager.rb +++ b/app/models/clusters/applications/cert_manager.rb @@ -64,11 +64,15 @@ module Clusters end def delete_private_key - "kubectl delete secret -n #{Gitlab::Kubernetes::Helm::NAMESPACE} #{private_key_name} --ignore-not-found" if private_key_name.present? + return unless private_key_name.present? + + args = %W(secret -n #{Gitlab::Kubernetes::Helm::NAMESPACE} #{private_key_name} --ignore-not-found) + + Gitlab::Kubernetes::KubectlCmd.delete(*args) end def delete_crd(definition) - "kubectl delete crd #{definition} --ignore-not-found" + Gitlab::Kubernetes::KubectlCmd.delete("crd", definition, "--ignore-not-found") end def cluster_issuer_file diff --git a/app/models/clusters/applications/knative.rb b/app/models/clusters/applications/knative.rb index 5eae23659ae..244fe738396 100644 --- a/app/models/clusters/applications/knative.rb +++ b/app/models/clusters/applications/knative.rb @@ -89,7 +89,7 @@ module Clusters def delete_knative_services cluster.kubernetes_namespaces.map do |kubernetes_namespace| - "kubectl delete ksvc --all -n #{kubernetes_namespace.namespace}" + Gitlab::Kubernetes::KubectlCmd.delete("ksvc", "--all", "-n", kubernetes_namespace.namespace) end end @@ -99,14 +99,14 @@ module Clusters def delete_knative_namespaces [ - "kubectl delete --ignore-not-found ns knative-serving", - "kubectl delete --ignore-not-found ns knative-build" + Gitlab::Kubernetes::KubectlCmd.delete("--ignore-not-found", "ns", "knative-serving"), + Gitlab::Kubernetes::KubectlCmd.delete("--ignore-not-found", "ns", "knative-build") ] end def delete_knative_and_istio_crds api_resources.map do |crd| - "kubectl delete --ignore-not-found crd #{crd}" + Gitlab::Kubernetes::KubectlCmd.delete("--ignore-not-found", "crd", "#{crd}") end end @@ -119,13 +119,13 @@ module Clusters def install_knative_metrics return [] unless cluster.application_prometheus_available? - ["kubectl apply -f #{METRICS_CONFIG}"] + [Gitlab::Kubernetes::KubectlCmd.apply_file(METRICS_CONFIG)] end def delete_knative_istio_metrics return [] unless cluster.application_prometheus_available? - ["kubectl delete --ignore-not-found -f #{METRICS_CONFIG}"] + [Gitlab::Kubernetes::KubectlCmd.delete("--ignore-not-found", "-f", METRICS_CONFIG)] end def verify_cluster? diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb index 08e52f32bb3..f31a6b8b50e 100644 --- a/app/models/clusters/applications/prometheus.rb +++ b/app/models/clusters/applications/prometheus.rb @@ -106,13 +106,13 @@ module Clusters def install_knative_metrics return [] unless cluster.application_knative_available? - ["kubectl apply -f #{Clusters::Applications::Knative::METRICS_CONFIG}"] + [Gitlab::Kubernetes::KubectlCmd.apply_file(Clusters::Applications::Knative::METRICS_CONFIG)] end def delete_knative_istio_metrics return [] unless cluster.application_knative_available? - ["kubectl delete -f #{Clusters::Applications::Knative::METRICS_CONFIG}"] + [Gitlab::Kubernetes::KubectlCmd.delete("-f", Clusters::Applications::Knative::METRICS_CONFIG)] end end end diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index a88cac6b8e6..4be4d95b4a1 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -40,8 +40,11 @@ class CommitStatus < ApplicationRecord scope :ordered, -> { order(:name) } scope :latest_ordered, -> { latest.ordered.includes(project: :namespace) } scope :retried_ordered, -> { retried.ordered.includes(project: :namespace) } + scope :before_stage, -> (index) { where('stage_idx < ?', index) } + scope :for_stage, -> (index) { where(stage_idx: index) } scope :after_stage, -> (index) { where('stage_idx > ?', index) } scope :processables, -> { where(type: %w[Ci::Build Ci::Bridge]) } + scope :for_ids, -> (ids) { where(id: ids) } scope :with_needs, -> (names = nil) do needs = Ci::BuildNeed.scoped_build.select(1) @@ -49,8 +52,10 @@ class CommitStatus < ApplicationRecord where('EXISTS (?)', needs).preload(:needs) end - scope :without_needs, -> do - where('NOT EXISTS (?)', Ci::BuildNeed.scoped_build.select(1)) + scope :without_needs, -> (names = nil) do + needs = Ci::BuildNeed.scoped_build.select(1) + needs = needs.where(name: names) if names + where('NOT EXISTS (?)', needs) end # We use `CommitStatusEnums.failure_reasons` here so that EE can more easily @@ -149,6 +154,18 @@ class CommitStatus < ApplicationRecord end end + def self.names + select(:name) + end + + def self.status_for_prior_stages(index) + before_stage(index).latest.status || 'success' + end + + def self.status_for_names(names) + where(name: names).latest.status || 'success' + end + def locking_enabled? will_save_change_to_status? end diff --git a/app/models/concerns/has_status.rb b/app/models/concerns/has_status.rb index 27a5c3d5286..71ebb586c13 100644 --- a/app/models/concerns/has_status.rb +++ b/app/models/concerns/has_status.rb @@ -106,10 +106,15 @@ module HasStatus scope :running_or_pending, -> { with_status(:running, :pending) } scope :finished, -> { with_status(:success, :failed, :canceled) } scope :failed_or_canceled, -> { with_status(:failed, :canceled) } + scope :incomplete, -> { without_statuses(completed_statuses) } scope :cancelable, -> do where(status: [:running, :preparing, :pending, :created, :scheduled]) end + + scope :without_statuses, -> (names) do + with_status(all_state_names - names.to_a) + end end def started? diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 4306dd9266f..bfd636fa62a 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -220,18 +220,7 @@ class MergeRequest < ApplicationRecord end def rebase_in_progress? - (rebase_jid.present? && Gitlab::SidekiqStatus.running?(rebase_jid)) || - gitaly_rebase_in_progress? - end - - # TODO: remove the Gitaly lookup after v12.1, when rebase_jid will be reliable - def gitaly_rebase_in_progress? - strong_memoize(:gitaly_rebase_in_progress) do - # The source project can be deleted - next false unless source_project - - source_project.repository.rebase_in_progress?(id) - end + rebase_jid.present? && Gitlab::SidekiqStatus.running?(rebase_jid) end # Use this method whenever you need to make sure the head_pipeline is synced with the diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 058350b16ce..9f9c4288667 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -172,6 +172,13 @@ class Namespace < ApplicationRecord end end + # any ancestor can disable emails for all descendants + def emails_disabled? + strong_memoize(:emails_disabled) do + Feature.enabled?(:emails_disabled, self, default_enabled: true) && self_and_ancestors.where(emails_disabled: true).exists? + end + end + def lfs_enabled? # User namespace will always default to the global setting Gitlab.config.lfs.enabled diff --git a/app/models/notification_recipient.rb b/app/models/notification_recipient.rb index a7f73c0f29c..8e44e3d8e17 100644 --- a/app/models/notification_recipient.rb +++ b/app/models/notification_recipient.rb @@ -4,6 +4,7 @@ class NotificationRecipient include Gitlab::Utils::StrongMemoize attr_reader :user, :type, :reason + def initialize(user, type, **opts) unless NotificationSetting.levels.key?(type) || type == :subscription raise ArgumentError, "invalid type: #{type.inspect}" @@ -30,6 +31,7 @@ class NotificationRecipient def notifiable? return false unless has_access? + return false if emails_disabled? return false if own_activity? # even users with :disabled notifications receive manual subscriptions @@ -109,6 +111,12 @@ class NotificationRecipient private + # They are disabled if the project or group has disallowed it. + # No need to check the group if there is already a project + def emails_disabled? + @project ? @project.emails_disabled? : @group&.emails_disabled? + end + def read_ability return if @skip_read_ability return @read_ability if instance_variable_defined?(:@read_ability) diff --git a/app/models/project.rb b/app/models/project.rb index a6e43efa1f3..8efe4b06f87 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -283,6 +283,7 @@ class Project < ApplicationRecord has_one :ci_cd_settings, class_name: 'ProjectCiCdSetting', inverse_of: :project, autosave: true, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent has_many :remote_mirrors, inverse_of: :project + has_many :cycle_analytics_stages, class_name: 'Analytics::CycleAnalytics::ProjectStage' accepts_nested_attributes_for :variables, allow_destroy: true accepts_nested_attributes_for :project_feature, update_only: true @@ -631,6 +632,13 @@ class Project < ApplicationRecord alias_method :ancestors, :ancestors_upto + def emails_disabled? + strong_memoize(:emails_disabled) do + # disabling in the namespace overrides the project setting + Feature.enabled?(:emails_disabled, self, default_enabled: true) && (super || namespace.emails_disabled?) + end + end + def lfs_enabled? return namespace.lfs_enabled? if self[:lfs_enabled].nil? @@ -1230,6 +1238,14 @@ class Project < ApplicationRecord end end + def has_active_hooks?(hooks_scope = :push_hooks) + hooks.hooks_for(hooks_scope).any? || SystemHook.hooks_for(hooks_scope).any? + end + + def has_active_services?(hooks_scope = :push_hooks) + services.public_send(hooks_scope).any? # rubocop:disable GitlabSecurity/PublicSend + end + def valid_repo? repository.exists? rescue diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb index 45de64a9990..8ca40138a8f 100644 --- a/app/models/project_services/emails_on_push_service.rb +++ b/app/models/project_services/emails_on_push_service.rb @@ -24,6 +24,7 @@ class EmailsOnPushService < Service def execute(push_data) return unless supported_events.include?(push_data[:object_kind]) + return if project.emails_disabled? EmailsOnPushWorker.perform_async( project_id, diff --git a/app/models/project_services/slash_commands_service.rb b/app/models/project_services/slash_commands_service.rb index 5f5cff97808..cb16ad75d14 100644 --- a/app/models/project_services/slash_commands_service.rb +++ b/app/models/project_services/slash_commands_service.rb @@ -35,6 +35,8 @@ class SlashCommandsService < Service chat_user = find_chat_user(params) if chat_user&.user + return Gitlab::SlashCommands::Presenters::Access.new.access_denied unless chat_user.user.can?(:use_slash_commands) + Gitlab::SlashCommands::Command.new(project, chat_user, params).execute else url = authorize_chat_name_url(params) |