Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-07-03 15:09:13 +00:00
parent b922b2f47a
commit e5d314d432
45 changed files with 888 additions and 192 deletions

View File

@ -11,7 +11,7 @@
if: '$CI_PROJECT_NAME != "gitlab-foss" && $CI_PROJECT_NAME != "gitlab-ce" && $CI_PROJECT_NAME != "gitlabhq"'
.if-default-refs: &if-default-refs
if: '$CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_MERGE_REQUEST_IID || $CI_COMMIT_TAG'
if: '$CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_MERGE_REQUEST_IID || $CI_COMMIT_TAG || $FORCE_GITLAB_CI'
.if-master-refs: &if-master-refs
if: '$CI_COMMIT_REF_NAME == "master"'

View File

@ -0,0 +1,6 @@
export const DEFAULT_RX = 0.4;
export const DEFAULT_BAR_WIDTH = 6;
export const DEFAULT_LABEL_WIDTH = 4;
export const DEFAULT_LABEL_HEIGHT = 5;
export const BAR_HEIGHTS = [5, 7, 9, 14, 21, 35, 50, 80];
export const GRID_YS = [30, 60, 90];

View File

@ -0,0 +1,95 @@
<script>
import { GlSkeletonLoader } from '@gitlab/ui';
import {
DEFAULT_RX,
DEFAULT_BAR_WIDTH,
DEFAULT_LABEL_WIDTH,
DEFAULT_LABEL_HEIGHT,
BAR_HEIGHTS,
GRID_YS,
} from './constants';
export default {
components: {
GlSkeletonLoader,
},
props: {
barWidth: {
type: Number,
default: DEFAULT_BAR_WIDTH,
required: false,
},
labelWidth: {
type: Number,
default: DEFAULT_LABEL_WIDTH,
required: false,
},
labelHeight: {
type: Number,
default: DEFAULT_LABEL_HEIGHT,
required: false,
},
rx: {
type: Number,
default: DEFAULT_RX,
required: false,
},
// skeleton-loader will generate a unique key if not defined
uniqueKey: {
type: String,
default: undefined,
required: false,
},
},
computed: {
labelCentering() {
return (this.barWidth - this.labelWidth) / 2;
},
},
methods: {
getBarXPosition(index) {
const numberOfBars = this.$options.BAR_HEIGHTS.length;
const numberOfSpaces = numberOfBars + 1;
const spaceBetweenBars = (100 - numberOfSpaces * this.barWidth) / numberOfBars;
return (0.5 + index) * (this.barWidth + spaceBetweenBars);
},
},
BAR_HEIGHTS,
GRID_YS,
};
</script>
<template>
<gl-skeleton-loader :unique-key="uniqueKey">
<rect
v-for="(y, index) in $options.GRID_YS"
:key="`grid-${index}`"
data-testid="skeleton-chart-grid"
x="0"
:y="`${y}%`"
width="100%"
height="1px"
/>
<rect
v-for="(height, index) in $options.BAR_HEIGHTS"
:key="`bar-${index}`"
data-testid="skeleton-chart-bar"
:x="`${getBarXPosition(index)}%`"
:y="`${90 - height}%`"
:width="`${barWidth}%`"
:height="`${height}%`"
:rx="`${rx}%`"
/>
<rect
v-for="(height, index) in $options.BAR_HEIGHTS"
:key="`label-${index}`"
data-testid="skeleton-chart-label"
:x="`${labelCentering + getBarXPosition(index)}%`"
:y="`${100 - labelHeight}%`"
:width="`${labelWidth}%`"
:height="`${labelHeight}%`"
:rx="`${rx}%`"
/>
</gl-skeleton-loader>
</template>

View File

