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.rb127
1 files changed, 70 insertions, 57 deletions
diff --git a/app/models/project.rb b/app/models/project.rb
index 5db349463d8..c0dd2eb8584 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -3,6 +3,7 @@
require 'carrierwave/orm/activerecord'
class Project < ApplicationRecord
+ extend ::Gitlab::Utils::Override
include Gitlab::ConfigHelper
include Gitlab::VisibilityLevel
include AccessRequestable
@@ -18,6 +19,7 @@ class Project < ApplicationRecord
include SelectForProjectAuthorization
include Presentable
include HasRepository
+ include HasWiki
include Routable
include GroupDescendant
include Gitlab::SQL::Pattern
@@ -175,6 +177,7 @@ class Project < ApplicationRecord
has_one :packagist_service
has_one :hangouts_chat_service
has_one :unify_circuit_service
+ has_one :webex_teams_service
has_one :root_of_fork_network,
foreign_key: 'root_project_id',
@@ -206,12 +209,14 @@ class Project < ApplicationRecord
has_many :services
has_many :events
has_many :milestones
+ has_many :iterations
has_many :notes
has_many :snippets, class_name: 'ProjectSnippet'
has_many :hooks, class_name: 'ProjectHook'
has_many :protected_branches
has_many :protected_tags
has_many :repository_languages, -> { order "share DESC" }
+ 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'
@@ -254,6 +259,9 @@ class Project < ApplicationRecord
has_many :prometheus_alerts, inverse_of: :project
has_many :prometheus_alert_events, inverse_of: :project
has_many :self_managed_prometheus_alert_events, inverse_of: :project
+ has_many :metrics_users_starred_dashboards, class_name: 'Metrics::UsersStarredDashboard', inverse_of: :project
+
+ has_many :alert_management_alerts, class_name: 'AlertManagement::Alert', inverse_of: :project
# Container repositories need to remove data from the container registry,
# which is not managed by the DB. Hence we're still using dependent: :destroy
@@ -295,6 +303,7 @@ class Project < ApplicationRecord
has_many :project_deploy_tokens
has_many :deploy_tokens, through: :project_deploy_tokens
has_many :resource_groups, class_name: 'Ci::ResourceGroup', inverse_of: :project
+ has_many :freeze_periods, class_name: 'Ci::FreezePeriod', inverse_of: :project
has_one :auto_devops, class_name: 'ProjectAutoDevops', inverse_of: :project, autosave: true
has_many :custom_attributes, class_name: 'ProjectCustomAttribute'
@@ -315,10 +324,13 @@ class Project < ApplicationRecord
has_many :import_failures, inverse_of: :project
has_many :jira_imports, -> { order 'jira_imports.created_at' }, class_name: 'JiraImportState', inverse_of: :project
- has_many :daily_report_results, class_name: 'Ci::DailyReportResult'
+ has_many :daily_build_group_report_results, class_name: 'Ci::DailyBuildGroupReportResult'
+
+ has_many :repository_storage_moves, class_name: 'ProjectRepositoryStorageMove'
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
accepts_nested_attributes_for :import_data
accepts_nested_attributes_for :auto_devops, update_only: true
accepts_nested_attributes_for :ci_cd_settings, update_only: true
@@ -342,6 +354,9 @@ class Project < ApplicationRecord
:wiki_access_level, :snippets_access_level, :builds_access_level,
:repository_access_level, :pages_access_level, :metrics_dashboard_access_level,
to: :project_feature, allow_nil: true
+ delegate :show_default_award_emojis, :show_default_award_emojis=,
+ :show_default_award_emojis?,
+ to: :project_setting, allow_nil: true
delegate :scheduled?, :started?, :in_progress?, :failed?, :finished?,
prefix: :import, to: :import_state, allow_nil: true
delegate :no_import?, to: :import_state, allow_nil: true
@@ -355,6 +370,7 @@ class Project < ApplicationRecord
delegate :external_dashboard_url, to: :metrics_setting, allow_nil: true, prefix: true
delegate :default_git_depth, :default_git_depth=, to: :ci_cd_settings, prefix: :ci
delegate :forward_deployment_enabled, :forward_deployment_enabled=, :forward_deployment_enabled?, to: :ci_cd_settings
+ delegate :actual_limits, :actual_plan_name, to: :namespace, allow_nil: true
# Validations
validates :creator, presence: true, on: :create
@@ -386,7 +402,6 @@ class Project < ApplicationRecord
validate :check_repository_path_availability, on: :update, if: ->(project) { project.renamed? }
validate :visibility_level_allowed_by_group, if: :should_validate_visibility_level?
validate :visibility_level_allowed_as_fork, if: :should_validate_visibility_level?
- validate :check_wiki_path_conflict
validate :validate_pages_https_only, if: -> { changes.has_key?(:pages_https_only) }
validates :repository_storage,
presence: true,
@@ -515,12 +530,14 @@ class Project < ApplicationRecord
def self.public_or_visible_to_user(user = nil, min_access_level = nil)
min_access_level = nil if user&.admin?
- if user
+ return public_to_user unless user
+
+ if user.is_a?(DeployToken)
+ user.projects
+ else
where('EXISTS (?) OR projects.visibility_level IN (?)',
user.authorizations_for_projects(min_access_level: min_access_level),
Gitlab::VisibilityLevel.levels_for_user(user))
- else
- public_to_user
end
end
@@ -785,6 +802,11 @@ class Project < ApplicationRecord
Feature.enabled?(:jira_issue_import, self, default_enabled: true)
end
+ # LFS and hashed repository storage are required for using Design Management.
+ def design_management_enabled?
+ lfs_enabled? && hashed_storage?(:repository)
+ end
+
def team
@team ||= ProjectTeam.new(self)
end
@@ -793,6 +815,12 @@ class Project < ApplicationRecord
@repository ||= Repository.new(full_path, self, shard: repository_storage, disk_path: disk_path)
end
+ def design_repository
+ strong_memoize(:design_repository) do
+ DesignManagement::Repository.new(self)
+ end
+ end
+
def cleanup
@repository = nil
end
@@ -819,7 +847,7 @@ class Project < ApplicationRecord
latest_pipeline = ci_pipelines.latest_successful_for_ref(ref)
return unless latest_pipeline
- latest_pipeline.builds.latest.with_artifacts_archive.find_by(name: job_name)
+ latest_pipeline.builds.latest.with_downloadable_artifacts.find_by(name: job_name)
end
def latest_successful_build_for_sha(job_name, sha)
@@ -828,7 +856,7 @@ class Project < ApplicationRecord
latest_pipeline = ci_pipelines.latest_successful_for_sha(sha)
return unless latest_pipeline
- latest_pipeline.builds.latest.with_artifacts_archive.find_by(name: job_name)
+ latest_pipeline.builds.latest.with_downloadable_artifacts.find_by(name: job_name)
end
def latest_successful_build_for_ref!(job_name, ref = default_branch)
@@ -865,10 +893,12 @@ class Project < ApplicationRecord
raise Projects::ImportService::Error, _('Jira import feature is disabled.') unless jira_issues_import_feature_flag_enabled?
raise Projects::ImportService::Error, _('Jira integration not configured.') unless jira_service&.active?
- return unless user
+ if user
+ raise Projects::ImportService::Error, _('Cannot import because issues are not available in this project.') unless feature_available?(:issues, user)
+ raise Projects::ImportService::Error, _('You do not have permissions to run the import.') unless user.can?(:admin_project, self)
+ end
- raise Projects::ImportService::Error, _('Cannot import because issues are not available in this project.') unless feature_available?(:issues, user)
- raise Projects::ImportService::Error, _('You do not have permissions to run the import.') unless user.can?(:admin_project, self)
+ raise Projects::ImportService::Error, _('Unable to connect to the Jira instance. Please check your Jira integration configuration.') unless jira_service.test(nil)[:success]
end
def human_import_status_name
@@ -1056,16 +1086,6 @@ class Project < ApplicationRecord
self.errors.add(:visibility_level, _("%{level_name} is not allowed since the fork source project has lower visibility.") % { level_name: level_name })
end
- def check_wiki_path_conflict
- return if path.blank?
-
- path_to_check = path.ends_with?('.wiki') ? path.chomp('.wiki') : "#{path}.wiki"
-
- if Project.where(namespace_id: namespace_id, path: path_to_check).exists?
- errors.add(:name, _('has already been taken'))
- end
- end
-
def pages_https_only
return false unless Gitlab.config.pages.external_https
@@ -1179,11 +1199,7 @@ class Project < ApplicationRecord
end
def issues_tracker
- if external_issue_tracker
- external_issue_tracker
- else
- default_issue_tracker
- end
+ external_issue_tracker || default_issue_tracker
end
def external_issue_reference_pattern
@@ -1328,11 +1344,7 @@ class Project < ApplicationRecord
# rubocop: enable CodeReuse/ServiceClass
def owner
- if group
- group
- else
- namespace.try(:owner)
- end
+ group || namespace.try(:owner)
end
def to_ability_name
@@ -1432,15 +1444,12 @@ class Project < ApplicationRecord
# Expires various caches before a project is renamed.
def expire_caches_before_rename(old_path)
- repo = Repository.new(old_path, self, shard: repository_storage)
- wiki = Repository.new("#{old_path}.wiki", self, shard: repository_storage, repo_type: Gitlab::GlRepository::WIKI)
+ project_repo = Repository.new(old_path, self, shard: repository_storage)
+ wiki_repo = Repository.new("#{old_path}#{Gitlab::GlRepository::WIKI.path_suffix}", self, shard: repository_storage, repo_type: Gitlab::GlRepository::WIKI)
+ design_repo = Repository.new("#{old_path}#{Gitlab::GlRepository::DESIGN.path_suffix}", self, shard: repository_storage, repo_type: Gitlab::GlRepository::DESIGN)
- if repo.exists?
- repo.before_delete
- end
-
- if wiki.exists?
- wiki.before_delete
+ [project_repo, wiki_repo, design_repo].each do |repo|
+ repo.before_delete if repo.exists?
end
end
@@ -1517,6 +1526,10 @@ class Project < ApplicationRecord
end
end
+ def bots
+ users.project_bot
+ end
+
# Filters `users` to return only authorized users of the project
def members_among(users)
if users.is_a?(ActiveRecord::Relation) && !users.loaded?
@@ -1565,10 +1578,6 @@ class Project < ApplicationRecord
create_repository(force: true) unless repository_exists?
end
- def wiki_repository_exists?
- wiki.repository_exists?
- end
-
# update visibility_level of forks
def update_forks_visibility_level
return if unlink_forks_upon_visibility_decrease_enabled?
@@ -1582,20 +1591,6 @@ class Project < ApplicationRecord
end
end
- def create_wiki
- ProjectWiki.new(self, self.owner).wiki
- true
- rescue ProjectWiki::CouldNotCreateWikiError
- errors.add(:base, _('Failed create wiki'))
- false
- end
-
- def wiki
- strong_memoize(:wiki) do
- ProjectWiki.new(self, self.owner)
- end
- end
-
def allowed_to_share_with_group?
!namespace.share_with_group_lock
end
@@ -2024,6 +2019,14 @@ class Project < ApplicationRecord
end
end
+ def ci_instance_variables_for(ref:)
+ if protected_for?(ref)
+ Ci::InstanceVariable.all_cached
+ else
+ Ci::InstanceVariable.unprotected_cached
+ end
+ end
+
def protected_for?(ref)
raise Repository::AmbiguousRefError if repository.ambiguous_ref?(ref)
@@ -2085,7 +2088,12 @@ class Project < ApplicationRecord
raise ArgumentError unless ::Gitlab.config.repositories.storages.key?(new_repository_storage_key)
- run_after_commit { ProjectUpdateRepositoryStorageWorker.perform_async(id, new_repository_storage_key) }
+ storage_move = repository_storage_moves.create!(
+ source_storage_name: repository_storage,
+ destination_storage_name: new_repository_storage_key
+ )
+ storage_move.schedule!
+
self.repository_read_only = true
end
@@ -2425,6 +2433,11 @@ class Project < ApplicationRecord
jira_imports.last
end
+ override :after_wiki_activity
+ def after_wiki_activity
+ touch(:last_activity_at, :last_repository_updated_at)
+ end
+
private
def find_service(services, name)