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: Layout/FirstArrayElementIndentation:
Details: grace period Details: grace period
Exclude: 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/github_import/importer/issues_importer_spec.rb'
- 'spec/lib/gitlab/search/found_blob_spec.rb' - 'spec/lib/gitlab/search/found_blob_spec.rb'
- 'spec/lib/gitlab/serializer/ci/variables_spec.rb' - 'spec/lib/gitlab/serializer/ci/variables_spec.rb'

View File

@ -524,8 +524,6 @@ gem 'retriable', '~> 3.1.2'
# LRU cache # LRU cache
gem 'lru_redux' gem 'lru_redux'
gem 'erubi', '~> 1.9.0'
# Locked as long as quoted-printable encoding issues are not resolved # Locked as long as quoted-printable encoding issues are not resolved
# Monkey-patched in `config/initializers/mail_encoding_patch.rb` # Monkey-patched in `config/initializers/mail_encoding_patch.rb`
# See https://gitlab.com/gitlab-org/gitlab/issues/197386 # 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_reply_trimmer","version":"0.1.6","platform":"ruby","checksum":"9fede222ce660993e4e2e3dad282535ceb7914e246eb8302c19aa9e021f7326e"},
{"name":"email_spec","version":"2.2.0","platform":"ruby","checksum":"60b7980580a835e7f676db60667f17a2d60e8e0e39c26d81cfc231805c544d79"}, {"name":"email_spec","version":"2.2.0","platform":"ruby","checksum":"60b7980580a835e7f676db60667f17a2d60e8e0e39c26d81cfc231805c544d79"},
{"name":"encryptor","version":"3.0.0","platform":"ruby","checksum":"abf23f94ab4d864b8cea85b43f3432044a60001982cda7c33c1cd90da8db1969"}, {"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":"escape_utils","version":"1.2.1","platform":"ruby","checksum":"e5292fe8d7e12a9bcb4502d99e28fb602e4e1514690d98a1c4957f6f77b4b162"},
{"name":"et-orbi","version":"1.2.7","platform":"ruby","checksum":"3b693d47f94a4060ccc07e60adda488759b1e8b9228a633ebbad842dfc245fb4"}, {"name":"et-orbi","version":"1.2.7","platform":"ruby","checksum":"3b693d47f94a4060ccc07e60adda488759b1e8b9228a633ebbad842dfc245fb4"},
{"name":"ethon","version":"0.15.0","platform":"ruby","checksum":"0809805a035bc10f54162ca99f15ded49e428e0488bcfe1c08c821e18261a74d"}, {"name":"ethon","version":"0.15.0","platform":"ruby","checksum":"0809805a035bc10f54162ca99f15ded49e428e0488bcfe1c08c821e18261a74d"},

View File

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

View File

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

View File

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

View File

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

View File

