Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-03-11 15:09:10 +00:00
parent 7ca4444627
commit 9c0f4306f6
56 changed files with 436 additions and 239 deletions

View File

@ -16,7 +16,6 @@ import {
import * as Sentry from '@sentry/browser';
import { isEmpty, omit } from 'lodash';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import {
integrationTypes,
integrationSteps,
@ -60,7 +59,6 @@ export default {
directives: {
GlModal: GlModalDirective,
},
mixins: [glFeatureFlagsMixin()],
inject: {
generic: {
default: {},
@ -163,12 +161,7 @@ export default {
};
},
showMappingBuilder() {
return (
this.multiIntegrations &&
this.glFeatures.multipleHttpIntegrationsCustomMapping &&
this.isHttp &&
this.alertFields?.length
);
return this.multiIntegrations && this.isHttp && this.alertFields?.length;
},
hasSamplePayload() {
return this.isValidNonEmptyJSON(this.currentIntegration?.payloadExample);
@ -234,12 +227,10 @@ export default {
},
submit() {
const { name, apiUrl } = this.integrationForm;
const customMappingVariables = this.glFeatures.multipleHttpIntegrationsCustomMapping
? {
payloadAttributeMappings: this.mapping,
payloadExample: this.samplePayload.json || '{}',
}
: {};
const customMappingVariables = {
payloadAttributeMappings: this.mapping,
payloadExample: this.samplePayload.json || '{}',
};
const variables =
this.selectedIntegration === typeSet.http

View File

@ -63,10 +63,7 @@ export default (el) => {
render(createElement) {
return createElement('alert-settings-wrapper', {
props: {
alertFields:
gon.features?.multipleHttpIntegrationsCustomMapping && parseBoolean(multiIntegrations)
? JSON.parse(alertFields)
: null,
alertFields: parseBoolean(multiIntegrations) ? JSON.parse(alertFields) : null,
},
});
},

View File

@ -3,7 +3,6 @@ import { buildApiUrl } from './api_utils';
import { DEFAULT_PER_PAGE } from './constants';
const GROUPS_PATH = '/api/:version/groups.json';
const GROUPS_MEMBERS_SINGLE_PATH = '/api/:version/groups/:group_id/members/:id';
export function getGroups(query, options, callback = () => {}) {
const url = buildApiUrl(GROUPS_PATH);
@ -21,11 +20,3 @@ export function getGroups(query, options, callback = () => {}) {
return data;
});
}
export function removeMemberFromGroup(groupId, memberId, options) {
const url = buildApiUrl(GROUPS_MEMBERS_SINGLE_PATH)
.replace(':group_id', groupId)
.replace(':id', memberId);
return axios.delete(url, { params: { ...options } });
}

View File

@ -79,12 +79,12 @@ export default {
<form>
<div class="gl-display-flex">
<gl-toggle
data-qa-selector="allow_duplicates_checkbox"
data-qa-selector="allow_duplicates_toggle"
:value="mavenDuplicatesAllowed"
@change="update($options.modelNames.MAVEN_DUPLICATES_ALLOWED, $event)"
/>
<div class="gl-ml-5">
<div data-testid="toggle-label">
<div data-testid="toggle-label" data-qa-selector="allow_duplicates_label">
<gl-sprintf :message="enabledButtonLabel">
<template #bold="{ content }">
<strong>{{ content }}</strong>

View File

@ -237,7 +237,6 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
[
*::ApplicationSettingsHelper.visible_attributes,
*::ApplicationSettingsHelper.external_authorization_service_attributes,
*ApplicationSetting.repository_storages_weighted_attributes,
*ApplicationSetting.kroki_formats_attributes.keys.map { |key| "kroki_formats_#{key}".to_sym },
:lets_encrypt_notification_email,
:lets_encrypt_terms_of_service_accepted,
@ -248,8 +247,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:default_branch_name,
disabled_oauth_sign_in_sources: [],
import_sources: [],
repository_storages: [],
restricted_visibility_levels: []
restricted_visibility_levels: [],
repository_storages_weighted: {}
]
end

View File

@ -6,10 +6,6 @@ module Projects
before_action :authorize_admin_operations!
before_action :authorize_read_prometheus_alerts!, only: [:reset_alerting_token]
before_action do
push_frontend_feature_flag(:multiple_http_integrations_custom_mapping, @project)
end
respond_to :json, only: [:reset_alerting_token, :reset_pagerduty_token]
helper_method :error_tracking_setting

View File

@ -37,13 +37,8 @@ module ApplicationSettingsHelper
end
def storage_weights
ApplicationSetting.repository_storages_weighted_attributes.map do |attribute|
storage = attribute.to_s.delete_prefix('repository_storages_weighted_')
{
name: attribute,
label: storage,
value: @application_setting.repository_storages_weighted[storage] || 0
}
Gitlab.config.repositories.storages.keys.each_with_object(OpenStruct.new) do |storage, weights|
weights[storage.to_sym] = @application_setting.repository_storages_weighted[storage] || 0
end
end

View File

@ -4,8 +4,8 @@ module DiffHelper
def mark_inline_diffs(old_line, new_line)
old_diffs, new_diffs = Gitlab::Diff::InlineDiff.new(old_line, new_line).inline_diffs
marked_old_line = Gitlab::Diff::InlineDiffMarker.new(old_line).mark(old_diffs, mode: :deletion)
marked_new_line = Gitlab::Diff::InlineDiffMarker.new(new_line).mark(new_diffs, mode: :addition)
marked_old_line = Gitlab::Diff::InlineDiffMarker.new(old_line).mark(old_diffs)
marked_new_line = Gitlab::Diff::InlineDiffMarker.new(new_line).mark(new_diffs)
[marked_old_line, marked_new_line]
end

View File

@ -25,10 +25,6 @@ class ApplicationSetting < ApplicationRecord
alias_attribute :instance_group_id, :instance_administrators_group_id
alias_attribute :instance_administrators_group, :instance_group
def self.repository_storages_weighted_attributes
@repository_storages_weighted_atributes ||= Gitlab.config.repositories.storages.keys.map { |k| "repository_storages_weighted_#{k}".to_sym }.freeze
end
def self.kroki_formats_attributes
{
blockdiag: {
@ -44,7 +40,6 @@ class ApplicationSetting < ApplicationRecord
end
store_accessor :kroki_formats, *ApplicationSetting.kroki_formats_attributes.keys, prefix: true
store_accessor :repository_storages_weighted, *Gitlab.config.repositories.storages.keys, prefix: true
# Include here so it can override methods from
# `add_authentication_token_field`
@ -503,6 +498,7 @@ class ApplicationSetting < ApplicationRecord
inclusion: { in: [true, false], message: _('must be a boolean value') }
before_validation :ensure_uuid!
before_validation :coerce_repository_storages_weighted, if: :repository_storages_weighted_changed?
before_save :ensure_runners_registration_token
before_save :ensure_health_check_access_token
@ -583,12 +579,6 @@ class ApplicationSetting < ApplicationRecord
recaptcha_enabled || login_recaptcha_protection_enabled
end
repository_storages_weighted_attributes.each do |attribute|
define_method :"#{attribute}=" do |value|
super(value.to_i)
end
end
kroki_formats_attributes.keys.each do |key|
define_method :"kroki_formats_#{key}=" do |value|
super(::Gitlab::Utils.to_boolean(value))

View File

@ -123,7 +123,7 @@ module ApplicationSettingImplementation
raw_blob_request_limit: 300,
recaptcha_enabled: false,
repository_checks_enabled: true,
repository_storages_weighted: { default: 100 },
repository_storages_weighted: { 'default' => 100 },
repository_storages: ['default'],
require_admin_approval_after_user_signup: true,
require_two_factor_authentication: false,
@ -298,10 +298,6 @@ module ApplicationSettingImplementation
Array(read_attribute(:repository_storages))
end
def repository_storages_weighted
read_attribute(:repository_storages_weighted)
end
def commit_email_hostname
super.presence || self.class.default_commit_email_hostname
end
@ -333,9 +329,10 @@ module ApplicationSettingImplementation
def normalized_repository_storage_weights
strong_memoize(:normalized_repository_storage_weights) do
weights_total = repository_storages_weighted.values.reduce(:+)
repository_storages_weights = repository_storages_weighted.slice(*Gitlab.config.repositories.storages.keys)
weights_total = repository_storages_weights.values.reduce(:+)
repository_storages_weighted.transform_values do |w|
repository_storages_weights.transform_values do |w|
next w if weights_total == 0
w.to_f / weights_total
@ -473,16 +470,20 @@ module ApplicationSettingImplementation
invalid.empty?
end
def coerce_repository_storages_weighted
repository_storages_weighted.transform_values!(&:to_i)
end
def check_repository_storages_weighted
invalid = repository_storages_weighted.keys - Gitlab.config.repositories.storages.keys
errors.add(:repository_storages_weighted, "can't include: %{invalid_storages}" % { invalid_storages: invalid.join(", ") }) unless
errors.add(:repository_storages_weighted, _("can't include: %{invalid_storages}") % { invalid_storages: invalid.join(", ") }) unless
invalid.empty?
repository_storages_weighted.each do |key, val|
next unless val.present?
errors.add(:"repository_storages_weighted_#{key}", "value must be an integer") unless val.is_a?(Integer)
errors.add(:"repository_storages_weighted_#{key}", "value must be between 0 and 100") unless val.between?(0, 100)
errors.add(:repository_storages_weighted, _("value for '%{storage}' must be an integer") % { storage: key }) unless val.is_a?(Integer)
errors.add(:repository_storages_weighted, _("value for '%{storage}' must be between 0 and 100") % { storage: key }) unless val.between?(0, 100)
end
end

View File

@ -42,7 +42,6 @@ class PipelineSerializer < BaseSerializer
[
:cancelable_statuses,
:latest_statuses_ordered_by_stage,
:latest_builds_report_results,
:retryable_builds,
:stages,
:latest_statuses,

View File

@ -125,8 +125,8 @@ module SystemNotes
old_diffs, new_diffs = Gitlab::Diff::InlineDiff.new(old_title, new_title).inline_diffs
marked_old_title = Gitlab::Diff::InlineDiffMarkdownMarker.new(old_title).mark(old_diffs, mode: :deletion)
marked_new_title = Gitlab::Diff::InlineDiffMarkdownMarker.new(new_title).mark(new_diffs, mode: :addition)
marked_old_title = Gitlab::Diff::InlineDiffMarkdownMarker.new(old_title).mark(old_diffs)
marked_new_title = Gitlab::Diff::InlineDiffMarkdownMarker.new(new_title).mark(new_diffs)
body = "changed title from **#{marked_old_title}** to **#{marked_new_title}**"

View File

@ -0,0 +1,28 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"title": "Security::Scan#info schema",
"description": "The schema validates the content of the Security::Scan#info attribute",
"additionalProperties": false,
"properties": {
"errors": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"type": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"type",
"message"
]
}
}
}
}

View File

@ -18,8 +18,9 @@
= _('Enter weights for storages for new repositories.')
= link_to sprite_icon('question-o'), help_page_path('administration/repository_storage_paths')
.form-check
- storage_weights.each do |attribute|
= f.text_field attribute[:name], class: 'form-text-input', value: attribute[:value]
= f.label attribute[:label], attribute[:label], class: 'label-bold form-check-label'
%br
= f.fields_for :repository_storages_weighted, storage_weights do |storage_form|
- Gitlab.config.repositories.storages.keys.each do |storage|
= storage_form.text_field storage, class: 'form-text-input'
= storage_form.label storage, storage, class: 'label-bold form-check-label'
%br
= f.submit _('Save changes'), class: "gl-button btn btn-confirm"

View File

@ -30,5 +30,5 @@
= render_if_exists 'import/github/ci_cd_only'
.form-actions.d-flex.justify-content-end
= link_to _('Cancel'), new_project_path, class: 'btn'
= submit_tag _('Authenticate'), class: 'btn btn-success ml-2', data: { qa_selector: 'authenticate_button' }
= link_to _('Cancel'), new_project_path, class: 'gl-button btn btn-default'
= submit_tag _('Authenticate'), class: 'gl-button btn btn-confirm ml-2', data: { qa_selector: 'authenticate_button' }

View File

@ -0,0 +1,5 @@
---
title: "Introduce `info` column for the `security_scans` table"
merge_request: 55983
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Allow saving repository weights after a storage has been removed
merge_request: 55689
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Apply new GitLab UI for buttons on GitHub Import page
merge_request: 56096
author: Yogi (@yo)
type: changed

View File

@ -0,0 +1,5 @@
---
title: Remove latest_builds_report_results preloading in pipeline serializer
merge_request: 56181
author:
type: performance

View File

@ -1,8 +1,8 @@
---
name: multiple_http_integrations_custom_mapping
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46437
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/273573
milestone: '13.6'
name: introduce_marker_ranges
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55669
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/324068
milestone: '13.10'
type: development
group: group::monitor
group: group::source code
default_enabled: false

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class AddInfoColumnIntoSecurityScansTable < ActiveRecord::Migration[6.0]
DOWNTIME = false
def change
add_column :security_scans, :info, :jsonb, null: false, default: {}
end
end

View File

@ -0,0 +1 @@
a81f3555d0e1159569687d4967edcd2b5706cdafd5defb8dc725e295eb969861

View File

@ -17244,7 +17244,8 @@ CREATE TABLE security_scans (
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
build_id bigint NOT NULL,
scan_type smallint NOT NULL
scan_type smallint NOT NULL,
info jsonb DEFAULT '{}'::jsonb NOT NULL
);
CREATE SEQUENCE security_scans_id_seq

View File

@ -71,7 +71,7 @@ Where:
| `enabled` | `true` or `false`. Enables the Registry in GitLab. By default this is `false`. |
| `host` | The host URL under which the Registry runs and users can use. |
| `port` | The port the external Registry domain listens on. |
| `api_url` | The internal API URL under which the Registry is exposed. It defaults to `http://localhost:5000`. |
| `api_url` | The internal API URL under which the Registry is exposed. It defaults to `http://localhost:5000`. Do not change this unless you are setting up an [external Docker registry](#use-an-external-container-registry-with-gitlab-as-an-auth-endpoint). |
| `key` | The private key location that is a pair of Registry's `rootcertbundle`. Read the [token auth configuration documentation](https://docs.docker.com/registry/configuration/#token). |
| `path` | This should be the same directory like specified in Registry's `rootdirectory`. Read the [storage configuration documentation](https://docs.docker.com/registry/configuration/#storage). This path needs to be readable by the GitLab user, the web-server user and the Registry user. Read more in [#configure-storage-for-the-container-registry](#configure-storage-for-the-container-registry). |
| `issuer` | This should be the same value as configured in Registry's `issuer`. Read the [token auth configuration documentation](https://docs.docker.com/registry/configuration/#token). |
@ -630,18 +630,18 @@ You can use GitLab as an auth endpoint with an external container registry.
```ruby
gitlab_rails['registry_enabled'] = true
gitlab_rails['registry_api_url'] = "http://localhost:5000"
gitlab_rails['registry_api_url'] = "https://<external_registry_host>:5000"
gitlab_rails['registry_issuer'] = "gitlab-issuer"
```
`gitlab_rails['registry_enabled'] = true` is needed to enable GitLab
Container Registry features and authentication endpoint. The GitLab bundled
Container Registry service does not start, even with this enabled.
`gitlab_rails['registry_api_url'] = "http://localhost:5000"` can
carry a different hostname and port depending on where the external registry
is hosted. It must also specify `https` if the external registry is
configured to use TLS.
- `gitlab_rails['registry_enabled'] = true` is needed to enable GitLab
Container Registry features and authentication endpoint. The GitLab bundled
Container Registry service does not start, even with this enabled.
- `gitlab_rails['registry_api_url'] = "http://<external_registry_host>:5000"`
must be changed to match the host where Registry is installed.
It must also specify `https` if the external registry is
configured to use TLS. Read more on the
[Docker registry documentation](https://docs.docker.com/registry/deploying/).
1. A certificate-key pair is required for GitLab and the external container
registry to communicate securely. You need to create a certificate-key
@ -688,12 +688,14 @@ You can use GitLab as an auth endpoint with an external container registry.
enabled: true
host: "registry.gitlab.example.com"
port: "5005"
api_url: "http://localhost:5000"
path: /var/opt/gitlab/gitlab-rails/shared/registry
key: /var/opt/gitlab/gitlab-rails/certificate.key
api_url: "https://<external_registry_host>:5000"
path: /var/lib/registry
key: /path/to/keyfile
issuer: gitlab-issuer
```
[Read more](#enable-the-container-registry) about what these parameters mean.
1. Save the file and [restart GitLab](../restart_gitlab.md#installations-from-source) for the changes to take effect.
## Configure Container Registry notifications

View File

@ -5190,6 +5190,7 @@ All possible ways to specify the API surface for an API fuzzing scan.
| ----- | ----------- |
| `HAR` | The API surface is specified by a HAR file. |
| `OPENAPI` | The API surface is specified by a OPENAPI file. |
| `POSTMAN` | The API surface is specified by a POSTMAN file. |
### `AvailabilityEnum`

View File

@ -68,7 +68,7 @@ For more details, please refer to our [full architecture documentation](https://
The setup process involves a few steps to enable GitOps deployments:
1. [Install the Agent server](#install-the-kubernetes-agent-server).
1. [Install the Agent server](#install-the-kubernetes-agent-server) for your GitLab instance.
1. [Define a configuration repository](#define-a-configuration-repository).
1. [Create an Agent record in GitLab](#create-an-agent-record-in-gitlab).
1. [Generate and copy a Secret token used to connect to the Agent](#create-the-kubernetes-secret).
@ -91,14 +91,19 @@ Upgrade your agent installations together with GitLab upgrades. To decide which
The available `agentk` and `kas` versions can be found in
[the container registry](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/container_registry/).
### Install the Kubernetes Agent Server
### Install the Kubernetes Agent Server **(FREE SELF)**
The GitLab Kubernetes Agent Server (KAS) can be deployed using [Omnibus GitLab](https://docs.gitlab.com/omnibus/) or the
[GitLab chart](https://gitlab.com/gitlab-org/charts/gitlab). If you don't already have
GitLab installed, please refer to our [installation documentation](../../../install/index.md).
[Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3834) in GitLab 13.10,
the GitLab Kubernetes Agent Server (KAS) is available on GitLab.com under `wss://kas.gitlab.com`.
If you are a GitLab.com user, skip this step and directly
[set up the configuration repository](#define-a-configuration-repository)
for your agent.
NOTE:
GitLab plans to include the KAS on [GitLab.com](https://gitlab.com/groups/gitlab-org/-/epics/3834).
The GitLab Kubernetes Agent Server (KAS) can be deployed using [Omnibus
GitLab](https://docs.gitlab.com/omnibus/) or the [GitLab
chart](https://gitlab.com/gitlab-org/charts/gitlab). If you don't already have
GitLab installed, please refer to our [installation
documentation](https://docs.gitlab.com/ee/install/README.html).
#### Install with Omnibus
@ -230,6 +235,9 @@ the Agent in subsequent steps. You can create an Agent record either:
Next, install the in-cluster component of the Agent.
NOTE:
For GitLab.com users, the KAS is available at `wss://kas.gitlab.com`.
#### One-liner installation
Replace the value of `agent-token` below with the token received from the previous step. Also, replace `kas-address` with the configured access of the Kubernetes Agent Server:

View File

@ -91,8 +91,6 @@ module API
end
params :optional_update_params_ee do
optional :issues_template, type: String, desc: 'Default description for Issues'
optional :merge_requests_template, type: String, desc: 'Default description for Merge Requests'
end
params :optional_update_params do
@ -130,10 +128,8 @@ module API
:emails_disabled,
:forking_access_level,
:issues_access_level,
:issues_template,
:lfs_enabled,
:merge_requests_access_level,
:merge_requests_template,
:merge_method,
:name,
:only_allow_merge_if_all_discussions_are_resolved,

View File

@ -120,7 +120,7 @@ module Banzai
end
def autolink_filter(text)
Gitlab::StringRegexMarker.new(CGI.unescapeHTML(text), text.html_safe).mark(LINK_PATTERN) do |link, left:, right:|
Gitlab::StringRegexMarker.new(CGI.unescapeHTML(text), text.html_safe).mark(LINK_PATTERN) do |link, left:, right:, mode:|
autolink_match(link).html_safe
end
end

View File

@ -76,7 +76,7 @@ module Banzai
end
def spaced_link_filter(text)
Gitlab::StringRegexMarker.new(CGI.unescapeHTML(text), text.html_safe).mark(LINK_OR_IMAGE_PATTERN) do |link, left:, right:|
Gitlab::StringRegexMarker.new(CGI.unescapeHTML(text), text.html_safe).mark(LINK_OR_IMAGE_PATTERN) do |link, left:, right:, mode:|
spaced_link_match(link).html_safe
end
end

View File

@ -80,7 +80,7 @@ module Gitlab
highlighted_lines.map!.with_index do |rich_line, i|
marker = StringRegexMarker.new((plain_lines[i].chomp! || plain_lines[i]), rich_line.html_safe)
marker.mark(regex, group: :name) do |text, left:, right:|
marker.mark(regex, group: :name) do |text, left:, right:, mode:|
url = yield(text)
url ? link_tag(text, url) : text
end

View File

@ -22,7 +22,7 @@ module Gitlab
i, j = match.offset(:name)
marker = StringRangeMarker.new(plain_line, rich_line.html_safe)
marker.mark([i..(j - 1)]) do |text, left:, right:|
marker.mark([i..(j - 1)]) do |text, left:, right:, mode:|
url = package_url(text, match[:version])
url ? link_tag(text, url) : text
end

View File

@ -21,7 +21,7 @@ module Gitlab
i2, j2 = match.offset(:checksum)
marker = StringRangeMarker.new(plain_line, rich_line.html_safe)
marker.mark([i0..(j0 - 1), i2..(j2 - 1)]) do |text, left:, right:|
marker.mark([i0..(j0 - 1), i2..(j2 - 1)]) do |text, left:, right:, mode:|
if left
url = package_url(text, match[:version])
url ? link_tag(text, url) : text

View File

@ -32,12 +32,12 @@ module Gitlab
end
if action == :delete
old_diffs << (old_pointer..(old_pointer + content_size - 1))
old_diffs << MarkerRange.new(old_pointer, old_pointer + content_size - 1, mode: MarkerRange::DELETION)
old_pointer += content_size
end
if action == :insert
new_diffs << (new_pointer..(new_pointer + content_size - 1))
new_diffs << MarkerRange.new(new_pointer, new_pointer + content_size - 1, mode: MarkerRange::ADDITION)
new_pointer += content_size
end
end

View File

@ -3,12 +3,13 @@
module Gitlab
module Diff
class Highlight
attr_reader :diff_file, :diff_lines, :raw_lines, :repository
attr_reader :diff_file, :diff_lines, :raw_lines, :repository, :project
delegate :old_path, :new_path, :old_sha, :new_sha, to: :diff_file, prefix: :diff
def initialize(diff_lines, repository: nil)
@repository = repository
@project = repository&.project
if diff_lines.is_a?(Gitlab::Diff::File)
@diff_file = diff_lines
@ -30,6 +31,12 @@ module Gitlab
if line_inline_diffs = inline_diffs[i]
begin
# MarkerRange objects are converted to Ranges to keep the previous behavior
# Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/324068
if Feature.disabled?(:introduce_marker_ranges, project, default_enabled: :yaml)
line_inline_diffs = line_inline_diffs.map { |marker_range| marker_range.to_range }
end
rich_line = InlineDiffMarker.new(diff_line.text, rich_line).mark(line_inline_diffs)
# This should only happen when the encoding of the diff doesn't
# match the blob, which is a bug. But we shouldn't fail to render

View File

@ -69,7 +69,12 @@ module Gitlab
def key
strong_memoize(:redis_key) do
['highlighted-diff-files', diffable.cache_key, VERSION, diff_options].join(":")
[
'highlighted-diff-files',
diffable.cache_key, VERSION,
diff_options,
Feature.enabled?(:introduce_marker_ranges, diffable.project, default_enabled: :yaml)
].join(":")
end
end

View File

@ -8,8 +8,8 @@ module Gitlab
deletion: "-"
}.freeze
def mark(line_inline_diffs, mode: nil)
super(line_inline_diffs) do |text, left:, right:|
def mark(line_inline_diffs)
super(line_inline_diffs) do |text, left:, right:, mode:|
symbol = MARKDOWN_SYMBOLS[mode]
"{#{symbol}#{text}#{symbol}}"
end

View File

@ -7,8 +7,8 @@ module Gitlab
super(line, rich_line || line)
end
def mark(line_inline_diffs, mode: nil)
super(line_inline_diffs) do |text, left:, right:|
def mark(line_inline_diffs)
super(line_inline_diffs) do |text, left:, right:, mode:|
%{<span class="#{html_class_names(left, right, mode)}">#{text}</span>}.html_safe
end
end

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
# It is a Range object extended with `mode` attribute
# MarkerRange not only keeps information about changed characters, but also
# the type of changes
module Gitlab
class MarkerRange < Range
DELETION = :deletion
ADDITION = :addition
# Converts Range object to MarkerRange class
def self.from_range(range)
return range if range.is_a?(self)
new(range.begin, range.end, exclude_end: range.exclude_end?)
end
def initialize(first, last, exclude_end: false, mode: nil)
super(first, last, exclude_end)
@mode = mode
end
def to_range
Range.new(self.begin, self.end, self.exclude_end?)
end
attr_reader :mode
end
end

View File

@ -15,8 +15,10 @@ module Gitlab
end
end
def mark(marker_ranges)
return rich_line unless marker_ranges&.any?
def mark(ranges)
return rich_line unless ranges&.any?
marker_ranges = ranges.map { |range| Gitlab::MarkerRange.from_range(range) }
if html_escaped
rich_marker_ranges = []
@ -24,7 +26,7 @@ module Gitlab
# Map the inline-diff range based on the raw line to character positions in the rich line
rich_positions = position_mapping[range].flatten
# Turn the array of character positions into ranges
rich_marker_ranges.concat(collapse_ranges(rich_positions))
rich_marker_ranges.concat(collapse_ranges(rich_positions, range.mode))
end
else
rich_marker_ranges = marker_ranges
@ -36,7 +38,7 @@ module Gitlab
offset_range = (range.begin + offset)..(range.end + offset)
original_text = rich_line[offset_range]
text = yield(original_text, left: i == 0, right: i == rich_marker_ranges.length - 1)
text = yield(original_text, left: i == 0, right: i == rich_marker_ranges.length - 1, mode: range.mode)
rich_line[offset_range] = text
@ -90,21 +92,21 @@ module Gitlab
end
# Takes an array of integers, and returns an array of ranges covering the same integers
def collapse_ranges(positions)
def collapse_ranges(positions, mode)
return [] if positions.empty?
ranges = []
start = prev = positions[0]
range = start..prev
range = MarkerRange.new(start, prev, mode: mode)
positions[1..-1].each do |pos|
if pos == prev + 1
range = start..pos
range = MarkerRange.new(start, pos, mode: mode)
prev = pos
else
ranges << range
start = prev = pos
range = start..prev
range = MarkerRange.new(start, prev, mode: mode)
end
end
ranges << range

View File

@ -1483,6 +1483,9 @@ msgstr ""
msgid "APIFuzzing|Ex: $TestUsername"
msgstr ""
msgid "APIFuzzing|Ex: Project_Test/File/example_fuzz"
msgstr ""
msgid "APIFuzzing|Ex: Project_Test/File/example_fuzz.har"
msgstr ""
@ -1507,6 +1510,9 @@ msgstr ""
msgid "APIFuzzing|Password for basic authentication"
msgstr ""
msgid "APIFuzzing|Postman collections are a group of saved requests you can organize into folders."
msgstr ""
msgid "APIFuzzing|Scan mode"
msgstr ""
@ -3224,6 +3230,9 @@ msgstr ""
msgid "An application called %{link_to_client} is requesting access to your GitLab account."
msgstr ""
msgid "An assignee list displays issues assigned to the selected user"
msgstr ""
msgid "An email notification was recently sent from the admin panel. Please wait %{wait_time_in_words} before attempting to send another message."
msgstr ""
@ -9413,6 +9422,9 @@ msgstr ""
msgid "DastProfiles|Authentication URL"
msgstr ""
msgid "DastProfiles|Branch missing"
msgstr ""
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@ -9584,6 +9596,9 @@ msgstr ""
msgid "DastProfiles|Scanner name"
msgstr ""
msgid "DastProfiles|Select branch"
msgstr ""
msgid "DastProfiles|Show debug messages"
msgstr ""
@ -12629,6 +12644,9 @@ msgstr ""
msgid "Failed to install."
msgstr ""
msgid "Failed to load assignees."
msgstr ""
msgid "Failed to load assignees. Please try again."
msgstr ""
@ -22817,6 +22835,9 @@ msgstr ""
msgid "Policy project doesn't exists"
msgstr ""
msgid "Postman collection"
msgstr ""
msgid "Pre-defined push rules."
msgstr ""
@ -26413,6 +26434,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
msgid "Search assignees"
msgstr ""
msgid "Search authors"
msgstr ""
@ -35100,6 +35124,9 @@ msgstr ""
msgid "can't be enabled because signed commits are required for this project"
msgstr ""
msgid "can't include: %{invalid_storages}"
msgstr ""
msgid "cannot be a date in the past"
msgstr ""
@ -36506,6 +36533,12 @@ msgstr ""
msgid "v%{version} published %{timeAgo}"
msgstr ""
msgid "value for '%{storage}' must be an integer"
msgstr ""
msgid "value for '%{storage}' must be between 0 and 100"
msgstr ""
msgid "verify ownership"
msgstr ""

View File

@ -12,18 +12,28 @@ module QA
end
view 'app/assets/javascripts/packages_and_registries/settings/group/components/maven_settings.vue' do
element :allow_duplicates_checkbox
element :allow_duplicates_toggle
element :allow_duplicates_label
end
def set_allow_duplicates_disabled
expand_content :package_registry_settings_content do
uncheck_element :allow_duplicates_checkbox
click_element(:allow_duplicates_toggle) if duplicates_enabled?
end
end
def has_allow_duplicates_enabled?
expand_content :package_registry_settings_content
!find_element(:allow_duplicates_checkbox).checked?
def set_allow_duplicates_enabled
expand_content :package_registry_settings_content do
click_element(:allow_duplicates_toggle) if duplicates_disabled?
end
end
def duplicates_enabled?
has_element?(:allow_duplicates_label, text: 'Allow duplicates')
end
def duplicates_disabled?
has_element?(:allow_duplicates_label, text: 'Do not allow duplicates')
end
end
end

View File

@ -223,9 +223,7 @@ module QA
project.group.visit!
Page::Group::Menu.perform(&:go_to_package_settings)
Page::Group::Settings::PackageRegistries.perform do |settings|
expect(settings).to have_allow_duplicates_enabled
end
Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_enabled)
end
it 'allows users to publish duplicate Maven packages at the group level', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1722' do

View File

@ -144,10 +144,10 @@ RSpec.describe Admin::ApplicationSettingsController do
end
it 'updates repository_storages_weighted setting' do
put :update, params: { application_setting: { repository_storages_weighted_default: 75 } }
put :update, params: { application_setting: { repository_storages_weighted: { default: 75 } } }
expect(response).to redirect_to(general_admin_application_settings_path)
expect(ApplicationSetting.current.repository_storages_weighted_default).to eq(75)
expect(ApplicationSetting.current.repository_storages_weighted).to eq('default' => 75)
end
it 'updates kroki_formats setting' do

View File

@ -384,7 +384,20 @@ RSpec.describe 'Admin updates settings' do
click_button 'Save changes'
end
expect(current_settings.repository_storages_weighted_default).to be 50
expect(current_settings.repository_storages_weighted).to eq('default' => 50)
end
it 'still saves when settings are outdated' do
current_settings.update_attribute :repository_storages_weighted, { 'default' => 100, 'outdated' => 100 }
visit repository_admin_application_settings_path
page.within('.as-repository-storage') do
fill_in 'application_setting_repository_storages_weighted_default', with: 50
click_button 'Save changes'
end
expect(current_settings.repository_storages_weighted).to eq('default' => 50)
end
end

View File

@ -19,7 +19,6 @@ RSpec.describe 'Alert integrations settings form', :js do
describe 'when viewing alert integrations as a maintainer' do
context 'with the default page permissions' do
before do
stub_feature_flags(multiple_http_integrations_custom_mapping: false)
visit project_settings_operations_path(project, anchor: 'js-alert-management-settings')
wait_for_requests
end

View File

@ -12,12 +12,7 @@ describe('AlertsSettingsForm', () => {
let wrapper;
const mockToastShow = jest.fn();
const createComponent = ({
data = {},
props = {},
multipleHttpIntegrationsCustomMapping = false,
multiIntegrations = true,
} = {}) => {
const createComponent = ({ data = {}, props = {}, multiIntegrations = true } = {}) => {
wrapper = mount(AlertsSettingsForm, {
data() {
return { ...data };
@ -29,7 +24,6 @@ describe('AlertsSettingsForm', () => {
},
provide: {
...defaultAlertSettingsConfig,
glFeatures: { multipleHttpIntegrationsCustomMapping },
multiIntegrations,
},
mocks: {
@ -142,27 +136,8 @@ describe('AlertsSettingsForm', () => {
describe('submitting integration form', () => {
describe('HTTP', () => {
it('create', async () => {
createComponent();
const integrationName = 'Test integration';
await selectOptionAtIndex(1);
enableIntegration(0, integrationName);
const submitBtn = findSubmitButton();
expect(submitBtn.exists()).toBe(true);
expect(submitBtn.text()).toBe('Save integration');
findForm().trigger('submit');
expect(wrapper.emitted('create-new-integration')[0]).toEqual([
{ type: typeSet.http, variables: { name: integrationName, active: true } },
]);
});
it('create with custom mapping', async () => {
createComponent({
multipleHttpIntegrationsCustomMapping: true,
multiIntegrations: true,
props: { alertFields },
});
@ -208,9 +183,19 @@ describe('AlertsSettingsForm', () => {
findForm().trigger('submit');
expect(wrapper.emitted('update-integration')[0]).toEqual([
{ type: typeSet.http, variables: { name: updatedIntegrationName, active: true } },
]);
expect(wrapper.emitted('update-integration')[0]).toEqual(
expect.arrayContaining([
{
type: typeSet.http,
variables: {
name: updatedIntegrationName,
active: true,
payloadAttributeMappings: [],
payloadExample: '{}',
},
},
]),
);
});
});
@ -301,7 +286,6 @@ describe('AlertsSettingsForm', () => {
beforeEach(() => {
createComponent({
multipleHttpIntegrationsCustomMapping: true,
data: {
currentIntegration: {
type: typeSet.http,
@ -408,22 +392,18 @@ describe('AlertsSettingsForm', () => {
describe('Mapping builder section', () => {
describe.each`
alertFieldsProvided | multiIntegrations | featureFlag | integrationOption | visible
${true} | ${true} | ${true} | ${1} | ${true}
${true} | ${true} | ${true} | ${2} | ${false}
${true} | ${true} | ${false} | ${1} | ${false}
${true} | ${true} | ${false} | ${2} | ${false}
${true} | ${false} | ${true} | ${1} | ${false}
${false} | ${true} | ${true} | ${1} | ${false}
`('', ({ alertFieldsProvided, multiIntegrations, featureFlag, integrationOption, visible }) => {
alertFieldsProvided | multiIntegrations | integrationOption | visible
${true} | ${true} | ${1} | ${true}
${true} | ${true} | ${2} | ${false}
${true} | ${false} | ${1} | ${false}
${false} | ${true} | ${1} | ${false}
`('', ({ alertFieldsProvided, multiIntegrations, integrationOption, visible }) => {
const visibleMsg = visible ? 'is rendered' : 'is not rendered';
const featureFlagMsg = featureFlag ? 'is enabled' : 'is disabled';
const alertFieldsMsg = alertFieldsProvided ? 'are provided' : 'are not provided';
const integrationType = integrationOption === 1 ? typeSet.http : typeSet.prometheus;
it(`${visibleMsg} when multipleHttpIntegrationsCustomMapping feature flag ${featureFlagMsg} and integration type is ${integrationType} and alert fields ${alertFieldsMsg}`, async () => {
it(`${visibleMsg} when integration type is ${integrationType} and alert fields ${alertFieldsMsg}`, async () => {
createComponent({
multipleHttpIntegrationsCustomMapping: featureFlag,
multiIntegrations,
props: {
alertFields: alertFieldsProvided ? alertFields : [],

View File

@ -130,20 +130,15 @@ RSpec.describe ApplicationSettingsHelper do
before do
helper.instance_variable_set(:@application_setting, application_setting)
stub_storage_settings({ 'default': {}, 'storage_1': {}, 'storage_2': {} })
allow(ApplicationSetting).to receive(:repository_storages_weighted_attributes).and_return(
[:repository_storages_weighted_default,
:repository_storages_weighted_storage_1,
:repository_storages_weighted_storage_2])
stub_application_setting(repository_storages_weighted: { 'default' => 100, 'storage_1' => 50, 'storage_2' => nil })
end
it 'returns storages correctly' do
expect(helper.storage_weights).to eq([
{ name: :repository_storages_weighted_default, label: 'default', value: 100 },
{ name: :repository_storages_weighted_storage_1, label: 'storage_1', value: 50 },
{ name: :repository_storages_weighted_storage_2, label: 'storage_2', value: 0 }
])
expect(helper.storage_weights).to eq(OpenStruct.new(
default: 100,
storage_1: 50,
storage_2: 0
))
end
end

View File

@ -238,7 +238,17 @@ RSpec.describe Gitlab::Diff::HighlightCache, :clean_gitlab_redis_cache do
subject { cache.key }
it 'returns cache key' do
is_expected.to start_with("highlighted-diff-files:#{cache.diffable.cache_key}:2")
is_expected.to eq("highlighted-diff-files:#{cache.diffable.cache_key}:2:#{cache.diff_options}:true")
end
context 'when feature flag is disabled' do
before do
stub_feature_flags(introduce_marker_ranges: false)
end
it 'returns the original version of the cache' do
is_expected.to eq("highlighted-diff-files:#{cache.diffable.cache_key}:2:#{cache.diff_options}:false")
end
end
end
end

View File

@ -50,11 +50,23 @@ RSpec.describe Gitlab::Diff::Highlight do
end
it 'highlights and marks added lines' do
code = %Q{+<span id="LC9" class="line" lang="ruby"> <span class="k">raise</span> <span class="no"><span class="idiff left">RuntimeError</span></span><span class="p"><span class="idiff">,</span></span><span class="idiff right"> </span><span class="s2">"System commands must be given as an array of strings"</span></span>\n}
code = %Q{+<span id="LC9" class="line" lang="ruby"> <span class="k">raise</span> <span class="no"><span class="idiff left addition">RuntimeError</span></span><span class="p"><span class="idiff addition">,</span></span><span class="idiff right addition"> </span><span class="s2">"System commands must be given as an array of strings"</span></span>\n}
expect(subject[5].rich_text).to eq(code)
end
context 'when introduce_marker_ranges is false' do
before do
stub_feature_flags(introduce_marker_ranges: false)
end
it 'keeps the old bevavior (without mode classes)' do
code = %Q{+<span id="LC9" class="line" lang="ruby"> <span class="k">raise</span> <span class="no"><span class="idiff left">RuntimeError</span></span><span class="p"><span class="idiff">,</span></span><span class="idiff right"> </span><span class="s2">"System commands must be given as an array of strings"</span></span>\n}
expect(subject[5].rich_text).to eq(code)
end
end
context 'when no diff_refs' do
before do
allow(diff_file).to receive(:diff_refs).and_return(nil)
@ -93,7 +105,7 @@ RSpec.describe Gitlab::Diff::Highlight do
end
it 'marks added lines' do
code = %q{+ raise <span class="idiff left right">RuntimeError, </span>&quot;System commands must be given as an array of strings&quot;}
code = %q{+ raise <span class="idiff left right addition">RuntimeError, </span>&quot;System commands must be given as an array of strings&quot;}
expect(subject[5].rich_text).to eq(code)
expect(subject[5].rich_text).to be_html_safe

View File

@ -5,8 +5,8 @@ require 'spec_helper'
RSpec.describe Gitlab::Diff::InlineDiffMarkdownMarker do
describe '#mark' do
let(:raw) { "abc 'def'" }
let(:inline_diffs) { [2..5] }
let(:subject) { described_class.new(raw).mark(inline_diffs, mode: :deletion) }
let(:inline_diffs) { [Gitlab::MarkerRange.new(2, 5, mode: Gitlab::MarkerRange::DELETION)] }
let(:subject) { described_class.new(raw).mark(inline_diffs) }
it 'does not escape html etities and marks the range' do
expect(subject).to eq("ab{-c 'd-}ef'")

View File

@ -0,0 +1,71 @@
# frozen_string_literal: true
require 'fast_spec_helper'
RSpec.describe Gitlab::MarkerRange do
subject(:marker_range) { described_class.new(first, last, mode: mode) }
let(:first) { 1 }
let(:last) { 10 }
let(:mode) { nil }
it { is_expected.to eq(first..last) }
it 'behaves like a Range' do
is_expected.to be_kind_of(Range)
end
describe '#mode' do
subject { marker_range.mode }
it { is_expected.to be_nil }
context 'when mode is provided' do
let(:mode) { :deletion }
it { is_expected.to eq(mode) }
end
end
describe '#to_range' do
subject { marker_range.to_range }
it { is_expected.to eq(first..last) }
context 'when mode is provided' do
let(:mode) { :deletion }
it 'is omitted during transformation' do
is_expected.not_to respond_to(:mode)
end
end
end
describe '.from_range' do
subject { described_class.from_range(range) }
let(:range) { 1..3 }
it 'converts Range to MarkerRange object' do
is_expected.to be_a(described_class)
end
it 'keeps correct range' do
is_expected.to eq(range)
end
context 'when range excludes end' do
let(:range) { 1...3 }
it 'keeps correct range' do
is_expected.to eq(range)
end
end
context 'when range is already a MarkerRange' do
let(:range) { marker_range }
it { is_expected.to be(marker_range) }
end
end
end

View File

@ -8,7 +8,7 @@ RSpec.describe Gitlab::StringRangeMarker do
raw = 'abc <def>'
inline_diffs = [2..5]
described_class.new(raw, rich).mark(inline_diffs) do |text, left:, right:|
described_class.new(raw, rich).mark(inline_diffs) do |text, left:, right:, mode:|
"LEFT#{text}RIGHT".html_safe
end
end

View File

@ -9,7 +9,7 @@ RSpec.describe Gitlab::StringRegexMarker do
let(:rich) { %{<span class="key">"name"</span><span class="punctuation">: </span><span class="value">"AFNetworking"</span>}.html_safe }
subject do
described_class.new(raw, rich).mark(/"[^"]+":\s*"(?<name>[^"]+)"/, group: :name) do |text, left:, right:|
described_class.new(raw, rich).mark(/"[^"]+":\s*"(?<name>[^"]+)"/, group: :name) do |text, left:, right:, mode:|
%{<a href="#">#{text}</a>}.html_safe
end
end
@ -25,7 +25,7 @@ RSpec.describe Gitlab::StringRegexMarker do
let(:rich) { %{a &lt;b&gt; &lt;c&gt; d}.html_safe }
subject do
described_class.new(raw, rich).mark(/<[a-z]>/) do |text, left:, right:|
described_class.new(raw, rich).mark(/<[a-z]>/) do |text, left:, right:, mode:|
%{<strong>#{text}</strong>}.html_safe
end
end

View File

@ -105,14 +105,14 @@ RSpec.describe ApplicationSetting do
it { is_expected.not_to allow_value(false).for(:hashed_storage_enabled) }
it { is_expected.not_to allow_value(101).for(:repository_storages_weighted_default) }
it { is_expected.to allow_value('90').for(:repository_storages_weighted_default) }
it { is_expected.not_to allow_value(-1).for(:repository_storages_weighted_default) }
it { is_expected.to allow_value(100).for(:repository_storages_weighted_default) }
it { is_expected.to allow_value(0).for(:repository_storages_weighted_default) }
it { is_expected.to allow_value(50).for(:repository_storages_weighted_default) }
it { is_expected.to allow_value(nil).for(:repository_storages_weighted_default) }
it { is_expected.not_to allow_value({ default: 100, shouldntexist: 50 }).for(:repository_storages_weighted) }
it { is_expected.to allow_value('default' => 0).for(:repository_storages_weighted) }
it { is_expected.to allow_value('default' => 50).for(:repository_storages_weighted) }
it { is_expected.to allow_value('default' => 100).for(:repository_storages_weighted) }
it { is_expected.to allow_value('default' => '90').for(:repository_storages_weighted) }
it { is_expected.to allow_value('default' => nil).for(:repository_storages_weighted) }
it { is_expected.not_to allow_value('default' => -1).for(:repository_storages_weighted).with_message("value for 'default' must be between 0 and 100") }
it { is_expected.not_to allow_value('default' => 101).for(:repository_storages_weighted).with_message("value for 'default' must be between 0 and 100") }
it { is_expected.not_to allow_value('default' => 100, shouldntexist: 50).for(:repository_storages_weighted).with_message("can't include: shouldntexist") }
it { is_expected.to allow_value(400).for(:notes_create_limit) }
it { is_expected.not_to allow_value('two').for(:notes_create_limit) }
@ -984,12 +984,6 @@ RSpec.describe ApplicationSetting do
it_behaves_like 'application settings examples'
describe 'repository_storages_weighted_attributes' do
it 'returns the keys for repository_storages_weighted' do
expect(subject.class.repository_storages_weighted_attributes).to eq([:repository_storages_weighted_default])
end
end
describe 'kroki_format_supported?' do
it 'returns true when Excalidraw is enabled' do
subject.kroki_formats_excalidraw = true
@ -1033,11 +1027,4 @@ RSpec.describe ApplicationSetting do
expect(subject.kroki_formats_excalidraw).to eq(true)
end
end
it 'does not allow to set weight for non existing storage' do
setting.repository_storages_weighted = { invalid_storage: 100 }
expect(setting).not_to be_valid
expect(setting.errors.messages[:repository_storages_weighted]).to match_array(["can't include: invalid_storage"])
end
end

View File

@ -289,6 +289,7 @@ RSpec.shared_examples 'application settings examples' do
describe '#pick_repository_storage' do
before do
allow(Gitlab.config.repositories.storages).to receive(:keys).and_return(%w(default backup))
allow(setting).to receive(:repository_storages_weighted).and_return({ 'default' => 20, 'backup' => 80 })
end
@ -304,15 +305,19 @@ RSpec.shared_examples 'application settings examples' do
describe '#normalized_repository_storage_weights' do
using RSpec::Parameterized::TableSyntax
where(:storages, :normalized) do
{ 'default' => 0, 'backup' => 100 } | { 'default' => 0.0, 'backup' => 1.0 }
{ 'default' => 100, 'backup' => 100 } | { 'default' => 0.5, 'backup' => 0.5 }
{ 'default' => 20, 'backup' => 80 } | { 'default' => 0.2, 'backup' => 0.8 }
{ 'default' => 0, 'backup' => 0 } | { 'default' => 0.0, 'backup' => 0.0 }
where(:config_storages, :storages, :normalized) do
%w(default backup) | { 'default' => 0, 'backup' => 100 } | { 'default' => 0.0, 'backup' => 1.0 }
%w(default backup) | { 'default' => 100, 'backup' => 100 } | { 'default' => 0.5, 'backup' => 0.5 }
%w(default backup) | { 'default' => 20, 'backup' => 80 } | { 'default' => 0.2, 'backup' => 0.8 }
%w(default backup) | { 'default' => 0, 'backup' => 0 } | { 'default' => 0.0, 'backup' => 0.0 }
%w(default) | { 'default' => 0, 'backup' => 100 } | { 'default' => 0.0 }
%w(default) | { 'default' => 100, 'backup' => 100 } | { 'default' => 1.0 }
%w(default) | { 'default' => 20, 'backup' => 80 } | { 'default' => 1.0 }
end
with_them do
before do
allow(Gitlab.config.repositories.storages).to receive(:keys).and_return(config_storages)
allow(setting).to receive(:repository_storages_weighted).and_return(storages)
end

View File

@ -3,34 +3,49 @@
require 'spec_helper'
RSpec.describe 'admin/application_settings/_repository_storage.html.haml' do
let(:app_settings) { create(:application_setting) }
let(:repository_storages_weighted_attributes) { [:repository_storages_weighted_default, :repository_storages_weighted_mepmep, :repository_storages_weighted_foobar]}
let(:repository_storages_weighted) do
{
"default" => 100,
"mepmep" => 50
}
end
let(:app_settings) { build(:application_setting, repository_storages_weighted: repository_storages_weighted) }
before do
allow(app_settings).to receive(:repository_storages_weighted).and_return(repository_storages_weighted)
allow(app_settings).to receive(:repository_storages_weighted_mepmep).and_return(100)
allow(app_settings).to receive(:repository_storages_weighted_foobar).and_return(50)
stub_storage_settings({ 'default': {}, 'mepmep': {}, 'foobar': {} })
assign(:application_setting, app_settings)
allow(ApplicationSetting).to receive(:repository_storages_weighted_attributes).and_return(repository_storages_weighted_attributes)
end
context 'when multiple storages are available' do
context 'additional storage config' do
let(:repository_storages_weighted) do
{
'default' => 100,
'mepmep' => 50
}
end
it 'lists them all' do
render
# lists storages that are saved with weights
repository_storages_weighted.each do |storage_name, storage_weight|
Gitlab.config.repositories.storages.keys.each do |storage_name|
expect(rendered).to have_content(storage_name)
end
# lists storage not saved with weight
expect(rendered).to have_content('foobar')
end
end
context 'fewer storage configs' do
let(:repository_storages_weighted) do
{
'default' => 100,
'mepmep' => 50,
'something_old' => 100
}
end
it 'lists only configured storages' do
render
Gitlab.config.repositories.storages.keys.each do |storage_name|
expect(rendered).to have_content(storage_name)
end
expect(rendered).not_to have_content('something_old')
end
end
end