Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-09-22 12:09:39 +00:00
parent 1086ac5177
commit 26879909dd
62 changed files with 590 additions and 1482 deletions

View file

@ -34,6 +34,13 @@
- tmp/rubocop_cache/
policy: pull
.coverage-cache:
cache:
key: "coverage-cache-v1"
paths:
- vendor/ruby/
policy: pull
.qa-cache:
cache:
key: "qa-v1"

View file

@ -11,6 +11,9 @@
stage: test
needs: ["setup-test-env", "retrieve-tests-metadata", "compile-test-assets"]
script:
# Only install knapsack after bundle install! Otherwise oddly some native
# gems could not be found under some circumstance. No idea why, hours wasted.
- run_timed_command "gem install knapsack --no-document"
- run_timed_command "scripts/gitaly-test-build"
- run_timed_command "scripts/gitaly-test-spawn"
- source scripts/rspec_helpers.sh
@ -32,6 +35,9 @@
.rspec-base-migration:
extends: .rails:rules:ee-and-foss-migration
script:
# Only install knapsack after bundle install! Otherwise oddly some native
# gems could not be found under some circumstance. No idea why, hours wasted.
- run_timed_command "gem install knapsack --no-document"
- run_timed_command "scripts/gitaly-test-build"
- run_timed_command "scripts/gitaly-test-spawn"
- source scripts/rspec_helpers.sh
@ -67,6 +73,9 @@
.rspec-ee-base-geo:
extends: .rspec-base
script:
# Only install knapsack after bundle install! Otherwise oddly some native
# gems could not be found under some circumstance. No idea why, hours wasted.
- run_timed_command "gem install knapsack --no-document"
- run_timed_command "scripts/gitaly-test-build"
- run_timed_command "scripts/gitaly-test-spawn"
- source scripts/rspec_helpers.sh
@ -160,6 +169,25 @@ update-rails-cache:
cache:
policy: push # We want to rebuild the cache from scratch to ensure stale dependencies are cleaned up.
.coverage-base:
extends:
- .default-retry
- .default-before_script
- .coverage-cache
variables:
SETUP_DB: "false"
USE_BUNDLE_INSTALL: "false"
update-coverage-cache:
extends:
- .coverage-base
- .shared:rules:update-cache
stage: prepare
script:
- run_timed_command "bundle install --jobs=$(nproc) --path=vendor --retry=3 --quiet --without default development test production puma unicorn kerberos metrics omnibus ed25519"
cache:
policy: push # We want to rebuild the cache from scratch to ensure stale dependencies are cleaned up.
.static-analysis-base:
extends:
- .default-retry
@ -178,7 +206,7 @@ update-static-analysis-cache:
script:
- rm -rf ./node_modules # We remove node_modules because there's no mechanism to remove stall entries.
- run_timed_command "retry yarn install --frozen-lockfile"
- bundle exec rubocop --parallel # For the moment we only cache `vendor/ruby/`, `node_modules/`, and `tmp/rubocop_cache` so we don't need to run all the tasks,
- run_timed_command "bundle exec rubocop --parallel" # For the moment we only cache `vendor/ruby/`, `node_modules/`, and `tmp/rubocop_cache` so we don't need to run all the tasks,
cache:
# We want to rebuild the cache from scratch to ensure stale dependencies are cleaned up but RuboCop has a mechanism
# for keeping only the N latest cache files, so we take advantage of it with `pull-push` and removing `node_modules` at the start of the job.
@ -313,7 +341,7 @@ db:backup_and_restore:
rspec:coverage:
extends:
- .rails-job-base
- .coverage-base
- .rails:rules:rspec-coverage
stage: post-test
# We cannot use needs since it would mean needing 84 jobs (since most are parallelized)
@ -333,11 +361,10 @@ rspec:coverage:
- rspec-ee system pg11 geo
- memory-static
- memory-on-boot
variables:
SETUP_DB: "false"
script:
- bundle exec scripts/merge-simplecov
- bundle exec scripts/gather-test-memory-data
- run_timed_command "bundle install --jobs=$(nproc) --path=vendor --retry=3 --quiet --without default development test production puma unicorn kerberos metrics omnibus ed25519"
- run_timed_command "bundle exec scripts/merge-simplecov"
- run_timed_command "bundle exec scripts/gather-test-memory-data"
coverage: '/LOC \((\d+\.\d+%)\) covered.$/'
artifacts:
name: coverage

View file

@ -375,8 +375,6 @@ group :development, :test do
gem 'scss_lint', '~> 0.56.0', require: false
gem 'haml_lint', '~> 0.34.0', require: false
gem 'simplecov', '~> 0.18.5', require: false
gem 'simplecov-cobertura', '~> 1.3.1', require: false
gem 'bundler-audit', '~> 0.6.1', require: false
gem 'benchmark-ips', '~> 2.3.0', require: false
@ -394,6 +392,11 @@ group :development, :test do
gem 'rblineprof', '~> 0.3.6', platform: :mri, require: false
end
group :development, :test, :coverage do
gem 'simplecov', '~> 0.18.5', require: false
gem 'simplecov-cobertura', '~> 1.3.1', require: false
end
# Gems required in omnibus-gitlab pipeline
group :development, :test, :omnibus do
gem 'license_finder', '~> 5.4', require: false

View file

@ -1,6 +1,7 @@
<script>
import { GlButton, GlIcon, GlLink, GlSprintf, GlTooltipDirective, GlTruncate } from '@gitlab/ui';
import PackageTags from './package_tags.vue';
import PackagePath from './package_path.vue';
import PublishMethod from './publish_method.vue';
import { getPackageTypeLabel } from '../utils';
import timeagoMixin from '~/vue_shared/mixins/timeago';
@ -15,6 +16,7 @@ export default {
GlSprintf,
GlTruncate,
PackageTags,
PackagePath,
PublishMethod,
ListItem,
},
@ -92,22 +94,12 @@ export default {
</gl-sprintf>
</div>
<div v-if="hasProjectLink" class="gl-display-flex gl-align-items-center">
<gl-icon name="review-list" class="gl-ml-3 gl-mr-2 gl-min-w-0" />
<gl-link
class="gl-text-body gl-min-w-0"
data-testid="packages-row-project"
:href="`/${packageEntity.project_path}`"
>
<gl-truncate :text="packageEntity.projectPathName" />
</gl-link>
</div>
<div v-if="showPackageType" class="d-flex align-items-center" data-testid="package-type">
<gl-icon name="package" class="gl-ml-3 gl-mr-2" />
<span>{{ packageType }}</span>
</div>
<package-path v-if="hasProjectLink" :path="packageEntity.project_path" />
</div>
</template>

View file

@ -0,0 +1,71 @@
<script>
import { GlIcon, GlLink, GlTooltipDirective } from '@gitlab/ui';
import { joinPaths } from '~/lib/utils/url_utility';
export default {
name: 'PackagePath',
components: {
GlIcon,
GlLink,
},
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
path: {
type: String,
required: true,
},
},
computed: {
pathPieces() {
return this.path.split('/');
},
root() {
// we skip the first part of the path since is the 'base' group
return this.pathPieces[1];
},
rootLink() {
return joinPaths(this.pathPieces[0], this.root);
},
leaf() {
return this.pathPieces[this.pathPieces.length - 1];
},
deeplyNested() {
return this.pathPieces.length > 3;
},
hasGroup() {
return this.root !== this.leaf;
},
},
};
</script>
<template>
<div class="gl-display-flex gl-align-items-center">
<gl-icon data-testid="base-icon" name="project" class="gl-mx-3 gl-min-w-0" />
<gl-link data-testid="root-link" class="gl-text-gray-500 gl-min-w-0" :href="`/${rootLink}`">
{{ root }}
</gl-link>
<template v-if="hasGroup">
<gl-icon data-testid="root-chevron" name="chevron-right" class="gl-mx-2 gl-min-w-0" />
<template v-if="deeplyNested">
<span
v-gl-tooltip="{ title: path }"
data-testid="ellipsis-icon"
class="gl-inset-border-1-gray-200 gl-rounded-base gl-px-2 gl-min-w-0"
>
<gl-icon name="ellipsis_h" />
</span>
<gl-icon data-testid="ellipsis-chevron" name="chevron-right" class="gl-mx-2 gl-min-w-0" />
</template>
<gl-link data-testid="leaf-link" class="gl-text-gray-500 gl-min-w-0" :href="`/${path}`">
{{ leaf }}
</gl-link>
</template>
</div>
</template>

View file

@ -56,16 +56,14 @@ module Emails
subject: @message.subject)
end
def prometheus_alert_fired_email(project_id, user_id, alert_payload)
def prometheus_alert_fired_email(project_id, user_id, alert_attributes)
@project = ::Project.find(project_id)
user = ::User.find(user_id)
@alert = ::Gitlab::Alerting::Alert
.new(project: @project, payload: alert_payload)
.present
return unless @alert.valid?
@alert = AlertManagement::Alert.new(alert_attributes.with_indifferent_access).present
return unless @alert.parsed_payload.has_required_attributes?
subject_text = "Alert: #{@alert.full_title}"
subject_text = "Alert: #{@alert.email_title}"
mail(to: user.notification_email_for(@project.group), subject: subject(subject_text))
end
end

View file

@ -191,7 +191,7 @@ module AlertManagement
end
def prometheus?
monitoring_tool == Gitlab::AlertManagement::AlertParams::MONITORING_TOOLS[:prometheus]
monitoring_tool == Gitlab::AlertManagement::Payload::MONITORING_TOOLS[:prometheus]
end
def register_new_event!

View file

@ -11,6 +11,7 @@ module Clusters
RESERVED_NAMESPACES = %w(gitlab-managed-apps).freeze
self.table_name = 'cluster_platforms_kubernetes'
self.reactive_cache_work_type = :external_dependency
belongs_to :cluster, inverse_of: :platform_kubernetes, class_name: 'Clusters::Cluster'