@ -1,9 +1,9 @@
.row.gl-mt-3.gl-mb-3 .row.gl-mt-3.gl-mb-3
.col-lg-12 .col-lg-12
.card = render Pajamas::CardComponent.new do |c|
.card-header - c.header do
= _("Manage your project's triggers") = _("Manage your project's triggers")
.card-body - c.body do
= render 'projects/triggers/form', btn_text: _('Add trigger') = render 'projects/triggers/form', btn_text: _('Add trigger')
%hr %hr
- if Feature.enabled?(:ci_pipeline_triggers_settings_vue_ui, @project) - if Feature.enabled?(:ci_pipeline_triggers_settings_vue_ui, @project)
@ -30,9 +30,7 @@
- else - else
%p.settings-message.text-center.gl-mb-3{ data: { testid: 'no_triggers_content' } } %p.settings-message.text-center.gl-mb-3{ data: { testid: 'no_triggers_content' } }
= _('No triggers exist yet. Use the form above to create one.') = _('No triggers exist yet. Use the form above to create one.')
- c.footer do
.card-footer
%p %p
= _("These examples show how to trigger this project's pipeline for a branch or tag.") = _("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. # 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 # Please read here for more information: https://github.com/ondrejbartas/sidekiq-cron#adding-cron-job
cron_jobs: 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 # Flag stuck CI jobs as failed
stuck_ci_jobs_worker: stuck_ci_jobs_worker:
cron: "0 * * * *" cron: "0 * * * *"

View File

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

View File

@ -5,6 +5,16 @@ module SidekiqLogArguments
end end
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? def enable_reliable_fetch?
return true unless Feature::FlipperFeature.table_exists? return true unless Feature::FlipperFeature.table_exists?
@ -78,30 +88,10 @@ Sidekiq.configure_server do |config|
Sidekiq::ReliableFetch.setup_reliable_fetch!(config) Sidekiq::ReliableFetch.setup_reliable_fetch!(config)
end 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::SidekiqVersioning.install!
Gitlab.ee do config.options[:cron_poll_interval] = Gitlab.config.cron_jobs.poll_interval
Gitlab::Mirror.configure_cron_job! load_cron_jobs!
Gitlab::Geo.configure_cron_jobs!
end
# Avoid autoload issue such as 'Mail::Parsers::AddressStruct' # Avoid autoload issue such as 'Mail::Parsers::AddressStruct'
# https://github.com/mikel/mail/issues/912#issuecomment-214850355 # 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). [use `extends` with `includes`](#use-extends-and-include-together).
`extends` supports multi-level inheritance. You should avoid using more than three levels, `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 ```yaml
.tests: .tests:

View File

@ -7,15 +7,18 @@ module API
GLOBAL_TEMPLATE_TYPES = { GLOBAL_TEMPLATE_TYPES = {
gitignores: { gitignores: {
gitlab_version: 8.8, gitlab_version: 8.8,
feature_category: :source_code_management feature_category: :source_code_management,
file_type: '.gitignore'
}, },
gitlab_ci_ymls: { gitlab_ci_ymls: {
gitlab_version: 8.9, gitlab_version: 8.9,
feature_category: :pipeline_authoring feature_category: :pipeline_authoring,
file_type: 'GitLab CI/CD YAML'
}, },
dockerfiles: { dockerfiles: {
gitlab_version: 8.15, gitlab_version: 8.15,
feature_category: :source_code_management feature_category: :source_code_management,
file_type: 'Dockerfile'
} }
}.freeze }.freeze
@ -26,7 +29,7 @@ module API
end end
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.' detail 'This feature was introduced in GitLab 8.7.'
success ::API::Entities::License success ::API::Entities::License
end end
@ -43,12 +46,14 @@ module API
present paginate(::Kaminari.paginate_array(templates)), with: ::API::Entities::License present paginate(::Kaminari.paginate_array(templates)), with: ::API::Entities::License
end 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.' detail 'This feature was introduced in GitLab 8.7.'
success ::API::Entities::License success ::API::Entities::License
end end
params do 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 end
get "templates/licenses/:name", requirements: { name: /[\w\.-]+/ }, feature_category: :source_code_management do get "templates/licenses/:name", requirements: { name: /[\w\.-]+/ }, feature_category: :source_code_management do
template = TemplateFinder.build(:licenses, nil, name: params[:name]).execute template = TemplateFinder.build(:licenses, nil, name: params[:name]).execute
@ -65,8 +70,9 @@ module API
GLOBAL_TEMPLATE_TYPES.each do |template_type, properties| GLOBAL_TEMPLATE_TYPES.each do |template_type, properties|
gitlab_version = properties[:gitlab_version] 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}." detail "This feature was introduced in GitLab #{gitlab_version}."
success Entities::TemplatesList success Entities::TemplatesList
end end
@ -78,12 +84,12 @@ module API
present paginate(templates), with: Entities::TemplatesList present paginate(templates), with: Entities::TemplatesList
end 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}." detail "This feature was introduced in GitLab #{gitlab_version}."
success Entities::Template success Entities::Template
end end
params do 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 end
get "templates/#{template_type}/:name", requirements: { name: /[\w\.-]+/ }, feature_category: properties[:feature_category] do get "templates/#{template_type}/:name", requirements: { name: /[\w\.-]+/ }, feature_category: properties[:feature_category] do
finder = TemplateFinder.build(template_type, nil, name: declared(params)[:name]) finder = TemplateFinder.build(template_type, nil, name: declared(params)[:name])

View File

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

View File

