Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-09-30 03:09:54 +00:00
parent d210b1bee1
commit c74f7b6ff5
36 changed files with 345 additions and 231 deletions

View File

@ -3,21 +3,6 @@
Layout/FirstArrayElementIndentation:
Details: grace period
Exclude:
- 'spec/lib/gitlab/database/each_database_spec.rb'
- 'spec/lib/gitlab/database/load_balancing/rack_middleware_spec.rb'
- 'spec/lib/gitlab/database/load_balancing/sticking_spec.rb'
- 'spec/lib/gitlab/database/obsolete_ignored_columns_spec.rb'
- 'spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb'
- 'spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb'
- 'spec/lib/gitlab/database/partitioning/time_partition_spec.rb'
- 'spec/lib/gitlab/database/partitioning_spec.rb'
- 'spec/lib/gitlab/database/similarity_score_spec.rb'
- 'spec/lib/gitlab/diff/char_diff_spec.rb'
- 'spec/lib/gitlab/diff/file_collection_sorter_spec.rb'
- 'spec/lib/gitlab/error_tracking/stack_trace_highlight_decorator_spec.rb'
- 'spec/lib/gitlab/git/repository_spec.rb'
- 'spec/lib/gitlab/gitaly_client/blob_service_spec.rb'
- 'spec/lib/gitlab/github_import/importer/diff_notes_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/issues_importer_spec.rb'
- 'spec/lib/gitlab/search/found_blob_spec.rb'
- 'spec/lib/gitlab/serializer/ci/variables_spec.rb'

View File

@ -524,8 +524,6 @@ gem 'retriable', '~> 3.1.2'
# LRU cache
gem 'lru_redux'
gem 'erubi', '~> 1.9.0'
# Locked as long as quoted-printable encoding issues are not resolved
# Monkey-patched in `config/initializers/mail_encoding_patch.rb`
# See https://gitlab.com/gitlab-org/gitlab/issues/197386

View File

@ -134,7 +134,7 @@
{"name":"email_reply_trimmer","version":"0.1.6","platform":"ruby","checksum":"9fede222ce660993e4e2e3dad282535ceb7914e246eb8302c19aa9e021f7326e"},
{"name":"email_spec","version":"2.2.0","platform":"ruby","checksum":"60b7980580a835e7f676db60667f17a2d60e8e0e39c26d81cfc231805c544d79"},
{"name":"encryptor","version":"3.0.0","platform":"ruby","checksum":"abf23f94ab4d864b8cea85b43f3432044a60001982cda7c33c1cd90da8db1969"},
{"name":"erubi","version":"1.9.0","platform":"ruby","checksum":"7d84d6037396418c4ba30bc40ed7a0aec9beb567ce55bcecb12e8c0cb1ed9fdb"},
{"name":"erubi","version":"1.11.0","platform":"ruby","checksum":"fda72d577feaf3bdcd646d33fa630be5f92f48e179a9278e4175a9cec20e7f85"},
{"name":"escape_utils","version":"1.2.1","platform":"ruby","checksum":"e5292fe8d7e12a9bcb4502d99e28fb602e4e1514690d98a1c4957f6f77b4b162"},
{"name":"et-orbi","version":"1.2.7","platform":"ruby","checksum":"3b693d47f94a4060ccc07e60adda488759b1e8b9228a633ebbad842dfc245fb4"},
{"name":"ethon","version":"0.15.0","platform":"ruby","checksum":"0809805a035bc10f54162ca99f15ded49e428e0488bcfe1c08c821e18261a74d"},

View File

@ -413,7 +413,7 @@ GEM
launchy (~> 2.1)
mail (~> 2.7)
encryptor (3.0.0)
erubi (1.9.0)
erubi (1.11.0)
escape_utils (1.2.1)
et-orbi (1.2.7)
tzinfo
@ -1586,7 +1586,6 @@ DEPENDENCIES
email_reply_trimmer (~> 0.1)
email_spec (~> 2.2.0)
error_tracking_open_api!
erubi (~> 1.9.0)
escape_utils (~> 1.1)
factory_bot_rails (~> 6.2.0)
faraday (~> 1.0)

View File

