diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-07-31 15:07:02 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-07-31 15:07:02 +0300 |
commit | 74ecf758e30be848144df1672b5080a29fafbc0a (patch) | |
tree | 0bc719293526a2384b9db6638d42d49f1f5c9c9c /app | |
parent | 26d2324ac136c7a28235789ff9a0b2974b5f7c7b (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r-- | app/controllers/projects/blob_controller.rb | 26 | ||||
-rw-r--r-- | app/controllers/projects/performance_monitoring/dashboards_controller.rb | 114 | ||||
-rw-r--r-- | app/controllers/search_controller.rb | 2 | ||||
-rw-r--r-- | app/helpers/environments_helper.rb | 1 | ||||
-rw-r--r-- | app/models/concerns/issuable_link.rb | 2 | ||||
-rw-r--r-- | app/models/concerns/linkable_item.rb | 40 | ||||
-rw-r--r-- | app/models/issue.rb | 24 | ||||
-rw-r--r-- | app/models/issue_link.rb | 9 | ||||
-rw-r--r-- | app/models/work_items/parent_link.rb | 11 | ||||
-rw-r--r-- | app/models/work_items/related_work_item_link.rb | 21 | ||||
-rw-r--r-- | app/services/issues/move_service.rb | 4 | ||||
-rw-r--r-- | app/services/metrics/dashboard/clone_dashboard_service.rb | 170 | ||||
-rw-r--r-- | app/services/metrics/dashboard/dynamic_embed_service.rb | 78 | ||||
-rw-r--r-- | app/services/projects/prometheus/alerts/notify_service.rb | 41 | ||||
-rw-r--r-- | app/services/search_service.rb | 4 |
15 files changed, 94 insertions, 453 deletions
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index 388135726a0..56e4b22ded2 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -274,8 +274,6 @@ class Projects::BlobController < Projects::ApplicationController @last_commit = @repository.last_commit_for_path(@commit.id, @blob.path, literal_pathspec: true) @code_navigation_path = Gitlab::CodeNavigationPath.new(@project, @blob.commit_id).full_json_path_for(@blob.path) - allow_lfs_direct_download - render 'show' end @@ -320,30 +318,6 @@ class Projects::BlobController < Projects::ApplicationController current_user&.id end - def allow_lfs_direct_download - return unless directly_downloading_lfs_object? && content_security_policy_enabled? - return unless (lfs_object = @project.lfs_objects.find_by_oid(@blob.lfs_oid)) - - request.content_security_policy.directives['connect-src'] ||= [] - request.content_security_policy.directives['connect-src'] << lfs_src(lfs_object) - end - - def directly_downloading_lfs_object? - Gitlab.config.lfs.enabled && - !Gitlab.config.lfs.object_store.proxy_download && - @blob&.stored_externally? - end - - def content_security_policy_enabled? - Gitlab.config.gitlab.content_security_policy.enabled - end - - def lfs_src(lfs_object) - file = lfs_object.file - file = file.cdn_enabled_url(request.remote_ip) if file.respond_to?(:cdn_enabled_url) - file.url - end - alias_method :tracking_project_source, :project def tracking_namespace_source diff --git a/app/controllers/projects/performance_monitoring/dashboards_controller.rb b/app/controllers/projects/performance_monitoring/dashboards_controller.rb deleted file mode 100644 index 1255ec1dde2..00000000000 --- a/app/controllers/projects/performance_monitoring/dashboards_controller.rb +++ /dev/null @@ -1,114 +0,0 @@ -# frozen_string_literal: true - -module Projects - module PerformanceMonitoring - class DashboardsController < ::Projects::ApplicationController - include BlobHelper - - before_action :check_repository_available! - before_action :validate_required_params! - - rescue_from ActionController::ParameterMissing do |exception| - respond_error(http_status: :bad_request, message: _('Request parameter %{param} is missing.') % { param: exception.param }) - end - - feature_category :metrics - urgency :low - - def create - return not_found if Feature.enabled?(:remove_monitor_metrics) - - result = ::Metrics::Dashboard::CloneDashboardService.new(project, current_user, dashboard_params).execute - - if result[:status] == :success - respond_success(result) - else - respond_error(result) - end - end - - def update - return not_found if Feature.enabled?(:remove_monitor_metrics) - - result = ::Metrics::Dashboard::UpdateDashboardService.new(project, current_user, dashboard_params.merge(file_content_params)).execute - - if result[:status] == :success - respond_update_success(result) - else - respond_error(result) - end - end - - private - - def respond_success(result) - set_web_ide_link_notice(result.dig(:dashboard, :path)) - respond_to do |format| - format.json { render status: result.delete(:http_status), json: result } - end - end - - def respond_error(result) - respond_to do |format| - format.json { render json: { error: result[:message] }, status: result[:http_status] } - end - end - - def set_web_ide_link_notice(new_dashboard_path) - web_ide_link_start = "<a href=\"#{ide_edit_path(project, redirect_safe_branch_name, new_dashboard_path)}\">" - message = _("Your dashboard has been copied. You can %{web_ide_link_start}edit it here%{web_ide_link_end}.") % { web_ide_link_start: web_ide_link_start, web_ide_link_end: "</a>" } - flash[:notice] = message.html_safe - end - - def respond_update_success(result) - set_web_ide_link_update_notice(result.dig(:dashboard, :path)) - respond_to do |format| - format.json { render status: result.delete(:http_status), json: result } - end - end - - def set_web_ide_link_update_notice(new_dashboard_path) - web_ide_link_start = "<a href=\"#{ide_edit_path(project, redirect_safe_branch_name, new_dashboard_path)}\">" - message = _("Your dashboard has been updated. You can %{web_ide_link_start}edit it here%{web_ide_link_end}.") % { web_ide_link_start: web_ide_link_start, web_ide_link_end: "</a>" } - flash[:notice] = message.html_safe - end - - def validate_required_params! - params.require(%i[branch file_name dashboard commit_message]) - end - - def redirect_safe_branch_name - repository.find_branch(params[:branch]).name - end - - def dashboard_params - params.permit(%i[branch file_name dashboard commit_message]).to_h - end - - def file_content_params - params.permit( - file_content: [ - :dashboard, - panel_groups: [ - :group, - :priority, - panels: [ - :type, - :title, - :y_label, - :weight, - metrics: [ - :id, - :unit, - :label, - :query, - :query_range - ] - ] - ] - ] - ) - end - end - end -end diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 2d6b51a49fc..af62ff8313d 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -252,7 +252,7 @@ class SearchController < ApplicationController end def search_type - 'basic' + search_service.search_type end end diff --git a/app/helpers/environments_helper.rb b/app/helpers/environments_helper.rb index 219dcf29563..cd768ba8a7b 100644 --- a/app/helpers/environments_helper.rb +++ b/app/helpers/environments_helper.rb @@ -54,7 +54,6 @@ module EnvironmentsHelper { 'settings_path' => edit_project_settings_integration_path(project, 'prometheus'), 'clusters_path' => project_clusters_path(project), - 'dashboards_endpoint' => project_performance_monitoring_dashboards_path(project, format: :json), 'default_branch' => project.default_branch, 'project_path' => project_path(project), 'tags_path' => project_tags_path(project), diff --git a/app/models/concerns/issuable_link.rb b/app/models/concerns/issuable_link.rb index 7f29083d6c6..5cb5f410a77 100644 --- a/app/models/concerns/issuable_link.rb +++ b/app/models/concerns/issuable_link.rb @@ -53,7 +53,7 @@ module IssuableLink return unless source && target if self.class.base_class.find_by(source: target, target: source) - errors.add(:source, "is already related to this #{self.class.issuable_type}") + errors.add(:source, "is already related to this #{self.class.issuable_type.to_s.humanize(capitalize: false)}") end end end diff --git a/app/models/concerns/linkable_item.rb b/app/models/concerns/linkable_item.rb new file mode 100644 index 00000000000..ce45549aca0 --- /dev/null +++ b/app/models/concerns/linkable_item.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +# == LinkableItem concern +# +# Contains common functionality shared between related issue links and related work item links +# +# Used by IssueLink, WorkItems::RelatedWorkItemLink +# +module LinkableItem + extend ActiveSupport::Concern + include FromUnion + include IssuableLink + + included do + validate :check_existing_parent_link + + scope :for_source, ->(item) { where(source_id: item.id) } + scope :for_target, ->(item) { where(target_id: item.id) } + scope :for_items, ->(source, target) do + where(source: source, target: target).or(where(source: target, target: source)) + end + + private + + def check_existing_parent_link + return unless source && target + + existing_relation = WorkItems::ParentLink.for_parents([source, target]).for_children([source, target]) + return if existing_relation.none? + + errors.add( + :source, + format( + _('is a parent or child of this %{item}'), + item: self.class.issuable_type.to_s.humanize(capitalize: false) + ) + ) + end + end +end diff --git a/app/models/issue.rb b/app/models/issue.rb index 6e48dcab9ed..2b280f62ee6 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -542,18 +542,18 @@ class Issue < ApplicationRecord end def related_issues(current_user, preload: nil) - related_issues = ::Issue - .select(['issues.*', 'issue_links.id AS issue_link_id', - 'issue_links.link_type as issue_link_type_value', - 'issue_links.target_id as issue_link_source_id', - 'issue_links.created_at as issue_link_created_at', - 'issue_links.updated_at as issue_link_updated_at']) - .joins("INNER JOIN issue_links ON - (issue_links.source_id = issues.id AND issue_links.target_id = #{id}) - OR - (issue_links.target_id = issues.id AND issue_links.source_id = #{id})") - .preload(preload) - .reorder('issue_link_id') + related_issues = self.class + .select(['issues.*', 'issue_links.id AS issue_link_id', + 'issue_links.link_type as issue_link_type_value', + 'issue_links.target_id as issue_link_source_id', + 'issue_links.created_at as issue_link_created_at', + 'issue_links.updated_at as issue_link_updated_at']) + .joins("INNER JOIN issue_links ON + (issue_links.source_id = issues.id AND issue_links.target_id = #{id}) + OR + (issue_links.target_id = issues.id AND issue_links.source_id = #{id})") + .preload(preload) + .reorder('issue_link_id') related_issues = yield related_issues if block_given? diff --git a/app/models/issue_link.rb b/app/models/issue_link.rb index af55a5dec91..1c596ad0341 100644 --- a/app/models/issue_link.rb +++ b/app/models/issue_link.rb @@ -1,18 +1,11 @@ # frozen_string_literal: true class IssueLink < ApplicationRecord - include FromUnion - include IssuableLink + include LinkableItem belongs_to :source, class_name: 'Issue' belongs_to :target, class_name: 'Issue' - scope :for_source_issue, ->(issue) { where(source_id: issue.id) } - scope :for_target_issue, ->(issue) { where(target_id: issue.id) } - scope :for_issues, ->(source, target) do - where(source: source, target: target).or(where(source: target, target: source)) - end - class << self def issuable_type :issue diff --git a/app/models/work_items/parent_link.rb b/app/models/work_items/parent_link.rb index 5dff9e8e8d5..d9e3690b6fc 100644 --- a/app/models/work_items/parent_link.rb +++ b/app/models/work_items/parent_link.rb @@ -19,8 +19,10 @@ module WorkItems validate :validate_same_project validate :validate_max_children validate :validate_confidentiality + validate :check_existing_related_link scope :for_parents, ->(parent_ids) { where(work_item_parent_id: parent_ids) } + scope :for_children, ->(children_ids) { where(work_item: children_ids) } class << self def has_public_children?(parent_id) @@ -109,5 +111,14 @@ module WorkItems errors.add :work_item, _('is already present in ancestors') end end + + def check_existing_related_link + return unless work_item && work_item_parent + + existing_link = WorkItems::RelatedWorkItemLink.for_items(work_item, work_item_parent) + return if existing_link.none? + + errors.add(:work_item, _('cannot assign a linked work item as a parent')) + end end end diff --git a/app/models/work_items/related_work_item_link.rb b/app/models/work_items/related_work_item_link.rb new file mode 100644 index 00000000000..1da776fa3bd --- /dev/null +++ b/app/models/work_items/related_work_item_link.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module WorkItems + class RelatedWorkItemLink < ApplicationRecord + include LinkableItem + + self.table_name = 'issue_links' + + belongs_to :source, class_name: 'WorkItem' + belongs_to :target, class_name: 'WorkItem' + + class << self + extend ::Gitlab::Utils::Override + + override :issuable_type + def issuable_type + :work_item + end + end + end +end diff --git a/app/services/issues/move_service.rb b/app/services/issues/move_service.rb index c1599ceef6e..e26e3d0835b 100644 --- a/app/services/issues/move_service.rb +++ b/app/services/issues/move_service.rb @@ -123,10 +123,10 @@ module Issues end def rewrite_related_issues - source_issue_links = IssueLink.for_source_issue(original_entity) + source_issue_links = IssueLink.for_source(original_entity) source_issue_links.update_all(source_id: new_entity.id) - target_issue_links = IssueLink.for_target_issue(original_entity) + target_issue_links = IssueLink.for_target(original_entity) target_issue_links.update_all(target_id: new_entity.id) end diff --git a/app/services/metrics/dashboard/clone_dashboard_service.rb b/app/services/metrics/dashboard/clone_dashboard_service.rb deleted file mode 100644 index b5b46b1280b..00000000000 --- a/app/services/metrics/dashboard/clone_dashboard_service.rb +++ /dev/null @@ -1,170 +0,0 @@ -# frozen_string_literal: true - -# Copies system dashboard definition in .yml file into designated -# .yml file inside `.gitlab/dashboards` -module Metrics - module Dashboard - class CloneDashboardService < ::BaseService - include Stepable - include Gitlab::Utils::StrongMemoize - - ALLOWED_FILE_TYPE = '.yml' - USER_DASHBOARDS_DIR = ::Gitlab::Metrics::Dashboard::RepoDashboardFinder::DASHBOARD_ROOT - SEQUENCES = { - ::Metrics::Dashboard::SystemDashboardService::DASHBOARD_PATH => [ - ::Gitlab::Metrics::Dashboard::Stages::CommonMetricsInserter, - ::Gitlab::Metrics::Dashboard::Stages::CustomMetricsInserter - ].freeze - }.freeze - - steps :check_push_authorized, - :check_branch_name, - :check_file_type, - :check_dashboard_template, - :create_file, - :refresh_repository_method_caches - - def execute - execute_steps - end - - private - - def check_push_authorized(result) - return error(_('You are not allowed to push into this branch. Create another branch or open a merge request.'), :forbidden) unless push_authorized? - - success(result) - end - - def check_branch_name(result) - return error(_('There was an error creating the dashboard, branch name is invalid.'), :bad_request) unless valid_branch_name? - return error(_('There was an error creating the dashboard, branch named: %{branch} already exists.') % { branch: params[:branch] }, :bad_request) unless new_or_default_branch? - - success(result) - end - - def check_file_type(result) - return error(_('The file name should have a .yml extension'), :bad_request) unless target_file_type_valid? - - success(result) - end - - # Only allow out of the box metrics dashboards to be cloned. This can be - # changed to allow cloning of any metrics dashboard, if desired. - # However, only metrics dashboards should be allowed. If any file is - # allowed to be cloned, this will become a security risk. - def check_dashboard_template(result) - return error(_('Not found.'), :not_found) unless dashboard_service&.out_of_the_box_dashboard? - - success(result) - end - - def create_file(result) - create_file_response = ::Files::CreateService.new(project, current_user, dashboard_attrs).execute - - if create_file_response[:status] == :success - success(result.merge(create_file_response)) - else - wrap_error(create_file_response) - end - end - - def refresh_repository_method_caches(result) - repository.refresh_method_caches([:metrics_dashboard]) - - success(result.merge(http_status: :created, dashboard: dashboard_details)) - end - - def dashboard_service - strong_memoize(:dashboard_service) do - Gitlab::Metrics::Dashboard::ServiceSelector.call(dashboard_service_options) - end - end - - def dashboard_attrs - { - commit_message: params[:commit_message], - file_path: new_dashboard_path, - file_content: new_dashboard_content, - encoding: 'text', - branch_name: branch, - start_branch: repository.branch_exists?(branch) ? branch : project.default_branch - } - end - - def dashboard_details - { - path: new_dashboard_path, - display_name: ::Metrics::Dashboard::CustomDashboardService.name_for_path(new_dashboard_path), - default: false, - system_dashboard: false - } - end - - def push_authorized? - Gitlab::UserAccess.new(current_user, container: project).can_push_to_branch?(branch) - end - - def dashboard_template - @dashboard_template ||= params[:dashboard] - end - - def branch - @branch ||= params[:branch] - end - - def new_or_default_branch? - !repository.branch_exists?(params[:branch]) || project.default_branch == params[:branch] - end - - def valid_branch_name? - Gitlab::GitRefValidator.validate(params[:branch]) - end - - def new_dashboard_path - @new_dashboard_path ||= File.join(USER_DASHBOARDS_DIR, file_name) - end - - def file_name - @file_name ||= File.basename(params[:file_name]) - end - - def target_file_type_valid? - File.extname(params[:file_name]) == ALLOWED_FILE_TYPE - end - - def wrap_error(result) - if result[:message] == 'A file with this name already exists' - error(_("A file with '%{file_name}' already exists in %{branch} branch") % { file_name: file_name, branch: branch }, :bad_request) - else - result - end - end - - def new_dashboard_content - ::Gitlab::Metrics::Dashboard::Processor - .new(project, raw_dashboard, sequence, {}) - .process.deep_stringify_keys.to_yaml - end - - def repository - @repository ||= project.repository - end - - def raw_dashboard - dashboard_service.new(project, current_user, dashboard_service_options).raw_dashboard - end - - def dashboard_service_options - { - embedded: false, - dashboard_path: dashboard_template - } - end - - def sequence - SEQUENCES[dashboard_template] || [] - end - end - end -end diff --git a/app/services/metrics/dashboard/dynamic_embed_service.rb b/app/services/metrics/dashboard/dynamic_embed_service.rb deleted file mode 100644 index a94538668c1..00000000000 --- a/app/services/metrics/dashboard/dynamic_embed_service.rb +++ /dev/null @@ -1,78 +0,0 @@ -# frozen_string_literal: true - -# Responsible for returning a filtered project dashboard -# containing only the request-provided metrics. The result -# is then cached for future requests. Metrics are identified -# based on a combination of identifiers for now, but the ideal -# would be similar to the approach in DefaultEmbedService, but -# a single unique identifier is not currently available across -# all metric types (custom, project-defined, cluster, or system). -# -# Use Gitlab::Metrics::Dashboard::Finder to retrive dashboards. -module Metrics - module Dashboard - class DynamicEmbedService < ::Metrics::Dashboard::BaseEmbedService - include Gitlab::Utils::StrongMemoize - - class << self - # Determines whether the provided params are sufficient - # to uniquely identify a panel from a yml-defined dashboard. - # - # See https://docs.gitlab.com/ee/operations/metrics/dashboards/index.html - # for additional info on defining custom dashboards. - def valid_params?(params) - [ - embedded?(params[:embedded]), - params[:group].present?, - params[:title].present?, - params[:y_label] - ].all? - end - end - - # Returns a new dashboard with only the matching - # metrics from the system dashboard, stripped of groups. - # @return [Hash] - def get_raw_dashboard - not_found! if panels.empty? - - { 'panel_groups' => [{ 'panels' => panels }] } - end - - private - - def panels - strong_memoize(:panels) do - not_found! unless base_dashboard - not_found! unless groups = base_dashboard['panel_groups'] - not_found! unless matching_group = find_group(groups) - not_found! unless all_panels = matching_group['panels'] - - find_panels(all_panels) - end - end - - def base_dashboard - strong_memoize(:base_dashboard) do - Gitlab::Metrics::Dashboard::Finder.find_raw(project, dashboard_path: dashboard_path) - end - end - - def find_group(groups) - groups.find do |candidate_group| - candidate_group['group'] == group - end - end - - def find_panels(all_panels) - all_panels.select do |panel| - panel['title'] == title && panel['y_label'] == y_label - end - end - - def not_found! - panels_not_found!(identifiers) - end - end - end -end diff --git a/app/services/projects/prometheus/alerts/notify_service.rb b/app/services/projects/prometheus/alerts/notify_service.rb index 22a882c4648..8f1f78beb5b 100644 --- a/app/services/projects/prometheus/alerts/notify_service.rb +++ b/app/services/projects/prometheus/alerts/notify_service.rb @@ -80,8 +80,7 @@ module Projects def valid_alert_manager_token?(token, integration) valid_for_alerts_endpoint?(token, integration) || - valid_for_manual?(token) || - valid_for_cluster?(token) + valid_for_manual?(token) end def valid_for_manual?(token) @@ -109,44 +108,6 @@ module Projects compare_token(token, integration.token) end - def valid_for_cluster?(token) - cluster_integration = find_cluster_integration(project) - return false unless cluster_integration - - cluster_integration_token = cluster_integration.alert_manager_token - - if token - compare_token(token, cluster_integration_token) - else - cluster_integration_token.nil? - end - end - - def find_cluster_integration(project) - alert_id = gitlab_alert_id - return unless alert_id - - alert = find_alert(project, alert_id) - return unless alert - - cluster = alert.environment.deployment_platform&.cluster - return unless cluster&.enabled? - return unless cluster.integration_prometheus_available? - - cluster.integration_prometheus - end - - def find_alert(project, metric) - Projects::Prometheus::AlertsFinder - .new(project: project, metric: metric) - .execute - .first - end - - def gitlab_alert_id - alerts&.first&.dig('labels', 'gitlab_alert_id') - end - def compare_token(expected, actual) return unless expected && actual diff --git a/app/services/search_service.rb b/app/services/search_service.rb index 433e9b0da6d..3d413ed9f7b 100644 --- a/app/services/search_service.rb +++ b/app/services/search_service.rb @@ -44,6 +44,10 @@ class SearchService project.blank? && group.blank? end + def search_type + 'basic' + end + def show_snippets? strong_memoize(:show_snippets) do params[:snippets] == 'true' |