summaryrefslogtreecommitdiff
path: root/app/models/project.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/project.rb')
-rw-r--r--app/models/project.rb147
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