View file

@ -182,7 +182,7 @@ module Issuable
end
def supports_time_tracking?
is_a?(TimeTrackable) && !incident?
is_a?(TimeTrackable)
end
def supports_severity?

View file

@ -9,7 +9,7 @@ module ReactiveCaching
ExceededReactiveCacheLimit = Class.new(StandardError)
WORK_TYPE = {
default: ReactiveCachingWorker,
no_dependency: ReactiveCachingWorker,
external_dependency: ExternalServiceReactiveCachingWorker
}.freeze
@ -30,7 +30,6 @@ module ReactiveCaching
self.reactive_cache_refresh_interval = 1.minute
self.reactive_cache_lifetime = 10.minutes
self.reactive_cache_hard_limit = nil # this value should be set in megabytes. E.g: 1.megabyte
self.reactive_cache_work_type = :default
self.reactive_cache_worker_finder = ->(id, *_args) do
find_by(primary_key => id)
end

View file

@ -8,5 +8,6 @@ module ReactiveService
# Default cache key: class name + project_id
self.reactive_cache_key = ->(service) { [service.class.model_name.singular, service.project_id] }
self.reactive_cache_work_type = :external_dependency
end
end

View file

@ -31,6 +31,7 @@ class MergeRequest < ApplicationRecord
self.reactive_cache_key = ->(model) { [model.project.id, model.iid] }
self.reactive_cache_refresh_interval = 10.minutes
self.reactive_cache_lifetime = 10.minutes
self.reactive_cache_work_type = :no_dependency
SORTING_PREFERENCE_FIELD = :merge_requests_sort

View file

@ -8,6 +8,7 @@ module AlertManagement
MARKDOWN_LINE_BREAK = " \n"
HORIZONTAL_LINE = "\n\n---\n\n"
INCIDENT_LABEL_NAME = ::IncidentManagement::CreateIncidentLabelService::LABEL_PROPERTIES[:title]
delegate :metrics_dashboard_url, :runbook, to: :parsed_payload
@ -38,6 +39,30 @@ module AlertManagement
Gitlab::Utils::InlineHash.merge_keys(payload)
end
def show_incident_issues_link?
project.incident_management_setting&.create_issue?
end
def show_performance_dashboard_link?
prometheus_alert.present?
end
def incident_issues_link
project_issues_url(project, label_name: INCIDENT_LABEL_NAME)
end
def performance_dashboard_link
if environment
metrics_project_environment_url(project, environment)
else
metrics_project_environments_url(project)
end
end
def email_title
[environment&.name, query_title].compact.join(': ')
end
private
attr_reader :alert, :project
@ -80,5 +105,11 @@ module AlertManagement
def host_links
hosts.join(' ')
end
def query_title
return title unless prometheus_alert
"#{prometheus_alert.title} #{prometheus_alert.computed_operator} #{prometheus_alert.threshold} for 5 minutes"
end
end
end

View file

@ -1,179 +0,0 @@
# frozen_string_literal: true
module Projects
module Prometheus
class AlertPresenter < Gitlab::View::Presenter::Delegated
GENERIC_ALERT_SUMMARY_ANNOTATIONS = %w(monitoring_tool service hosts).freeze
MARKDOWN_LINE_BREAK = " \n".freeze
INCIDENT_LABEL_NAME = ::IncidentManagement::CreateIncidentLabelService::LABEL_PROPERTIES[:title].freeze
METRIC_TIME_WINDOW = 30.minutes
def full_title
[environment_name, alert_title].compact.join(': ')
end
def project_full_path
project.full_path
end
def metric_query
gitlab_alert&.full_query
end
def environment_name
environment&.name
end
def performance_dashboard_link
if environment
metrics_project_environment_url(project, environment)
else
metrics_project_environments_url(project)
end
end
def show_performance_dashboard_link?
gitlab_alert.present?
end
def show_incident_issues_link?
project.incident_management_setting&.create_issue?
end
def incident_issues_link
project_issues_url(project, label_name: INCIDENT_LABEL_NAME)
end
def start_time
starts_at&.strftime('%d %B %Y, %-l:%M%p (%Z)')
end
def issue_summary_markdown
<<~MARKDOWN.chomp
#{metadata_list}
#{metric_embed_for_alert}
MARKDOWN
end
def metric_embed_for_alert
"\n[](#{metrics_dashboard_url})" if metrics_dashboard_url
end
def metrics_dashboard_url
strong_memoize(:metrics_dashboard_url) do
embed_url_for_gitlab_alert || embed_url_for_self_managed_alert
end
end
def details_url
return unless am_alert
::Gitlab::Routing.url_helpers.details_project_alert_management_url(
project,
am_alert.iid
)
end
private
def alert_title
query_title || title
end
def query_title
return unless gitlab_alert
"#{gitlab_alert.title} #{gitlab_alert.computed_operator} #{gitlab_alert.threshold} for 5 minutes"
end
def metadata_list
metadata = []
metadata << list_item('Start time', start_time) if start_time
metadata << list_item('full_query', backtick(full_query)) if full_query
metadata << list_item(service.label.humanize, service.value) if service
metadata << list_item(monitoring_tool.label.humanize, monitoring_tool.value) if monitoring_tool
metadata << list_item(hosts.label.humanize, host_links) if hosts
metadata << list_item('GitLab alert', details_url) if details_url
metadata.join(MARKDOWN_LINE_BREAK)
end
def details
Gitlab::Utils::InlineHash.merge_keys(payload)
end
def list_item(key, value)
"**#{key}:** #{value}".strip
end
def backtick(value)
"`#{value}`"
end
GENERIC_ALERT_SUMMARY_ANNOTATIONS.each do |annotation_name|
define_method(annotation_name) do
annotations.find { |a| a.label == annotation_name }
end
end
def host_links
Array(hosts.value).join(' ')
end
def embed_url_for_gitlab_alert
return unless gitlab_alert
metrics_dashboard_project_prometheus_alert_url(
project,
gitlab_alert.prometheus_metric_id,
environment_id: environment.id,
embedded: true,
**alert_embed_window_params(embed_time)
)
end
def embed_url_for_self_managed_alert
return unless environment && full_query && title
metrics_dashboard_project_environment_url(
project,
environment,
embed_json: dashboard_for_self_managed_alert.to_json,
embedded: true,
**alert_embed_window_params(embed_time)
)
end
def embed_time
starts_at || Time.current
end
def alert_embed_window_params(time)
{
start: format_embed_timestamp(time - METRIC_TIME_WINDOW),
end: format_embed_timestamp(time + METRIC_TIME_WINDOW)
}
end
def format_embed_timestamp(time)
time.utc.strftime('%FT%TZ')
end
def dashboard_for_self_managed_alert
{
panel_groups: [{
panels: [{
type: 'area-chart',
title: title,
y_label: y_label,
metrics: [{
query_range: full_query
}]
}]
}]
}
end
end
end
end

View file

@ -47,7 +47,7 @@ module AlertManagement
def create_alert_management_alert
if alert.save
alert.execute_services
SystemNoteService.create_new_alert(alert, Gitlab::AlertManagement::AlertParams::MONITORING_TOOLS[:prometheus])
SystemNoteService.create_new_alert(alert, Gitlab::AlertManagement::Payload::MONITORING_TOOLS[:prometheus])
return
end

View file

@ -10,6 +10,8 @@ module PodLogs
CACHE_KEY_GET_POD_LOG = 'get_pod_log'
K8S_NAME_MAX_LENGTH = 253
self.reactive_cache_work_type = :external_dependency
def id
cluster.id
end

View file

@ -11,7 +11,6 @@ module PodLogs
:pod_logs,
:filter_return_keys
self.reactive_cache_work_type = :external_dependency
self.reactive_cache_worker_finder = ->(id, _cache_key, namespace, params) { new(::Clusters::Cluster.find(id), namespace, params: params) }
private

View file

@ -17,7 +17,6 @@ module PodLogs
:split_logs,
:filter_return_keys
self.reactive_cache_work_type = :external_dependency
self.reactive_cache_worker_finder = ->(id, _cache_key, namespace, params) { new(::Clusters::Cluster.find(id), namespace, params: params) }
private

View file

@ -7,43 +7,34 @@ module Projects
include ::IncidentManagement::Settings
def execute(token)
return bad_request unless valid_payload_size?
return forbidden unless alerts_service_activated?
return unauthorized unless valid_token?(token)
alert = process_alert
process_alert
return bad_request unless alert.persisted?
process_incident_issues(alert) if process_issues?
process_incident_issues if process_issues?
send_alert_email if send_email?
ServiceResponse.success
rescue Gitlab::Alerting::NotificationPayloadParser::BadPayloadError
bad_request
end
private
delegate :alerts_service, :alerts_service_activated?, to: :project
def am_alert_params
strong_memoize(:am_alert_params) do
Gitlab::AlertManagement::AlertParams.from_generic_alert(project: project, payload: params.to_h)
end
end
def process_alert
existing_alert = find_alert_by_fingerprint(am_alert_params[:fingerprint])
if existing_alert
process_existing_alert(existing_alert)
if alert.persisted?
process_existing_alert
else
create_alert
end
end
def process_existing_alert(alert)
if am_alert_params[:ended_at].present?
process_resolved_alert(alert)
def process_existing_alert
if incoming_payload.ends_at.present?
process_resolved_alert
else
alert.register_new_event!
end
@ -51,10 +42,10 @@ module Projects
alert
end
def process_resolved_alert(alert)
def process_resolved_alert
return unless auto_close_incident?
if alert.resolve(am_alert_params[:ended_at])
if alert.resolve(incoming_payload.ends_at)
close_issue(alert.issue)
end
@ -72,20 +63,13 @@ module Projects
end
def create_alert
alert = AlertManagement::Alert.create(am_alert_params.except(:ended_at))
alert.execute_services if alert.persisted?
return unless alert.save
alert.execute_services
SystemNoteService.create_new_alert(alert, 'Generic Alert Endpoint')
alert
end
def find_alert_by_fingerprint(fingerprint)
return unless fingerprint
AlertManagement::Alert.not_resolved.for_fingerprint(project, fingerprint).first
end
def process_incident_issues(alert)
def process_incident_issues
return if alert.issue
::IncidentManagement::ProcessAlertWorker.perform_async(nil, nil, alert.id)
@ -94,11 +78,33 @@ module Projects
def send_alert_email
notification_service
.async
.prometheus_alerts_fired(project, [parsed_payload])
.prometheus_alerts_fired(project, [alert.attributes])
end
def parsed_payload
Gitlab::Alerting::NotificationPayloadParser.call(params.to_h, project)
def alert
strong_memoize(:alert) do
existing_alert || new_alert
end
end
def existing_alert
return unless incoming_payload.gitlab_fingerprint
AlertManagement::Alert.not_resolved.for_fingerprint(project, incoming_payload.gitlab_fingerprint).first
end
def new_alert
AlertManagement::Alert.new(**incoming_payload.alert_params, ended_at: nil)
end
def incoming_payload
strong_memoize(:incoming_payload) do
Gitlab::AlertManagement::Payload.parse(project, params.to_h)
end
end
def valid_payload_size?
Gitlab::Utils::DeepSize.new(params).valid?
end
def valid_token?(token)