@ -151,6 +151,7 @@
.design-dropzone-card {
transition: border $general-hover-transition-duration $general-hover-transition-curve;
color: $gl-text-color;
&:focus,
&:active {

View File

@ -4,6 +4,8 @@ textarea {
input {
border-radius: $border-radius-base;
color: $gl-text-color;
background-color: $input-bg;
}
input[type='text'].danger {

View File

@ -27,7 +27,13 @@
.timeline-entry {
color: $gl-text-color;
background-color: $white;
// [dark-theme]: only give background color to actual notes
// in the timeline, the note form textarea has a background
// of it's own
&:not(.note-form) {
background-color: $white;
}
.timeline-entry-inner {
position: relative;

View File

@ -479,9 +479,9 @@ $gl-btn-active-gradient: inset 0 2px 3px $gl-btn-active-background;
$added: #63c363;
$deleted: #f77;
$line-added: #ecfdf0;
$line-added-dark: #c7f0d2;
$line-added-dark: #c7f0d2 !default;
$line-removed: #fbe9eb;
$line-removed-dark: #fac5cd;
$line-removed-dark: #fac5cd !default;
$line-number-old: #f9d7dc;
$line-number-new: #ddfbe6;
$line-number-select: #fbf2da;

View File

@ -14,7 +14,7 @@ $btn-line-height: 20px;
$table-accent-bg: $gray-light;
$table-border-color: $gray-200;
$card-border-color: $border-color;
$card-cap-bg: $gray-light;
$card-cap-bg: $gray-light !default;
$success: $green-500;
$info: $blue-500;
$warning: $orange-500;

View File

@ -62,7 +62,8 @@
background-color: $white;
&.is-focused {
@extend .form-control:focus;
border-color: $input-focus-border-color;
box-shadow: $input-focus-box-shadow;
.comment-toolbar,
.nav-links {

View File

@ -103,6 +103,8 @@ $input-focus-bg: $gray-100;
$input-color: $gray-900;
$input-group-addon-bg: $gray-900;
$card-cap-bg: $gray-50;
$tooltip-bg: $gray-800;
$tooltip-color: $gray-10;
@ -118,6 +120,11 @@ $issues-today-border: #333a40;
$yiq-text-dark: $gray-50;
$yiq-text-light: $gray-950;
// Commit Diff Colors
$line-added-dark: $green-200;
$line-removed-dark: $red-200;
// Misc component overrides that should live elsewhere
.gl-label {
filter: brightness(0.9) contrast(1.1);
}

View File

@ -3,7 +3,6 @@
class Dashboard::ProjectsController < Dashboard::ApplicationController
include ParamsBackwardCompatibility
include RendersMemberAccess
include OnboardingExperimentHelper
include SortingHelper
include SortingPreference
include FiltersEvents

View File

@ -16,10 +16,10 @@ module Types
value 'UPDATED_TIME_DESC', 'Created time by descending order', value: :updated_at_desc
value 'EVENT_COUNT_ASC', 'Events count by ascending order', value: :event_count_asc
value 'EVENT_COUNT_DESC', 'Events count by descending order', value: :event_count_desc
value 'SEVERITY_ASC', 'Severity by ascending order', value: :severity_asc
value 'SEVERITY_DESC', 'Severity by descending order', value: :severity_desc
value 'STATUS_ASC', 'Status by ascending order', value: :status_asc
value 'STATUS_DESC', 'Status by descending order', value: :status_desc
value 'SEVERITY_ASC', 'Severity from less critical to more critical', value: :severity_asc
value 'SEVERITY_DESC', 'Severity from more critical to less critical', value: :severity_desc
value 'STATUS_ASC', 'Status by order: Ignored > Resolved > Acknowledged > Triggered', value: :status_asc
value 'STATUS_DESC', 'Status by order: Triggered > Acknowledged > Resolved > Ignored', value: :status_desc
end
end
end

View File

@ -1,9 +0,0 @@
# frozen_string_literal: true
module OnboardingExperimentHelper
def allow_access_to_onboarding?
::Gitlab.dev_env_or_com? && Feature.enabled?(:user_onboarding)
end
end
OnboardingExperimentHelper.prepend_if_ee('EE::OnboardingExperimentHelper')

View File

@ -121,8 +121,16 @@ module AlertManagement
scope :order_start_time, -> (sort_order) { order(started_at: sort_order) }
scope :order_end_time, -> (sort_order) { order(ended_at: sort_order) }
scope :order_event_count, -> (sort_order) { order(events: sort_order) }
scope :order_severity, -> (sort_order) { order(severity: sort_order) }
scope :order_status, -> (sort_order) { order(status: sort_order) }
# Ascending sort order sorts severity from less critical to more critical.
# Descending sort order sorts severity from more critical to less critical.
# https://gitlab.com/gitlab-org/gitlab/-/issues/221242#what-is-the-expected-correct-behavior
scope :order_severity, -> (sort_order) { order(severity: sort_order == :asc ? :desc : :asc) }
# Ascending sort order sorts statuses: Ignored > Resolved > Acknowledged > Triggered
# Descending sort order sorts statuses: Triggered > Acknowledged > Resolved > Ignored
# https://gitlab.com/gitlab-org/gitlab/-/issues/221242#what-is-the-expected-correct-behavior
scope :order_status, -> (sort_order) { order(status: sort_order == :asc ? :desc : :asc) }
scope :counts_by_status, -> { group(:status).count }
scope :counts_by_project_id, -> { group(:project_id).count }

View File

@ -3,7 +3,7 @@
module Clusters
module Applications
class Runner < ApplicationRecord
VERSION = '0.18.0'
VERSION = '0.18.1'
self.table_name = 'clusters_applications_runners'

View File

@ -107,6 +107,7 @@ class MergeRequest < ApplicationRecord
after_create :ensure_merge_request_diff
after_update :clear_memoized_shas
after_update :clear_memoized_source_branch_exists
after_update :reload_diff_if_branch_changed
after_commit :ensure_metrics, on: [:create, :update], unless: :importing?
after_commit :expire_etag_cache, unless: :importing?
@ -862,6 +863,10 @@ class MergeRequest < ApplicationRecord
clear_memoization(:target_branch_head)
end
def clear_memoized_source_branch_exists
clear_memoization(:source_branch_exists)
end
def reload_diff_if_branch_changed
if (saved_change_to_source_branch? || saved_change_to_target_branch?) &&
(source_branch_head && target_branch_head)
@ -1109,9 +1114,17 @@ class MergeRequest < ApplicationRecord
end
def source_branch_exists?
return false unless self.source_project
if Feature.enabled?(:memoize_source_branch_merge_request, project)
strong_memoize(:source_branch_exists) do
next false unless self.source_project
self.source_project.repository.branch_exists?(self.source_branch)
self.source_project.repository.branch_exists?(self.source_branch)
end
else
return false unless self.source_project
self.source_project.repository.branch_exists?(self.source_branch)
end
end
def target_branch_exists?

View File

@ -10,7 +10,7 @@
.col.form-group
= f.label :title, _('Title'), class: 'label-bold'
= f.text_field :title, class: "form-control input-lg qa-key-title-field", required: true, placeholder: s_('Profiles|e.g. My MacBook key')
%p.form-text.text-muted= s_('Profiles|Give your individual key a title')
%p.form-text.text-muted= s_('Profiles|Give your individual key a title. This will be publically visible.')
.col.form-group
= f.label :expires_at, s_('Profiles|Expires at'), class: 'label-bold'

View File

@ -0,0 +1,5 @@
---
title: Further improve the performance for loading large diffs on a Merge request
merge_request: 34516
author:
type: performance

View File

@ -0,0 +1,5 @@
---
title: Change the sort order for alert severity and status.
merge_request: 35774
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Add note about SSH key title being public information
merge_request: 35574
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Minor UI fixes for Issue page in dark mode
merge_request: 35395
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Update GitLab Runner Helm Chart to 0.18.1
merge_request: 35712
author:
type: other

View File

@ -395,12 +395,12 @@ enum AlertManagementAlertSort {
EVENT_COUNT_DESC
"""
Severity by ascending order
Severity from less critical to more critical
"""
SEVERITY_ASC
"""
Severity by descending order
Severity from more critical to less critical
"""
SEVERITY_DESC
@ -415,12 +415,12 @@ enum AlertManagementAlertSort {
STARTED_AT_DESC
"""
Status by ascending order
Status by order: Ignored > Resolved > Acknowledged > Triggered
"""
STATUS_ASC
"""
Status by descending order
Status by order: Triggered > Acknowledged > Resolved > Ignored
"""
STATUS_DESC

View File

@ -1103,25 +1103,25 @@
},
{
"name": "SEVERITY_ASC",
"description": "Severity by ascending order",
"description": "Severity from less critical to more critical",
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "SEVERITY_DESC",
"description": "Severity by descending order",
"description": "Severity from more critical to less critical",
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "STATUS_ASC",
"description": "Status by ascending order",
"description": "Status by order: Ignored > Resolved > Acknowledged > Triggered",
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "STATUS_DESC",
"description": "Status by descending order",
"description": "Status by order: Triggered > Acknowledged > Resolved > Ignored",
"isDeprecated": false,
"deprecationReason": null
}

View File

@ -594,6 +594,7 @@ appear to be associated to any of the services running, since they all appear to
| `ldap_enabled` | | | | | |
| `mattermost_enabled` | | | | | |
| `omniauth_enabled` | | | | | |
| `prometheus_enabled` | | | | | Whether the bundled Prometheus is enabled |
| `prometheus_metrics_enabled` | | | | | |
| `reply_by_email_enabled` | | | | | |
| `average` | `avg_cycle_analytics - code` | | | | |
@ -671,6 +672,7 @@ appear to be associated to any of the services running, since they all appear to
| `merge_requests_users` | `usage_activity_by_stage_monthly` | `create` | | | Unique count of users who used a merge request |
| `duration_s` | `topology` | `enablement` | | | Time it took to collect topology data |
| `application_requests_per_hour` | `topology` | `enablement` | | | Number of requests to the web application per hour |
| `failures` | `topology` | `enablement` | | | Contains information about failed queries |
| `nodes` | `topology` | `enablement` | | | The list of server nodes on which GitLab components are running |
| `node_memory_total_bytes` | `topology > nodes` | `enablement` | | | The total available memory of this node |
| `node_cpus` | `topology > nodes` | `enablement` | | | The number of CPU cores of this node |
@ -723,6 +725,7 @@ The following is example content of the Usage Ping payload.
"ldap_enabled": false,
"mattermost_enabled": false,
"omniauth_enabled": true,
"prometheus_enabled": false,
"prometheus_metrics_enabled": false,
"reply_by_email_enabled": "incoming+%{key}@incoming.gitlab.com",
"signup_enabled": true,
@ -879,6 +882,7 @@ The following is example content of the Usage Ping payload.
"topology": {
"duration_s": 0.013836685999194742,
"application_requests_per_hour": 4224,
"failures": [],
"nodes": [
{
"node_memory_total_bytes": 33269903360,

View File

@ -18,8 +18,8 @@ Using Credentials inventory, GitLab administrators can see all the personal acce
- Who they belong to.
- Their access scope.
- Their usage pattern.
- When they expire.
- When they were revoked.
- When they expire. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214809) in GitLab 13.2.
- When they were revoked. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214809) in GitLab 13.2.
To access the Credentials inventory, navigate to **Admin Area > Credentials**.

View File

@ -85,6 +85,60 @@ it. This is because squashing is only available when accepting a merge request,
so a merge request may need to be rebased before squashing, even though
squashing can itself be considered equivalent to rebasing.
## Squash Commits Options
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/17613) in GitLab 13.2.
> - It's deployed behind a feature flag, disabled by default.
> - It's disabled on GitLab.com.
> - It's not recommended for production use.
> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-squash-commit-options-core-only). **(CORE ONLY)**
With Squash Commits Options you can configure the behavior of Squash and Merge for your project.
To set it up, navigate to your project's **Settings > General** and expand **Merge requests**.
You will find the following options to choose, which will affect existing and new merge requests
submitted to your project:
- **Do not allow**: users cannot use Squash and Merge to squash all the commits immediately before
merging. The checkbox to enable or disable it will be unchecked and hidden from the users.
- **Allow**: users will have the option to enable Squash and Merge on a merge request basis.
The checkbox will be unchecked (disabled) by default, but and the user is allowed to enable it.
- **Encourage**: users will have the option to enable Squash and Merge on a merge request basis.
The checkbox will be checked (enabled) by default to encourage its use, but the user is allowed to
disable it.
- **Require**: Squash and Merge is enabled for all merge requests, so it will always be performed.
The checkbox to enable or disable it will be checked and hidden from the users.
The Squash and Merge checkbox is displayed when you create a merge request and when you edit the description of an existing one, except when Squash Commit Options is set to **Do not allow** or **Require**.
NOTE: **Note:**
If your project is set to **Do not allow** Squash and Merge, the users still have the option to
squash commits locally through the command line and force-push to their remote branch before merging.
### Enable or disable Squash Commit Options **(CORE ONLY)**
Squash Commit Options is under development and not ready for production use. It is
deployed behind a feature flag that is **disabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
can enable it for your instance. Squash Commit Options can be enabled or disabled per-project.
To enable it:
```ruby
# Instance-wide
Feature.enable(:squash_options)
# or by project
Feature.enable(:squash_options, Project.find(<project id>))
```
To disable it:
```ruby
# Instance-wide
Feature.enable(:squash_options)
# or by project
Feature.disable(:squash_options, Project.find(<project id>))
```
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues

View File

@ -5,6 +5,8 @@ module Gitlab
class PrometheusClient
include Gitlab::Utils::StrongMemoize
Error = Class.new(StandardError)
ConnectionError = Class.new(Gitlab::PrometheusClient::Error)
UnexpectedResponseError = Class.new(Gitlab::PrometheusClient::Error)
QueryError = Class.new(Gitlab::PrometheusClient::Error)
HEALTHY_RESPONSE = "Prometheus is Healthy.\n"
@ -44,7 +46,7 @@ module Gitlab
path = api_path(type)
get(path, args)
rescue Gitlab::HTTP::ResponseError => ex
raise PrometheusClient::Error, "Network connection error" unless ex.response && ex.response.try(:code)
raise PrometheusClient::ConnectionError, "Network connection error" unless ex.response && ex.response.try(:code)
handle_querying_api_response(ex.response)
end
@ -115,7 +117,7 @@ module Gitlab
response = get(path, args)
handle_querying_api_response(response)
rescue Gitlab::HTTP::ResponseError => ex
raise PrometheusClient::Error, "Network connection error" unless ex.response && ex.response.try(:code)
raise PrometheusClient::ConnectionError, "Network connection error" unless ex.response && ex.response.try(:code)
handle_querying_api_response(ex.response)
end
@ -137,18 +139,18 @@ module Gitlab
def get(path, args)
Gitlab::HTTP.get(path, { query: args }.merge(http_options) )
rescue SocketError
raise PrometheusClient::Error, "Can't connect to #{api_url}"
raise PrometheusClient::ConnectionError, "Can't connect to #{api_url}"
rescue OpenSSL::SSL::SSLError
raise PrometheusClient::Error, "#{api_url} contains invalid SSL data"
raise PrometheusClient::ConnectionError, "#{api_url} contains invalid SSL data"
rescue Errno::ECONNREFUSED
raise PrometheusClient::Error, 'Connection refused'
raise PrometheusClient::ConnectionError, 'Connection refused'
end
def handle_management_api_response(response)
if response.code == 200
response.body
else
raise PrometheusClient::Error, "#{response.code} - #{response.body}"
raise PrometheusClient::UnexpectedResponseError, "#{response.code} - #{response.body}"
end
end
@ -156,7 +158,7 @@ module Gitlab
response_code = response.try(:code)
response_body = response.try(:body)
raise PrometheusClient::Error, "#{response_code} - #{response_body}" unless response_code
raise PrometheusClient::UnexpectedResponseError, "#{response_code} - #{response_body}" unless response_code
json_data = parse_json(response_body) if [200, 400].include?(response_code)
@ -166,7 +168,7 @@ module Gitlab
when 400
raise PrometheusClient::QueryError, json_data['error'] || 'Bad data received'
else
raise PrometheusClient::Error, "#{response_code} - #{response_body}"
raise PrometheusClient::UnexpectedResponseError, "#{response_code} - #{response_body}"
end
end
@ -178,7 +180,7 @@ module Gitlab
def parse_json(response_body)
Gitlab::Json.parse(response_body, legacy_mode: true)
rescue JSON::ParserError
raise PrometheusClient::Error, 'Parsing response failed'
raise PrometheusClient::UnexpectedResponseError, 'Parsing response failed'
end
end
end

View File

@ -18,7 +18,6 @@ module Gitlab
class << self
include Gitlab::Utils::UsageData
include Gitlab::Utils::StrongMemoize
include Gitlab::UsageDataConcerns::Topology
def data(force_refresh: false)
Rails.cache.fetch('usage_data', force: force_refresh, expires_in: 2.weeks) do
@ -210,6 +209,7 @@ module Gitlab
ldap_enabled: alt_usage_data(fallback: nil) { Gitlab.config.ldap.enabled },
mattermost_enabled: alt_usage_data(fallback: nil) { Gitlab.config.mattermost.enabled },
omniauth_enabled: alt_usage_data(fallback: nil) { Gitlab::Auth.omniauth_enabled? },
prometheus_enabled: alt_usage_data(fallback: nil) { Gitlab::Prometheus::Internal.prometheus_enabled? },
prometheus_metrics_enabled: alt_usage_data(fallback: nil) { Gitlab::Metrics.prometheus_metrics_enabled? },
reply_by_email_enabled: alt_usage_data(fallback: nil) { Gitlab::IncomingEmail.enabled? },
signup_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.allow_signup? },
@ -303,6 +303,10 @@ module Gitlab
}
end
def topology_usage_data
Gitlab::UsageData::Topology.new.topology_usage_data
end
def ingress_modsecurity_usage
##
# This method measures usage of the Modsecurity Web Application Firewall across the entire

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true
module Gitlab
module UsageDataConcerns
module Topology
class UsageData
class Topology
include Gitlab::Utils::UsageData
JOB_TO_SERVICE_NAME = {
@ -16,11 +16,20 @@ module Gitlab
'node' => 'node-exporter'
}.freeze
def topology_usage_data
topology_data, duration = measure_duration do
alt_usage_data(fallback: {}) { topology_fetch_all_data }
CollectionFailure = Struct.new(:query, :error) do
def to_h
{ query => error }
end
{ topology: topology_data.merge(duration_s: duration) }
end
def topology_usage_data
@failures = []
topology_data, duration = measure_duration { topology_fetch_all_data }
{
topology: topology_data
.merge(duration_s: duration)
.merge(failures: @failures.map(&:to_h))
}
end
private
@ -32,10 +41,17 @@ module Gitlab
nodes: topology_node_data(client)
}.compact
end
rescue => e
@failures << CollectionFailure.new('other', e.class.to_s)
{}
end
def topology_app_requests_per_hour(client)
result = client.query(one_week_average('gitlab_usage_ping:ops:rate5m')).first
result = query_safely('gitlab_usage_ping:ops:rate5m', 'app_requests', fallback: nil) do |query|
client.query(one_week_average(query)).first
end
return unless result
# the metric is recorded as a per-second rate
@ -62,11 +78,15 @@ module Gitlab
end
def topology_node_memory(client)
aggregate_by_instance(client, 'gitlab_usage_ping:node_memory_total_bytes:avg')
query_safely('gitlab_usage_ping:node_memory_total_bytes:avg', 'node_memory', fallback: {}) do |query|
aggregate_by_instance(client, query)
end
end
def topology_node_cpus(client)
aggregate_by_instance(client, 'gitlab_usage_ping:node_cpus:count')
query_safely('gitlab_usage_ping:node_cpus:count', 'node_cpus', fallback: {}) do |query|
aggregate_by_instance(client, query)
end
end
def topology_all_service_memory(client)
@ -78,19 +98,39 @@ module Gitlab
end
def topology_service_memory_rss(client)
aggregate_by_labels(client, 'gitlab_usage_ping:node_service_process_resident_memory_bytes:avg')
query_safely(
'gitlab_usage_ping:node_service_process_resident_memory_bytes:avg', 'service_rss', fallback: []
) { |query| aggregate_by_labels(client, query) }
end
def topology_service_memory_uss(client)
aggregate_by_labels(client, 'gitlab_usage_ping:node_service_process_unique_memory_bytes:avg')
query_safely(
'gitlab_usage_ping:node_service_process_unique_memory_bytes:avg', 'service_uss', fallback: []
) { |query| aggregate_by_labels(client, query) }
end
def topology_service_memory_pss(client)
aggregate_by_labels(client, 'gitlab_usage_ping:node_service_process_proportional_memory_bytes:avg')
query_safely(
'gitlab_usage_ping:node_service_process_proportional_memory_bytes:avg', 'service_pss', fallback: []
) { |query| aggregate_by_labels(client, query) }
end
def topology_all_service_process_count(client)
aggregate_by_labels(client, 'gitlab_usage_ping:node_service_process:count')
query_safely(
'gitlab_usage_ping:node_service_process:count', 'service_process_count', fallback: []
) { |query| aggregate_by_labels(client, query) }
end
def query_safely(query, query_name, fallback:)
result = yield query
return result if result.present?
@failures << CollectionFailure.new(query_name, 'empty_result')
fallback
rescue => e
@failures << CollectionFailure.new(query_name, e.class.to_s)
fallback
end
def topology_node_services(instance, all_process_counts, all_process_memory)

View File

@ -2238,6 +2238,9 @@ msgstr ""
msgid "Allow users to request access (if visibility is public or internal)"
msgstr ""
msgid "Allowed"
msgstr ""
msgid "Allowed Geo IP"
msgstr ""
@ -7441,6 +7444,9 @@ msgstr ""
msgid "Deletion pending. This project will be removed on %{date}. Repository and other project resources are read-only."
msgstr ""
msgid "Denied"
msgstr ""
msgid "Denied authorization of chat nickname %{user_name}."
msgstr ""
@ -13466,6 +13472,9 @@ msgstr ""
msgid "Licenses|%{remainingComponentsCount} more"
msgstr ""
msgid "Licenses|Acceptable license to be used in the project"
msgstr ""
msgid "Licenses|Component"
msgstr ""
@ -13478,6 +13487,9 @@ msgstr ""
msgid "Licenses|Detected licenses that are out-of-compliance with the project's assigned policies"
msgstr ""
msgid "Licenses|Disallow Merge request if detected and will instruct the developer to remove"
msgstr ""
msgid "Licenses|Displays licenses detected in the project, based on the %{linkStart}latest successful%{linkEnd} scan"
msgstr ""
@ -16869,9 +16881,6 @@ msgstr ""
msgid "Please type %{phrase_code} to proceed or close this modal to cancel."
msgstr ""
msgid "Please upgrade PostgreSQL to version 9.6 or greater. The status of the replication cannot be determined reliably with the current version."
msgstr ""
msgid "Please use this form to report to the admin users who create spam issues, comments or behave inappropriately."
msgstr ""
@ -17250,7 +17259,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
msgid "Profiles|Give your individual key a title"
msgid "Profiles|Give your individual key a title. This will be publically visible."
msgstr ""
msgid "Profiles|Include private contributions on my profile"

View File

@ -75,10 +75,30 @@ FactoryBot.define do
without_ended_at
end
trait :low_severity do
trait :critical do
severity { 'critical' }
end
trait :high do
severity { 'high' }
end
trait :medium do
severity { 'medium' }
end
trait :low do
severity { 'low' }
end
trait :info do
severity { 'info' }
end
trait :unknown do
severity { 'unknown' }
end
trait :prometheus do
monitoring_tool { Gitlab::AlertManagement::AlertParams::MONITORING_TOOLS[:prometheus] }
end
@ -91,7 +111,7 @@ FactoryBot.define do
with_monitoring_tool
with_host
with_description
low_severity
low
end
end
end

View File

@ -11,7 +11,7 @@ RSpec.describe AlertManagement::AlertsFinder, '#execute' do
let(:params) { {} }
describe '#execute' do
subject { described_class.new(current_user, project, params).execute }
subject(:execute) { described_class.new(current_user, project, params).execute }
context 'user is not a developer or above' do
it { is_expected.to be_empty }
@ -144,81 +144,55 @@ RSpec.describe AlertManagement::AlertsFinder, '#execute' do
end
context 'when sorting by severity' do
let_it_be(:alert_critical) { create(:alert_management_alert, project: project, severity: :critical) }
let_it_be(:alert_high) { create(:alert_management_alert, project: project, severity: :high) }
let_it_be(:alert_medium) { create(:alert_management_alert, project: project, severity: :medium) }
let_it_be(:alert_low) { create(:alert_management_alert, project: project, severity: :low) }
let_it_be(:alert_info) { create(:alert_management_alert, project: project, severity: :info) }
let_it_be(:alert_unknown) { create(:alert_management_alert, project: project, severity: :unknown) }
let_it_be(:alert_critical) { create(:alert_management_alert, :critical, project: project) }
let_it_be(:alert_high) { create(:alert_management_alert, :high, project: project) }
let_it_be(:alert_medium) { create(:alert_management_alert, :medium, project: project) }
let_it_be(:alert_low) { create(:alert_management_alert, :low, project: project) }
let_it_be(:alert_info) { create(:alert_management_alert, :info, project: project) }
let_it_be(:alert_unknown) { create(:alert_management_alert, :unknown, project: project) }
context 'sorts alerts ascending' do
context 'with ascending sort order' do
let(:params) { { sort: 'severity_asc' } }
it do
is_expected.to eq [
alert_2,
alert_critical,
alert_1,
alert_high,
alert_medium,
alert_low,
alert_info,
alert_unknown
]
it 'sorts alerts by severity from less critical to more critical' do
expect(execute.pluck(:severity).uniq).to eq(%w(unknown info low medium high critical))
end
end
context 'sorts alerts descending' do
context 'with descending sort order' do
let(:params) { { sort: 'severity_desc' } }
it do
is_expected.to eq [
alert_unknown,
alert_info,
alert_low,
alert_medium,
alert_1,
alert_high,
alert_critical,
alert_2
]
it 'sorts alerts by severity from more critical to less critical' do
expect(execute.pluck(:severity).uniq).to eq(%w(critical high medium low info unknown))
end
end
end
context 'when sorting by status' do
let(:statuses) { AlertManagement::Alert::STATUSES }
let(:triggered) { statuses[:triggered] }
let(:acknowledged) { statuses[:acknowledged] }
let(:resolved) { statuses[:resolved] }
let(:ignored) { statuses[:ignored] }
let_it_be(:alert_triggered) { create(:alert_management_alert, project: project) }
let_it_be(:alert_acknowledged) { create(:alert_management_alert, :acknowledged, project: project) }
let_it_be(:alert_resolved) { create(:alert_management_alert, :resolved, project: project) }
let_it_be(:alert_ignored) { create(:alert_management_alert, :ignored, project: project) }
context 'sorts alerts ascending' do
context 'with ascending sort order' do
let(:params) { { sort: 'status_asc' } }
it do
is_expected.to eq [
alert_triggered,
alert_acknowledged,
alert_1,
alert_resolved,
alert_2,
alert_ignored
]
it 'sorts by status: Ignored > Resolved > Acknowledged > Triggered' do
expect(execute.map(&:status).uniq).to eq([ignored, resolved, acknowledged, triggered])
end
end
context 'sorts alerts descending' do
context 'with descending sort order' do
let(:params) { { sort: 'status_desc' } }
it do
is_expected.to eq [
alert_2,
alert_ignored,
alert_1,
alert_resolved,
alert_acknowledged,
alert_triggered
]
it 'sorts by status: Triggered > Acknowledged > Resolved > Ignored' do
expect(execute.map(&:status).uniq).to eq([triggered, acknowledged, resolved, ignored])
end
end
end

View File

@ -0,0 +1,324 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Resizable Skeleton Loader default setup renders the bars, labels, and grid with correct position, size, and rx percentages 1`] = `
<gl-skeleton-loader-stub
baseurl=""
height="130"
preserveaspectratio="xMidYMid meet"
width="400"
>
<rect
data-testid="skeleton-chart-grid"
height="1px"
width="100%"
x="0"
y="30%"
/>
<rect
data-testid="skeleton-chart-grid"
height="1px"
width="100%"
x="0"
y="60%"
/>
<rect
data-testid="skeleton-chart-grid"
height="1px"
width="100%"
x="0"
y="90%"
/>
<rect
data-testid="skeleton-chart-bar"
height="5%"
rx="0.4%"
width="6%"
x="5.875%"
y="85%"
/>
<rect
data-testid="skeleton-chart-bar"
height="7%"
rx="0.4%"
width="6%"
x="17.625%"
y="83%"
/>
<rect
data-testid="skeleton-chart-bar"
height="9%"
rx="0.4%"
width="6%"
x="29.375%"
y="81%"
/>
<rect
data-testid="skeleton-chart-bar"
height="14%"
rx="0.4%"
width="6%"
x="41.125%"
y="76%"
/>
<rect
data-testid="skeleton-chart-bar"
height="21%"
rx="0.4%"
width="6%"
x="52.875%"
y="69%"
/>
<rect
data-testid="skeleton-chart-bar"
height="35%"
rx="0.4%"
width="6%"
x="64.625%"
y="55%"
/>
<rect
data-testid="skeleton-chart-bar"
height="50%"
rx="0.4%"
width="6%"
x="76.375%"
y="40%"
/>
<rect
data-testid="skeleton-chart-bar"
height="80%"
rx="0.4%"
width="6%"
x="88.125%"
y="10%"
/>
<rect
data-testid="skeleton-chart-label"
height="5%"
rx="0.4%"
width="4%"
x="6.875%"
y="95%"
/>
<rect
data-testid="skeleton-chart-label"
height="5%"
rx="0.4%"
width="4%"
x="18.625%"
y="95%"
/>
<rect
data-testid="skeleton-chart-label"
height="5%"
rx="0.4%"
width="4%"
x="30.375%"
y="95%"
/>
<rect
data-testid="skeleton-chart-label"
height="5%"
rx="0.4%"
width="4%"
x="42.125%"
y="95%"
/>
<rect
data-testid="skeleton-chart-label"
height="5%"
rx="0.4%"
width="4%"
x="53.875%"
y="95%"
/>
<rect
data-testid="skeleton-chart-label"
height="5%"
rx="0.4%"
width="4%"
x="65.625%"
y="95%"
/>
<rect
data-testid="skeleton-chart-label"
height="5%"
rx="0.4%"
width="4%"
x="77.375%"
y="95%"
/>
<rect
data-testid="skeleton-chart-label"
height="5%"
rx="0.4%"
width="4%"
x="89.125%"
y="95%"
/>
</gl-skeleton-loader-stub>
`;
exports[`Resizable Skeleton Loader with custom settings renders the correct position, and size percentages for bars and labels with different settings 1`] = `
<gl-skeleton-loader-stub
baseurl=""
height="130"
preserveaspectratio="xMidYMid meet"
uniquekey=""
width="400"
>
<rect
data-testid="skeleton-chart-grid"
height="1px"
width="100%"
x="0"
y="30%"
/>
<rect
data-testid="skeleton-chart-grid"
height="1px"
width="100%"
x="0"
y="60%"
/>
<rect
data-testid="skeleton-chart-grid"
height="1px"
width="100%"
x="0"
y="90%"
/>
<rect
data-testid="skeleton-chart-bar"
height="5%"
rx="0.6%"
width="3%"
x="6.0625%"
y="85%"
/>
<rect
data-testid="skeleton-chart-bar"
height="7%"
rx="0.6%"
width="3%"
x="18.1875%"
y="83%"
/>
<rect
data-testid="skeleton-chart-bar"
height="9%"
rx="0.6%"
width="3%"
x="30.3125%"
y="81%"
/>
<rect
data-testid="skeleton-chart-bar"
height="14%"
rx="0.6%"
width="3%"
x="42.4375%"
y="76%"
/>
<rect
data-testid="skeleton-chart-bar"
height="21%"
rx="0.6%"
width="3%"
x="54.5625%"
y="69%"
/>
<rect
data-testid="skeleton-chart-bar"
height="35%"
rx="0.6%"
width="3%"
x="66.6875%"
y="55%"
/>
<rect
data-testid="skeleton-chart-bar"
height="50%"
rx="0.6%"
width="3%"
x="78.8125%"
y="40%"
/>
<rect
data-testid="skeleton-chart-bar"
height="80%"
rx="0.6%"
width="3%"
x="90.9375%"
y="10%"
/>
<rect
data-testid="skeleton-chart-label"
height="2%"
rx="0.6%"
width="7%"
x="4.0625%"
y="98%"
/>
<rect
data-testid="skeleton-chart-label"
height="2%"
rx="0.6%"
width="7%"
x="16.1875%"
y="98%"
/>
<rect
data-testid="skeleton-chart-label"
height="2%"
rx="0.6%"
width="7%"
x="28.3125%"
y="98%"
/>
<rect
data-testid="skeleton-chart-label"
height="2%"
rx="0.6%"
width="7%"
x="40.4375%"
y="98%"
/>
<rect
data-testid="skeleton-chart-label"
height="2%"
rx="0.6%"
width="7%"
x="52.5625%"
y="98%"
/>
<rect
data-testid="skeleton-chart-label"
height="2%"
rx="0.6%"
width="7%"
x="64.6875%"
y="98%"
/>
<rect
data-testid="skeleton-chart-label"
height="2%"
rx="0.6%"
width="7%"
x="76.8125%"
y="98%"
/>
<rect
data-testid="skeleton-chart-label"
height="2%"
rx="0.6%"
width="7%"
x="88.9375%"
y="98%"
/>
</gl-skeleton-loader-stub>
`;

View File

@ -0,0 +1,55 @@
import { shallowMount } from '@vue/test-utils';
import ChartSkeletonLoader from '~/vue_shared/components/resizable_chart/skeleton_loader.vue';
describe('Resizable Skeleton Loader', () => {
let wrapper;
const createComponent = (propsData = {}) => {
wrapper = shallowMount(ChartSkeletonLoader, {
propsData,
});
};
const verifyElementsPresence = () => {
const gridItems = wrapper.findAll('[data-testid="skeleton-chart-grid"]').wrappers;
const barItems = wrapper.findAll('[data-testid="skeleton-chart-bar"]').wrappers;
const labelItems = wrapper.findAll('[data-testid="skeleton-chart-label"]').wrappers;
expect(gridItems.length).toBe(3);
expect(barItems.length).toBe(8);
expect(labelItems.length).toBe(8);
};
afterEach(() => {
if (wrapper?.destroy) {
wrapper.destroy();
}
});
describe('default setup', () => {
beforeEach(() => {
createComponent({ uniqueKey: null });
});
it('renders the bars, labels, and grid with correct position, size, and rx percentages', () => {
expect(wrapper.element).toMatchSnapshot();
});
it('renders the correct number of grid items, bars, and labels', () => {
verifyElementsPresence();
});
});
describe('with custom settings', () => {
beforeEach(() => {
createComponent({ uniqueKey: '', rx: 0.6, barWidth: 3, labelWidth: 7, labelHeight: 2 });
});
it('renders the correct position, and size percentages for bars and labels with different settings', () => {
expect(wrapper.element).toMatchSnapshot();
});
it('renders the correct number of grid items, bars, and labels', () => {
verifyElementsPresence();
});
});
});

View File

@ -1,38 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe OnboardingExperimentHelper, type: :helper do
describe '.allow_access_to_onboarding?' do
context "when we're not gitlab.com or dev env" do
it 'returns false' do
allow(::Gitlab).to receive(:dev_env_or_com?).and_return(false)
expect(helper.allow_access_to_onboarding?).to be(false)
end
end
context "when we're gitlab.com or dev env" do
before do
allow(::Gitlab).to receive(:dev_env_or_com?).and_return(true)
end
context 'and the :user_onboarding feature is not enabled' do
it 'returns false' do
stub_feature_flags(user_onboarding: false)
expect(helper.allow_access_to_onboarding?).to be(false)
end
end
context 'and the :user_onboarding feature is enabled' do
it 'returns true' do
stub_feature_flags(user_onboarding: true)
allow(helper).to receive(:current_user).and_return(create(:user))
expect(helper.allow_access_to_onboarding?).to be(true)
end
end
end
end
end

View File

@ -32,7 +32,7 @@ RSpec.describe Gitlab::PrometheusClient do
it 'raises error when status code not 200' do
stub_request(:get, subject.health_url).to_return(status: 500, body: '')
expect { subject.healthy? }.to raise_error(Gitlab::PrometheusClient::Error)
expect { subject.healthy? }.to raise_error(Gitlab::PrometheusClient::UnexpectedResponseError)
end
end
@ -41,41 +41,41 @@ RSpec.describe Gitlab::PrometheusClient do
# - execute_query: A query call
shared_examples 'failure response' do
context 'when request returns 400 with an error message' do
it 'raises a Gitlab::PrometheusClient::Error error' do
it 'raises a Gitlab::PrometheusClient::QueryError error' do
req_stub = stub_prometheus_request(query_url, status: 400, body: { error: 'bar!' })
expect { execute_query }
.to raise_error(Gitlab::PrometheusClient::Error, 'bar!')
.to raise_error(Gitlab::PrometheusClient::QueryError, 'bar!')
expect(req_stub).to have_been_requested
end
end
context 'when request returns 400 without an error message' do
it 'raises a Gitlab::PrometheusClient::Error error' do
it 'raises a Gitlab::PrometheusClient::QueryError error' do
req_stub = stub_prometheus_request(query_url, status: 400)
expect { execute_query }
.to raise_error(Gitlab::PrometheusClient::Error, 'Bad data received')
.to raise_error(Gitlab::PrometheusClient::QueryError, 'Bad data received')
expect(req_stub).to have_been_requested
end
end
context 'when request returns 500' do
it 'raises a Gitlab::PrometheusClient::Error error' do
it 'raises a Gitlab::PrometheusClient::UnexpectedResponseError error' do
req_stub = stub_prometheus_request(query_url, status: 500, body: { message: 'FAIL!' })
expect { execute_query }
.to raise_error(Gitlab::PrometheusClient::Error, '500 - {"message":"FAIL!"}')
.to raise_error(Gitlab::PrometheusClient::UnexpectedResponseError, '500 - {"message":"FAIL!"}')
expect(req_stub).to have_been_requested
end
end
context 'when request returns non json data' do
it 'raises a Gitlab::PrometheusClient::Error error' do
it 'raises a Gitlab::PrometheusClient::UnexpectedResponseError error' do
req_stub = stub_prometheus_request(query_url, status: 200, body: 'not json')
expect { execute_query }
.to raise_error(Gitlab::PrometheusClient::Error, 'Parsing response failed')
.to raise_error(Gitlab::PrometheusClient::UnexpectedResponseError, 'Parsing response failed')
expect(req_stub).to have_been_requested
end
end
@ -85,35 +85,35 @@ RSpec.describe Gitlab::PrometheusClient do
let(:prometheus_url) {"https://prometheus.invalid.example.com/api/v1/query?query=1"}
shared_examples 'exceptions are raised' do
it 'raises a Gitlab::PrometheusClient::Error error when a SocketError is rescued' do
it 'raises a Gitlab::PrometheusClient::ConnectionError error when a SocketError is rescued' do
req_stub = stub_prometheus_request_with_exception(prometheus_url, SocketError)
expect { subject }
.to raise_error(Gitlab::PrometheusClient::Error, "Can't connect to #{prometheus_url}")
.to raise_error(Gitlab::PrometheusClient::ConnectionError, "Can't connect to #{prometheus_url}")
expect(req_stub).to have_been_requested
end
it 'raises a Gitlab::PrometheusClient::Error error when a SSLError is rescued' do
it 'raises a Gitlab::PrometheusClient::ConnectionError error when a SSLError is rescued' do
req_stub = stub_prometheus_request_with_exception(prometheus_url, OpenSSL::SSL::SSLError)
expect { subject }
.to raise_error(Gitlab::PrometheusClient::Error, "#{prometheus_url} contains invalid SSL data")
.to raise_error(Gitlab::PrometheusClient::ConnectionError, "#{prometheus_url} contains invalid SSL data")
expect(req_stub).to have_been_requested
end
it 'raises a Gitlab::PrometheusClient::Error error when a Gitlab::HTTP::ResponseError is rescued' do
it 'raises a Gitlab::PrometheusClient::ConnectionError error when a Gitlab::HTTP::ResponseError is rescued' do
req_stub = stub_prometheus_request_with_exception(prometheus_url, Gitlab::HTTP::ResponseError)
expect { subject }
.to raise_error(Gitlab::PrometheusClient::Error, "Network connection error")
.to raise_error(Gitlab::PrometheusClient::ConnectionError, "Network connection error")
expect(req_stub).to have_been_requested
end
it 'raises a Gitlab::PrometheusClient::Error error when a Gitlab::HTTP::ResponseError with a code is rescued' do
it 'raises a Gitlab::PrometheusClient::ConnectionError error when a Gitlab::HTTP::ResponseError with a code is rescued' do
req_stub = stub_prometheus_request_with_exception(prometheus_url, Gitlab::HTTP::ResponseError.new(code: 400))
expect { subject }
.to raise_error(Gitlab::PrometheusClient::Error, "Network connection error")
.to raise_error(Gitlab::PrometheusClient::ConnectionError, "Network connection error")
expect(req_stub).to have_been_requested
end
end
@ -400,9 +400,9 @@ RSpec.describe Gitlab::PrometheusClient do
context "without response code" do
let(:response_error) { Gitlab::HTTP::ResponseError }
it 'raises PrometheusClient::Error' do
it 'raises PrometheusClient::ConnectionError' do
expect { subject.proxy('query', { query: prometheus_query }) }.to(
raise_error(Gitlab::PrometheusClient::Error, 'Network connection error')
raise_error(Gitlab::PrometheusClient::ConnectionError, 'Network connection error')
)
end
end

View File

@ -2,11 +2,11 @@
require 'spec_helper'
RSpec.describe Gitlab::UsageDataConcerns::Topology do
RSpec.describe Gitlab::UsageData::Topology do
include UsageDataHelpers
describe '#topology_usage_data' do
subject { Class.new.extend(described_class).topology_usage_data }
subject { described_class.new.topology_usage_data }
before do
# this pins down time shifts when benchmarking durations
@ -34,6 +34,7 @@ RSpec.describe Gitlab::UsageDataConcerns::Topology do
expect(subject[:topology]).to eq({
duration_s: 0,
application_requests_per_hour: 36,
failures: [],
nodes: [
{
node_memory_total_bytes: 512,
@ -76,7 +77,7 @@ RSpec.describe Gitlab::UsageDataConcerns::Topology do
end
context 'and some node memory metrics are missing' do
it 'removes the respective entries' do
it 'removes the respective entries and includes the failures' do
expect_prometheus_api_to(
receive_app_request_volume_query(result: []),
receive_node_memory_query(result: []),
@ -89,6 +90,12 @@ RSpec.describe Gitlab::UsageDataConcerns::Topology do
expect(subject[:topology]).to eq({
duration_s: 0,
failures: [
{ 'app_requests' => 'empty_result' },
{ 'node_memory' => 'empty_result' },
{ 'service_rss' => 'empty_result' },
{ 'service_uss' => 'empty_result' }
],
nodes: [
{
node_cpus: 16,
@ -123,31 +130,50 @@ RSpec.describe Gitlab::UsageDataConcerns::Topology do
end
end
context 'and no results are found' do
it 'does not report anything' do
expect_prometheus_api_to receive(:query).at_least(:once).and_return({})
context 'and an error is raised when querying Prometheus' do
it 'returns empty result with failures' do
expect_prometheus_api_to receive(:query)
.at_least(:once)
.and_raise(Gitlab::PrometheusClient::ConnectionError)
expect(subject[:topology]).to eq({
duration_s: 0,
failures: [
{ 'app_requests' => 'Gitlab::PrometheusClient::ConnectionError' },
{ 'node_memory' => 'Gitlab::PrometheusClient::ConnectionError' },
{ 'node_cpus' => 'Gitlab::PrometheusClient::ConnectionError' },
{ 'service_rss' => 'Gitlab::PrometheusClient::ConnectionError' },
{ 'service_uss' => 'Gitlab::PrometheusClient::ConnectionError' },
{ 'service_pss' => 'Gitlab::PrometheusClient::ConnectionError' },
{ 'service_process_count' => 'Gitlab::PrometheusClient::ConnectionError' }
],
nodes: []
})
end
end
context 'and a connection error is raised' do
it 'does not report anything' do
expect_prometheus_api_to receive(:query).and_raise('Connection failed')
expect(subject[:topology]).to eq({ duration_s: 0 })
end
end
end
context 'when embedded Prometheus server is disabled' do
it 'does not report anything' do
it 'returns empty result with no failures' do
expect(Gitlab::Prometheus::Internal).to receive(:prometheus_enabled?).and_return(false)
expect(subject[:topology]).to eq({ duration_s: 0 })
expect(subject[:topology]).to eq({
duration_s: 0,
failures: []
})
end
end
context 'when top-level function raises error' do
it 'returns empty result with generic failure' do
allow(Gitlab::Prometheus::Internal).to receive(:prometheus_enabled?).and_raise(RuntimeError)
expect(subject[:topology]).to eq({
duration_s: 0,
failures: [
{ 'other' => 'RuntimeError' }
]
})
end
end
end

View File

@ -347,6 +347,20 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
expect(subject[:grafana_link_enabled]).to eq(Gitlab::CurrentSettings.grafana_enabled?)
end
context 'with embedded Prometheus' do
it 'returns true when embedded Prometheus is enabled' do
allow(Gitlab::Prometheus::Internal).to receive(:prometheus_enabled?).and_return(true)
expect(subject[:prometheus_enabled]).to eq(true)
end
it 'returns false when embedded Prometheus is disabled' do
allow(Gitlab::Prometheus::Internal).to receive(:prometheus_enabled?).and_return(false)
expect(subject[:prometheus_enabled]).to eq(false)
end
end
context 'with embedded grafana' do
it 'returns true when embedded grafana is enabled' do
stub_application_setting(grafana_enabled: true)

View File

@ -1217,6 +1217,59 @@ RSpec.describe MergeRequest do
end
end
describe "#source_branch_exists?" do
let(:merge_request) { subject }
let(:repository) { merge_request.source_project.repository }
context 'when memoize_source_branch_merge_request feature is enabled' do
before do
stub_feature_flags(memoize_source_branch_merge_request: true)
end
context 'when the source project is set' do
it 'memoizes the value and returns the result' do
expect(repository).to receive(:branch_exists?).once.with(merge_request.source_branch).and_return(true)
2.times { expect(merge_request.source_branch_exists?).to eq(true) }
end
end
context 'when the source project is not set' do
before do
merge_request.source_project = nil
end
it 'returns false' do
expect(merge_request.source_branch_exists?).to eq(false)
end
end
end
context 'when memoize_source_branch_merge_request feature is disabled' do
before do
stub_feature_flags(memoize_source_branch_merge_request: false)
end
context 'when the source project is set' do
it 'does not memoize the value and returns the result' do
expect(repository).to receive(:branch_exists?).twice.with(merge_request.source_branch).and_return(true)
2.times { expect(merge_request.source_branch_exists?).to eq(true) }
end
end
context 'when the source project is not set' do
before do
merge_request.source_project = nil
end
it 'returns false' do
expect(merge_request.source_branch_exists?).to eq(false)
end
end
end
end
describe '#default_merge_commit_message' do
it 'includes merge information as the title' do
request = build(:merge_request, source_branch: 'source', target_branch: 'target')

View File

@ -23,7 +23,7 @@ RSpec.describe PrometheusService, :use_clean_rails_memory_store_caching do
# result = { success: false, result: error }
expect(result[:success]).to be_falsy
expect(result[:result]).to be_instance_of(Gitlab::PrometheusClient::Error)
expect(result[:result]).to be_instance_of(Gitlab::PrometheusClient::UnexpectedResponseError)
expect(redirect_req_stub).to have_been_requested
expect(redirected_req_stub).not_to have_been_requested

View File

@ -110,14 +110,14 @@ RSpec.describe 'getting Alert Management Alerts' do
it_behaves_like 'a working graphql query'
it 'sorts in the correct order' do
expect(iids).to eq [resolved_alert.iid.to_s, triggered_alert.iid.to_s]
expect(iids).to eq [triggered_alert.iid.to_s, resolved_alert.iid.to_s]
end
context 'ascending order' do
let(:params) { 'sort: SEVERITY_ASC' }
it 'sorts in the correct order' do
expect(iids).to eq [triggered_alert.iid.to_s, resolved_alert.iid.to_s]
expect(iids).to eq [resolved_alert.iid.to_s, triggered_alert.iid.to_s]
end
end
end

View File

@ -30,6 +30,7 @@ RSpec.describe MergeRequests::Conflicts::ListService do
it 'returns a falsey value when one of the MR branches is missing' do
merge_request = create_merge_request('conflict-resolvable')
merge_request.project.repository.rm_branch(merge_request.author, 'conflict-resolvable')
merge_request.clear_memoized_source_branch_exists
expect(conflicts_service(merge_request).can_be_resolved_in_ui?).to be_falsey
end