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.rb245
1 files changed, 153 insertions, 92 deletions
diff --git a/app/models/project.rb b/app/models/project.rb
index 224193fba08..452a5c8973c 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -111,9 +111,9 @@ class Project < ApplicationRecord
attribute :ci_config_path, default: -> { Gitlab::CurrentSettings.default_ci_config_path }
add_authentication_token_field :runners_token,
- encrypted: -> { Feature.enabled?(:projects_tokens_optional_encryption) ? :optional : :required },
- format_with_prefix: :runners_token_prefix,
- require_prefix_for_validation: true
+ encrypted: :required,
+ format_with_prefix: :runners_token_prefix,
+ require_prefix_for_validation: true
# Storage specific hooks
after_initialize :use_hashed_storage
@@ -185,6 +185,7 @@ class Project < ApplicationRecord
has_one :bugzilla_integration, class_name: 'Integrations::Bugzilla'
has_one :buildkite_integration, class_name: 'Integrations::Buildkite'
has_one :campfire_integration, class_name: 'Integrations::Campfire'
+ has_one :clickup_integration, class_name: 'Integrations::Clickup'
has_one :confluence_integration, class_name: 'Integrations::Confluence'
has_one :custom_issue_tracker_integration, class_name: 'Integrations::CustomIssueTracker'
has_one :datadog_integration, class_name: 'Integrations::Datadog'
@@ -194,6 +195,7 @@ class Project < ApplicationRecord
has_one :emails_on_push_integration, class_name: 'Integrations::EmailsOnPush'
has_one :ewm_integration, class_name: 'Integrations::Ewm'
has_one :external_wiki_integration, class_name: 'Integrations::ExternalWiki'
+ has_one :gitlab_slack_application_integration, class_name: 'Integrations::GitlabSlackApplication'
has_one :google_play_integration, class_name: 'Integrations::GooglePlay'
has_one :hangouts_chat_integration, class_name: 'Integrations::HangoutsChat'
has_one :harbor_integration, class_name: 'Integrations::Harbor'
@@ -217,6 +219,7 @@ class Project < ApplicationRecord
has_one :slack_slash_commands_integration, class_name: 'Integrations::SlackSlashCommands'
has_one :squash_tm_integration, class_name: 'Integrations::SquashTm'
has_one :teamcity_integration, class_name: 'Integrations::Teamcity'
+ has_one :telegram_integration, class_name: 'Integrations::Telegram'
has_one :unify_circuit_integration, class_name: 'Integrations::UnifyCircuit'
has_one :webex_teams_integration, class_name: 'Integrations::WebexTeams'
has_one :youtrack_integration, class_name: 'Integrations::Youtrack'
@@ -224,10 +227,7 @@ class Project < ApplicationRecord
has_one :wiki_repository, class_name: 'Projects::WikiRepository', inverse_of: :project
has_one :design_management_repository, class_name: 'DesignManagement::Repository', inverse_of: :project
- has_one :root_of_fork_network,
- foreign_key: 'root_project_id',
- inverse_of: :root_project,
- class_name: 'ForkNetwork'
+ has_one :root_of_fork_network, foreign_key: 'root_project_id', inverse_of: :root_project, class_name: 'ForkNetwork'
has_one :fork_network_member
has_one :fork_network, through: :fork_network_member
has_one :forked_from_project, through: :fork_network_member
@@ -247,24 +247,19 @@ class Project < ApplicationRecord
has_many :fork_network_projects, through: :fork_network, source: :projects
# Packages
- has_many :packages,
- class_name: 'Packages::Package'
- has_many :package_files,
- through: :packages, class_name: 'Packages::PackageFile'
+ has_many :packages, class_name: 'Packages::Package'
+ has_many :package_files, through: :packages, class_name: 'Packages::PackageFile'
# repository_files must be destroyed by ruby code in order to properly remove carrierwave uploads
has_many :rpm_repository_files,
- inverse_of: :project,
- class_name: 'Packages::Rpm::RepositoryFile',
- dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
+ inverse_of: :project,
+ class_name: 'Packages::Rpm::RepositoryFile',
+ dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
# debian_distributions and associated component_files must be destroyed by ruby code in order to properly remove carrierwave uploads
has_many :debian_distributions,
- class_name: 'Packages::Debian::ProjectDistribution',
- dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
- has_many :npm_metadata_caches,
- class_name: 'Packages::Npm::MetadataCache'
- has_one :packages_cleanup_policy,
- class_name: 'Packages::Cleanup::Policy',
- inverse_of: :project
+ class_name: 'Packages::Debian::ProjectDistribution',
+ dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
+ has_many :npm_metadata_caches, class_name: 'Packages::Npm::MetadataCache'
+ has_one :packages_cleanup_policy, class_name: 'Packages::Cleanup::Policy', inverse_of: :project
has_one :import_state, autosave: true, class_name: 'ProjectImportState', inverse_of: :project
has_one :import_export_upload, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
@@ -388,10 +383,7 @@ class Project < ApplicationRecord
# 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',
- inverse_of: :project
+ has_many :ci_pipelines, -> { ci_sources }, class_name: 'Ci::Pipeline', inverse_of: :project
has_many :stages, class_name: 'Ci::Stage', inverse_of: :project
has_many :ci_refs, class_name: 'Ci::Ref', inverse_of: :project
has_many :pipeline_metadata, class_name: 'Ci::PipelineMetadata', inverse_of: :project
@@ -473,8 +465,8 @@ class Project < ApplicationRecord
accepts_nested_attributes_for :container_expiration_policy, update_only: true
accepts_nested_attributes_for :remote_mirrors,
- allow_destroy: true,
- reject_if: ->(attrs) { attrs[:id].blank? && attrs[:url].blank? }
+ allow_destroy: true,
+ reject_if: ->(attrs) { attrs[:id].blank? && attrs[:url].blank? }
accepts_nested_attributes_for :incident_management_setting, update_only: true
accepts_nested_attributes_for :error_tracking_setting, update_only: true
@@ -483,60 +475,63 @@ class Project < ApplicationRecord
accepts_nested_attributes_for :prometheus_integration, update_only: true
accepts_nested_attributes_for :alerting_setting, update_only: true
- delegate :merge_requests_access_level, :forking_access_level, :issues_access_level,
- :wiki_access_level, :snippets_access_level, :builds_access_level,
- :repository_access_level, :package_registry_access_level, :pages_access_level,
- :metrics_dashboard_access_level, :analytics_access_level,
- :operations_access_level, :security_and_compliance_access_level,
- :container_registry_access_level, :environments_access_level, :feature_flags_access_level,
- :monitor_access_level, :releases_access_level, :infrastructure_access_level,
- to: :project_feature, allow_nil: true
-
- delegate :show_default_award_emojis, :show_default_award_emojis=,
- :enforce_auth_checks_on_uploads, :enforce_auth_checks_on_uploads=,
- :warn_about_potentially_unwanted_characters, :warn_about_potentially_unwanted_characters=,
- to: :project_setting, allow_nil: true
-
- delegate :show_diff_preview_in_email, :show_diff_preview_in_email=, :show_diff_preview_in_email?,
- :runner_registration_enabled, :runner_registration_enabled?, :runner_registration_enabled=,
- to: :project_setting
-
- delegate :squash_always?, :squash_never?, :squash_enabled_by_default?, :squash_readonly?, to: :project_setting
- delegate :squash_option, :squash_option=, to: :project_setting
- delegate :mr_default_target_self, :mr_default_target_self=, to: :project_setting
- delegate :previous_default_branch, :previous_default_branch=, to: :project_setting
+ delegate :merge_requests_access_level, :forking_access_level, :issues_access_level, :wiki_access_level, :snippets_access_level, :builds_access_level, :repository_access_level, :package_registry_access_level, :pages_access_level, :metrics_dashboard_access_level, :analytics_access_level, :operations_access_level, :security_and_compliance_access_level, :container_registry_access_level, :environments_access_level, :feature_flags_access_level, :monitor_access_level, :releases_access_level, :infrastructure_access_level, :model_experiments_access_level, to: :project_feature, allow_nil: true
delegate :name, to: :owner, allow_nil: true, prefix: true
- delegate :members, to: :team, prefix: true
- delegate :add_member, :add_members, :member?, to: :team
- delegate :add_guest, :add_reporter, :add_developer, :add_maintainer, :add_owner, :add_role, to: :team
- delegate :group_runners_enabled, :group_runners_enabled=, to: :ci_cd_settings, allow_nil: true
- delegate :root_ancestor, to: :namespace, allow_nil: true
+ delegate :log_jira_dvcs_integration_usage, :jira_dvcs_server_last_sync_at, :jira_dvcs_cloud_last_sync_at, to: :feature_usage
delegate :last_pipeline, to: :commit, allow_nil: true
- delegate :external_dashboard_url, to: :metrics_setting, allow_nil: true, prefix: true
- delegate :dashboard_timezone, to: :metrics_setting, allow_nil: true, prefix: true
- delegate :default_git_depth, :default_git_depth=, to: :ci_cd_settings, prefix: :ci, allow_nil: true
- delegate :forward_deployment_enabled, :forward_deployment_enabled=, to: :ci_cd_settings, prefix: :ci, allow_nil: true
- delegate :job_token_scope_enabled, :job_token_scope_enabled=, to: :ci_cd_settings, prefix: :ci_outbound, allow_nil: true
- delegate :inbound_job_token_scope_enabled, :inbound_job_token_scope_enabled=, to: :ci_cd_settings, prefix: :ci, allow_nil: true
- delegate :keep_latest_artifact, :keep_latest_artifact=, to: :ci_cd_settings, allow_nil: true
- delegate :allow_fork_pipelines_to_run_in_parent_project, :allow_fork_pipelines_to_run_in_parent_project=, to: :ci_cd_settings, prefix: :ci, allow_nil: true
- delegate :restrict_user_defined_variables, :restrict_user_defined_variables=, to: :ci_cd_settings, allow_nil: true
- delegate :separated_caches, :separated_caches=, to: :ci_cd_settings, prefix: :ci, allow_nil: true
- delegate :runner_token_expiration_interval, :runner_token_expiration_interval=, :runner_token_expiration_interval_human_readable, :runner_token_expiration_interval_human_readable=, to: :ci_cd_settings, allow_nil: true
- delegate :actual_limits, :actual_plan_name, :actual_plan, to: :namespace, allow_nil: true
- delegate :allow_merge_on_skipped_pipeline, :allow_merge_on_skipped_pipeline?,
- :allow_merge_on_skipped_pipeline=, :has_confluence?, :has_shimo?,
- to: :project_setting
- delegate :merge_commit_template, :merge_commit_template=, to: :project_setting, allow_nil: true
- delegate :squash_commit_template, :squash_commit_template=, to: :project_setting, allow_nil: true
- delegate :issue_branch_template, :issue_branch_template=, to: :project_setting, allow_nil: true
- delegate :log_jira_dvcs_integration_usage, :jira_dvcs_server_last_sync_at, :jira_dvcs_cloud_last_sync_at, to: :feature_usage
+ with_options to: :team do
+ delegate :members, prefix: true
+ delegate :add_member, :add_members, :member?
+ delegate :add_guest, :add_reporter, :add_developer, :add_maintainer, :add_owner, :add_role
+ end
- delegate :maven_package_requests_forwarding,
- :pypi_package_requests_forwarding,
- :npm_package_requests_forwarding,
- to: :namespace
+ with_options to: :metrics_setting, allow_nil: true, prefix: true do
+ delegate :external_dashboard_url
+ delegate :dashboard_timezone
+ end
+
+ with_options to: :namespace do
+ delegate :actual_limits, :actual_plan_name, :actual_plan, :root_ancestor, allow_nil: true
+ delegate :maven_package_requests_forwarding, :pypi_package_requests_forwarding, :npm_package_requests_forwarding
+ end
+
+ with_options to: :ci_cd_settings, allow_nil: true do
+ delegate :group_runners_enabled, :group_runners_enabled=
+ delegate :keep_latest_artifact, :keep_latest_artifact=
+ delegate :restrict_user_defined_variables, :restrict_user_defined_variables=
+ delegate :runner_token_expiration_interval, :runner_token_expiration_interval=, :runner_token_expiration_interval_human_readable, :runner_token_expiration_interval_human_readable=
+ delegate :job_token_scope_enabled, :job_token_scope_enabled=, prefix: :ci_outbound
+
+ with_options prefix: :ci do
+ delegate :default_git_depth, :default_git_depth=
+ delegate :forward_deployment_enabled, :forward_deployment_enabled=
+ 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=
+ end
+ end
+
+ with_options to: :project_setting do
+ delegate :allow_merge_on_skipped_pipeline, :allow_merge_on_skipped_pipeline?, :allow_merge_on_skipped_pipeline=
+ delegate :has_confluence?
+ 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 :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=
+ delegate :squash_option, :squash_option=
+
+ with_options allow_nil: true do
+ delegate :merge_commit_template, :merge_commit_template=
+ delegate :squash_commit_template, :squash_commit_template=
+ delegate :issue_branch_template, :issue_branch_template=
+ delegate :show_default_award_emojis, :show_default_award_emojis=
+ delegate :enforce_auth_checks_on_uploads, :enforce_auth_checks_on_uploads=
+ delegate :warn_about_potentially_unwanted_characters, :warn_about_potentially_unwanted_characters=
+ end
+ end
# Validations
validates :creator, presence: true, on: :create
@@ -602,6 +597,42 @@ class Project < ApplicationRecord
.or(arel_table[:storage_version].eq(nil)))
end
+ scope :sorted_by_name_desc, -> {
+ keyset_order = Gitlab::Pagination::Keyset::Order.build([
+ Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
+ attribute_name: :name,
+ column_expression: Project.arel_table[:name],
+ order_expression: Project.arel_table[:name].desc,
+ distinct: false,
+ nullable: :nulls_last
+ ),
+ Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
+ attribute_name: :id,
+ order_expression: Project.arel_table[:id].desc
+ )
+ ])
+
+ reorder(keyset_order)
+ }
+
+ scope :sorted_by_name_asc, -> {
+ keyset_order = Gitlab::Pagination::Keyset::Order.build([
+ Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
+ attribute_name: :name,
+ column_expression: Project.arel_table[:name],
+ order_expression: Project.arel_table[:name].asc,
+ distinct: false,
+ nullable: :nulls_last
+ ),
+ Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
+ attribute_name: :id,
+ order_expression: Project.arel_table[:id].asc
+ )
+ ])
+
+ reorder(keyset_order)
+ }
+
scope :sorted_by_updated_asc, -> { reorder(self.arel_table['updated_at'].asc) }
scope :sorted_by_updated_desc, -> { reorder(self.arel_table['updated_at'].desc) }
scope :sorted_by_stars_desc, -> { reorder(self.arel_table['star_count'].desc) }
@@ -751,11 +782,12 @@ class Project < ApplicationRecord
chronic_duration_attr :build_timeout_human_readable, :build_timeout,
default: 3600, error_message: N_('Maximum job timeout has a value which could not be accepted')
- validates :build_timeout, allow_nil: true,
- numericality: { greater_than_or_equal_to: 10.minutes,
- less_than: MAX_BUILD_TIMEOUT,
- only_integer: true,
- message: N_('needs to be between 10 minutes and 1 month') }
+ validates :build_timeout, allow_nil: true, numericality: {
+ greater_than_or_equal_to: 10.minutes,
+ less_than: MAX_BUILD_TIMEOUT,
+ only_integer: true,
+ message: N_('needs to be between 10 minutes and 1 month')
+ }
# Used by Projects::CleanupService to hold a map of rewritten object IDs
mount_uploader :bfg_object_map, AttachmentUploader
@@ -768,6 +800,20 @@ class Project < ApplicationRecord
preload(:project_feature, :route, :creator, group: :parent, namespace: [:route, :owner])
end
+ def self.with_slack_application_disabled
+ # Using Arel to avoid exposing what the column backing the type: attribute is
+ # rubocop: disable GitlabSecurity/PublicSend
+ with_active_slack = Integration.active.by_name(:gitlab_slack_application)
+ join_contraint = arel_table[:id].eq(Integration.arel_table[:project_id])
+ constraint = with_active_slack.where_clause.send(:predicates).reduce(join_contraint) { |a, b| a.and(b) }
+ join = arel_table.join(Integration.arel_table, Arel::Nodes::OuterJoin).on(constraint).join_sources
+ # rubocop: enable GitlabSecurity/PublicSend
+
+ joins(join).where(integrations: { id: nil })
+ rescue Integration::UnknownType
+ all
+ end
+
def self.eager_load_namespace_and_owner
includes(namespace: :owner)
end
@@ -782,9 +828,11 @@ class Project < ApplicationRecord
if user.is_a?(DeployToken)
where(id: user.accessible_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))
+ where(
+ 'EXISTS (?) OR projects.visibility_level IN (?)',
+ user.authorizations_for_projects(min_access_level: min_access_level),
+ Gitlab::VisibilityLevel.levels_for_user(user)
+ )
end
end
@@ -863,11 +911,12 @@ class Project < ApplicationRecord
# search.
#
# query - The search query as a String.
- def search(query, include_namespace: false)
+ def search(query, include_namespace: false, use_minimum_char_limit: true)
if include_namespace
- joins(:route).fuzzy_search(query, [Route.arel_table[:path], Route.arel_table[:name], :description])
+ joins(:route).fuzzy_search(query, [Route.arel_table[:path], Route.arel_table[:name], :description],
+ use_minimum_char_limit: use_minimum_char_limit)
else
- fuzzy_search(query, [:path, :name, :description])
+ fuzzy_search(query, [:path, :name, :description], use_minimum_char_limit: use_minimum_char_limit)
end
end
@@ -1205,8 +1254,8 @@ class Project < ApplicationRecord
@repository ||= Gitlab::GlRepository::PROJECT.repository_for(self)
end
- def design_management_repository
- super || create_design_management_repository
+ def find_or_create_design_management_repository
+ design_management_repository || create_design_management_repository
end
def design_repository
@@ -1676,7 +1725,13 @@ class Project < ApplicationRecord
end
def disabled_integrations
- %w[shimo zentao]
+ return [] if Rails.env.development?
+
+ names = %w[shimo zentao]
+
+ # The Slack Slash Commands integration is only available for customers who cannot use the GitLab for Slack app.
+ # The GitLab for Slack app integration is only available when enabled through settings.
+ names << (Gitlab::CurrentSettings.slack_app_enabled ? 'slack_slash_commands' : 'gitlab_slack_application')
end
def find_or_initialize_integration(name)
@@ -2871,7 +2926,13 @@ class Project < ApplicationRecord
def default_branch_protected?
branch_protection = Gitlab::Access::BranchProtection.new(self.namespace.default_branch_protection)
- branch_protection.fully_protected? || branch_protection.developer_can_merge?
+ branch_protection.fully_protected? || branch_protection.developer_can_merge? || branch_protection.developer_can_initial_push?
+ end
+
+ def initial_push_to_default_branch_allowed_for_developer?
+ branch_protection = Gitlab::Access::BranchProtection.new(self.namespace.default_branch_protection)
+
+ !branch_protection.any? || branch_protection.developer_can_push? || branch_protection.developer_can_initial_push?
end
def environments_for_scope(scope)