Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
d210b1bee1
commit
c74f7b6ff5
|
@ -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'
|
||||||
|
|
2
Gemfile
2
Gemfile
|
@ -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
|
||||||
|
|
|
@ -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"},
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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!')
|
|
||||||
|
|
|
@ -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.")
|
||||||
|
|
||||||
|
|
|
@ -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 * * * *"
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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])
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"><?php</span></span>'],
|
[2, '<span id="LC1" class="line" lang="hack"><span class="cp"><?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>']
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue