From bcc77054ee9aefd1e332e04a4189390fd5a3112e Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Tue, 11 Feb 2020 15:08:44 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- .../javascripts/blob/file_template_mediator.js | 6 +- .../javascripts/code_navigation/store/actions.js | 2 +- app/models/container_expiration_policy.rb | 2 +- .../project_incident_management_setting.rb | 34 ++++++ app/models/project.rb | 2 + .../incident_management/create_issue_service.rb | 126 +++++++++++++++++++++ app/views/projects/blob/_blob.html.haml | 2 +- app/workers/all_queues.yml | 6 + app/workers/concerns/worker_context.rb | 2 +- app/workers/container_expiration_policy_worker.rb | 10 +- .../incident_management/process_alert_worker.rb | 29 +++++ 11 files changed, 208 insertions(+), 13 deletions(-) create mode 100644 app/models/incident_management/project_incident_management_setting.rb create mode 100644 app/services/incident_management/create_issue_service.rb create mode 100644 app/workers/incident_management/process_alert_worker.rb (limited to 'app') diff --git a/app/assets/javascripts/blob/file_template_mediator.js b/app/assets/javascripts/blob/file_template_mediator.js index 2df7a84ead0..0fb02ca5965 100644 --- a/app/assets/javascripts/blob/file_template_mediator.js +++ b/app/assets/javascripts/blob/file_template_mediator.js @@ -117,11 +117,7 @@ export default class FileTemplateMediator { selector.hide(); } }); - - if (this.editor.getValue() !== '') { - this.setTypeSelectorToggleText(item.name); - } - + this.setTypeSelectorToggleText(item.name); this.cacheToggleText(); } diff --git a/app/assets/javascripts/code_navigation/store/actions.js b/app/assets/javascripts/code_navigation/store/actions.js index 10483abfb23..cb6d30c775d 100644 --- a/app/assets/javascripts/code_navigation/store/actions.js +++ b/app/assets/javascripts/code_navigation/store/actions.js @@ -16,7 +16,7 @@ export default { commit(types.REQUEST_DATA); api - .lsifData(state.projectPath, state.commitId, state.path) + .lsifData(state.projectPath, state.commitId, state.blobPath) .then(({ data }) => { const normalizedData = data.reduce((acc, d) => { if (d.hover) { diff --git a/app/models/container_expiration_policy.rb b/app/models/container_expiration_policy.rb index c929a78a7f9..ccb0a0f8acd 100644 --- a/app/models/container_expiration_policy.rb +++ b/app/models/container_expiration_policy.rb @@ -14,7 +14,7 @@ class ContainerExpirationPolicy < ApplicationRecord validates :keep_n, inclusion: { in: ->(_) { self.keep_n_options.keys } }, allow_nil: true scope :active, -> { where(enabled: true) } - scope :preloaded, -> { preload(:project) } + scope :preloaded, -> { preload(project: [:route]) } def self.keep_n_options { diff --git a/app/models/incident_management/project_incident_management_setting.rb b/app/models/incident_management/project_incident_management_setting.rb new file mode 100644 index 00000000000..bf57c5b883f --- /dev/null +++ b/app/models/incident_management/project_incident_management_setting.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module IncidentManagement + class ProjectIncidentManagementSetting < ApplicationRecord + include Gitlab::Utils::StrongMemoize + + belongs_to :project + + validate :issue_template_exists, if: :create_issue? + + def available_issue_templates + Gitlab::Template::IssueTemplate.all(project) + end + + def issue_template_content + strong_memoize(:issue_template_content) do + issue_template&.content if issue_template_key.present? + end + end + + private + + def issue_template_exists + return unless issue_template_key.present? + + errors.add(:issue_template_key, 'not found') unless issue_template + end + + def issue_template + Gitlab::Template::IssueTemplate.find(issue_template_key, project) + rescue Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError + end + end +end diff --git a/app/models/project.rb b/app/models/project.rb index 8454ece814f..b5639039bb6 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -187,6 +187,7 @@ class Project < ApplicationRecord has_one :import_state, autosave: true, class_name: 'ProjectImportState', inverse_of: :project has_one :import_export_upload, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent has_one :project_repository, inverse_of: :project + has_one :incident_management_setting, inverse_of: :project, class_name: 'IncidentManagement::ProjectIncidentManagementSetting' has_one :error_tracking_setting, inverse_of: :project, class_name: 'ErrorTracking::ProjectErrorTrackingSetting' has_one :metrics_setting, inverse_of: :project, class_name: 'ProjectMetricsSetting' has_one :grafana_integration, inverse_of: :project @@ -316,6 +317,7 @@ class Project < ApplicationRecord 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 accepts_nested_attributes_for :metrics_setting, update_only: true, allow_destroy: true accepts_nested_attributes_for :grafana_integration, update_only: true, allow_destroy: true diff --git a/app/services/incident_management/create_issue_service.rb b/app/services/incident_management/create_issue_service.rb new file mode 100644 index 00000000000..94b6f037924 --- /dev/null +++ b/app/services/incident_management/create_issue_service.rb @@ -0,0 +1,126 @@ +# frozen_string_literal: true + +module IncidentManagement + class CreateIssueService < BaseService + include Gitlab::Utils::StrongMemoize + + INCIDENT_LABEL = { + title: 'incident', + color: '#CC0033', + description: <<~DESCRIPTION.chomp + Denotes a disruption to IT services and \ + the associated issues require immediate attention + DESCRIPTION + }.freeze + + def initialize(project, params) + super(project, User.alert_bot, params) + end + + def execute + return error_with('setting disabled') unless incident_management_setting.create_issue? + return error_with('invalid alert') unless alert.valid? + + issue = create_issue + return error_with(issue_errors(issue)) unless issue.valid? + + success(issue: issue) + end + + private + + def create_issue + issue = do_create_issue(label_ids: issue_label_ids) + + # Create an unlabelled issue if we couldn't create the issue + # due to labels errors. + # See https://gitlab.com/gitlab-org/gitlab-foss/issues/65042 + if issue.errors.include?(:labels) + log_label_error(issue) + issue = do_create_issue + end + + issue + end + + def do_create_issue(**params) + Issues::CreateService.new( + project, + current_user, + title: issue_title, + description: issue_description, + **params + ).execute + end + + def issue_title + alert.full_title + end + + def issue_description + horizontal_line = "\n---\n\n" + + [ + alert_summary, + alert_markdown, + issue_template_content + ].compact.join(horizontal_line) + end + + def issue_label_ids + [ + find_or_create_label(**INCIDENT_LABEL) + ].compact.map(&:id) + end + + def find_or_create_label(**params) + Labels::FindOrCreateService + .new(current_user, project, **params) + .execute + end + + def alert_summary + alert.issue_summary_markdown + end + + def alert_markdown + alert.alert_markdown + end + + def alert + strong_memoize(:alert) do + Gitlab::Alerting::Alert.new(project: project, payload: params).present + end + end + + def issue_template_content + incident_management_setting.issue_template_content + end + + def incident_management_setting + strong_memoize(:incident_management_setting) do + project.incident_management_setting || + project.build_incident_management_setting + end + end + + def issue_errors(issue) + issue.errors.full_messages.to_sentence + end + + def log_label_error(issue) + log_info <<~TEXT.chomp + Cannot create incident issue with labels \ + #{issue.labels.map(&:title).inspect} \ + for "#{project.full_name}": #{issue.errors.full_messages.to_sentence}. + Retrying without labels. + TEXT + end + + def error_with(message) + log_error(%{Cannot create incident issue for "#{project.full_name}": #{message}}) + + error(message) + end + end +end diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml index 9803d65c4fb..91d1fc06a41 100644 --- a/app/views/projects/blob/_blob.html.haml +++ b/app/views/projects/blob/_blob.html.haml @@ -10,7 +10,7 @@ #blob-content-holder.blob-content-holder - if native_code_navigation_enabled?(@project) - #js-code-navigation{ data: { commit_id: blob.commit_id, path: blob.path, project_path: @project.full_path } } + #js-code-navigation{ data: { commit_id: blob.commit_id, blob_path: blob.path, project_path: @project.full_path } } %article.file-holder = render 'projects/blob/header', blob: blob = render 'projects/blob/content', blob: blob diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index e836dd92770..22dd7f5843f 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -429,6 +429,12 @@ :latency_sensitive: :resource_boundary: :unknown :weight: 1 +- :name: incident_management:incident_management_process_alert + :feature_category: :incident_management + :has_external_dependencies: + :latency_sensitive: + :resource_boundary: :unknown + :weight: 2 - :name: mail_scheduler:mail_scheduler_issue_due :feature_category: :issue_tracking :has_external_dependencies: diff --git a/app/workers/concerns/worker_context.rb b/app/workers/concerns/worker_context.rb index ca006eaad5d..f2ff3ecfb6b 100644 --- a/app/workers/concerns/worker_context.rb +++ b/app/workers/concerns/worker_context.rb @@ -60,6 +60,6 @@ module WorkerContext end def with_context(context, &block) - Gitlab::ApplicationContext.new(context).use(&block) + Gitlab::ApplicationContext.new(context).use { yield(**context) } end end diff --git a/app/workers/container_expiration_policy_worker.rb b/app/workers/container_expiration_policy_worker.rb index a930dfa0186..e07a6546e2d 100644 --- a/app/workers/container_expiration_policy_worker.rb +++ b/app/workers/container_expiration_policy_worker.rb @@ -2,15 +2,17 @@ class ContainerExpirationPolicyWorker include ApplicationWorker - include CronjobQueue # rubocop:disable Scalability/CronWorkerContext + include CronjobQueue feature_category :container_registry def perform ContainerExpirationPolicy.runnable_schedules.preloaded.find_each do |container_expiration_policy| - ContainerExpirationPolicyService.new( - container_expiration_policy.project, container_expiration_policy.project.owner - ).execute(container_expiration_policy) + with_context(project: container_expiration_policy.project, + user: container_expiration_policy.project.owner) do |project:, user:| + ContainerExpirationPolicyService.new(project, user) + .execute(container_expiration_policy) + end end end end diff --git a/app/workers/incident_management/process_alert_worker.rb b/app/workers/incident_management/process_alert_worker.rb new file mode 100644 index 00000000000..f3d5bc5c66b --- /dev/null +++ b/app/workers/incident_management/process_alert_worker.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module IncidentManagement + class ProcessAlertWorker + include ApplicationWorker + + queue_namespace :incident_management + feature_category :incident_management + + def perform(project_id, alert) + project = find_project(project_id) + return unless project + + create_issue(project, alert) + end + + private + + def find_project(project_id) + Project.find_by_id(project_id) + end + + def create_issue(project, alert) + IncidentManagement::CreateIssueService + .new(project, alert) + .execute + end + end +end -- cgit v1.2.3