@ -46,12 +46,14 @@ $notification-box-shadow-color: rgba(0, 0, 0, 0.25);
.flash-notice,
.flash-success,
.flash-warning {
padding: $gl-padding $gl-padding-32 $gl-padding ($gl-padding + $gl-padding-4);
margin-top: 10px;
&:not(.gl-alert) {
padding: $gl-padding $gl-padding-32 $gl-padding ($gl-padding + $gl-padding-4);
margin-top: 10px;
.container-fluid,
.container-fluid.container-limited {
background: transparent;
.container-fluid,
.container-fluid.container-limited {
background: transparent;
}
}
}

View File

@ -12,8 +12,8 @@ module Pajamas
def initialize(
title: nil, variant: :info, dismissible: true, show_icon: true,
alert_options: {}, close_button_options: {})
@title = title
@variant = variant
@title = title.presence
@variant = filter_attribute(variant&.to_sym, VARIANT_ICONS.keys, default: :info)
@dismissible = dismissible
@show_icon = show_icon
@alert_options = alert_options
@ -35,7 +35,7 @@ module Pajamas
renders_one :body
renders_one :actions
ICONS = {
VARIANT_ICONS = {
info: 'information-o',
warning: 'warning',
success: 'check-circle',
@ -44,7 +44,7 @@ module Pajamas
}.freeze
def icon
ICONS[@variant]
VARIANT_ICONS[@variant]
end
def icon_classes

View File

@ -1,9 +1,8 @@
- flash_container_no_margin = local_assigns.fetch(:flash_container_no_margin, false)
- flash_container_class = ('flash-container-no-margin' if flash_container_no_margin)
-# We currently only support `alert`, `notice`, `success`, 'toast', and 'raw'
- icons = {'alert' => 'error', 'notice' => 'information-o', 'success' => 'check-circle'}
- type_to_variant = {'alert' => 'danger', 'notice' => 'info', 'success' => 'success'}
-# We currently only support `alert`, `notice`, `success`, `warning`, 'toast', and 'raw'
- type_to_variant = {'alert' => 'danger', 'notice' => 'info', 'success' => 'success', 'warning' => 'warning'}
- closable = %w[alert notice success]
.flash-container.flash-container-page.sticky{ data: { qa_selector: 'flash_container' }, class: flash_container_class }
- flash.each do |key, value|
@ -14,9 +13,5 @@
- elsif value == I18n.t('devise.failure.unconfirmed')
= render 'shared/confirm_your_email_alert'
- elsif value
%div{ class: "flash-#{key} mb-2", data: { testid: "alert-#{type_to_variant[key]}" } }
= sprite_icon(icons[key], css_class: 'align-middle mr-1') unless icons[key].nil?
%span= value
- if closable.include?(key)
%div{ class: "close-icon-wrapper js-close-icon" }
= sprite_icon('close', css_class: 'close-icon gl-vertical-align-baseline!')
= render Pajamas::AlertComponent.new(variant: type_to_variant[key], dismissible: closable.include?(key), alert_options: {class: "flash-#{key}", data: { testid: "alert-#{type_to_variant[key]}" }}) do |c|
= c.with_body { value }

View File

@ -1,9 +1,9 @@
.row.gl-mt-3.gl-mb-3
.col-lg-12
.card
.card-header
= render Pajamas::CardComponent.new do |c|
- c.header do
= _("Manage your project's triggers")
.card-body
- c.body do
= render 'projects/triggers/form', btn_text: _('Add trigger')
%hr
- if Feature.enabled?(:ci_pipeline_triggers_settings_vue_ui, @project)
@ -30,9 +30,7 @@
- else
%p.settings-message.text-center.gl-mb-3{ data: { testid: 'no_triggers_content' } }
= _('No triggers exist yet. Use the form above to create one.')
.card-footer
- c.footer do
%p
= _("These examples show how to trigger this project's pipeline for a branch or tag.")

View File

@ -505,6 +505,11 @@ production: &base
# Periodically executed jobs, to self-heal GitLab, do external synchronizations, etc.
# Please read here for more information: https://github.com/ondrejbartas/sidekiq-cron#adding-cron-job
cron_jobs:
# Interval, in seconds, for each Sidekiq process to check for scheduled cron jobs that need to be enqueued. If set
# to 0, disable polling for cron jobs entirely. This is useful in setups with multiple Sidekiq processes if you want
# to limit which ones perform this task. Note that at least one process in your instance needs to have polling
# enabled for cron jobs to be executed.
poll_interval: 30
# Flag stuck CI jobs as failed
stuck_ci_jobs_worker:
cron: "0 * * * *"

View File

@ -457,6 +457,7 @@ if Gitlab.ee? && Settings['ee_cron_jobs']
Settings.cron_jobs.merge!(Settings.ee_cron_jobs)
end
Settings.cron_jobs['poll_interval'] ||= 30
Settings.cron_jobs['stuck_ci_jobs_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['stuck_ci_jobs_worker']['cron'] ||= '0 * * * *'
Settings.cron_jobs['stuck_ci_jobs_worker']['job_class'] = 'StuckCiJobsWorker'

View File

@ -5,6 +5,16 @@ module SidekiqLogArguments
end
end
def load_cron_jobs!
Sidekiq::Cron::Job.load_from_hash! Gitlab::SidekiqConfig.cron_jobs
Gitlab.ee do
Gitlab::Mirror.configure_cron_job!
Gitlab::Geo.configure_cron_jobs!
end
end
def enable_reliable_fetch?
return true unless Feature::FlipperFeature.table_exists?
@ -78,30 +88,10 @@ Sidekiq.configure_server do |config|
Sidekiq::ReliableFetch.setup_reliable_fetch!(config)
end
Gitlab.config.load_dynamic_cron_schedules!
# Sidekiq-cron: load recurring jobs from gitlab.yml
# UGLY Hack to get nested hash from settingslogic
cron_jobs = Gitlab::Json.parse(Gitlab.config.cron_jobs.to_json)
# UGLY hack: Settingslogic doesn't allow 'class' key
cron_jobs_required_keys = %w(job_class cron)
cron_jobs.each do |k, v|
if cron_jobs[k] && cron_jobs_required_keys.all? { |s| cron_jobs[k].key?(s) }
cron_jobs[k]['class'] = cron_jobs[k].delete('job_class')
else
cron_jobs.delete(k)
Gitlab::AppLogger.error("Invalid cron_jobs config key: '#{k}'. Check your gitlab config file.")
end
end
Sidekiq::Cron::Job.load_from_hash! cron_jobs
Gitlab::SidekiqVersioning.install!
Gitlab.ee do
Gitlab::Mirror.configure_cron_job!
Gitlab::Geo.configure_cron_jobs!
end
config.options[:cron_poll_interval] = Gitlab.config.cron_jobs.poll_interval
load_cron_jobs!
# Avoid autoload issue such as 'Mail::Parsers::AddressStruct'
# https://github.com/mikel/mail/issues/912#issuecomment-214850355

View File

@ -220,7 +220,7 @@ multiple jobs. It is similar to [YAML anchors](#anchors), but simpler and you ca
[use `extends` with `includes`](#use-extends-and-include-together).
`extends` supports multi-level inheritance. You should avoid using more than three levels,
but you can use as many as eleven. The following example has two levels of inheritance:
due to the additional complexity, but you can use as many as eleven. The following example has two levels of inheritance:
```yaml
.tests:

View File

@ -7,15 +7,18 @@ module API
GLOBAL_TEMPLATE_TYPES = {
gitignores: {
gitlab_version: 8.8,
feature_category: :source_code_management
feature_category: :source_code_management,
file_type: '.gitignore'
},
gitlab_ci_ymls: {
gitlab_version: 8.9,
feature_category: :pipeline_authoring
feature_category: :pipeline_authoring,
file_type: 'GitLab CI/CD YAML'
},
dockerfiles: {
gitlab_version: 8.15,
feature_category: :source_code_management
feature_category: :source_code_management,
file_type: 'Dockerfile'
}
}.freeze
@ -26,7 +29,7 @@ module API
end
end
desc 'Get the list of the available license template' do
desc 'Get all license templates' do
detail 'This feature was introduced in GitLab 8.7.'
success ::API::Entities::License
end
@ -43,12 +46,14 @@ module API
present paginate(::Kaminari.paginate_array(templates)), with: ::API::Entities::License
end
desc 'Get the text for a specific license' do
desc 'Get a single license template' do
detail 'This feature was introduced in GitLab 8.7.'
success ::API::Entities::License
end
params do
requires :name, type: String, desc: 'The name of the template'
requires :name, type: String, desc: 'The name of the license template'
optional :project, type: String, desc: 'The copyrighted project name'
optional :fullname, type: String, desc: 'The full-name of the copyright holder'
end
get "templates/licenses/:name", requirements: { name: /[\w\.-]+/ }, feature_category: :source_code_management do
template = TemplateFinder.build(:licenses, nil, name: params[:name]).execute
@ -65,8 +70,9 @@ module API
GLOBAL_TEMPLATE_TYPES.each do |template_type, properties|
gitlab_version = properties[:gitlab_version]
file_type = properties[:file_type]
desc 'Get the list of the available template' do
desc "Get all #{file_type} templates" do
detail "This feature was introduced in GitLab #{gitlab_version}."
success Entities::TemplatesList
end
@ -78,12 +84,12 @@ module API
present paginate(templates), with: Entities::TemplatesList
end
desc 'Get the text for a specific template present in local filesystem' do
desc "Get a single #{file_type} template" do
detail "This feature was introduced in GitLab #{gitlab_version}."
success Entities::Template
end
params do
requires :name, type: String, desc: 'The name of the template'
requires :name, type: String, desc: "The name of the #{file_type} template"
end
get "templates/#{template_type}/:name", requirements: { name: /[\w\.-]+/ }, feature_category: properties[:feature_category] do
finder = TemplateFinder.build(template_type, nil, name: declared(params)[:name])

View File

@ -13,8 +13,12 @@ end
module Gitlab
module Patch
module SidekiqCronPoller
def enqueue
super if poll_interval_average > 0
end
def poll_interval_average
Sidekiq.options[:poll_interval] || Sidekiq::Cron::POLL_INTERVAL
Sidekiq.options[:cron_poll_interval]
end
end
end

View File

@ -53,8 +53,33 @@ module Gitlab
end
end
def cron_jobs
@cron_jobs ||= begin
Gitlab.config.load_dynamic_cron_schedules!
# Load recurring jobs from gitlab.yml
# UGLY Hack to get nested hash from settingslogic
jobs = Gitlab::Json.parse(Gitlab.config.cron_jobs.to_json)
jobs.delete('poll_interval') # Would be interpreted as a job otherwise
# UGLY hack: Settingslogic doesn't allow 'class' key
required_keys = %w[job_class cron]
jobs.each do |k, v|
if jobs[k] && required_keys.all? { |s| jobs[k].key?(s) }
jobs[k]['class'] = jobs[k].delete('job_class')
else
jobs.delete(k)
Gitlab::AppLogger.error("Invalid cron_jobs config key: '#{k}'. Check your gitlab config file.")
end
end
jobs
end
end
def cron_workers
@cron_workers ||= Settings.cron_jobs.map { |job_name, options| options['job_class'].constantize }
@cron_workers ||= cron_jobs.map { |job_name, options| options['class'].constantize }
end
def workers

View File

@ -313,11 +313,6 @@
category: geo
redis_slot: geo
aggregation: daily
# Growth
- name: users_clicking_registration_features_offer
category: growth
redis_slot: users
aggregation: weekly
# Manage
- name: unique_active_user
category: manage

View File

@ -45,11 +45,37 @@ RSpec.describe Pajamas::AlertComponent, :aggregate_failures, type: :component do
end
end
describe 'title' do
before do
render_inline described_class.new(title: title)
end
context 'with non-empty string' do
let(:title) { '_title_' }
it 'sets the title' do
expect(page).to have_selector('.gl-alert-title')
expect(page).to have_content(title)
expect(page).not_to have_selector('.gl-alert-icon-no-title')
end
end
context 'with nil, empty or blank string' do
where(:title) { [nil, '', ' '] }
with_them do
it 'does not set a title' do
expect(page).not_to have_selector('.gl-alert-title')
expect(page).to have_selector('.gl-alert-icon-no-title')
end
end
end
end
context 'with custom options' do
context 'with simple options' do
before do
render_inline described_class.new(
title: '_title_',
alert_options: {
class: '_alert_class_',
data: {
@ -60,12 +86,6 @@ RSpec.describe Pajamas::AlertComponent, :aggregate_failures, type: :component do
)
end
it 'sets the title' do
expect(page).to have_selector('.gl-alert-title')
expect(page).to have_content('_title_')
expect(page).not_to have_selector('.gl-alert-icon-no-title')
end
it 'sets the alert_class' do
expect(page).to have_selector('._alert_class_')
end
@ -129,7 +149,7 @@ RSpec.describe Pajamas::AlertComponent, :aggregate_failures, type: :component do
end
context 'with setting variant type' do
where(:variant) { [:warning, :success, :danger, :tip] }
where(:variant) { [:warning, "success", :danger, "tip"] }
before do
render_inline described_class.new(variant: variant)
@ -138,7 +158,18 @@ RSpec.describe Pajamas::AlertComponent, :aggregate_failures, type: :component do
with_them do
it 'renders the variant' do
expect(page).to have_selector(".gl-alert-#{variant}")
expect(page).to have_selector("[data-testid='#{described_class::ICONS[variant]}-icon']")
expect(page).to have_selector("[data-testid='#{described_class::VARIANT_ICONS[variant.to_sym]}-icon']")
end
end
context "with unknown or nil variant" do
where(:variant) { [:foo, nil] }
with_them do
it "adds the default variant class" do
expect(page).to have_selector(".gl-alert-info")
expect(page).to have_selector("[data-testid='information-o-icon']")
end
end
end
end

View File

@ -1,12 +1,13 @@
# frozen_string_literal: true
module Pajamas
class AlertComponentPreview < ViewComponent::Preview
# @param title text
# @param body text
# @param dismissible toggle
# @param variant select [info, warning, success, danger, tip]
def default(body: nil, dismissible: true, variant: :info)
def default(title: "Alert title (optional)", body: "Alert message goes here.", dismissible: true, variant: :info)
render(Pajamas::AlertComponent.new(
title: "Title",
title: title,
dismissible: dismissible,
variant: variant.to_sym
)) do |c|

View File

@ -42,4 +42,61 @@ RSpec.describe 'sidekiq' do
it { is_expected.to be_falsey }
end
end
describe 'load_cron_jobs!' do
subject { load_cron_jobs! }
let(:cron_for_service_ping) { '4 7 * * 4' }
let(:cron_jobs_settings) do
{
'gitlab_service_ping_worker' => {
'cron' => nil,
'job_class' => 'GitlabServicePingWorker'
},
'import_export_project_cleanup_worker' => {
'cron' => '0 * * * *',
'job_class' => 'ImportExportProjectCleanupWorker'
},
"invalid_worker" => {
'cron' => '0 * * * *'
}
}
end
let(:cron_jobs_hash) do
{
'gitlab_service_ping_worker' => {
'cron' => cron_for_service_ping,
'class' => 'GitlabServicePingWorker'
},
'import_export_project_cleanup_worker' => {
'cron' => '0 * * * *',
'class' => 'ImportExportProjectCleanupWorker'
}
}
end
around do |example|
original_settings = Gitlab.config['cron_jobs']
Gitlab.config['cron_jobs'] = cron_jobs_settings
example.run
Gitlab.config['cron_jobs'] = original_settings
end
it 'loads the cron jobs into sidekiq-cron' do
allow(Settings).to receive(:cron_for_service_ping).and_return(cron_for_service_ping)
expect(Sidekiq::Cron::Job).to receive(:load_from_hash!).with(cron_jobs_hash)
if Gitlab.ee?
expect(Gitlab::Mirror).to receive(:configure_cron_job!)
expect(Gitlab::Geo).to receive(:configure_cron_jobs!)
end
subject
end
end
end

View File

@ -93,12 +93,13 @@ RSpec.describe Gitlab::Database::EachDatabase do
end
it 'yields each model with SharedModel connected to each database connection' do
expect_yielded_models([model1, model2], [
{ model: model1, connection: ActiveRecord::Base.connection, name: 'main' },
{ model: model1, connection: Ci::ApplicationRecord.connection, name: 'ci' },
{ model: model2, connection: ActiveRecord::Base.connection, name: 'main' },
{ model: model2, connection: Ci::ApplicationRecord.connection, name: 'ci' }
])
expect_yielded_models([model1, model2],
[
{ model: model1, connection: ActiveRecord::Base.connection, name: 'main' },
{ model: model1, connection: Ci::ApplicationRecord.connection, name: 'ci' },
{ model: model2, connection: ActiveRecord::Base.connection, name: 'main' },
{ model: model2, connection: Ci::ApplicationRecord.connection, name: 'ci' }
])
end
context 'when the model limits connection names' do
@ -108,10 +109,11 @@ RSpec.describe Gitlab::Database::EachDatabase do
end
it 'only yields the model with SharedModel connected to the limited connections' do
expect_yielded_models([model1, model2], [
{ model: model1, connection: ActiveRecord::Base.connection, name: 'main' },
{ model: model2, connection: Ci::ApplicationRecord.connection, name: 'ci' }
])
expect_yielded_models([model1, model2],
[
{ model: model1, connection: ActiveRecord::Base.connection, name: 'main' },
{ model: model2, connection: Ci::ApplicationRecord.connection, name: 'ci' }
])
end
end
end
@ -132,10 +134,11 @@ RSpec.describe Gitlab::Database::EachDatabase do
end
it 'yields each model after connecting SharedModel' do
expect_yielded_models([main_model, ci_model], [
{ model: main_model, connection: main_connection, name: 'main' },
{ model: ci_model, connection: ci_connection, name: 'ci' }
])
expect_yielded_models([main_model, ci_model],
[
{ model: main_model, connection: main_connection, name: 'main' },
{ model: ci_model, connection: ci_connection, name: 'ci' }
])
end
end
@ -154,21 +157,23 @@ RSpec.describe Gitlab::Database::EachDatabase do
context 'when a single name is passed in' do
it 'yields models only connected to the given database' do
expect_yielded_models([main_model, ci_model, shared_model], [
{ model: ci_model, connection: Ci::ApplicationRecord.connection, name: 'ci' },
{ model: shared_model, connection: Ci::ApplicationRecord.connection, name: 'ci' }
], only_on: 'ci')
expect_yielded_models([main_model, ci_model, shared_model],
[
{ model: ci_model, connection: Ci::ApplicationRecord.connection, name: 'ci' },
{ model: shared_model, connection: Ci::ApplicationRecord.connection, name: 'ci' }
], only_on: 'ci')
end
end
context 'when a list of names are passed in' do
it 'yields models only connected to the given databases' do
expect_yielded_models([main_model, ci_model, shared_model], [
{ model: main_model, connection: ActiveRecord::Base.connection, name: 'main' },
{ model: ci_model, connection: Ci::ApplicationRecord.connection, name: 'ci' },
{ model: shared_model, connection: ActiveRecord::Base.connection, name: 'main' },
{ model: shared_model, connection: Ci::ApplicationRecord.connection, name: 'ci' }
], only_on: %i[main ci])
expect_yielded_models([main_model, ci_model, shared_model],
[
{ model: main_model, connection: ActiveRecord::Base.connection, name: 'main' },
{ model: ci_model, connection: Ci::ApplicationRecord.connection, name: 'ci' },
{ model: shared_model, connection: ActiveRecord::Base.connection, name: 'main' },
{ model: shared_model, connection: Ci::ApplicationRecord.connection, name: 'ci' }
], only_on: %i[main ci])
end
end
end

View File

@ -9,10 +9,10 @@ RSpec.describe Gitlab::Database::LoadBalancing::RackMiddleware, :redis do
let(:single_sticking_object) { Set.new([[ActiveRecord::Base.sticking, :user, 42]]) }
let(:multiple_sticking_objects) do
Set.new([
[ActiveRecord::Base.sticking, :user, 42],
[ActiveRecord::Base.sticking, :runner, '123456789'],
[ActiveRecord::Base.sticking, :runner, '1234']
])
[ActiveRecord::Base.sticking, :user, 42],
[ActiveRecord::Base.sticking, :runner, '123456789'],
[ActiveRecord::Base.sticking, :runner, '1234']
])
end
after do
@ -182,11 +182,12 @@ RSpec.describe Gitlab::Database::LoadBalancing::RackMiddleware, :redis do
it 'returns the sticking object' do
env = { described_class::STICK_OBJECT => multiple_sticking_objects }
expect(middleware.sticking_namespaces(env)).to eq([
[ActiveRecord::Base.sticking, :user, 42],
[ActiveRecord::Base.sticking, :runner, '123456789'],
[ActiveRecord::Base.sticking, :runner, '1234']
])
expect(middleware.sticking_namespaces(env)).to eq(
[
[ActiveRecord::Base.sticking, :user, 42],
[ActiveRecord::Base.sticking, :runner, '123456789'],
[ActiveRecord::Base.sticking, :runner, '1234']
])
end
end

View File

@ -41,10 +41,12 @@ RSpec.describe Gitlab::Database::LoadBalancing::Sticking, :redis do
sticking.stick_or_unstick_request(env, :user, 42)
sticking.stick_or_unstick_request(env, :runner, '123456789')
expect(env[Gitlab::Database::LoadBalancing::RackMiddleware::STICK_OBJECT].to_a).to eq([
[sticking, :user, 42],
[sticking, :runner, '123456789']
])
expect(env[Gitlab::Database::LoadBalancing::RackMiddleware::STICK_OBJECT].to_a).to eq(
[
[sticking, :user, 42],
[sticking, :runner,
'123456789']
])
end
end

View File

@ -53,15 +53,16 @@ RSpec.describe Gitlab::Database::ObsoleteIgnoredColumns do
describe '#execute' do
it 'returns a list of class names and columns pairs' do
travel_to(REMOVE_DATE) do
expect(subject.execute).to eq([
['Testing::A', {
'unused' => IgnorableColumns::ColumnIgnore.new(Date.parse('2019-01-01'), '12.0'),
'also_unused' => IgnorableColumns::ColumnIgnore.new(Date.parse('2019-02-01'), '12.1')
}],
['Testing::B', {
'other' => IgnorableColumns::ColumnIgnore.new(Date.parse('2019-01-01'), '12.0')
}]
])
expect(subject.execute).to eq(
[
['Testing::A', {
'unused' => IgnorableColumns::ColumnIgnore.new(Date.parse('2019-01-01'), '12.0'),
'also_unused' => IgnorableColumns::ColumnIgnore.new(Date.parse('2019-02-01'), '12.1')
}],
['Testing::B', {
'other' => IgnorableColumns::ColumnIgnore.new(Date.parse('2019-01-01'), '12.0')
}]
])
end
end
end

View File

@ -29,10 +29,11 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy do
end
it 'detects both partitions' do
expect(subject).to eq([
Gitlab::Database::Partitioning::TimePartition.new(table_name, nil, '2020-05-01', partition_name: '_test_partitioned_test_000000'),
Gitlab::Database::Partitioning::TimePartition.new(table_name, '2020-05-01', '2020-06-01', partition_name: '_test_partitioned_test_202005')
])
expect(subject).to eq(
[
Gitlab::Database::Partitioning::TimePartition.new(table_name, nil, '2020-05-01', partition_name: '_test_partitioned_test_000000'),
Gitlab::Database::Partitioning::TimePartition.new(table_name, '2020-05-01', '2020-06-01', partition_name: '_test_partitioned_test_202005')
])
end
end

View File

@ -36,14 +36,15 @@ RSpec.describe Gitlab::Database::Partitioning::SlidingListStrategy do
describe '#current_partitions' do
it 'detects both partitions' do
expect(strategy.current_partitions).to eq([
Gitlab::Database::Partitioning::SingleNumericListPartition.new(
table_name, 1, partition_name: '_test_partitioned_test_1'
),
Gitlab::Database::Partitioning::SingleNumericListPartition.new(
table_name, 2, partition_name: '_test_partitioned_test_2'
)
])
expect(strategy.current_partitions).to eq(
[
Gitlab::Database::Partitioning::SingleNumericListPartition.new(
table_name, 1, partition_name: '_test_partitioned_test_1'
),
Gitlab::Database::Partitioning::SingleNumericListPartition.new(
table_name, 2, partition_name: '_test_partitioned_test_2'
)
])
end
end

View File

@ -156,12 +156,13 @@ RSpec.describe Gitlab::Database::Partitioning::TimePartition do
described_class.new(table, '2020-03-01', '2020-04-01')
]
expect(partitions.sort).to eq([
described_class.new(table, nil, '2020-02-01'),
described_class.new(table, '2020-02-01', '2020-03-01'),
described_class.new(table, '2020-03-01', '2020-04-01'),
described_class.new(table, '2020-04-01', '2020-05-01')
])
expect(partitions.sort).to eq(
[
described_class.new(table, nil, '2020-02-01'),
described_class.new(table, '2020-02-01', '2020-03-01'),
described_class.new(table, '2020-03-01', '2020-04-01'),
described_class.new(table, '2020-04-01', '2020-05-01')
])
end
it 'returns nil for partitions of different tables' do

View File

@ -130,12 +130,14 @@ RSpec.describe Gitlab::Database::Partitioning do
context 'when no partitioned models are given' do
it 'manages partitions for each registered model' do
described_class.register_models([models.first])
described_class.register_tables([
{
table_name: table_names.last,
partitioned_column: :created_at, strategy: :monthly
}
])
described_class.register_tables(
[
{
table_name: table_names.last,
partitioned_column: :created_at,
strategy: :monthly
}
])
expect { described_class.sync_partitions }
.to change { find_partitions(table_names.first).size }.from(0)

View File

@ -78,10 +78,11 @@ RSpec.describe Gitlab::Database::SimilarityScore do
describe 'score multiplier' do
let(:order_expression) do
Gitlab::Database::SimilarityScore.build_expression(search: search, rules: [
{ column: Arel.sql('path'), multiplier: 1 },
{ column: Arel.sql('name'), multiplier: 0.8 }
]).to_sql
Gitlab::Database::SimilarityScore.build_expression(search: search, rules:
[
{ column: Arel.sql('path'), multiplier: 1 },
{ column: Arel.sql('name'), multiplier: 0.8 }
]).to_sql
end
let(:search) { 'different' }
@ -93,10 +94,11 @@ RSpec.describe Gitlab::Database::SimilarityScore do
describe 'annotation' do
it 'annotates the generated SQL expression' do
expression = Gitlab::Database::SimilarityScore.build_expression(search: 'test', rules: [
{ column: Arel.sql('path'), multiplier: 1 },
{ column: Arel.sql('name'), multiplier: 0.8 }
])
expression = Gitlab::Database::SimilarityScore.build_expression(search: 'test', rules:
[
{ column: Arel.sql('path'), multiplier: 1 },
{ column: Arel.sql('name'), multiplier: 0.8 }
])
expect(Gitlab::Database::SimilarityScore).to be_order_by_similarity(expression)
end

View File

@ -20,22 +20,24 @@ RSpec.describe Gitlab::Diff::CharDiff do
it 'treats nil values as blank strings' do
changes = subject.generate_diff
expect(changes).to eq([
[:insert, "Hello \n World"]
])
expect(changes).to eq(
[
[:insert, "Hello \n World"]
])
end
end
it 'generates an array of changes' do
changes = subject.generate_diff
expect(changes).to eq([
[:equal, "Hel"],
[:insert, "l"],
[:equal, "o \n Worl"],
[:delete, "l"],
[:equal, "d"]
])
expect(changes).to eq(
[
[:equal, "Hel"],
[:insert, "l"],
[:equal, "o \n Worl"],
[:delete, "l"],
[:equal, "d"]
])
end
end

View File

@ -33,27 +33,28 @@ RSpec.describe Gitlab::Diff::FileCollectionSorter do
let(:sorted_files_paths) { subject.sort.map { |file| file.new_path.presence || file.old_path } }
it 'returns list sorted directory first' do
expect(sorted_files_paths).to eq([
'.dir/test',
'1-folder/nested/A-file.ext',
'1-folder/nested/M-file.ext',
'1-folder/nested/Z-file.ext',
'1-folder/A-file.ext',
'1-folder/M-file.ext',
'1-folder/README',
'1-folder/README',
'1-folder/Z-file.ext',
'2-folder/nested/A-file.ext',
'2-folder/A-file.ext',
'2-folder/M-file.ext',
'2-folder/Z-file.ext',
'.file',
'A-file.ext',
'M-file.ext',
'README',
'README',
'Z-file.ext'
])
expect(sorted_files_paths).to eq(
[
'.dir/test',
'1-folder/nested/A-file.ext',
'1-folder/nested/M-file.ext',
'1-folder/nested/Z-file.ext',
'1-folder/A-file.ext',
'1-folder/M-file.ext',
'1-folder/README',
'1-folder/README',
'1-folder/Z-file.ext',
'2-folder/nested/A-file.ext',
'2-folder/A-file.ext',
'2-folder/M-file.ext',
'2-folder/Z-file.ext',
'.file',
'A-file.ext',
'M-file.ext',
'README',
'README',
'Z-file.ext'
])
end
end
end

View File

@ -53,9 +53,9 @@ RSpec.describe Gitlab::ErrorTracking::StackTraceHighlightDecorator do
'lineNo' => 3,
'filename' => 'hello_world.php',
'context' => [
[1, '<span id="LC1" class="line" lang="hack"><span class="c1">// PHP/Hack example</span></span>'],
[2, '<span id="LC1" class="line" lang="hack"><span class="cp">&lt;?php</span></span>'],
[3, '<span id="LC1" class="line" lang="hack"><span class="k">echo</span> <span class="s1">\'Hello, World!\'</span><span class="p">;</span></span>']
[1, '<span id="LC1" class="line" lang="hack"><span class="c1">// PHP/Hack example</span></span>'],
[2, '<span id="LC1" class="line" lang="hack"><span class="cp">&lt;?php</span></span>'],
[3, '<span id="LC1" class="line" lang="hack"><span class="k">echo</span> <span class="s1">\'Hello, World!\'</span><span class="p">;</span></span>']
]
},
{

View File

@ -1769,12 +1769,13 @@ RSpec.describe Gitlab::Git::Repository do
it 'returns exactly the expected results' do
languages = repository.languages(TestEnv::BRANCH_SHA['master'])
expect(languages).to match_array([
{ value: a_value_within(0.1).of(66.7), label: "Ruby", color: "#701516", highlight: "#701516" },
{ value: a_value_within(0.1).of(22.96), label: "JavaScript", color: "#f1e05a", highlight: "#f1e05a" },
{ value: a_value_within(0.1).of(7.9), label: "HTML", color: "#e34c26", highlight: "#e34c26" },
{ value: a_value_within(0.1).of(2.51), label: "CoffeeScript", color: "#244776", highlight: "#244776" }
])
expect(languages).to match_array(
[
{ value: a_value_within(0.1).of(66.7), label: "Ruby", color: "#701516", highlight: "#701516" },
{ value: a_value_within(0.1).of(22.96), label: "JavaScript", color: "#f1e05a", highlight: "#f1e05a" },
{ value: a_value_within(0.1).of(7.9), label: "HTML", color: "#e34c26", highlight: "#e34c26" },
{ value: a_value_within(0.1).of(2.51), label: "CoffeeScript", color: "#244776", highlight: "#244776" }
])
end
it "uses the repository's HEAD when no ref is passed" do

View File

@ -174,20 +174,22 @@ RSpec.describe Gitlab::GitalyClient::BlobService do
expect(service)
.to receive(:list_blobs)
.with(gitaly_request_with_params(expected_params), kind_of(Hash))
.and_return([
Gitaly::ListBlobsResponse.new(blobs: [
Gitaly::ListBlobsResponse::Blob.new(oid: "012345", size: 8, data: "0x01"),
Gitaly::ListBlobsResponse::Blob.new(data: "23")
]),
Gitaly::ListBlobsResponse.new(blobs: [
Gitaly::ListBlobsResponse::Blob.new(data: "45"),
Gitaly::ListBlobsResponse::Blob.new(oid: "56", size: 4, data: "0x5"),
Gitaly::ListBlobsResponse::Blob.new(data: "6")
]),
Gitaly::ListBlobsResponse.new(blobs: [
Gitaly::ListBlobsResponse::Blob.new(oid: "78", size: 4, data: "0x78")
.and_return(
[
Gitaly::ListBlobsResponse.new(
blobs: [
Gitaly::ListBlobsResponse::Blob.new(oid: "012345", size: 8, data: "0x01"),
Gitaly::ListBlobsResponse::Blob.new(data: "23")
]),
Gitaly::ListBlobsResponse.new(
blobs: [
Gitaly::ListBlobsResponse::Blob.new(data: "45"),
Gitaly::ListBlobsResponse::Blob.new(oid: "56", size: 4, data: "0x5"),
Gitaly::ListBlobsResponse::Blob.new(data: "6")
]),
Gitaly::ListBlobsResponse.new(
blobs: [Gitaly::ListBlobsResponse::Blob.new(oid: "78", size: 4, data: "0x78")])
])
])
end
blobs = subject.to_a

View File

@ -97,9 +97,10 @@ RSpec.describe Gitlab::GithubImport::Importer::DiffNotesImporter do
.to receive(:each_object_to_import)
.and_yield(github_comment)
expect(Gitlab::GithubImport::ImportDiffNoteWorker).to receive(:bulk_perform_in).with(1.second, [
[project.id, an_instance_of(Hash), an_instance_of(String)]
], batch_size: 1000, batch_delay: 1.minute)
expect(Gitlab::GithubImport::ImportDiffNoteWorker).to receive(:bulk_perform_in)
.with(1.second, [
[project.id, an_instance_of(Hash), an_instance_of(String)]
], batch_size: 1000, batch_delay: 1.minute)
waiter = importer.parallel_import

View File

@ -109,7 +109,6 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
'secure',
'importer',
'geo',
'growth',
'work_items',
'ci_users',
'error_tracking',

View File

@ -28,7 +28,7 @@ RSpec.describe 'layouts/_flash' do
let(:flash) { { flash_type => 'This is a closable flash message' } }
it 'shows a close button' do
expect(rendered).to include('js-close-icon')
expect(rendered).to include('js-close')
end
end
end
@ -42,7 +42,7 @@ RSpec.describe 'layouts/_flash' do
let(:flash) { { flash_type => 'This is a non closable flash message' } }
it 'does not show a close button' do
expect(rendered).not_to include('js-close-icon')
expect(rendered).not_to include('js-close')
end
end
end