View file

@ -125,7 +125,7 @@ module Projects
notification_service
.async
.prometheus_alerts_fired(project, firings)
.prometheus_alerts_fired(project, alerts_attributes)
end
def process_prometheus_alerts
@ -136,6 +136,18 @@ module Projects
end
end
def alerts_attributes
firings.map do |payload|
alert_params = Gitlab::AlertManagement::Payload.parse(
project,
payload,
monitoring_tool: Gitlab::AlertManagement::Payload::MONITORING_TOOLS[:prometheus]
).alert_params
AlertManagement::Alert.new(alert_params).attributes
end
end
def bad_request
ServiceResponse.error(message: 'Bad Request', http_status: :bad_request)
end

View file

@ -1,17 +1,17 @@
%p
= _('An alert has been triggered in %{project_path}.') % { project_path: @alert.project_full_path }
= _('An alert has been triggered in %{project_path}.') % { project_path: @alert.project.full_path }
- if description = @alert.description
%p
= _('Description:')
= description
- if env_name = @alert.environment_name
- if env_name = @alert.environment&.name
%p
= _('Environment:')
= env_name
- if metric_query = @alert.metric_query
- if metric_query = @alert.prometheus_alert&.full_query
%p
= _('Metric:')
@ -25,4 +25,3 @@
- if @alert.show_performance_dashboard_link?
%p
= link_to(_('View performance dashboard.'), @alert.performance_dashboard_link)

View file

@ -1,14 +1,14 @@
<%= _('An alert has been triggered in %{project_path}.') % { project_path: @alert.project_full_path } %>.
<%= _('An alert has been triggered in %{project_path}.') % { project_path: @alert.project.full_path } %>.
<% if description = @alert.description %>
<%= _('Description:') %> <%= description %>
<% end %>
<% if env_name = @alert.environment_name %>
<% if env_name = @alert.environment&.name %>
<%= _('Environment:') %> <%= env_name %>
<% end %>
<% if metric_query = @alert.metric_query %>
<% if metric_query = @alert.prometheus_alert&.full_query %>
<%= _('Metric:') %> <%= metric_query %>
<% end %>

View file

@ -6,7 +6,7 @@
- if diff_file.submodule?
- blob = diff_file.blob
%span
= icon('archive fw')
= sprite_icon('archive')
%strong.file-title-name
= submodule_link(blob, diff_file.content_sha, diff_file.repository)

View file

@ -0,0 +1,5 @@
---
title: Breadcrumb like UI for project path in packages list
merge_request: 42684
author:
type: changed

View file

@ -0,0 +1,5 @@
---
title: Allow time tracking in incidents
merge_request: 42965
author:
type: changed

View file

@ -1,7 +1,7 @@
---
name: boards_with_swimlanes
introduced_by_url:
rollout_issue_url:
group:
introduced_by_url:
rollout_issue_url:
group: group::project management
type: development
default_enabled: false

View file

@ -1,7 +1,7 @@
---
name: bulk_update_health_status
introduced_by_url:
rollout_issue_url:
group:
introduced_by_url:
rollout_issue_url:
group: group::portfolio management
type: development
default_enabled: true

View file

@ -1,7 +1,7 @@
---
name: burnup_charts
introduced_by_url:
rollout_issue_url:
group:
introduced_by_url:
rollout_issue_url:
group: group::project management
type: development
default_enabled: false

View file

@ -1,7 +1,7 @@
---
name: graphql_board_lists
introduced_by_url:
rollout_issue_url:
group:
introduced_by_url:
rollout_issue_url:
group: group::project management
type: development
default_enabled: false

View file

@ -1,7 +1,7 @@
---
name: multi_select_board
introduced_by_url:
rollout_issue_url:
group:
introduced_by_url:
rollout_issue_url:
group: group::project management
type: development
default_enabled: true

View file

@ -1,7 +1,7 @@
---
name: tribute_autocomplete
introduced_by_url:
rollout_issue_url:
group:
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32671
rollout_issue_url:
group: group::project management
type: development
default_enabled: false

View file

@ -1,7 +1,7 @@
---
name: vue_issuable_sidebar
introduced_by_url:
rollout_issue_url:
group:
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18199
rollout_issue_url:
group: group::project management
type: development
default_enabled: false

View file

@ -1,7 +1,7 @@
---
name: vue_issuables_list
introduced_by_url:
rollout_issue_url:
group:
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/15091
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/208093
group: group::project management
type: development
default_enabled: false

View file

@ -1,7 +1,7 @@
---
name: vue_sidebar_labels
introduced_by_url:
rollout_issue_url:
group:
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41561
rollout_issue_url:
group: group::project management
type: development
default_enabled: false

View file

