diff options
Diffstat (limited to 'app/models')
28 files changed, 239 insertions, 101 deletions
diff --git a/app/models/analytics/instance_statistics.rb b/app/models/analytics/instance_statistics.rb deleted file mode 100644 index df7b26e4fa6..00000000000 --- a/app/models/analytics/instance_statistics.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -module Analytics - module InstanceStatistics - def self.table_name_prefix - 'analytics_instance_statistics_' - end - end -end diff --git a/app/models/analytics/instance_statistics/measurement.rb b/app/models/analytics/usage_trends/measurement.rb index c8b76e005ef..40d7c7fae2e 100644 --- a/app/models/analytics/instance_statistics/measurement.rb +++ b/app/models/analytics/usage_trends/measurement.rb @@ -1,8 +1,10 @@ # frozen_string_literal: true module Analytics - module InstanceStatistics + module UsageTrends class Measurement < ApplicationRecord + self.table_name = 'analytics_instance_statistics_measurements' + EXPERIMENTAL_IDENTIFIERS = %i[pipelines_succeeded pipelines_failed pipelines_canceled pipelines_skipped].freeze enum identifier: { @@ -58,4 +60,4 @@ module Analytics end end -Analytics::InstanceStatistics::Measurement.prepend_if_ee('EE::Analytics::InstanceStatistics::Measurement') +Analytics::UsageTrends::Measurement.prepend_if_ee('EE::Analytics::UsageTrends::Measurement') diff --git a/app/models/bulk_imports/entity.rb b/app/models/bulk_imports/entity.rb index 16224fde502..ae1e3693809 100644 --- a/app/models/bulk_imports/entity.rb +++ b/app/models/bulk_imports/entity.rb @@ -37,8 +37,9 @@ class BulkImports::Entity < ApplicationRecord validates :project, absence: true, if: :group validates :group, absence: true, if: :project - validates :source_type, :source_full_path, :destination_name, - :destination_namespace, presence: true + validates :source_type, :source_full_path, :destination_name, presence: true + validates :destination_namespace, exclusion: [nil], if: :group + validates :destination_namespace, presence: true, if: :project validate :validate_parent_is_a_group, if: :parent validate :validate_imported_entity_type diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index db151126caf..d072bced639 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -564,7 +564,10 @@ module Ci end def features - { trace_sections: true } + { + trace_sections: true, + failure_reasons: self.class.failure_reasons.keys + } end def merge_request diff --git a/app/models/clusters/agent_token.rb b/app/models/clusters/agent_token.rb index b260822f784..8266f40133d 100644 --- a/app/models/clusters/agent_token.rb +++ b/app/models/clusters/agent_token.rb @@ -7,9 +7,11 @@ module Clusters self.table_name = 'cluster_agent_tokens' - belongs_to :agent, class_name: 'Clusters::Agent' + belongs_to :agent, class_name: 'Clusters::Agent', optional: false belongs_to :created_by_user, class_name: 'User', optional: true before_save :ensure_token + + validates :description, length: { maximum: 1024 } end end diff --git a/app/models/concerns/project_features_compatibility.rb b/app/models/concerns/project_features_compatibility.rb index 07bec07e556..a06bfdf5825 100644 --- a/app/models/concerns/project_features_compatibility.rb +++ b/app/models/concerns/project_features_compatibility.rb @@ -34,6 +34,10 @@ module ProjectFeaturesCompatibility write_feature_attribute_boolean(:snippets_access_level, value) end + def security_and_compliance_enabled=(value) + write_feature_attribute_boolean(:security_and_compliance_access_level, value) + end + def repository_access_level=(value) write_feature_attribute_string(:repository_access_level, value) end @@ -78,6 +82,10 @@ module ProjectFeaturesCompatibility write_feature_attribute_string(:operations_access_level, value) end + def security_and_compliance_access_level=(value) + write_feature_attribute_string(:security_and_compliance_access_level, value) + end + private def write_feature_attribute_boolean(field, value) diff --git a/app/models/custom_emoji.rb b/app/models/custom_emoji.rb index f4c914c6a3a..aea48a5ec20 100644 --- a/app/models/custom_emoji.rb +++ b/app/models/custom_emoji.rb @@ -6,6 +6,7 @@ class CustomEmoji < ApplicationRecord belongs_to :namespace, inverse_of: :custom_emoji belongs_to :group, -> { where(type: 'Group') }, foreign_key: 'namespace_id' + belongs_to :creator, class_name: "User", inverse_of: :created_custom_emoji # For now only external emoji are supported. See https://gitlab.com/gitlab-org/gitlab/-/issues/230467 validates :external, inclusion: { in: [true] } @@ -15,6 +16,7 @@ class CustomEmoji < ApplicationRecord validate :valid_emoji_name validates :group, presence: true + validates :creator, presence: true validates :name, uniqueness: { scope: [:namespace_id, :name] }, presence: true, diff --git a/app/models/group.rb b/app/models/group.rb index 1eaa4499eb5..afcf3fe69e6 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -34,6 +34,7 @@ class Group < Namespace has_many :milestones has_many :iterations + has_many :iterations_cadences, class_name: 'Iterations::Cadence' has_many :services has_many :shared_group_links, foreign_key: :shared_with_group_id, class_name: 'GroupGroupLink' has_many :shared_with_group_links, foreign_key: :shared_group_id, class_name: 'GroupGroupLink' @@ -364,13 +365,28 @@ class Group < Namespace # rubocop: enable CodeReuse/ServiceClass # rubocop: disable CodeReuse/ServiceClass - def refresh_members_authorized_projects(blocking: true, priority: UserProjectAccessChangedService::HIGH_PRIORITY) + def refresh_members_authorized_projects( + blocking: true, + priority: UserProjectAccessChangedService::HIGH_PRIORITY, + direct_members_only: false + ) + + user_ids = if direct_members_only + users_ids_of_direct_members + else + user_ids_for_project_authorizations + end + UserProjectAccessChangedService - .new(user_ids_for_project_authorizations) + .new(user_ids) .execute(blocking: blocking, priority: priority) end # rubocop: enable CodeReuse/ServiceClass + def users_ids_of_direct_members + direct_members.pluck(:user_id) + end + def user_ids_for_project_authorizations members_with_parents.pluck(:user_id) end @@ -381,6 +397,12 @@ class Group < Namespace end end + def direct_members + GroupMember.active_without_invites_and_requests + .non_minimal_access + .where(source_id: id) + end + def members_with_parents # Avoids an unnecessary SELECT when the group has no parents source_ids = diff --git a/app/models/iteration.rb b/app/models/iteration.rb index 7a35bb1cd1f..012a062712f 100644 --- a/app/models/iteration.rb +++ b/app/models/iteration.rb @@ -16,6 +16,7 @@ class Iteration < ApplicationRecord belongs_to :project belongs_to :group + belongs_to :iterations_cadence, class_name: 'Iterations::Cadence', foreign_key: :iterations_cadence_id, inverse_of: :iterations has_internal_id :iid, scope: :project has_internal_id :iid, scope: :group @@ -26,6 +27,9 @@ class Iteration < ApplicationRecord validate :dates_do_not_overlap, if: :start_or_due_dates_changed? validate :future_date, if: :start_or_due_dates_changed?, unless: :skip_future_date_validation validate :no_project, unless: :skip_project_validation + validate :validate_group + + before_create :set_iterations_cadence scope :upcoming, -> { with_state(:upcoming) } scope :started, -> { with_state(:started) } @@ -135,6 +139,30 @@ class Iteration < ApplicationRecord errors.add(:project_id, s_("is not allowed. We do not currently support project-level iterations")) end + + # TODO: this method should be removed as part of https://gitlab.com/gitlab-org/gitlab/-/issues/296099 + def set_iterations_cadence + return if iterations_cadence + # For now we support only group iterations + # issue to clarify project iterations: https://gitlab.com/gitlab-org/gitlab/-/issues/299864 + return unless group + + self.iterations_cadence = group.iterations_cadences.first || create_default_cadence + end + + def create_default_cadence + cadence_title = "#{group.name} Iterations" + + Iterations::Cadence.create!(group: group, title: cadence_title, start_date: start_date) + end + + # TODO: remove this as part of https://gitlab.com/gitlab-org/gitlab/-/issues/296100 + def validate_group + return unless iterations_cadence + return if iterations_cadence.group_id == group_id + + errors.add(:group, s_('is not valid. The iteration group has to match the iteration cadence group.')) + end end Iteration.prepend_if_ee('EE::Iteration') diff --git a/app/models/iterations/cadence.rb b/app/models/iterations/cadence.rb new file mode 100644 index 00000000000..4f8e148d18f --- /dev/null +++ b/app/models/iterations/cadence.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class Iterations::Cadence < ApplicationRecord + self.table_name = 'iterations_cadences' + + belongs_to :group + has_many :iterations, foreign_key: :iterations_cadence_id, inverse_of: :iterations_cadence + + validates :title, presence: true + validates :start_date, presence: true + validates :group_id, presence: true + validates :active, presence: true + validates :automatic, presence: true +end diff --git a/app/models/list.rb b/app/models/list.rb index 49834af3dfb..5bd00a1d7ef 100644 --- a/app/models/list.rb +++ b/app/models/list.rb @@ -14,6 +14,7 @@ class List < ApplicationRecord validates :label_id, uniqueness: { scope: :board_id }, if: :label? scope :preload_associated_models, -> { preload(:board, label: :priorities) } + scope :without_types, ->(list_types) { where.not(list_type: list_types) } alias_method :preferences, :list_user_preferences diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 1374e8a814a..8d558098d94 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -317,6 +317,8 @@ class MergeRequest < ApplicationRecord scope :preload_author, -> { preload(:author) } scope :preload_approved_by_users, -> { preload(:approved_by_users) } scope :preload_metrics, -> (relation) { preload(metrics: relation) } + scope :preload_project_and_latest_diff, -> { preload(:source_project, :latest_merge_request_diff) } + scope :preload_latest_diff_comment, -> { preload(latest_merge_request_diff: :merge_request_diff_commits) } scope :with_web_entity_associations, -> { preload(:author, :target_project) } scope :with_auto_merge_enabled, -> do @@ -374,8 +376,7 @@ class MergeRequest < ApplicationRecord alias_attribute :auto_merge_enabled, :merge_when_pipeline_succeeds alias_method :issuing_parent, :target_project - delegate :active?, :builds_with_coverage, to: :head_pipeline, prefix: true, allow_nil: true - delegate :success?, :active?, to: :actual_head_pipeline, prefix: true, allow_nil: true + delegate :builds_with_coverage, to: :head_pipeline, prefix: true, allow_nil: true RebaseLockTimeout = Class.new(StandardError) @@ -435,6 +436,18 @@ class MergeRequest < ApplicationRecord target_project.latest_pipeline(target_branch, sha) end + def head_pipeline_active? + !!head_pipeline&.active? + end + + def actual_head_pipeline_active? + !!actual_head_pipeline&.active? + end + + def actual_head_pipeline_success? + !!actual_head_pipeline&.success? + end + # Pattern used to extract `!123` merge request references from text # # This pattern supports cross-project references. diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 3342fb1fce9..21e8a6fec74 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -164,6 +164,10 @@ class Namespace < ApplicationRecord name = host.delete_suffix(gitlab_host) Namespace.where(parent_id: nil).by_path(name) end + + def top_most + where(parent_id: nil) + end end def package_settings @@ -400,6 +404,10 @@ class Namespace < ApplicationRecord !has_parent? end + def recent? + created_at >= 90.days.ago + end + private def all_projects_with_pages diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb index 82e39e4f207..72813b17501 100644 --- a/app/models/notification_setting.rb +++ b/app/models/notification_setting.rb @@ -49,7 +49,8 @@ class NotificationSetting < ApplicationRecord :failed_pipeline, :fixed_pipeline, :success_pipeline, - :moved_project + :moved_project, + :merge_when_pipeline_succeeds ].freeze def self.email_events(source = nil) diff --git a/app/models/packages/nuget.rb b/app/models/packages/nuget.rb index 42c167e9b7f..f152eedb8fc 100644 --- a/app/models/packages/nuget.rb +++ b/app/models/packages/nuget.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true module Packages module Nuget + TEMPORARY_PACKAGE_NAME = 'NuGet.Temporary.Package' + def self.table_name_prefix 'packages_nuget_' end diff --git a/app/models/packages/package.rb b/app/models/packages/package.rb index 391540634be..b0e7ff09982 100644 --- a/app/models/packages/package.rb +++ b/app/models/packages/package.rb @@ -40,11 +40,11 @@ class Packages::Package < ApplicationRecord validate :unique_debian_package_name, if: :debian_package? validate :valid_conan_package_recipe, if: :conan? - validate :valid_npm_package_name, if: :npm? validate :valid_composer_global_name, if: :composer? validate :package_already_taken, if: :npm? validates :name, format: { with: Gitlab::Regex.conan_recipe_component_regex }, if: :conan? validates :name, format: { with: Gitlab::Regex.generic_package_name_regex }, if: :generic? + validates :name, format: { with: Gitlab::Regex.npm_package_name_regex }, if: :npm? validates :name, format: { with: Gitlab::Regex.nuget_package_name_regex }, if: :nuget? validates :name, format: { with: Gitlab::Regex.debian_package_name_regex }, if: :debian_package? validates :name, inclusion: { in: %w[incoming] }, if: :debian_incoming? @@ -98,12 +98,12 @@ class Packages::Package < ApplicationRecord end scope :preload_composer, -> { preload(:composer_metadatum) } - scope :without_nuget_temporary_name, -> { where.not(name: Packages::Nuget::CreatePackageService::TEMPORARY_PACKAGE_NAME) } + scope :without_nuget_temporary_name, -> { where.not(name: Packages::Nuget::TEMPORARY_PACKAGE_NAME) } scope :has_version, -> { where.not(version: nil) } scope :processed, -> do where.not(package_type: :nuget).or( - where.not(name: Packages::Nuget::CreatePackageService::TEMPORARY_PACKAGE_NAME) + where.not(name: Packages::Nuget::TEMPORARY_PACKAGE_NAME) ) end scope :preload_files, -> { preload(:package_files) } @@ -247,14 +247,6 @@ class Packages::Package < ApplicationRecord end end - def valid_npm_package_name - return unless project&.root_namespace - - unless name =~ %r{\A@#{project.root_namespace.path}/[^/]+\z} - errors.add(:name, 'is not valid') - end - end - def package_already_taken return unless project diff --git a/app/models/packages/rubygems.rb b/app/models/packages/rubygems.rb new file mode 100644 index 00000000000..1aa6b16f47e --- /dev/null +++ b/app/models/packages/rubygems.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true +module Packages + module Rubygems + TEMPORARY_PACKAGE_NAME = 'Gem.Temporary.Package' + + def self.table_name_prefix + 'packages_rubygems_' + end + end +end diff --git a/app/models/packages/rubygems/metadatum.rb b/app/models/packages/rubygems/metadatum.rb index 42db1f3defc..d4e5feb7c98 100644 --- a/app/models/packages/rubygems/metadatum.rb +++ b/app/models/packages/rubygems/metadatum.rb @@ -3,7 +3,6 @@ module Packages module Rubygems class Metadatum < ApplicationRecord - self.table_name = 'packages_rubygems_metadata' self.primary_key = :package_id belongs_to :package, -> { where(package_type: :rubygems) }, inverse_of: :rubygems_metadatum diff --git a/app/models/pages/lookup_path.rb b/app/models/pages/lookup_path.rb index c6781f8f6e3..46c347e5cf5 100644 --- a/app/models/pages/lookup_path.rb +++ b/app/models/pages/lookup_path.rb @@ -52,7 +52,7 @@ module Pages def zip_source return unless deployment&.file - return if deployment.file.file_storage? && !Feature.enabled?(:pages_serve_with_zip_file_protocol, project) + return if deployment.file.file_storage? && !Feature.enabled?(:pages_serve_with_zip_file_protocol, project, default_enabled: true) return if deployment.migrated? && !Feature.enabled?(:pages_serve_from_migrated_zip, project) diff --git a/app/models/project.rb b/app/models/project.rb index 2b9b7dcf733..08e3203a81e 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -392,7 +392,8 @@ class Project < ApplicationRecord :merge_requests_access_level, :forking_access_level, :issues_access_level, :wiki_access_level, :snippets_access_level, :builds_access_level, :repository_access_level, :pages_access_level, :metrics_dashboard_access_level, :analytics_access_level, - :operations_enabled?, :operations_access_level, to: :project_feature, allow_nil: true + :operations_enabled?, :operations_access_level, :security_and_compliance_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 @@ -2532,6 +2533,10 @@ class Project < ApplicationRecord Projects::GitGarbageCollectWorker end + def inherited_issuable_templates_enabled? + Feature.enabled?(:inherited_issuable_templates, self, default_enabled: :yaml) + end + private def find_service(services, name) diff --git a/app/models/project_feature.rb b/app/models/project_feature.rb index 7b204cfb1c0..3f86a1ce979 100644 --- a/app/models/project_feature.rb +++ b/app/models/project_feature.rb @@ -3,7 +3,8 @@ class ProjectFeature < ApplicationRecord include Featurable - FEATURES = %i(issues forking merge_requests wiki snippets builds repository pages metrics_dashboard analytics operations).freeze + FEATURES = %i(issues forking merge_requests wiki snippets builds repository pages metrics_dashboard analytics operations security_and_compliance).freeze + EXPORTABLE_FEATURES = (FEATURES - [:security_and_compliance]).freeze set_available_features(FEATURES) @@ -37,16 +38,17 @@ class ProjectFeature < ApplicationRecord validate :repository_children_level validate :allowed_access_levels - default_value_for :builds_access_level, value: ENABLED, allows_nil: false - default_value_for :issues_access_level, value: ENABLED, allows_nil: false - default_value_for :forking_access_level, value: ENABLED, allows_nil: false - default_value_for :merge_requests_access_level, value: ENABLED, allows_nil: false - default_value_for :snippets_access_level, value: ENABLED, allows_nil: false - default_value_for :wiki_access_level, value: ENABLED, allows_nil: false - default_value_for :repository_access_level, value: ENABLED, allows_nil: false - default_value_for :analytics_access_level, value: ENABLED, allows_nil: false + default_value_for :builds_access_level, value: ENABLED, allows_nil: false + default_value_for :issues_access_level, value: ENABLED, allows_nil: false + default_value_for :forking_access_level, value: ENABLED, allows_nil: false + default_value_for :merge_requests_access_level, value: ENABLED, allows_nil: false + default_value_for :snippets_access_level, value: ENABLED, allows_nil: false + default_value_for :wiki_access_level, value: ENABLED, allows_nil: false + default_value_for :repository_access_level, value: ENABLED, allows_nil: false + default_value_for :analytics_access_level, value: ENABLED, allows_nil: false default_value_for :metrics_dashboard_access_level, value: PRIVATE, allows_nil: false - default_value_for :operations_access_level, value: ENABLED, allows_nil: false + default_value_for :operations_access_level, value: ENABLED, allows_nil: false + default_value_for :security_and_compliance_access_level, value: PRIVATE, allows_nil: false default_value_for(:pages_access_level, allows_nil: false) do |feature| if ::Gitlab::Pages.access_control_is_forced? diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index 5857d86f921..12f7bac23e4 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -124,15 +124,11 @@ class JiraService < IssueTrackerService end def fields - transition_id_help_path = help_page_path('user/project/integrations/jira', anchor: 'obtaining-a-transition-id') - transition_id_help_link_start = '<a href="%{transition_id_help_path}" target="_blank" rel="noopener noreferrer">'.html_safe % { transition_id_help_path: transition_id_help_path } - [ { type: 'text', name: 'url', title: s_('JiraService|Web URL'), placeholder: 'https://jira.example.com', required: true }, { type: 'text', name: 'api_url', title: s_('JiraService|Jira API URL'), placeholder: s_('JiraService|If different from Web URL') }, { type: 'text', name: 'username', title: s_('JiraService|Username or Email'), placeholder: s_('JiraService|Use a username for server version and an email for cloud version'), required: true }, - { type: 'password', name: 'password', title: s_('JiraService|Password or API token'), placeholder: s_('JiraService|Use a password for server version and an API token for cloud version'), required: true }, - { type: 'text', name: 'jira_issue_transition_id', title: s_('JiraService|Jira workflow transition IDs'), placeholder: s_('JiraService|For example, 12, 24'), help: s_('JiraService|Set transition IDs for Jira workflow transitions. %{link_start}Learn more%{link_end}'.html_safe % { link_start: transition_id_help_link_start, link_end: '</a>'.html_safe }) } + { type: 'password', name: 'password', title: s_('JiraService|Password or API token'), placeholder: s_('JiraService|Use a password for server version and an API token for cloud version'), required: true } ] end @@ -159,17 +155,19 @@ class JiraService < IssueTrackerService # support any events. end - def find_issue(issue_key, rendered_fields: false) - options = {} - options = options.merge(expand: 'renderedFields') if rendered_fields + def find_issue(issue_key, rendered_fields: false, transitions: false) + expands = [] + expands << 'renderedFields' if rendered_fields + expands << 'transitions' if transitions + options = { expand: expands.join(',') } if expands.any? - jira_request { client.Issue.find(issue_key, options) } + jira_request { client.Issue.find(issue_key, options || {}) } end def close_issue(entity, external_issue, current_user) - issue = find_issue(external_issue.iid) + issue = find_issue(external_issue.iid, transitions: automatic_issue_transitions?) - return if issue.nil? || has_resolution?(issue) || !jira_issue_transition_id.present? + return if issue.nil? || has_resolution?(issue) commit_id = case entity when Commit then entity.id @@ -260,24 +258,52 @@ class JiraService < IssueTrackerService end end + def automatic_issue_transitions? + jira_issue_transition_id.blank? + end + # jira_issue_transition_id can have multiple values split by , or ; # the issue is transitioned at the order given by the user # if any transition fails it will log the error message and stop the transition sequence def transition_issue(issue) - jira_issue_transition_id.scan(Gitlab::Regex.jira_transition_id_regex).each do |transition_id| - issue.transitions.build.save!(transition: { id: transition_id }) - rescue => error - log_error( - "Issue transition failed", - error: { - exception_class: error.class.name, - exception_message: error.message, - exception_backtrace: Gitlab::BacktraceCleaner.clean_backtrace(error.backtrace) - }, - client_url: client_url - ) - return false + return transition_issue_to_done(issue) if automatic_issue_transitions? + + jira_issue_transition_id.scan(Gitlab::Regex.jira_transition_id_regex).all? do |transition_id| + transition_issue_to_id(issue, transition_id) + end + end + + def transition_issue_to_id(issue, transition_id) + issue.transitions.build.save!( + transition: { id: transition_id } + ) + + true + rescue => error + log_error( + "Issue transition failed", + error: { + exception_class: error.class.name, + exception_message: error.message, + exception_backtrace: Gitlab::BacktraceCleaner.clean_backtrace(error.backtrace) + }, + client_url: client_url + ) + + false + end + + def transition_issue_to_done(issue) + transitions = issue.transitions rescue [] + + transition = transitions.find do |transition| + status = transition&.to&.statusCategory + status && status['key'] == 'done' end + + return false unless transition + + transition_issue_to_id(issue, transition.id) end def log_usage(action, user) diff --git a/app/models/project_services/mattermost_service.rb b/app/models/project_services/mattermost_service.rb index c1055db78e5..9cff979fcf2 100644 --- a/app/models/project_services/mattermost_service.rb +++ b/app/models/project_services/mattermost_service.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class MattermostService < ChatNotificationService - include ::SlackService::Notifier + include SlackMattermost::Notifier def title 'Mattermost notifications' diff --git a/app/models/project_services/slack_mattermost/notifier.rb b/app/models/project_services/slack_mattermost/notifier.rb new file mode 100644 index 00000000000..1a78cea5933 --- /dev/null +++ b/app/models/project_services/slack_mattermost/notifier.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module SlackMattermost + module Notifier + private + + def notify(message, opts) + # See https://gitlab.com/gitlab-org/slack-notifier/#custom-http-client + notifier = Slack::Messenger.new(webhook, opts.merge(http_client: HTTPClient)) + notifier.ping( + message.pretext, + attachments: message.attachments, + fallback: message.fallback + ) + end + + class HTTPClient + def self.post(uri, params = {}) + params.delete(:http_options) # these are internal to the client and we do not want them + Gitlab::HTTP.post(uri, body: params) + end + end + end +end diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb index 79245e84238..abe799bdff5 100644 --- a/app/models/project_services/slack_service.rb +++ b/app/models/project_services/slack_service.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class SlackService < ChatNotificationService + include SlackMattermost::Notifier + prop_accessor EVENT_CHANNEL['alert'] def title @@ -35,27 +37,4 @@ class SlackService < ChatNotificationService super end - - module Notifier - private - - def notify(message, opts) - # See https://gitlab.com/gitlab-org/slack-notifier/#custom-http-client - notifier = Slack::Messenger.new(webhook, opts.merge(http_client: HTTPClient)) - notifier.ping( - message.pretext, - attachments: message.attachments, - fallback: message.fallback - ) - end - - class HTTPClient - def self.post(uri, params = {}) - params.delete(:http_options) # these are internal to the client and we do not want them - Gitlab::HTTP.post(uri, body: params) - end - end - end - - include Notifier end diff --git a/app/models/repository.rb b/app/models/repository.rb index 06a13194e1a..84ca8f0c12a 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -43,7 +43,7 @@ class Repository changelog license_blob license_key gitignore gitlab_ci_yml branch_names tag_names branch_count tag_count avatar exists? root_ref merged_branch_names - has_visible_content? issue_template_names_by_category merge_request_template_names_by_category + has_visible_content? issue_template_names_hash merge_request_template_names_hash user_defined_metrics_dashboard_paths xcode_project? has_ambiguous_refs?).freeze # Methods that use cache_method but only memoize the value @@ -60,8 +60,8 @@ class Repository gitignore: :gitignore, gitlab_ci: :gitlab_ci_yml, avatar: :avatar, - issue_template: :issue_template_names_by_category, - merge_request_template: :merge_request_template_names_by_category, + issue_template: :issue_template_names_hash, + merge_request_template: :merge_request_template_names_hash, metrics_dashboard: :user_defined_metrics_dashboard_paths, xcode_config: :xcode_project? }.freeze @@ -573,15 +573,15 @@ class Repository cache_method :avatar # store issue_template_names as hash - def issue_template_names_by_category + def issue_template_names_hash Gitlab::Template::IssueTemplate.repository_template_names(project) end - cache_method :issue_template_names_by_category, fallback: {} + cache_method :issue_template_names_hash, fallback: {} - def merge_request_template_names_by_category + def merge_request_template_names_hash Gitlab::Template::MergeRequestTemplate.repository_template_names(project) end - cache_method :merge_request_template_names_by_category, fallback: {} + cache_method :merge_request_template_names_hash, fallback: {} def user_defined_metrics_dashboard_paths Gitlab::Metrics::Dashboard::RepoDashboardFinder.list_dashboards(project) diff --git a/app/models/snippet.rb b/app/models/snippet.rb index ab8782ed87f..b68e166af48 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -216,8 +216,10 @@ class Snippet < ApplicationRecord def blobs return [] unless repository_exists? - branch = default_branch - list_files(branch).map { |file| Blob.lazy(repository, branch, file) } + files = list_files(default_branch) + items = files.map { |file| [default_branch, file] } + + repository.blobs_at(items).compact end def hook_attrs diff --git a/app/models/user.rb b/app/models/user.rb index 1f8b680c7e5..d91fc3ebce4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -179,6 +179,7 @@ class User < ApplicationRecord has_many :merge_request_reviewers, inverse_of: :reviewer has_many :assigned_issues, class_name: "Issue", through: :issue_assignees, source: :issue has_many :assigned_merge_requests, class_name: "MergeRequest", through: :merge_request_assignees, source: :merge_request + has_many :created_custom_emoji, class_name: 'CustomEmoji', inverse_of: :creator has_many :bulk_imports |