@ -53,8 +53,33 @@ module Gitlab
end end
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 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 end
def workers def workers

View File

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

View File

@ -45,11 +45,37 @@ RSpec.describe Pajamas::AlertComponent, :aggregate_failures, type: :component do
end end
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 custom options' do
context 'with simple options' do context 'with simple options' do
before do before do
render_inline described_class.new( render_inline described_class.new(
title: '_title_',
alert_options: { alert_options: {
class: '_alert_class_', class: '_alert_class_',
data: { data: {
@ -60,12 +86,6 @@ RSpec.describe Pajamas::AlertComponent, :aggregate_failures, type: :component do
) )
end 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 it 'sets the alert_class' do
expect(page).to have_selector('._alert_class_') expect(page).to have_selector('._alert_class_')
end end
@ -129,7 +149,7 @@ RSpec.describe Pajamas::AlertComponent, :aggregate_failures, type: :component do
end end
context 'with setting variant type' do context 'with setting variant type' do
where(:variant) { [:warning, :success, :danger, :tip] } where(:variant) { [:warning, "success", :danger, "tip"] }
before do before do
render_inline described_class.new(variant: variant) render_inline described_class.new(variant: variant)
@ -138,7 +158,18 @@ RSpec.describe Pajamas::AlertComponent, :aggregate_failures, type: :component do
with_them do with_them do
it 'renders the variant' do it 'renders the variant' do
expect(page).to have_selector(".gl-alert-#{variant}") 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 end
end end

View File

@ -1,12 +1,13 @@
# frozen_string_literal: true # frozen_string_literal: true
module Pajamas module Pajamas
class AlertComponentPreview < ViewComponent::Preview class AlertComponentPreview < ViewComponent::Preview
# @param title text
# @param body text # @param body text
# @param dismissible toggle # @param dismissible toggle
# @param variant select [info, warning, success, danger, tip] # @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( render(Pajamas::AlertComponent.new(
title: "Title", title: title,
dismissible: dismissible, dismissible: dismissible,
variant: variant.to_sym variant: variant.to_sym
)) do |c| )) do |c|

View File

@ -42,4 +42,61 @@ RSpec.describe 'sidekiq' do
it { is_expected.to be_falsey } it { is_expected.to be_falsey }
end end
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 end

View File