@ -2,7 +2,7 @@
TELEMETRY_CHANGED_FILES_MESSAGE = <<~MSG
For the following files, a review from the [Data team and Telemetry team](https://gitlab.com/groups/gitlab-org/growth/telemetry/engineers/-/group_members?with_inherited_permissions=exclude) is recommended
Please check the ~telemetry [guide](https://docs.gitlab.com/ee/development/telemetry/usage_ping.html) and reach out to @gitlab-org/growth/telemetry/engineers group for a review.
Please check the ~telemetry [guide](https://docs.gitlab.com/ee/development/telemetry/usage_ping.html) and reach out to %<telemetry_engineers_group>s group for a review.
%<changed_files>s
@ -13,6 +13,8 @@ UPDATE_METRICS_DEFINITIONS_MESSAGE = <<~MSG
MSG
TELEMETRY_ENGINEERS_GROUP = '@gitlab-org/growth/telemetry/engineers'
tracking_files = [
'lib/gitlab/tracking.rb',
'spec/lib/gitlab/tracking_spec.rb',
@ -28,7 +30,14 @@ snowplow_events_changed_files = git.modified_files & tracking_files
changed_files = (usage_data_changed_files + snowplow_events_changed_files)
if changed_files.any?
warn format(TELEMETRY_CHANGED_FILES_MESSAGE, changed_files: helper.markdown_list(changed_files))
mention = if helper.draft_mr?
"`#{TELEMETRY_ENGINEERS_GROUP}`"
else
TELEMETRY_ENGINEERS_GROUP
end
warn format(TELEMETRY_CHANGED_FILES_MESSAGE, changed_files: helper.markdown_list(changed_files), telemetry_engineers_group: mention)
warn format(UPDATE_METRICS_DEFINITIONS_MESSAGE) unless helper.changed_files(/usage_ping\.md/).any?
telemetry_labels = ['telemetry']

View file

@ -85,9 +85,7 @@ The ReactiveCaching concern can be used in models as well as `project_services`
1. Implement the `calculate_reactive_cache` method in your model/service.
1. Call `with_reactive_cache` in your model/service where the cached value is needed.
1. If the `calculate_reactive_cache` method above submits requests to external services
(e.g. Prometheus, K8s), make sure to change the
[`reactive_cache_work_type` accordingly](#selfreactive_cache_work_type).
1. Set the [`reactive_cache_work_type` accordingly](#selfreactive_cache_work_type).
### In controllers
@ -252,7 +250,7 @@ self.reactive_cache_hard_limit = 5.megabytes
- This is the type of work performed by the `calculate_reactive_cache` method. Based on this attribute,
it's able to pick the right worker to process the caching job. Make sure to
set it as `:external_dependency` if the work performs any external request
(e.g. Kubernetes, Sentry).
(e.g. Kubernetes, Sentry); otherwise set it to `:no_dependency`.
#### `self.reactive_cache_worker_finder`

View file

@ -157,6 +157,11 @@ PREFIX=/usr sudo -E make install
After installation, be sure to [enable Elasticsearch](#enabling-elasticsearch).
NOTE: **Note:**
If you see an error such as `Permission denied - /home/git/gitlab-elasticsearch-indexer/` while indexing, you
may need to set the `production -> elasticsearch -> indexer_path` setting in your `gitlab.yml` file to
`/usr/local/bin/gitlab-elasticsearch-indexer`, which is where the binary is installed.
## Enabling Elasticsearch
NOTE: **Note:**
@ -725,13 +730,11 @@ Here are some common pitfalls and how to overcome them:
newer versions of Elasticsearch. When indexing changes are made, it may
be necessary for you to [reindex](#zero-downtime-reindexing) after updating GitLab.
- **I indexed all the repositories but I can't find anything**
- **I indexed all the repositories but I can't get any hits for my search term in the UI**
Make sure you indexed all the database data [as stated above](#enabling-elasticsearch).
Beyond that, check via the [Elasticsearch Search API](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html) to see if the data shows up on the Elasticsearch side.
If it shows up via the [Elasticsearch Search API](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html), check that it shows up via the rails console (`sudo gitlab-rails console`):
If there aren't any results (hits) in the UI search, check if you are seeing the same results via the rails console (`sudo gitlab-rails console`):
```ruby
u = User.find_by_username('your-username')
@ -739,6 +742,16 @@ Here are some common pitfalls and how to overcome them:
pp s.search_objects.to_a
```
Beyond that, check via the [Elasticsearch Search API](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html) to see if the data shows up on the Elasticsearch side:
```shell
curl --request GET <elasticsearch_server_ip>:9200/gitlab-production/_search?q=<search_term>
```
More [complex Elasticsearch API calls](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html) are also possible.
It is important to understand at which level the problem is manifesting (UI, Rails code, Elasticsearch side) to be able to [troubleshoot further](../administration/troubleshooting/elasticsearch.md#search-results-workflow).
NOTE: **Note:**
The above instructions are not to be used for scenarios that only index a [subset of namespaces](#limiting-namespaces-and-projects).

View file

@ -1,46 +0,0 @@
# frozen_string_literal: true
module Gitlab
module AlertManagement
class AlertParams
MONITORING_TOOLS = {
prometheus: 'Prometheus'
}.freeze
def self.from_generic_alert(project:, payload:)
parsed_payload = Gitlab::Alerting::NotificationPayloadParser.call(payload, project).with_indifferent_access
annotations = parsed_payload[:annotations]
{
project_id: project.id,
title: annotations[:title],
description: annotations[:description],
monitoring_tool: annotations[:monitoring_tool],
service: annotations[:service],
hosts: Array(annotations[:hosts]),
payload: payload,
started_at: parsed_payload['startsAt'],
ended_at: parsed_payload['endsAt'],
severity: annotations[:severity],
fingerprint: annotations[:fingerprint],
environment: annotations[:environment]
}
end
def self.from_prometheus_alert(project:, parsed_alert:)
{
project_id: project.id,
title: parsed_alert.title,
description: parsed_alert.description,
monitoring_tool: MONITORING_TOOLS[:prometheus],
payload: parsed_alert.payload,
started_at: parsed_alert.starts_at,
ended_at: parsed_alert.ends_at,
fingerprint: parsed_alert.gitlab_fingerprint,
environment: parsed_alert.environment,
prometheus_alert: parsed_alert.gitlab_alert
}
end
end
end
end

View file

@ -8,6 +8,8 @@ module Gitlab
DEFAULT_TITLE = 'New: Incident'
DEFAULT_SEVERITY = 'critical'
attribute :description, paths: 'description'
attribute :ends_at, paths: 'end_time', type: :time
attribute :environment_name, paths: 'gitlab_environment_name'
attribute :hosts, paths: 'hosts'
attribute :monitoring_tool, paths: 'monitoring_tool'
@ -23,3 +25,5 @@ module Gitlab
end
end
end
Gitlab::AlertManagement::Payload::Generic.prepend_if_ee('EE::Gitlab::AlertManagement::Payload::Generic')

View file

@ -1,215 +0,0 @@
# frozen_string_literal: true
module Gitlab
module Alerting
class Alert
include ActiveModel::Model
include Gitlab::Utils::StrongMemoize
include Presentable
attr_accessor :project, :payload, :am_alert
def self.for_alert_management_alert(project:, alert:)
params = if alert.prometheus?
alert.payload
else
Gitlab::Alerting::NotificationPayloadParser.call(alert.payload.to_h, alert.project)
end
self.new(project: project, payload: params, am_alert: alert)
end
def gitlab_alert
strong_memoize(:gitlab_alert) do
parse_gitlab_alert_from_payload
end
end
def metric_id
strong_memoize(:metric_id) do
payload&.dig('labels', 'gitlab_alert_id')
end
end
def gitlab_prometheus_alert_id
strong_memoize(:gitlab_prometheus_alert_id) do
payload&.dig('labels', 'gitlab_prometheus_alert_id')
end
end
def title
strong_memoize(:title) do
gitlab_alert&.title || parse_title_from_payload
end
end
def description
strong_memoize(:description) do
parse_description_from_payload
end
end
def environment
strong_memoize(:environment) do
gitlab_alert&.environment || parse_environment_from_payload
end
end
def annotations
strong_memoize(:annotations) do
parse_annotations_from_payload || []
end
end
def starts_at
strong_memoize(:starts_at) do
parse_datetime_from_payload('startsAt')
end
end
def starts_at_raw
strong_memoize(:starts_at_raw) do
payload&.dig('startsAt')
end
end
def ends_at
strong_memoize(:ends_at) do
parse_datetime_from_payload('endsAt')
end
end
def full_query
strong_memoize(:full_query) do
gitlab_alert&.full_query || parse_expr_from_payload
end
end
def y_label
strong_memoize(:y_label) do
parse_y_label_from_payload || title
end
end
def alert_markdown
strong_memoize(:alert_markdown) do
parse_alert_markdown_from_payload
end
end
def status
strong_memoize(:status) do
payload&.dig('status')
end
end
def firing?
status == 'firing'
end
def resolved?
status == 'resolved'
end
def gitlab_managed?
metric_id.present?
end
def gitlab_fingerprint
Gitlab::AlertManagement::Fingerprint.generate(plain_gitlab_fingerprint)
end
def valid?
payload.respond_to?(:dig) && project && title && starts_at
end
def present
super(presenter_class: Projects::Prometheus::AlertPresenter)
end
private
def plain_gitlab_fingerprint
if gitlab_managed?
[metric_id, starts_at_raw].join('/')
else # self managed
[starts_at_raw, title, full_query].join('/')
end
end
def parse_environment_from_payload
environment_name = payload&.dig('labels', 'gitlab_environment_name')
return unless environment_name
EnvironmentsFinder.new(project, nil, { name: environment_name })
.find
&.first
end
def parse_gitlab_alert_from_payload
alerts_found = matching_gitlab_alerts
return if alerts_found.blank? || alerts_found.size > 1
alerts_found.first
end
def matching_gitlab_alerts
return unless metric_id || gitlab_prometheus_alert_id
Projects::Prometheus::AlertsFinder
.new(project: project, metric: metric_id, id: gitlab_prometheus_alert_id)
.execute
end
def parse_title_from_payload
payload&.dig('annotations', 'title') ||
payload&.dig('annotations', 'summary') ||
payload&.dig('labels', 'alertname')
end
def parse_description_from_payload
payload&.dig('annotations', 'description')
end
def parse_annotations_from_payload
payload&.dig('annotations')&.map do |label, value|
Alerting::AlertAnnotation.new(label: label, value: value)
end
end
def parse_datetime_from_payload(field)
value = payload&.dig(field)
return unless value
# value is a rfc3339 timestamp
# Timestamps from Prometheus and Alertmanager are UTC RFC3339 timestamps like: '2018-03-12T09:06:00Z' (Z represents 0 offset or UTC)
# .utc sets the datetime zone to `UTC`
Time.rfc3339(value).utc
rescue ArgumentError
end
# Parses `g0.expr` from `generatorURL`.
#
# Example: http://localhost:9090/graph?g0.expr=vector%281%29&g0.tab=1
def parse_expr_from_payload
url = payload&.dig('generatorURL')
return unless url
uri = URI(url)
Rack::Utils.parse_query(uri.query).fetch('g0.expr')
rescue URI::InvalidURIError, KeyError
end
def parse_alert_markdown_from_payload
payload&.dig('annotations', 'gitlab_incident_markdown')
end
def parse_y_label_from_payload
payload&.dig('annotations', 'gitlab_y_label')
end
end
end
end

View file

@ -214,6 +214,12 @@ module Gitlab
title.gsub(DRAFT_REGEX, '').gsub(/`/, '\\\`')
end
def draft_mr?
return false unless gitlab_helper
DRAFT_REGEX.match?(gitlab_helper.mr_json['title'])
end
def security_mr?
return false unless gitlab_helper

View file

@ -145,11 +145,11 @@
"url-loader": "^3.0.0",
"uuid": "8.1.0",
"visibilityjs": "^1.2.4",
"vue": "^2.6.10",
"vue": "^2.6.12",
"vue-apollo": "^3.0.3",
"vue-loader": "^15.9.0",
"vue-loader": "^15.9.3",
"vue-router": "^3.4.3",
"vue-template-compiler": "^2.6.10",
"vue-template-compiler": "^2.6.12",
"vue-virtual-scroll-list": "^1.4.4",
"vuedraggable": "^2.23.0",
"vuex": "^3.5.1",

View file

@ -2,7 +2,7 @@
export SETUP_DB=${SETUP_DB:-true}
export USE_BUNDLE_INSTALL=${USE_BUNDLE_INSTALL:-true}
export BUNDLE_INSTALL_FLAGS=${BUNDLE_INSTALL_FLAGS:-"--without=production --without=development --jobs=$(nproc) --path=vendor --retry=3 --quiet"}
export BUNDLE_INSTALL_FLAGS=${BUNDLE_INSTALL_FLAGS:-"--without=production development --jobs=$(nproc) --path=vendor --retry=3 --quiet"}
if [ "$USE_BUNDLE_INSTALL" != "false" ]; then
bundle --version
@ -14,10 +14,6 @@ if [ "$USE_BUNDLE_INSTALL" != "false" ]; then
run_timed_command "bundle pristine pg"
fi
# Only install knapsack after bundle install! Otherwise oddly some native
# gems could not be found under some circumstance. No idea why, hours wasted.
run_timed_command "gem install knapsack --no-document"
cp config/gitlab.yml.example config/gitlab.yml
sed -i 's/bin_path: \/usr\/bin\/git/bin_path: \/usr\/local\/bin\/git/' config/gitlab.yml

View file

@ -12,7 +12,6 @@ RSpec.describe Projects::Import::JiraController do
def ensure_correct_config
sign_in(user)
project.add_maintainer(user)
stub_feature_flags(jira_issue_import: true)
stub_jira_service_test
end
@ -77,7 +76,6 @@ RSpec.describe Projects::Import::JiraController do
before do
sign_in(user)
project.add_maintainer(user)
stub_feature_flags(jira_issue_import: true)
end
context 'when Jira service is not enabled for the project' do

View file

@ -100,7 +100,7 @@ FactoryBot.define do
end
trait :prometheus do
monitoring_tool { Gitlab::AlertManagement::AlertParams::MONITORING_TOOLS[:prometheus] }
monitoring_tool { Gitlab::AlertManagement::Payload::MONITORING_TOOLS[:prometheus] }
payload do
{
annotations: {
@ -123,5 +123,17 @@ FactoryBot.define do
with_description
low
end
trait :from_payload do
after(:build) do |alert|
alert_params = ::Gitlab::AlertManagement::Payload.parse(
alert.project,
alert.payload,
monitoring_tool: alert.monitoring_tool
).alert_params
alert.assign_attributes(alert_params)
end
end
end
end

View file

@ -1,25 +0,0 @@
# frozen_string_literal: true
FactoryBot.define do
factory :alerting_alert, class: 'Gitlab::Alerting::Alert' do
project
payload { {} }
transient do
metric_id { nil }
after(:build) do |alert, evaluator|
unless alert.payload.key?('startsAt')
alert.payload['startsAt'] = Time.now.rfc3339
end
if metric_id = evaluator.metric_id
alert.payload['labels'] ||= {}
alert.payload['labels']['gitlab_alert_id'] = metric_id.to_s
end
end
end
skip_create
end
end

View file

@ -51,27 +51,6 @@ exports[`packages_list_row renders 1`] = `
<!---->
<div
class="gl-display-flex gl-align-items-center"
>
<gl-icon-stub
class="gl-ml-3 gl-mr-2 gl-min-w-0"
name="review-list"
size="16"
/>
<gl-link-stub
class="gl-text-body gl-min-w-0"
data-testid="packages-row-project"
href="/foo/bar/baz"
>
<gl-truncate-stub
position="end"
text="foo/bar/baz"
/>
</gl-link-stub>
</div>
<div
class="d-flex align-items-center"
data-testid="package-type"
@ -86,6 +65,10 @@ exports[`packages_list_row renders 1`] = `
Maven
</span>
</div>
<package-path-stub
path="foo/bar/baz"
/>
</div>
</div>
</div>

View file

@ -1,6 +1,7 @@
import { shallowMount } from '@vue/test-utils';
import PackagesListRow from '~/packages/shared/components/package_list_row.vue';
import PackageTags from '~/packages/shared/components/package_tags.vue';
import PackagePath from '~/packages/shared/components/package_path.vue';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
import { packageList } from '../../mock_data';
@ -11,7 +12,7 @@ describe('packages_list_row', () => {
const [packageWithoutTags, packageWithTags] = packageList;
const findPackageTags = () => wrapper.find(PackageTags);
const findProjectLink = () => wrapper.find('[data-testid="packages-row-project"]');
const findPackagePath = () => wrapper.find(PackagePath);
const findDeleteButton = () => wrapper.find('[data-testid="action-delete"]');
const findPackageType = () => wrapper.find('[data-testid="package-type"]');
@ -63,8 +64,9 @@ describe('packages_list_row', () => {
mountComponent({ isGroup: true });
});
it('has project field', () => {
expect(findProjectLink().exists()).toBe(true);
it('has a package path component', () => {
expect(findPackagePath().exists()).toBe(true);
expect(findPackagePath().props()).toMatchObject({ path: 'foo/bar/baz' });
});
});

View file

@ -0,0 +1,86 @@
import { shallowMount } from '@vue/test-utils';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import PackagePath from '~/packages/shared/components/package_path.vue';
describe('PackagePath', () => {
let wrapper;
const mountComponent = (propsData = { path: 'foo' }) => {
wrapper = shallowMount(PackagePath, {
propsData,
directives: {
GlTooltip: createMockDirective(),
},
});
};
const BASE_ICON = 'base-icon';
const ROOT_LINK = 'root-link';
const ROOT_CHEVRON = 'root-chevron';
const ELLIPSIS_ICON = 'ellipsis-icon';
const ELLIPSIS_CHEVRON = 'ellipsis-chevron';
const LEAF_LINK = 'leaf-link';
const findItem = name => wrapper.find(`[data-testid="${name}"]`);
const findTooltip = w => getBinding(w.element, 'gl-tooltip');
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
describe.each`
path | rootUrl | shouldExist | shouldNotExist
${'foo/bar'} | ${'/foo/bar'} | ${[]} | ${[ROOT_CHEVRON, ELLIPSIS_ICON, ELLIPSIS_CHEVRON, LEAF_LINK]}
${'foo/bar/baz'} | ${'/foo/bar'} | ${[ROOT_CHEVRON, LEAF_LINK]} | ${[ELLIPSIS_ICON, ELLIPSIS_CHEVRON]}
${'foo/bar/baz/baz2'} | ${'/foo/bar'} | ${[ROOT_CHEVRON, LEAF_LINK, ELLIPSIS_ICON, ELLIPSIS_CHEVRON]} | ${[]}
${'foo/bar/baz/baz2/bar2'} | ${'/foo/bar'} | ${[ROOT_CHEVRON, LEAF_LINK, ELLIPSIS_ICON, ELLIPSIS_CHEVRON]} | ${[]}
`('given path $path', ({ path, shouldExist, shouldNotExist, rootUrl }) => {
const pathPieces = path.split('/').slice(1);
const hasTooltip = shouldExist.includes(ELLIPSIS_ICON);
beforeEach(() => {
mountComponent({ path });
});
it('should have a base icon', () => {
expect(findItem(BASE_ICON).exists()).toBe(true);
});
it('should have a root link', () => {
const root = findItem(ROOT_LINK);
expect(root.exists()).toBe(true);
expect(root.attributes('href')).toBe(rootUrl);
});
if (hasTooltip) {
it('should have a tooltip', () => {
const tooltip = findTooltip(findItem(ELLIPSIS_ICON));
expect(tooltip).toBeDefined();
expect(tooltip.value).toMatchObject({
title: path,
});
});
}
if (shouldExist.length) {
it.each(shouldExist)(`should have %s`, element => {
expect(findItem(element).exists()).toBe(true);
});
}
if (shouldNotExist.length) {
it.each(shouldNotExist)(`should not have %s`, element => {
expect(findItem(element).exists()).toBe(false);
});
}
if (shouldExist.includes(LEAF_LINK)) {
it('the last link should be the last piece of the path', () => {
const leaf = findItem(LEAF_LINK);
expect(leaf.attributes('href')).toBe(`/${path}`);
expect(leaf.text()).toBe(pathPieces[pathPieces.length - 1]);
});
}
});
});

View file

@ -1,101 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::AlertManagement::AlertParams do
let_it_be(:project) { create(:project, :repository, :private) }
describe '.from_generic_alert' do
let(:started_at) { Time.current.change(usec: 0).rfc3339 }
let(:default_payload) do
{
'title' => 'Alert title',
'description' => 'Description',
'monitoring_tool' => 'Monitoring tool name',
'service' => 'Service',
'hosts' => ['gitlab.com'],
'start_time' => started_at,
'some' => { 'extra' => { 'payload' => 'here' } }
}
end
let(:payload) { default_payload }
subject { described_class.from_generic_alert(project: project, payload: payload) }
it 'returns Alert compatible parameters' do
is_expected.to eq(
project_id: project.id,
title: 'Alert title',
description: 'Description',
monitoring_tool: 'Monitoring tool name',
service: 'Service',
severity: 'critical',
hosts: ['gitlab.com'],
payload: payload,
started_at: started_at,
ended_at: nil,
fingerprint: nil,
environment: nil
)
end
context 'when severity given' do
let(:payload) { default_payload.merge(severity: 'low') }
it 'returns Alert compatible parameters' do
expect(subject[:severity]).to eq('low')
end
end
context 'when there are no hosts in the payload' do
let(:payload) { {} }
it 'hosts param is an empty array' do
expect(subject[:hosts]).to be_empty
end
end
end
describe '.from_prometheus_alert' do
let(:payload) do
{
'status' => 'firing',
'labels' => {
'alertname' => 'GitalyFileServerDown',
'channel' => 'gitaly',
'pager' => 'pagerduty',
'severity' => 's1'
},
'annotations' => {
'description' => 'Alert description',
'runbook' => 'troubleshooting/gitaly-down.md',
'title' => 'Alert title'
},
'startsAt' => '2020-04-27T10:10:22.265949279Z',
'endsAt' => '0001-01-01T00:00:00Z',
'generatorURL' => 'http://8d467bd4607a:9090/graph?g0.expr=vector%281%29&g0.tab=1',
'fingerprint' => 'b6ac4d42057c43c1'
}
end
let(:parsed_alert) { Gitlab::Alerting::Alert.new(project: project, payload: payload) }
subject { described_class.from_prometheus_alert(project: project, parsed_alert: parsed_alert) }
it 'returns Alert-compatible params' do
is_expected.to eq(
project_id: project.id,
title: 'Alert title',
description: 'Alert description',
monitoring_tool: 'Prometheus',
payload: payload,
started_at: parsed_alert.starts_at,
ended_at: parsed_alert.ends_at,
fingerprint: parsed_alert.gitlab_fingerprint,
environment: parsed_alert.environment,
prometheus_alert: parsed_alert.gitlab_alert
)
end
end
end

View file

@ -86,4 +86,34 @@ RSpec.describe Gitlab::AlertManagement::Payload::Generic do
it_behaves_like 'parsable alert payload field', 'gitlab_environment_name'
end
describe '#description' do
subject { parsed_payload.description }
it_behaves_like 'parsable alert payload field', 'description'
end
describe '#ends_at' do
let(:current_time) { Time.current.change(usec: 0).utc }
subject { parsed_payload.ends_at }
around do |example|
Timecop.freeze(current_time) { example.run }
end
context 'without end_time' do
it { is_expected.to be_nil }
end
context "with end_time" do
let(:value) { 10.minutes.ago.change(usec: 0).utc }
before do
raw_payload['end_time'] = value.to_s
end
it { is_expected.to eq(value) }
end
end
end

View file

@ -1,299 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Alerting::Alert do
let_it_be(:project) { create(:project) }
let(:alert) { build(:alerting_alert, project: project, payload: payload) }
let(:payload) { {} }
shared_context 'gitlab alert' do
let!(:gitlab_alert) { create(:prometheus_alert, project: project) }
let(:gitlab_alert_id) { gitlab_alert.id }
before do
payload['labels'] = {
'gitlab_alert_id' => gitlab_alert.prometheus_metric_id.to_s,
'gitlab_prometheus_alert_id' => gitlab_alert_id
}
end
end
shared_context 'full query' do
before do
payload['generatorURL'] = 'http://localhost:9090/graph?g0.expr=vector%281%29'
end
end
shared_examples 'invalid alert' do
it 'is invalid' do
expect(alert).not_to be_valid
end
end
shared_examples 'parse payload' do |*pairs|
context 'without payload' do
it { is_expected.to be_nil }
end
pairs.each do |pair|
context "with #{pair}" do
let(:value) { 'some value' }
before do
section, name = pair.split('/')
payload[section] = { name => value }
end
it { is_expected.to eq(value) }
end
end
end
describe '#gitlab_alert' do
subject { alert.gitlab_alert }
context 'without payload' do
it { is_expected.to be_nil }
end
context 'with gitlab alert' do
include_context 'gitlab alert'
it { is_expected.to eq(gitlab_alert) }
end
context 'with unknown gitlab alert' do
include_context 'gitlab alert' do
let(:gitlab_alert_id) { 'unknown' }
end
it { is_expected.to be_nil }
end
context 'when two alerts with the same metric exist' do
include_context 'gitlab alert'
let!(:second_gitlab_alert) do
create(:prometheus_alert,
project: project,
prometheus_metric_id: gitlab_alert.prometheus_metric_id
)
end
context 'alert id given in params' do
before do
payload['labels'] = {
'gitlab_alert_id' => gitlab_alert.prometheus_metric_id.to_s,
'gitlab_prometheus_alert_id' => second_gitlab_alert.id
}
end
it { is_expected.to eq(second_gitlab_alert) }
end
context 'metric id given in params' do
# This tests the case when two alerts are found, as metric id
# is not unique.
# Note the metric id was incorrectly named as 'gitlab_alert_id'
# in PrometheusAlert#to_param.
before do
payload['labels'] = { 'gitlab_alert_id' => gitlab_alert.prometheus_metric_id }
end
it { is_expected.to be_nil }
end
end
end
describe '#title' do
subject { alert.title }
it_behaves_like 'parse payload',
'annotations/title',
'annotations/summary',
'labels/alertname'
context 'with gitlab alert' do
include_context 'gitlab alert'
context 'with annotations/title' do
let(:value) { 'annotation title' }
before do
payload['annotations'] = { 'title' => value }
end
it { is_expected.to eq(gitlab_alert.title) }
end
end
end
describe '#description' do
subject { alert.description }
it_behaves_like 'parse payload', 'annotations/description'
end
describe '#annotations' do
subject { alert.annotations }
context 'without payload' do
it { is_expected.to eq([]) }
end
context 'with payload' do
before do
payload['annotations'] = { 'foo' => 'value1', 'bar' => 'value2' }
end
it 'parses annotations' do
expect(subject.size).to eq(2)
expect(subject.map(&:label)).to eq(%w[foo bar])
expect(subject.map(&:value)).to eq(%w[value1 value2])
end
end
end
describe '#environment' do
subject { alert.environment }
context 'without gitlab_alert' do
it { is_expected.to be_nil }
end
context 'with gitlab alert' do
include_context 'gitlab alert'
it { is_expected.to eq(gitlab_alert.environment) }
end
end
describe '#starts_at' do
subject { alert.starts_at }
context 'with empty startsAt' do
before do
payload['startsAt'] = nil
end
it { is_expected.to be_nil }
end
context 'with invalid startsAt' do
before do
payload['startsAt'] = 'invalid'
end
it { is_expected.to be_nil }
end
context 'with payload' do
let(:time) { Time.current.change(usec: 0) }
before do
payload['startsAt'] = time.rfc3339
end
it { is_expected.to eq(time) }
end
end
describe '#full_query' do
using RSpec::Parameterized::TableSyntax
subject { alert.full_query }
where(:generator_url, :expected_query) do
nil | nil
'http://localhost' | nil
'invalid url' | nil
'http://localhost:9090/graph?g1.expr=vector%281%29' | nil
'http://localhost:9090/graph?g0.expr=vector%281%29' | 'vector(1)'
end
with_them do
before do
payload['generatorURL'] = generator_url
end
it { is_expected.to eq(expected_query) }
end
context 'with gitlab alert' do
include_context 'gitlab alert'
include_context 'full query'
it { is_expected.to eq(gitlab_alert.full_query) }
end
end
describe '#y_label' do
subject { alert.y_label }
it_behaves_like 'parse payload', 'annotations/gitlab_y_label'
context 'when y_label is not included in the payload' do
it_behaves_like 'parse payload', 'annotations/title'
end
end
describe '#alert_markdown' do
subject { alert.alert_markdown }
it_behaves_like 'parse payload', 'annotations/gitlab_incident_markdown'
end
describe '#gitlab_fingerprint' do
subject { alert.gitlab_fingerprint }
context 'when the alert is a GitLab managed alert' do
include_context 'gitlab alert'
it 'returns a fingerprint' do
plain_fingerprint = [alert.metric_id, alert.starts_at_raw].join('/')
is_expected.to eq(Digest::SHA1.hexdigest(plain_fingerprint))
end
end
context 'when the alert is from self managed Prometheus' do
include_context 'full query'
it 'returns a fingerprint' do
plain_fingerprint = [alert.starts_at_raw, alert.title, alert.full_query].join('/')
is_expected.to eq(Digest::SHA1.hexdigest(plain_fingerprint))
end
end
end
describe '#valid?' do
before do
payload.update(
'annotations' => { 'title' => 'some title' },
'startsAt' => Time.current.rfc3339
)
end
subject { alert }
it { is_expected.to be_valid }
context 'without project' do
let(:project) { nil }
it { is_expected.not_to be_valid }
end
context 'without starts_at' do
before do
payload['startsAt'] = nil
end
it { is_expected.not_to be_valid }
end
end
end

View file

@ -435,6 +435,28 @@ RSpec.describe Gitlab::Danger::Helper do
end
end
describe '#draft_mr?' do
it 'returns false when `gitlab_helper` is unavailable' do
expect(helper).to receive(:gitlab_helper).and_return(nil)
expect(helper).not_to be_draft_mr
end
it 'returns true for a draft MR' do
expect(fake_gitlab).to receive(:mr_json)
.and_return('title' => 'Draft: My MR title')
expect(helper).to be_draft_mr
end
it 'returns false for non draft MR' do
expect(fake_gitlab).to receive(:mr_json)
.and_return('title' => 'My MR title')
expect(helper).not_to be_draft_mr
end
end
describe '#cherry_pick_mr?' do
it 'returns false when `gitlab_helper` is unavailable' do
expect(helper).to receive(:gitlab_helper).and_return(nil)

View file

@ -30,35 +30,104 @@ RSpec.describe Emails::Projects do
let_it_be(:user) { create(:user) }
describe '#prometheus_alert_fired_email' do
let(:default_title) { Gitlab::AlertManagement::Payload::Generic::DEFAULT_TITLE }
let(:payload) { { 'startsAt' => Time.now.rfc3339 } }
let(:alert_attributes) { build(:alert_management_alert, :from_payload, payload: payload, project: project).attributes }
subject do
Notify.prometheus_alert_fired_email(project.id, user.id, alert_params)
Notify.prometheus_alert_fired_email(project.id, user.id, alert_attributes)
end
let(:alert_params) do
{ 'startsAt' => Time.now.rfc3339 }
context 'missing required attributes' do
let(:alert_attributes) { build(:alert_management_alert, :prometheus, :from_payload, payload: payload, project: project).attributes }
it_behaves_like 'no email'
end
context 'with a gitlab alert' do
before do
alert_params['labels'] = { 'gitlab_alert_id' => alert.prometheus_metric_id.to_s }
end
let(:title) do
"#{alert.title} #{alert.computed_operator} #{alert.threshold}"
end
let(:metrics_url) do
metrics_project_environment_url(project, environment)
end
let(:environment) { alert.environment }
let!(:alert) { create(:prometheus_alert, project: project) }
context 'with minimum required attributes' do
let(:payload) { {} }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like 'a user cannot unsubscribe through footer link'
it 'has expected subject' do
is_expected.to have_subject("#{project.name} | Alert: #{default_title}")
end
it 'has expected content' do
is_expected.to have_body_text('An alert has been triggered')
is_expected.to have_body_text(project.full_path)
is_expected.not_to have_body_text('Description:')
is_expected.not_to have_body_text('Environment:')
is_expected.not_to have_body_text('Metric:')
end
end
context 'with description' do
let(:payload) { { 'description' => 'alert description' } }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like 'a user cannot unsubscribe through footer link'
it 'has expected subject' do
is_expected.to have_subject("#{project.name} | Alert: #{default_title}")
end
it 'has expected content' do
is_expected.to have_body_text('An alert has been triggered')
is_expected.to have_body_text(project.full_path)
is_expected.to have_body_text('Description:')
is_expected.to have_body_text('alert description')
is_expected.not_to have_body_text('Environment:')
is_expected.not_to have_body_text('Metric:')
end
end
context 'with environment' do
let_it_be(:environment) { create(:environment, project: project) }
let(:payload) { { 'gitlab_environment_name' => environment.name } }
let(:metrics_url) { metrics_project_environment_url(project, environment) }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like 'a user cannot unsubscribe through footer link'
it 'has expected subject' do
is_expected.to have_subject("#{project.name} | Alert: #{environment.name}: #{default_title}")
end
it 'has expected content' do
is_expected.to have_body_text('An alert has been triggered')
is_expected.to have_body_text(project.full_path)
is_expected.to have_body_text('Environment:')
is_expected.to have_body_text(environment.name)
is_expected.not_to have_body_text('Description:')
is_expected.not_to have_body_text('Metric:')
end
end
context 'with gitlab alerting rule' do
let_it_be(:prometheus_alert) { create(:prometheus_alert, project: project) }
let_it_be(:environment) { prometheus_alert.environment }
let(:alert_attributes) { build(:alert_management_alert, :prometheus, :from_payload, payload: payload, project: project).attributes }
let(:title) { "#{prometheus_alert.title} #{prometheus_alert.computed_operator} #{prometheus_alert.threshold}" }
let(:metrics_url) { metrics_project_environment_url(project, environment) }
before do
payload['labels'] = {
'gitlab_alert_id' => prometheus_alert.prometheus_metric_id,
'alertname' => prometheus_alert.title
}
end
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like 'a user cannot unsubscribe through footer link'
it_behaves_like 'shows the incident issues url'
it 'has expected subject' do
is_expected.to have_subject("#{project.name} | Alert: #{environment.name}: #{title} for 5 minutes")
end
@ -69,68 +138,10 @@ RSpec.describe Emails::Projects do
is_expected.to have_body_text('Environment:')
is_expected.to have_body_text(environment.name)
is_expected.to have_body_text('Metric:')
is_expected.to have_body_text(alert.full_query)
is_expected.to have_body_text(prometheus_alert.full_query)
is_expected.to have_body_text(metrics_url)
end
it_behaves_like 'shows the incident issues url'
end
context 'with no payload' do
let(:alert_params) { {} }
it_behaves_like 'no email'
end
context 'with an unknown alert' do
before do
alert_params['labels'] = { 'gitlab_alert_id' => 'unknown' }
end
it_behaves_like 'no email'
end
context 'with an external alert' do
let(:title) { 'alert title' }
let(:metrics_url) do
metrics_project_environments_url(project)
end
before do
alert_params['annotations'] = { 'title' => title }
alert_params['generatorURL'] = 'http://localhost:9090/graph?g0.expr=vector%281%29&g0.tab=1'
end
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like 'a user cannot unsubscribe through footer link'
it 'has expected subject' do
is_expected.to have_subject("#{project.name} | Alert: #{title}")
end
it 'has expected content' do
is_expected.to have_body_text('An alert has been triggered')
is_expected.to have_body_text(project.full_path)
is_expected.not_to have_body_text('Description:')
is_expected.not_to have_body_text('Environment:')
end
context 'with annotated description' do
let(:description) { 'description' }
before do
alert_params['annotations']['description'] = description
end
it 'shows the description' do
is_expected.to have_body_text('Description:')
is_expected.to have_body_text(description)
end
end
it_behaves_like 'shows the incident issues url'
end
end
end

View file

@ -824,7 +824,7 @@ RSpec.describe Issuable do
where(:issuable_type, :supports_time_tracking) do
:issue | true
:incident | false
:incident | true
:merge_request | true
end

View file

@ -14,6 +14,7 @@ RSpec.describe ReactiveCaching, :use_clean_rails_memory_store_caching do
self.reactive_cache_lifetime = 5.minutes
self.reactive_cache_refresh_interval = 15.seconds
self.reactive_cache_work_type = :no_dependency
attr_reader :id
@ -372,4 +373,14 @@ RSpec.describe ReactiveCaching, :use_clean_rails_memory_store_caching do
it { expect(subject.reactive_cache_hard_limit).to be_nil }
it { expect(subject.reactive_cache_worker_finder).to respond_to(:call) }
end
describe 'classes including this concern' do
it 'sets reactive_cache_work_type' do
classes = ObjectSpace.each_object(Class).select do |klass|
klass < described_class && klass.name
end
expect(classes).to all(have_attributes(reactive_cache_work_type: be_in(described_class::WORK_TYPE.keys)))
end
end
end

View file

@ -1,346 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Projects::Prometheus::AlertPresenter do
include Gitlab::Routing.url_helpers
let_it_be(:project, reload: true) { create(:project) }
let(:presenter) { described_class.new(alert) }
let(:payload) { {} }
let(:alert) { create(:alerting_alert, project: project, payload: payload) }
shared_context 'gitlab alert' do
let(:gitlab_alert) { create(:prometheus_alert, project: project) }
let(:metric_id) { gitlab_alert.prometheus_metric_id }
let(:alert) do
create(:alerting_alert, project: project, metric_id: metric_id, payload: payload)
end
end
describe '#project_full_path' do
subject { presenter.project_full_path }
it { is_expected.to eq(project.full_path) }
end
describe '#start_time' do
subject { presenter.start_time }
let(:starts_at) { '2020-10-31T14:02:04Z' }
before do
payload['startsAt'] = starts_at
end
context 'with valid utc datetime' do
it { is_expected.to eq('31 October 2020, 2:02PM (UTC)') }
context 'with admin time zone not UTC' do
before do
allow(Time).to receive(:zone).and_return(ActiveSupport::TimeZone.new('Perth'))
end
it { is_expected.to eq('31 October 2020, 2:02PM (UTC)') }
end
end
context 'with invalid datetime' do
let(:starts_at) { 'invalid' }
it { is_expected.to be_nil }
end
end
describe '#issue_summary_markdown' do
let(:markdown_line_break) { ' ' }
subject { presenter.issue_summary_markdown }
context 'without default payload' do
it do
is_expected.to eq(
<<~MARKDOWN.chomp
**Start time:** #{presenter.start_time}
MARKDOWN
)
end
end
context 'with optional attributes' do
before do
payload['annotations'] = {
'title' => 'Alert Title',
'foo' => 'value1',
'bar' => 'value2',
'description' => 'Alert Description',
'monitoring_tool' => 'monitoring_tool_name',
'service' => 'service_name',
'hosts' => ['http://localhost:3000', 'http://localhost:3001']
}
payload['generatorURL'] = 'http://host?g0.expr=query'
end
it do
is_expected.to eq(
<<~MARKDOWN.chomp
**Start time:** #{presenter.start_time}#{markdown_line_break}
**full_query:** `query`#{markdown_line_break}
**Service:** service_name#{markdown_line_break}
**Monitoring tool:** monitoring_tool_name#{markdown_line_break}
**Hosts:** http://localhost:3000 http://localhost:3001
MARKDOWN
)
end
end
context 'when hosts is a string' do
before do
payload['annotations'] = { 'hosts' => 'http://localhost:3000' }
end
it do
is_expected.to eq(
<<~MARKDOWN.chomp
**Start time:** #{presenter.start_time}#{markdown_line_break}
**Hosts:** http://localhost:3000
MARKDOWN
)
end
end
context 'with embedded metrics' do
let(:starts_at) { '2018-03-12T09:06:00Z' }
shared_examples_for 'markdown with metrics embed' do
let(:embed_regex) { /\n\[\]\(#{Regexp.quote(presenter.metrics_dashboard_url)}\)\z/ }
context 'without a starting time available' do
around do |example|
Timecop.freeze(starts_at) { example.run }
end
before do
payload.delete('startsAt')
end
it { is_expected.to match(embed_regex) }
end
context 'with a starting time available' do
it { is_expected.to match(embed_regex) }
end
end
context 'for gitlab-managed prometheus alerts' do
include_context 'gitlab-managed prometheus alert attributes'
let(:alert) do
create(:alerting_alert, project: project, metric_id: prometheus_metric_id, payload: payload)
end
it_behaves_like 'markdown with metrics embed'
end
context 'for alerts from a self-managed prometheus' do
include_context 'self-managed prometheus alert attributes'
it_behaves_like 'markdown with metrics embed'
context 'without y_label' do
let(:y_label) { title }
before do
payload['annotations'].delete('gitlab_y_label')
end
it_behaves_like 'markdown with metrics embed'
end
context 'when not enough information is present for an embed' do
shared_examples_for 'does not include an embed' do
it { is_expected.not_to match(/\[\]\(.+\)/) }
end
context 'without title' do
before do
payload['annotations'].delete('title')
end
it_behaves_like 'does not include an embed'
end
context 'without environment' do
before do
payload['labels'].delete('gitlab_environment_name')
end
it_behaves_like 'does not include an embed'
end
context 'without full_query' do
before do
payload.delete('generatorURL')
end
it_behaves_like 'does not include an embed'
end
end
end
end
end
describe '#show_performance_dashboard_link?' do
subject { presenter.show_performance_dashboard_link? }
it { is_expected.to be_falsey }
context 'with gitlab alert' do
include_context 'gitlab alert'
it { is_expected.to eq(true) }
end
end
describe '#show_incident_issues_link?' do
subject { presenter.show_incident_issues_link? }
it { is_expected.to be_falsey }
context 'create issue setting enabled' do
before do
create(:project_incident_management_setting, project: project, create_issue: true)
end
it { is_expected.to eq(true) }
end
end
describe '#details_url' do
subject { presenter.details_url }
it { is_expected.to eq(nil) }
context 'alert management alert present' do
let_it_be(:am_alert) { create(:alert_management_alert, project: project) }
let(:alert) { create(:alerting_alert, project: project, payload: payload, am_alert: am_alert) }
it { is_expected.to eq("http://localhost/#{project.full_path}/-/alert_management/#{am_alert.iid}/details") }
end
end
context 'with gitlab alert' do
include_context 'gitlab alert'
describe '#full_title' do
let(:query_title) do
"#{gitlab_alert.title} #{gitlab_alert.computed_operator} #{gitlab_alert.threshold} for 5 minutes"
end
let(:expected_subject) do
"#{alert.environment.name}: #{query_title}"
end
subject { presenter.full_title }
it { is_expected.to eq(expected_subject) }
end
describe '#metric_query' do
subject { presenter.metric_query }
it { is_expected.to eq(gitlab_alert.full_query) }
end
describe '#environment_name' do
subject { presenter.environment_name }
it { is_expected.to eq(alert.environment.name) }
end
describe '#performance_dashboard_link' do
let(:expected_link) { metrics_project_environment_url(project, alert.environment) }
subject { presenter.performance_dashboard_link }
it { is_expected.to eq(expected_link) }
end
describe '#incident_issues_link' do
let(:expected_link) { project_issues_url(project, label_name: described_class::INCIDENT_LABEL_NAME) }
subject { presenter.incident_issues_link }
it { is_expected.to eq(expected_link) }
end
end
context 'without gitlab alert' do
describe '#full_title' do
subject { presenter.full_title }
context 'with title' do
let(:title) { 'some title' }
before do
expect(alert).to receive(:title).and_return(title)
end
it { is_expected.to eq(title) }
end
context 'without title' do
it { is_expected.to eq('') }
end
end
describe '#metric_query' do
subject { presenter.metric_query }
it { is_expected.to be_nil }
end
describe '#environment_name' do
subject { presenter.environment_name }
it { is_expected.to be_nil }
end
describe '#performance_dashboard_link' do
let(:expected_link) { metrics_project_environments_url(project) }
subject { presenter.performance_dashboard_link }
it { is_expected.to eq(expected_link) }
end
end
describe '#metrics_dashboard_url' do
subject { presenter.metrics_dashboard_url }
context 'for a non-prometheus alert' do
it { is_expected.to be_nil }
end
context 'for a self-managed prometheus alert' do
include_context 'self-managed prometheus alert attributes'
let(:prometheus_payload) { payload }
it { is_expected.to eq(dashboard_url_for_alert) }
end
context 'for a gitlab-managed prometheus alert' do
include_context 'gitlab-managed prometheus alert attributes'
let(:prometheus_payload) { payload }
it { is_expected.to eq(dashboard_url_for_alert) }
end
end
end

View file

@ -3082,32 +3082,25 @@ RSpec.describe NotificationService, :mailer do
describe '#prometheus_alerts_fired' do
let!(:project) { create(:project) }
let!(:prometheus_alert) { create(:prometheus_alert, project: project) }
let!(:master) { create(:user) }
let!(:developer) { create(:user) }
let(:alert_attributes) { build(:alert_management_alert, project: project).attributes }
before do
project.add_maintainer(master)
end
it 'sends the email to owners and masters' do
expect(Notify).to receive(:prometheus_alert_fired_email).with(project.id, master.id, prometheus_alert).and_call_original
expect(Notify).to receive(:prometheus_alert_fired_email).with(project.id, project.owner.id, prometheus_alert).and_call_original
expect(Notify).not_to receive(:prometheus_alert_fired_email).with(project.id, developer.id, prometheus_alert)
expect(Notify).to receive(:prometheus_alert_fired_email).with(project.id, master.id, alert_attributes).and_call_original
expect(Notify).to receive(:prometheus_alert_fired_email).with(project.id, project.owner.id, alert_attributes).and_call_original
expect(Notify).not_to receive(:prometheus_alert_fired_email).with(project.id, developer.id, alert_attributes)
subject.prometheus_alerts_fired(prometheus_alert.project, [prometheus_alert])
subject.prometheus_alerts_fired(project, [alert_attributes])
end
it_behaves_like 'project emails are disabled' do
before do
allow_next_instance_of(::Gitlab::Alerting::Alert) do |instance|
allow(instance).to receive(:valid?).and_return(true)
end
end
let(:alert_params) { { 'labels' => { 'gitlab_alert_id' => 'unknown' } } }
let(:notification_target) { prometheus_alert.project }
let(:notification_trigger) { subject.prometheus_alerts_fired(prometheus_alert.project, [alert_params]) }
let(:notification_target) { project }
let(:notification_trigger) { subject.prometheus_alerts_fired(project, [alert_attributes]) }
around do |example|
perform_enqueued_jobs { example.run }

View file

@ -197,11 +197,10 @@ RSpec.describe Projects::Alerting::NotifyService do
end
context 'with overlong payload' do
let(:payload_raw) do
{
title: 'a' * Gitlab::Utils::DeepSize::DEFAULT_MAX_SIZE,
start_time: starts_at.rfc3339
}
let(:deep_size_object) { instance_double(Gitlab::Utils::DeepSize, valid?: false) }
before do
allow(Gitlab::Utils::DeepSize).to receive(:new).and_return(deep_size_object)
end
it_behaves_like 'does not process incident issues due to error', http_status: :bad_request
@ -215,17 +214,6 @@ RSpec.describe Projects::Alerting::NotifyService do
it_behaves_like 'processes incident issues'
context 'with an invalid payload' do
before do
allow(Gitlab::Alerting::NotificationPayloadParser)
.to receive(:call)
.and_raise(Gitlab::Alerting::NotificationPayloadParser::BadPayloadError)
end
it_behaves_like 'does not process incident issues due to error', http_status: :bad_request
it_behaves_like 'does not an create alert management alert'
end
context 'when alert already exists' do
let(:fingerprint_sha) { Digest::SHA1.hexdigest(fingerprint) }
let!(:alert) { create(:alert_management_alert, project: project, fingerprint: fingerprint_sha) }

View file

@ -2,7 +2,6 @@
require 'simplecov'
require 'simplecov-cobertura'
require 'active_support/core_ext/numeric/time'
require_relative '../lib/gitlab/utils'
module SimpleCovEnv
@ -75,7 +74,7 @@ module SimpleCovEnv
add_group 'Libraries', %w[/lib /ee/lib]
add_group 'Tooling', %w[/haml_lint /rubocop /tooling]
merge_timeout 365.days
merge_timeout 365 * 24 * 3600
end
end
end

View file

@ -6,7 +6,7 @@ RSpec.describe IncidentManagement::ProcessPrometheusAlertWorker do
describe '#perform' do
let_it_be(:project) { create(:project) }
let_it_be(:prometheus_alert) { create(:prometheus_alert, project: project) }
let(:payload_key) { Gitlab::Alerting::Alert.new(project: project, payload: alert_params).gitlab_fingerprint }
let(:payload_key) { Gitlab::AlertManagement::Payload::Prometheus.new(project: project, payload: alert_params).gitlab_fingerprint }
let!(:prometheus_alert_event) { create(:prometheus_alert_event, prometheus_alert: prometheus_alert, payload_key: payload_key) }
let!(:settings) { create(:project_incident_management_setting, project: project, create_issue: true) }

View file

@ -12302,10 +12302,10 @@ vue-jest@4.0.0-beta.2:
source-map "^0.5.6"
ts-jest "^23.10.5"
vue-loader@^15.9.0:
version "15.9.0"
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.9.0.tgz#5d4b0378a4606188fc83e587ed23c94bc3a10998"
integrity sha512-FeDHvTSpwyLeF7LIV1PYkvqUQgTJ8UmOxhSlCyRSxaXCKk+M6NF4tDQsLsPPNeDPyR7TfRQ8MLg6v+8PsDV9xQ==
vue-loader@^15.9.3:
version "15.9.3"
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.9.3.tgz#0de35d9e555d3ed53969516cac5ce25531299dda"
integrity sha512-Y67VnGGgVLH5Voostx8JBZgPQTlDQeOVBLOEsjc2cXbCYBKexSKEpOA56x0YZofoDOTszrLnIShyOX1p9uCEHA==
dependencies:
"@vue/component-compiler-utils" "^3.1.0"
hash-sum "^1.0.2"
@ -12331,10 +12331,10 @@ vue-style-loader@^4.1.0:
hash-sum "^1.0.2"
loader-utils "^1.0.2"
vue-template-compiler@^2.5.20, vue-template-compiler@^2.6.10:
version "2.6.10"
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.10.tgz#323b4f3495f04faa3503337a82f5d6507799c9cc"
integrity sha512-jVZkw4/I/HT5ZMvRnhv78okGusqe0+qH2A0Em0Cp8aq78+NK9TII263CDVz2QXZsIT+yyV/gZc/j/vlwa+Epyg==
vue-template-compiler@^2.5.20, vue-template-compiler@^2.6.12:
version "2.6.12"
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.12.tgz#947ed7196744c8a5285ebe1233fe960437fcc57e"
integrity sha512-OzzZ52zS41YUbkCBfdXShQTe69j1gQDZ9HIX8miuC9C3rBCk9wIRjLiZZLrmX9V+Ftq/YEyv1JaVr5Y/hNtByg==
dependencies:
de-indent "^1.0.2"
he "^1.1.0"
@ -12349,10 +12349,10 @@ vue-virtual-scroll-list@^1.4.4:
resolved "https://registry.yarnpkg.com/vue-virtual-scroll-list/-/vue-virtual-scroll-list-1.4.4.tgz#5fca7a13f785899bbfb70471ec4fe222437d8495"
integrity sha512-wU7FDpd9Xy4f62pf8SBg/ak21jMI/pdx4s4JPah+z/zuhmeAafQgp8BjtZvvt+b0BZOsOS1FJuCfUH7azTkivQ==
vue@^2.6.10:
version "2.6.10"
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637"
integrity sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==
vue@^2.6.12:
version "2.6.12"
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.12.tgz#f5ebd4fa6bd2869403e29a896aed4904456c9123"
integrity sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg==
vuedraggable@^2.23.0:
version "2.23.0"