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
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/project.rb')
-rw-r--r--app/models/project.rb108
1 files changed, 62 insertions, 46 deletions
diff --git a/app/models/project.rb b/app/models/project.rb
index 8959eccbd1f..ad8757880fd 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -43,6 +43,9 @@ class Project < ApplicationRecord
include Subquery
include IssueParent
include UpdatedAtFilterable
+ include IgnorableColumns
+
+ ignore_column :emails_disabled, remove_with: '16.3', remove_after: '2023-08-22'
extend Gitlab::Cache::RequestCache
extend Gitlab::Utils::Override
@@ -125,7 +128,6 @@ class Project < ApplicationRecord
before_validation :remove_leading_spaces_on_name
after_validation :check_pending_delete
before_save :ensure_runners_token
- before_save :update_new_emails_created_column, if: -> { emails_disabled_changed? }
after_create -> { create_or_load_association(:project_feature) }
after_create -> { create_or_load_association(:ci_cd_settings) }
@@ -165,11 +167,14 @@ class Project < ApplicationRecord
belongs_to :namespace
# Sync deletion via DB Trigger to ensure we do not have
# a project without a project_namespace (or vice-versa)
- belongs_to :project_namespace, autosave: true, class_name: 'Namespaces::ProjectNamespace', foreign_key: 'project_namespace_id'
+ belongs_to :project_namespace, autosave: true, class_name: 'Namespaces::ProjectNamespace', foreign_key: 'project_namespace_id', inverse_of: :project
alias_method :parent, :namespace
alias_attribute :parent_id, :namespace_id
has_one :catalog_resource, class_name: 'Ci::Catalog::Resource', inverse_of: :project
+ has_many :ci_components, class_name: 'Ci::Catalog::Resources::Component', inverse_of: :project
+ has_many :catalog_resource_versions, class_name: 'Ci::Catalog::Resources::Version', inverse_of: :project
+
has_one :last_event, -> { order 'events.created_at DESC' }, class_name: 'Event'
has_many :boards
@@ -312,7 +317,8 @@ class Project < ApplicationRecord
has_many :designs, inverse_of: :project, class_name: 'DesignManagement::Design'
has_many :project_authorizations
- has_many :authorized_users, through: :project_authorizations, source: :user, class_name: 'User'
+ has_many :authorized_users, -> { allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/422045') },
+ through: :project_authorizations, source: :user, class_name: 'User'
has_many :project_members, -> { where(requested_at: nil) },
as: :source, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
@@ -506,6 +512,7 @@ class Project < ApplicationRecord
with_options prefix: :ci do
delegate :default_git_depth, :default_git_depth=
delegate :forward_deployment_enabled, :forward_deployment_enabled=
+ delegate :forward_deployment_rollback_allowed, :forward_deployment_rollback_allowed=
delegate :inbound_job_token_scope_enabled, :inbound_job_token_scope_enabled=
delegate :allow_fork_pipelines_to_run_in_parent_project, :allow_fork_pipelines_to_run_in_parent_project=
delegate :separated_caches, :separated_caches=
@@ -518,6 +525,7 @@ class Project < ApplicationRecord
delegate :has_shimo?
delegate :show_diff_preview_in_email, :show_diff_preview_in_email=, :show_diff_preview_in_email?
delegate :runner_registration_enabled, :runner_registration_enabled=, :runner_registration_enabled?
+ delegate :emails_enabled, :emails_enabled=, :emails_enabled?
delegate :squash_always?, :squash_never?, :squash_enabled_by_default?, :squash_readonly?
delegate :mr_default_target_self, :mr_default_target_self=
delegate :previous_default_branch, :previous_default_branch=
@@ -585,6 +593,7 @@ class Project < ApplicationRecord
scope :pending_delete, -> { where(pending_delete: true) }
scope :without_deleted, -> { where(pending_delete: false) }
scope :not_hidden, -> { where(hidden: false) }
+ scope :not_in_groups, ->(groups) { where.not(group: groups) }
scope :not_aimed_for_deletion, -> { where(marked_for_deletion_at: nil).without_deleted }
scope :with_storage_feature, ->(feature) do
@@ -703,6 +712,7 @@ class Project < ApplicationRecord
# includes(:route) which we use in ProjectsFinder.
joins("INNER JOIN routes rs ON rs.source_id = projects.id AND rs.source_type = 'Project'")
.where('rs.path LIKE ?', "#{sanitize_sql_like(path)}/%")
+ .allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/421843')
end
scope :with_feature_enabled, ->(feature) {
@@ -932,6 +942,7 @@ class Project < ApplicationRecord
if include_namespace
joins(:route).fuzzy_search(query, [Route.arel_table[:path], Route.arel_table[:name], :description],
use_minimum_char_limit: use_minimum_char_limit)
+ .allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/421843')
else
fuzzy_search(query, [:path, :name, :description], use_minimum_char_limit: use_minimum_char_limit)
end
@@ -1209,14 +1220,8 @@ class Project < ApplicationRecord
end
def emails_disabled?
- strong_memoize(:emails_disabled) do
- # disabling in the namespace overrides the project setting
- super || namespace.emails_disabled?
- end
- end
-
- def emails_enabled?
- !emails_disabled?
+ # disabling in the namespace overrides the project setting
+ !emails_enabled?
end
override :lfs_enabled?
@@ -1760,7 +1765,8 @@ class Project < ApplicationRecord
# rubocop: disable CodeReuse/ServiceClass
def create_labels
Label.templates.each do |label|
- params = label.attributes.except('id', 'template', 'created_at', 'updated_at', 'type')
+ # slice on column_names to ensure an added DB column will not break a mixed deployment
+ params = label.attributes.slice(*Label.column_names).except('id', 'template', 'created_at', 'updated_at', 'type')
Labels::FindOrCreateService.new(nil, self, params).execute(skip_authorization: true)
end
end
@@ -1951,6 +1957,8 @@ class Project < ApplicationRecord
def track_project_repository
repository = project_repository || build_project_repository
repository.update!(shard_name: repository_storage, disk_path: disk_path)
+
+ cleanup if replicate_object_pool_on_move_ff_enabled?
end
def create_repository(force: false, default_branch: nil)
@@ -2466,7 +2474,7 @@ class Project < ApplicationRecord
break unless pages_enabled?
variables.append(key: 'CI_PAGES_DOMAIN', value: Gitlab.config.pages.host)
- variables.append(key: 'CI_PAGES_URL', value: Gitlab::Pages::UrlBuilder.new(self).pages_url)
+ variables.append(key: 'CI_PAGES_URL', value: Gitlab::Pages::UrlBuilder.new(self).pages_url(with_unique_domain: true))
end
end
@@ -2825,8 +2833,26 @@ class Project < ApplicationRecord
update_column(:pool_repository_id, nil)
end
+ # After repository is moved from shard to shard, disconnect it from the previous object pool and connect to the new pool
+ def swap_pool_repository!
+ return unless replicate_object_pool_on_move_ff_enabled?
+ return unless repository_exists?
+
+ old_pool_repository = pool_repository
+ return if old_pool_repository.blank?
+ return if pool_repository_shard_matches_repository?(old_pool_repository)
+
+ new_pool_repository = PoolRepository.by_source_project_and_shard_name(old_pool_repository.source_project, repository_storage).take!
+ update!(pool_repository: new_pool_repository)
+
+ old_pool_repository.unlink_repository(repository, disconnect: !pending_delete?)
+ end
+
def link_pool_repository
- pool_repository&.link_repository(repository)
+ return unless pool_repository
+ return if (pool_repository.shard_name != repository.shard) && replicate_object_pool_on_move_ff_enabled?
+
+ pool_repository.link_repository(repository)
end
def has_pool_repository?
@@ -3048,6 +3074,12 @@ class Project < ApplicationRecord
ci_cd_settings.forward_deployment_enabled?
end
+ def ci_forward_deployment_rollback_allowed?
+ return false unless ci_cd_settings
+
+ ci_cd_settings.forward_deployment_rollback_allowed?
+ end
+
def ci_allow_fork_pipelines_to_run_in_parent_project?
return false unless ci_cd_settings
@@ -3151,6 +3183,8 @@ class Project < ApplicationRecord
end
def created_and_owned_by_banned_user?
+ return false unless creator
+
creator.banned? && team.max_member_access(creator.id) == Gitlab::Access::OWNER
end
@@ -3170,6 +3204,10 @@ class Project < ApplicationRecord
group&.work_items_mvc_2_feature_flag_enabled? || Feature.enabled?(:work_items_mvc_2)
end
+ def linked_work_items_feature_flag_enabled?
+ group&.linked_work_items_feature_flag_enabled? || Feature.enabled?(:linked_work_items, self)
+ end
+
def enqueue_record_project_target_platforms
return unless Gitlab.com?
@@ -3437,7 +3475,7 @@ class Project < ApplicationRecord
# create project_namespace when project is created
build_project_namespace if project_namespace_creation_enabled?
- sync_attributes(project_namespace) if sync_project_namespace?
+ project_namespace.sync_attributes_from_project(self) if sync_project_namespace?
end
def project_namespace_creation_enabled?
@@ -3448,27 +3486,6 @@ class Project < ApplicationRecord
(changes.keys & %w(name path namespace_id namespace visibility_level shared_runners_enabled)).any? && project_namespace.present?
end
- def sync_attributes(project_namespace)
- attributes_to_sync = changes.slice(*%w(name path namespace_id namespace visibility_level shared_runners_enabled))
- .transform_values { |val| val[1] }
-
- # if visibility_level is not set explicitly for project, it defaults to 0,
- # but for namespace visibility_level defaults to 20,
- # so it gets out of sync right away if we do not set it explicitly when creating the project namespace
- attributes_to_sync['visibility_level'] ||= visibility_level if new_record?
-
- # when a project is associated with a group while the group is created we need to ensure we associate the new
- # group with the project namespace as well.
- # E.g.
- # project = create(:project) <- project is saved
- # create(:group, projects: [project]) <- associate project with a group that is not yet created.
- if attributes_to_sync.has_key?('namespace_id') && attributes_to_sync['namespace_id'].blank? && namespace.present?
- attributes_to_sync['parent'] = namespace
- end
-
- project_namespace.assign_attributes(attributes_to_sync)
- end
-
def reload_project_namespace_details
return unless (previous_changes.keys & %w(description description_html cached_markdown_version)).any? && project_namespace.namespace_details.present?
@@ -3511,19 +3528,18 @@ class Project < ApplicationRecord
end
end
- def update_new_emails_created_column
- return if project_setting.nil?
- return if project_setting.emails_enabled == !emails_disabled
+ def runners_token_prefix
+ RunnersTokenPrefixable::RUNNERS_TOKEN_PREFIX
+ end
- if project_setting.persisted?
- project_setting.update!(emails_enabled: !emails_disabled)
- elsif project_setting
- project_setting.emails_enabled = !emails_disabled
- end
+ def replicate_object_pool_on_move_ff_enabled?
+ Feature.enabled?(:replicate_object_pool_on_move, self)
end
- def runners_token_prefix
- RunnersTokenPrefixable::RUNNERS_TOKEN_PREFIX
+ def pool_repository_shard_matches_repository?(pool)
+ pool_repository_shard = pool.shard.name
+
+ pool_repository_shard == repository_storage
end
end