diff options
Diffstat (limited to 'app/models/project.rb')
-rw-r--r-- | app/models/project.rb | 147 |
1 files changed, 66 insertions, 81 deletions
diff --git a/app/models/project.rb b/app/models/project.rb index e1b6a9c41dd..4db0eaa0442 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -3,7 +3,6 @@ require 'carrierwave/orm/activerecord' class Project < ApplicationRecord - extend ::Gitlab::Utils::Override include Gitlab::ConfigHelper include Gitlab::VisibilityLevel include AccessRequestable @@ -147,6 +146,7 @@ class Project < ApplicationRecord has_one :discord_service has_one :drone_ci_service has_one :emails_on_push_service + has_one :ewm_service has_one :pipelines_email_service has_one :irker_service has_one :pivotaltracker_service @@ -245,7 +245,6 @@ class Project < ApplicationRecord has_many :lfs_file_locks has_many :project_group_links has_many :invited_groups, through: :project_group_links, source: :group - has_many :pages_domains has_many :todos has_many :notification_settings, as: :source, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent @@ -254,6 +253,7 @@ class Project < ApplicationRecord has_one :import_data, class_name: 'ProjectImportData', inverse_of: :project, autosave: true has_one :project_feature, inverse_of: :project has_one :statistics, class_name: 'ProjectStatistics' + has_one :feature_usage, class_name: 'ProjectFeatureUsage' has_one :cluster_project, class_name: 'Clusters::Project' has_many :clusters, through: :cluster_project, class_name: 'Clusters::Cluster' @@ -279,10 +279,9 @@ class Project < ApplicationRecord # The relation :all_pipelines is intended to be used when we want to get the # whole list of pipelines associated to the project has_many :all_pipelines, class_name: 'Ci::Pipeline', inverse_of: :project - # The relation :ci_pipelines is intended to be used when we want to get only - # those pipeline which are directly related to CI. There are - # other pipelines, like webide ones, that we won't retrieve - # if we use this relation. + # The relation :ci_pipelines includes all those that directly contribute to the + # latest status of a ref. This does not include dangling pipelines such as those + # from webide, child pipelines, etc. has_many :ci_pipelines, -> { ci_sources }, class_name: 'Ci::Pipeline', @@ -327,8 +326,6 @@ class Project < ApplicationRecord has_many :sourced_pipelines, class_name: 'Ci::Sources::Pipeline', foreign_key: :source_project_id has_many :source_pipelines, class_name: 'Ci::Sources::Pipeline', foreign_key: :project_id - has_one :pages_metadatum, class_name: 'ProjectPagesMetadatum', inverse_of: :project - has_many :import_failures, inverse_of: :project has_many :jira_imports, -> { order 'jira_imports.created_at' }, class_name: 'JiraImportState', inverse_of: :project @@ -339,10 +336,19 @@ class Project < ApplicationRecord has_many :webide_pipelines, -> { webide_source }, class_name: 'Ci::Pipeline', inverse_of: :project has_many :reviews, inverse_of: :project + # GitLab Pages + has_many :pages_domains + has_one :pages_metadatum, class_name: 'ProjectPagesMetadatum', inverse_of: :project + has_many :pages_deployments + # Can be too many records. We need to implement delete_all in batches. # Issue https://gitlab.com/gitlab-org/gitlab/-/issues/228637 has_many :product_analytics_events, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent + has_many :operations_feature_flags, class_name: 'Operations::FeatureFlag' + has_one :operations_feature_flags_client, class_name: 'Operations::FeatureFlagsClient' + has_many :operations_feature_flags_user_lists, class_name: 'Operations::FeatureFlags::UserList' + accepts_nested_attributes_for :variables, allow_destroy: true accepts_nested_attributes_for :project_feature, update_only: true accepts_nested_attributes_for :project_setting, update_only: true @@ -393,6 +399,8 @@ class Project < ApplicationRecord to: :project_setting delegate :active?, to: :prometheus_service, allow_nil: true, prefix: true + delegate :log_jira_dvcs_integration_usage, :jira_dvcs_server_last_sync_at, :jira_dvcs_cloud_last_sync_at, to: :feature_usage + # Validations validates :creator, presence: true, on: :create validates :description, length: { maximum: 2000 }, allow_blank: true @@ -454,14 +462,17 @@ class Project < ApplicationRecord # Sometimes queries (e.g. using CTEs) require explicit disambiguation with table name scope :projects_order_id_desc, -> { reorder(self.arel_table['id'].desc) } - scope :sorted_by_similarity_desc, -> (search) do + scope :sorted_by_similarity_desc, -> (search, include_in_select: false) do order_expression = Gitlab::Database::SimilarityScore.build_expression(search: search, rules: [ { column: arel_table["path"], multiplier: 1 }, { column: arel_table["name"], multiplier: 0.7 }, { column: arel_table["description"], multiplier: 0.2 } ]) - reorder(order_expression.desc, arel_table['id'].desc) + query = reorder(order_expression.desc, arel_table['id'].desc) + + query = query.select(*query.arel.projections, order_expression.as('similarity')) if include_in_select + query end scope :with_packages, -> { joins(:packages) } @@ -476,6 +487,9 @@ class Project < ApplicationRecord scope :for_milestones, ->(ids) { joins(:milestones).where('milestones.id' => ids).distinct } scope :with_push, -> { joins(:events).merge(Event.pushed_action) } scope :with_project_feature, -> { joins('LEFT JOIN project_features ON projects.id = project_features.project_id') } + scope :with_active_jira_services, -> { joins(:services).merge(::JiraService.active) } # rubocop:disable CodeReuse/ServiceClass + scope :with_jira_dvcs_cloud, -> { joins(:feature_usage).merge(ProjectFeatureUsage.with_jira_dvcs_integration_enabled(cloud: true)) } + scope :with_jira_dvcs_server, -> { joins(:feature_usage).merge(ProjectFeatureUsage.with_jira_dvcs_integration_enabled(cloud: false)) } scope :inc_routes, -> { includes(:route, namespace: :route) } scope :with_statistics, -> { includes(:statistics) } scope :with_namespace, -> { includes(:namespace) } @@ -545,6 +559,8 @@ class Project < ApplicationRecord preload(:project_feature, :route, namespace: [:route, :owner]) } + scope :imported_from, -> (type) { where(import_type: type) } + enum auto_cancel_pending_pipelines: { disabled: 0, enabled: 1 } chronic_duration_attr :build_timeout_human_readable, :build_timeout, @@ -882,12 +898,12 @@ class Project < ApplicationRecord end def repository - @repository ||= Repository.new(full_path, self, shard: repository_storage, disk_path: disk_path) + @repository ||= Gitlab::GlRepository::PROJECT.repository_for(self) end def design_repository strong_memoize(:design_repository) do - DesignManagement::Repository.new(self) + Gitlab::GlRepository::DESIGN.repository_for(self) end end @@ -942,13 +958,12 @@ class Project < ApplicationRecord latest_successful_build_for_ref(job_name, ref) || raise(ActiveRecord::RecordNotFound.new("Couldn't find job #{job_name}")) end - def latest_pipeline_for_ref(ref = default_branch) + def latest_pipeline(ref = default_branch, sha = nil) ref = ref.presence || default_branch - sha = commit(ref)&.sha - + sha ||= commit(ref)&.sha return unless sha - ci_pipelines.newest_first(ref: ref, sha: sha).first + ci_pipelines.newest_first(ref: ref, sha: sha).take end def merge_base_commit(first_commit_id, second_commit_id) @@ -1442,6 +1457,10 @@ class Project < ApplicationRecord http_url_to_repo end + def feature_usage + super.presence || build_feature_usage + end + def forked? fork_network && fork_network.root_project != self end @@ -1452,44 +1471,10 @@ class Project < ApplicationRecord forked_from_project || fork_network&.root_project end - # TODO: Remove this method once all LfsObjectsProject records are backfilled - # for forks. - # - # See https://gitlab.com/gitlab-org/gitlab/issues/122002 for more info. - def lfs_storage_project - @lfs_storage_project ||= begin - result = self - - # TODO: Make this go to the fork_network root immediately - # dependant on the discussion in: https://gitlab.com/gitlab-org/gitlab-foss/issues/39769 - result = result.fork_source while result&.forked? - - result || self - end - end - - # This will return all `lfs_objects` that are accessible to the project and - # the fork source. This is needed since older forks won't have access to some - # LFS objects directly and have to get it from the fork source. - # - # TODO: Remove this method once all LfsObjectsProject records are backfilled - # for forks. At that point, projects can look at their own `lfs_objects`. - # - # See https://gitlab.com/gitlab-org/gitlab/issues/122002 for more info. - def all_lfs_objects + def lfs_objects_for_repository_types(*types) LfsObject - .distinct .joins(:lfs_objects_projects) - .where(lfs_objects_projects: { project_id: [self, lfs_storage_project] }) - end - - # TODO: Remove this method once all LfsObjectsProject records are backfilled - # for forks. At that point, projects can look at their own `lfs_objects` so - # `lfs_objects_oids` can be used instead. - # - # See https://gitlab.com/gitlab-org/gitlab/issues/122002 for more info. - def all_lfs_objects_oids(oids: []) - oids(all_lfs_objects, oids: oids) + .where(lfs_objects_projects: { project: self, repository_type: types }) end def lfs_objects_oids(oids: []) @@ -1653,21 +1638,6 @@ class Project < ApplicationRecord !namespace.share_with_group_lock end - def pipeline_for(ref, sha = nil, id = nil) - sha ||= commit(ref).try(:sha) - return unless sha - - if id.present? - pipelines_for(ref, sha).find_by(id: id) - else - pipelines_for(ref, sha).take - end - end - - def pipelines_for(ref, sha) - ci_pipelines.order(id: :desc).where(sha: sha, ref: ref) - end - def latest_successful_pipeline_for_default_branch if defined?(@latest_successful_pipeline_for_default_branch) return @latest_successful_pipeline_for_default_branch @@ -1826,12 +1796,12 @@ class Project < ApplicationRecord end # rubocop: enable CodeReuse/ServiceClass - def mark_pages_as_deployed - ensure_pages_metadatum.update!(deployed: true) + def mark_pages_as_deployed(artifacts_archive: nil) + ensure_pages_metadatum.update!(deployed: true, artifacts_archive: artifacts_archive) end def mark_pages_as_not_deployed - ensure_pages_metadatum.update!(deployed: false) + ensure_pages_metadatum.update!(deployed: false, artifacts_archive: nil) end def write_repository_config(gl_full_path: full_path) @@ -2140,8 +2110,8 @@ class Project < ApplicationRecord data = repository.route_map_for(sha) Gitlab::RouteMap.new(data) if data - rescue Gitlab::RouteMap::FormatError - nil + rescue Gitlab::RouteMap::FormatError + nil end end @@ -2424,6 +2394,10 @@ class Project < ApplicationRecord false end + def jira_subscription_exists? + JiraConnectSubscription.for_project(self).exists? + end + def uses_default_ci_config? ci_config_path.blank? || ci_config_path == Gitlab::FileDetector::PATTERNS[:gitlab_ci] end @@ -2464,11 +2438,6 @@ class Project < ApplicationRecord jira_imports.last end - override :after_wiki_activity - def after_wiki_activity - touch(:last_activity_at, :last_repository_updated_at) - end - def metrics_setting super || build_metrics_setting end @@ -2518,6 +2487,20 @@ class Project < ApplicationRecord .exists? end + def default_branch_or_master + default_branch || 'master' + end + + def ci_config_path_or_default + ci_config_path.presence || Ci::Pipeline::DEFAULT_CONFIG_PATH + end + + def enabled_group_deploy_keys + return GroupDeployKey.none unless group + + GroupDeployKey.for_groups(group.self_and_ancestors_ids) + end + private def find_service(services, name) @@ -2533,11 +2516,11 @@ class Project < ApplicationRecord end def services_templates - @services_templates ||= Service.templates + @services_templates ||= Service.for_template end def services_instances - @services_instances ||= Service.instances + @services_instances ||= Service.for_instance end def closest_namespace_setting(name) @@ -2678,9 +2661,11 @@ class Project < ApplicationRecord end def oids(objects, oids: []) - collection = oids.any? ? objects.where(oid: oids) : objects + objects = objects.where(oid: oids) if oids.any? - collection.pluck(:oid) + [].tap do |out| + objects.each_batch { |relation| out.concat(relation.pluck(:oid)) } + end end end |