@ -93,12 +93,13 @@ RSpec.describe Gitlab::Database::EachDatabase do
end end
it 'yields each model with SharedModel connected to each database connection' do it 'yields each model with SharedModel connected to each database connection' do
expect_yielded_models([model1, model2], [ expect_yielded_models([model1, model2],
{ model: model1, connection: ActiveRecord::Base.connection, name: 'main' }, [
{ model: model1, connection: Ci::ApplicationRecord.connection, name: 'ci' }, { model: model1, connection: ActiveRecord::Base.connection, name: 'main' },
{ model: model2, connection: ActiveRecord::Base.connection, name: 'main' }, { model: model1, connection: Ci::ApplicationRecord.connection, name: 'ci' },
{ model: model2, connection: Ci::ApplicationRecord.connection, name: 'ci' } { model: model2, connection: ActiveRecord::Base.connection, name: 'main' },
]) { model: model2, connection: Ci::ApplicationRecord.connection, name: 'ci' }
])
end end
context 'when the model limits connection names' do context 'when the model limits connection names' do
@ -108,10 +109,11 @@ RSpec.describe Gitlab::Database::EachDatabase do
end end
it 'only yields the model with SharedModel connected to the limited connections' do it 'only yields the model with SharedModel connected to the limited connections' do
expect_yielded_models([model1, model2], [ expect_yielded_models([model1, model2],
{ model: model1, connection: ActiveRecord::Base.connection, name: 'main' }, [
{ model: model2, connection: Ci::ApplicationRecord.connection, name: 'ci' } { model: model1, connection: ActiveRecord::Base.connection, name: 'main' },
]) { model: model2, connection: Ci::ApplicationRecord.connection, name: 'ci' }
])
end end
end end
end end
@ -132,10 +134,11 @@ RSpec.describe Gitlab::Database::EachDatabase do
end end
it 'yields each model after connecting SharedModel' do it 'yields each model after connecting SharedModel' do
expect_yielded_models([main_model, ci_model], [ expect_yielded_models([main_model, ci_model],
{ model: main_model, connection: main_connection, name: 'main' }, [
{ model: ci_model, connection: ci_connection, name: 'ci' } { model: main_model, connection: main_connection, name: 'main' },
]) { model: ci_model, connection: ci_connection, name: 'ci' }
])
end end
end end
@ -154,21 +157,23 @@ RSpec.describe Gitlab::Database::EachDatabase do
context 'when a single name is passed in' do context 'when a single name is passed in' do
it 'yields models only connected to the given database' do it 'yields models only connected to the given database' do
expect_yielded_models([main_model, ci_model, shared_model], [ 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' } { model: ci_model, connection: Ci::ApplicationRecord.connection, name: 'ci' },
], only_on: 'ci') { model: shared_model, connection: Ci::ApplicationRecord.connection, name: 'ci' }
], only_on: 'ci')
end end
end end
context 'when a list of names are passed in' do context 'when a list of names are passed in' do
it 'yields models only connected to the given databases' do it 'yields models only connected to the given databases' do
expect_yielded_models([main_model, ci_model, shared_model], [ 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: main_model, connection: ActiveRecord::Base.connection, name: 'main' },
{ model: shared_model, connection: ActiveRecord::Base.connection, name: 'main' }, { model: ci_model, connection: Ci::ApplicationRecord.connection, name: 'ci' },
{ model: shared_model, connection: Ci::ApplicationRecord.connection, name: 'ci' } { model: shared_model, connection: ActiveRecord::Base.connection, name: 'main' },
], only_on: %i[main ci]) { model: shared_model, connection: Ci::ApplicationRecord.connection, name: 'ci' }
], only_on: %i[main ci])
end end
end 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(:single_sticking_object) { Set.new([[ActiveRecord::Base.sticking, :user, 42]]) }
let(:multiple_sticking_objects) do let(:multiple_sticking_objects) do
Set.new([ Set.new([
[ActiveRecord::Base.sticking, :user, 42], [ActiveRecord::Base.sticking, :user, 42],
[ActiveRecord::Base.sticking, :runner, '123456789'], [ActiveRecord::Base.sticking, :runner, '123456789'],
[ActiveRecord::Base.sticking, :runner, '1234'] [ActiveRecord::Base.sticking, :runner, '1234']
]) ])
end end
after do after do
@ -182,11 +182,12 @@ RSpec.describe Gitlab::Database::LoadBalancing::RackMiddleware, :redis do
it 'returns the sticking object' do it 'returns the sticking object' do
env = { described_class::STICK_OBJECT => multiple_sticking_objects } env = { described_class::STICK_OBJECT => multiple_sticking_objects }
expect(middleware.sticking_namespaces(env)).to eq([ expect(middleware.sticking_namespaces(env)).to eq(
[ActiveRecord::Base.sticking, :user, 42], [
[ActiveRecord::Base.sticking, :runner, '123456789'], [ActiveRecord::Base.sticking, :user, 42],
[ActiveRecord::Base.sticking, :runner, '1234'] [ActiveRecord::Base.sticking, :runner, '123456789'],
]) [ActiveRecord::Base.sticking, :runner, '1234']
])
end end
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, :user, 42)
sticking.stick_or_unstick_request(env, :runner, '123456789') sticking.stick_or_unstick_request(env, :runner, '123456789')
expect(env[Gitlab::Database::LoadBalancing::RackMiddleware::STICK_OBJECT].to_a).to eq([ expect(env[Gitlab::Database::LoadBalancing::RackMiddleware::STICK_OBJECT].to_a).to eq(
[sticking, :user, 42], [
[sticking, :runner, '123456789'] [sticking, :user, 42],
]) [sticking, :runner,
'123456789']
])
end end
end end

View File

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

View File

@ -29,10 +29,11 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy do
end end
it 'detects both partitions' do it 'detects both partitions' do
expect(subject).to eq([ 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') 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
end end

View File

@ -36,14 +36,15 @@ RSpec.describe Gitlab::Database::Partitioning::SlidingListStrategy do
describe '#current_partitions' do describe '#current_partitions' do
it 'detects both partitions' do it 'detects both partitions' do
expect(strategy.current_partitions).to eq([ 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, 1, partition_name: '_test_partitioned_test_1'
Gitlab::Database::Partitioning::SingleNumericListPartition.new( ),
table_name, 2, partition_name: '_test_partitioned_test_2' Gitlab::Database::Partitioning::SingleNumericListPartition.new(
) table_name, 2, partition_name: '_test_partitioned_test_2'
]) )
])
end end
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') described_class.new(table, '2020-03-01', '2020-04-01')
] ]
expect(partitions.sort).to eq([ 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, nil, '2020-02-01'),
described_class.new(table, '2020-03-01', '2020-04-01'), described_class.new(table, '2020-02-01', '2020-03-01'),
described_class.new(table, '2020-04-01', '2020-05-01') described_class.new(table, '2020-03-01', '2020-04-01'),
]) described_class.new(table, '2020-04-01', '2020-05-01')
])
end end
it 'returns nil for partitions of different tables' do 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 context 'when no partitioned models are given' do
it 'manages partitions for each registered model' do it 'manages partitions for each registered model' do
described_class.register_models([models.first]) described_class.register_models([models.first])
described_class.register_tables([ described_class.register_tables(
{ [
table_name: table_names.last, {
partitioned_column: :created_at, strategy: :monthly table_name: table_names.last,
} partitioned_column: :created_at,
]) strategy: :monthly
}
])
expect { described_class.sync_partitions } expect { described_class.sync_partitions }
.to change { find_partitions(table_names.first).size }.from(0) .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 describe 'score multiplier' do
let(:order_expression) do let(:order_expression) do
Gitlab::Database::SimilarityScore.build_expression(search: search, rules: [ Gitlab::Database::SimilarityScore.build_expression(search: search, rules:
{ column: Arel.sql('path'), multiplier: 1 }, [
{ column: Arel.sql('name'), multiplier: 0.8 } { column: Arel.sql('path'), multiplier: 1 },
]).to_sql { column: Arel.sql('name'), multiplier: 0.8 }
]).to_sql
end end
let(:search) { 'different' } let(:search) { 'different' }
@ -93,10 +94,11 @@ RSpec.describe Gitlab::Database::SimilarityScore do
describe 'annotation' do describe 'annotation' do
it 'annotates the generated SQL expression' do it 'annotates the generated SQL expression' do
expression = Gitlab::Database::SimilarityScore.build_expression(search: 'test', rules: [ expression = Gitlab::Database::SimilarityScore.build_expression(search: 'test', rules:
{ column: Arel.sql('path'), multiplier: 1 }, [
{ column: Arel.sql('name'), multiplier: 0.8 } { column: Arel.sql('path'), multiplier: 1 },
]) { column: Arel.sql('name'), multiplier: 0.8 }
])
expect(Gitlab::Database::SimilarityScore).to be_order_by_similarity(expression) expect(Gitlab::Database::SimilarityScore).to be_order_by_similarity(expression)
end end

View File

@ -20,22 +20,24 @@ RSpec.describe Gitlab::Diff::CharDiff do
it 'treats nil values as blank strings' do it 'treats nil values as blank strings' do
changes = subject.generate_diff changes = subject.generate_diff
expect(changes).to eq([ expect(changes).to eq(
[:insert, "Hello \n World"] [
]) [:insert, "Hello \n World"]
])
end end
end end
it 'generates an array of changes' do it 'generates an array of changes' do
changes = subject.generate_diff changes = subject.generate_diff
expect(changes).to eq([ expect(changes).to eq(
[:equal, "Hel"], [
[:insert, "l"], [:equal, "Hel"],
[:equal, "o \n Worl"], [:insert, "l"],
[:delete, "l"], [:equal, "o \n Worl"],
[:equal, "d"] [:delete, "l"],
]) [:equal, "d"]
])
end end
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 } } let(:sorted_files_paths) { subject.sort.map { |file| file.new_path.presence || file.old_path } }
it 'returns list sorted directory first' do it 'returns list sorted directory first' do
expect(sorted_files_paths).to eq([ expect(sorted_files_paths).to eq(
'.dir/test', [
'1-folder/nested/A-file.ext', '.dir/test',
'1-folder/nested/M-file.ext', '1-folder/nested/A-file.ext',
'1-folder/nested/Z-file.ext', '1-folder/nested/M-file.ext',
'1-folder/A-file.ext', '1-folder/nested/Z-file.ext',
'1-folder/M-file.ext', '1-folder/A-file.ext',
'1-folder/README', '1-folder/M-file.ext',
'1-folder/README', '1-folder/README',
'1-folder/Z-file.ext', '1-folder/README',
'2-folder/nested/A-file.ext', '1-folder/Z-file.ext',
'2-folder/A-file.ext', '2-folder/nested/A-file.ext',
'2-folder/M-file.ext', '2-folder/A-file.ext',
'2-folder/Z-file.ext', '2-folder/M-file.ext',
'.file', '2-folder/Z-file.ext',
'A-file.ext', '.file',
'M-file.ext', 'A-file.ext',
'README', 'M-file.ext',
'README', 'README',
'Z-file.ext' 'README',
]) 'Z-file.ext'
])
end end
end end
end end

View File

@ -53,9 +53,9 @@ RSpec.describe Gitlab::ErrorTracking::StackTraceHighlightDecorator do
'lineNo' => 3, 'lineNo' => 3,
'filename' => 'hello_world.php', 'filename' => 'hello_world.php',
'context' => [ 'context' => [
[1, '<span id="LC1" class="line" lang="hack"><span class="c1">// PHP/Hack example</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>'], [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>'] [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 it 'returns exactly the expected results' do
languages = repository.languages(TestEnv::BRANCH_SHA['master']) languages = repository.languages(TestEnv::BRANCH_SHA['master'])
expect(languages).to match_array([ 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(66.7), label: "Ruby", color: "#701516", highlight: "#701516" },
{ value: a_value_within(0.1).of(7.9), label: "HTML", color: "#e34c26", highlight: "#e34c26" }, { value: a_value_within(0.1).of(22.96), label: "JavaScript", color: "#f1e05a", highlight: "#f1e05a" },
{ value: a_value_within(0.1).of(2.51), label: "CoffeeScript", color: "#244776", highlight: "#244776" } { 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 end
it "uses the repository's HEAD when no ref is passed" do 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) expect(service)
.to receive(:list_blobs) .to receive(:list_blobs)
.with(gitaly_request_with_params(expected_params), kind_of(Hash)) .with(gitaly_request_with_params(expected_params), kind_of(Hash))
.and_return([ .and_return(
Gitaly::ListBlobsResponse.new(blobs: [ [
Gitaly::ListBlobsResponse::Blob.new(oid: "012345", size: 8, data: "0x01"), Gitaly::ListBlobsResponse.new(
Gitaly::ListBlobsResponse::Blob.new(data: "23") blobs: [
]), Gitaly::ListBlobsResponse::Blob.new(oid: "012345", size: 8, data: "0x01"),
Gitaly::ListBlobsResponse.new(blobs: [ Gitaly::ListBlobsResponse::Blob.new(data: "23")
Gitaly::ListBlobsResponse::Blob.new(data: "45"), ]),
Gitaly::ListBlobsResponse::Blob.new(oid: "56", size: 4, data: "0x5"), Gitaly::ListBlobsResponse.new(
Gitaly::ListBlobsResponse::Blob.new(data: "6") blobs: [
]), Gitaly::ListBlobsResponse::Blob.new(data: "45"),
Gitaly::ListBlobsResponse.new(blobs: [ Gitaly::ListBlobsResponse::Blob.new(oid: "56", size: 4, data: "0x5"),
Gitaly::ListBlobsResponse::Blob.new(oid: "78", size: 4, data: "0x78") Gitaly::ListBlobsResponse::Blob.new(data: "6")
]),
Gitaly::ListBlobsResponse.new(
blobs: [Gitaly::ListBlobsResponse::Blob.new(oid: "78", size: 4, data: "0x78")])
]) ])
])
end end
blobs = subject.to_a blobs = subject.to_a

View File

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

View File

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

View File

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