Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
d210b1bee1
commit
c74f7b6ff5
36 changed files with 345 additions and 231 deletions
|
@ -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'
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -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
|
||||
|
|
|
@ -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"},
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -46,6 +46,7 @@ $notification-box-shadow-color: rgba(0, 0, 0, 0.25);
|
|||
.flash-notice,
|
||||
.flash-success,
|
||||
.flash-warning {
|
||||
&:not(.gl-alert) {
|
||||
padding: $gl-padding $gl-padding-32 $gl-padding ($gl-padding + $gl-padding-4);
|
||||
margin-top: 10px;
|
||||
|
||||
|
@ -54,6 +55,7 @@ $notification-box-shadow-color: rgba(0, 0, 0, 0.25);
|
|||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.flash-alert {
|
||||
background-color: $red-50;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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.")
|
||||
|
||||
|
|
|
@ -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 * * * *"
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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|
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -93,7 +93,8 @@ RSpec.describe Gitlab::Database::EachDatabase do
|
|||
end
|
||||
|
||||
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: model2, connection: ActiveRecord::Base.connection, name: 'main' },
|
||||
|
@ -108,7 +109,8 @@ 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], [
|
||||
expect_yielded_models([model1, model2],
|
||||
[
|
||||
{ model: model1, connection: ActiveRecord::Base.connection, name: 'main' },
|
||||
{ model: model2, connection: Ci::ApplicationRecord.connection, name: 'ci' }
|
||||
])
|
||||
|
@ -132,7 +134,8 @@ RSpec.describe Gitlab::Database::EachDatabase do
|
|||
end
|
||||
|
||||
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' }
|
||||
])
|
||||
|
@ -154,7 +157,8 @@ 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], [
|
||||
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')
|
||||
|
@ -163,7 +167,8 @@ RSpec.describe Gitlab::Database::EachDatabase do
|
|||
|
||||
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], [
|
||||
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' },
|
||||
|
|
|
@ -182,7 +182,8 @@ 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([
|
||||
expect(middleware.sticking_namespaces(env)).to eq(
|
||||
[
|
||||
[ActiveRecord::Base.sticking, :user, 42],
|
||||
[ActiveRecord::Base.sticking, :runner, '123456789'],
|
||||
[ActiveRecord::Base.sticking, :runner, '1234']
|
||||
|
|
|
@ -41,9 +41,11 @@ 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([
|
||||
expect(env[Gitlab::Database::LoadBalancing::RackMiddleware::STICK_OBJECT].to_a).to eq(
|
||||
[
|
||||
[sticking, :user, 42],
|
||||
[sticking, :runner, '123456789']
|
||||
[sticking, :runner,
|
||||
'123456789']
|
||||
])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -53,7 +53,8 @@ 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([
|
||||
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')
|
||||
|
|
|
@ -29,7 +29,8 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy do
|
|||
end
|
||||
|
||||
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')
|
||||
])
|
||||
|
|
|
@ -36,7 +36,8 @@ RSpec.describe Gitlab::Database::Partitioning::SlidingListStrategy do
|
|||
|
||||
describe '#current_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'
|
||||
),
|
||||
|
|
|
@ -156,7 +156,8 @@ RSpec.describe Gitlab::Database::Partitioning::TimePartition do
|
|||
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, '2020-03-01', '2020-04-01'),
|
||||
|
|
|
@ -130,10 +130,12 @@ 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([
|
||||
described_class.register_tables(
|
||||
[
|
||||
{
|
||||
table_name: table_names.last,
|
||||
partitioned_column: :created_at, strategy: :monthly
|
||||
partitioned_column: :created_at,
|
||||
strategy: :monthly
|
||||
}
|
||||
])
|
||||
|
||||
|
|
|
@ -78,7 +78,8 @@ RSpec.describe Gitlab::Database::SimilarityScore do
|
|||
|
||||
describe 'score multiplier' 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 }
|
||||
]).to_sql
|
||||
|
@ -93,7 +94,8 @@ 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: [
|
||||
expression = Gitlab::Database::SimilarityScore.build_expression(search: 'test', rules:
|
||||
[
|
||||
{ column: Arel.sql('path'), multiplier: 1 },
|
||||
{ column: Arel.sql('name'), multiplier: 0.8 }
|
||||
])
|
||||
|
|
|
@ -20,7 +20,8 @@ RSpec.describe Gitlab::Diff::CharDiff do
|
|||
it 'treats nil values as blank strings' do
|
||||
changes = subject.generate_diff
|
||||
|
||||
expect(changes).to eq([
|
||||
expect(changes).to eq(
|
||||
[
|
||||
[:insert, "Hello \n World"]
|
||||
])
|
||||
end
|
||||
|
@ -29,7 +30,8 @@ RSpec.describe Gitlab::Diff::CharDiff do
|
|||
it 'generates an array of changes' do
|
||||
changes = subject.generate_diff
|
||||
|
||||
expect(changes).to eq([
|
||||
expect(changes).to eq(
|
||||
[
|
||||
[:equal, "Hel"],
|
||||
[:insert, "l"],
|
||||
[:equal, "o \n Worl"],
|
||||
|
|
|
@ -33,7 +33,8 @@ 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([
|
||||
expect(sorted_files_paths).to eq(
|
||||
[
|
||||
'.dir/test',
|
||||
'1-folder/nested/A-file.ext',
|
||||
'1-folder/nested/M-file.ext',
|
||||
|
|
|
@ -1769,7 +1769,8 @@ 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([
|
||||
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" },
|
||||
|
|
|
@ -174,19 +174,21 @@ 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: [
|
||||
.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.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")
|
||||
])
|
||||
Gitaly::ListBlobsResponse.new(
|
||||
blobs: [Gitaly::ListBlobsResponse::Blob.new(oid: "78", size: 4, data: "0x78")])
|
||||
])
|
||||
end
|
||||
|
||||
|
|
|
@ -97,7 +97,8 @@ 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, [
|
||||
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)
|
||||
|
||||
|
|
|
@ -109,7 +109,6 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
|
|||
'secure',
|
||||
'importer',
|
||||
'geo',
|
||||
'growth',
|
||||
'work_items',
|
||||
'ci_users',
|
||||
'error_tracking',
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue