Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-11-16 15:09:30 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-11-16 15:09:30 +0300
commite3748b81ca29b24197276767e245158d8f84fda3 (patch)
tree02b2dbe099f8e09e9e85dc71cce1bd8e858be7ac
parent4e1af5260dc9187ca0637fcfcf56b450f6443192 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop_todo/layout/line_length.yml1
-rw-r--r--.rubocop_todo/rspec/timecop_travel.yml1
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/boards/components/board_list_header.vue3
-rw-r--r--app/assets/javascripts/lib/utils/dom_utils.js12
-rw-r--r--app/workers/authorized_keys_worker.rb2
-rw-r--r--app/workers/gitlab_shell_worker.rb12
-rw-r--r--config/feature_flags/development/verify_gitlab_shell_worker_method_names.yml8
-rw-r--r--config/gitlab_loose_foreign_keys.yml4
-rw-r--r--config/initializers/database_query_analyzers.rb1
-rw-r--r--config/open_api.yml2
-rw-r--r--config/sidekiq_queues.yml2
-rw-r--r--db/fixtures/development/17_cycle_analytics.rb5
-rw-r--r--doc/.vale/gitlab/Uppercase.yml1
-rw-r--r--doc/.vale/gitlab/spelling-exceptions.txt1
-rw-r--r--lefthook.yml2
-rw-r--r--lib/api/admin/plan_limits.rb28
-rw-r--r--lib/api/api.rb2
-rw-r--r--lib/api/entities/plan_limit.rb34
-rw-r--r--lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer.rb (renamed from lib/gitlab/database/query_analyzers/ci/partitioning_analyzer.rb)40
-rw-r--r--lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer.rb39
-rw-r--r--lib/gitlab/shell.rb5
-rw-r--r--lib/gitlab/slash_commands/incident_management/incident_command.rb2
-rw-r--r--lib/gitlab/slash_commands/incident_management/incident_new.rb8
-rw-r--r--locale/gitlab.pot48
-rw-r--r--qa/qa/specs/spec_helper.rb2
-rw-r--r--qa/spec/tools/test_resources_data_processor_spec.rb2
-rw-r--r--spec/db/schema_spec.rb5
-rw-r--r--spec/frontend/fixtures/freeze_period.rb2
-rw-r--r--spec/frontend/lib/utils/dom_utils_spec.js28
-rw-r--r--spec/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer_spec.rb163
-rw-r--r--spec/lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer_spec.rb121
-rw-r--r--spec/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer_spec.rb70
-rw-r--r--spec/lib/gitlab/slash_commands/incident_management/incident_new_spec.rb60
-rw-r--r--spec/workers/concerns/reenqueuer_spec.rb21
-rw-r--r--spec/workers/gitlab_shell_worker_spec.rb50
36 files changed, 444 insertions, 345 deletions
diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml
index 8b34f2d5e9b..75e04ddcbd4 100644
--- a/.rubocop_todo/layout/line_length.yml
+++ b/.rubocop_todo/layout/line_length.yml
@@ -2906,7 +2906,6 @@ Layout/LineLength:
- 'ee/spec/workers/update_all_mirrors_worker_spec.rb'
- 'ee/spec/workers/vulnerability_exports/export_deletion_worker_spec.rb'
- 'lib/api/admin/instance_clusters.rb'
- - 'lib/api/admin/plan_limits.rb'
- 'lib/api/api.rb'
- 'lib/api/appearance.rb'
- 'lib/api/award_emoji.rb'
diff --git a/.rubocop_todo/rspec/timecop_travel.yml b/.rubocop_todo/rspec/timecop_travel.yml
index a8ca3a5fad5..3a9ebc443fd 100644
--- a/.rubocop_todo/rspec/timecop_travel.yml
+++ b/.rubocop_todo/rspec/timecop_travel.yml
@@ -1,5 +1,4 @@
---
RSpec/TimecopTravel:
Exclude:
- - spec/workers/concerns/reenqueuer_spec.rb
- qa/spec/support/repeater_spec.rb
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 5d4b003c8fe..1f9ab02102a 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-cdc87c3fefb4386c150cb4d71fcb4530d2b0501b
+40398eb9e22e8cf09365f508f6779030ee90432a
diff --git a/app/assets/javascripts/boards/components/board_list_header.vue b/app/assets/javascripts/boards/components/board_list_header.vue
index cb2f68df0d1..bfc4b52baaf 100644
--- a/app/assets/javascripts/boards/components/board_list_header.vue
+++ b/app/assets/javascripts/boards/components/board_list_header.vue
@@ -171,6 +171,9 @@ export default {
filters: this.filterParams,
};
},
+ context: {
+ isSingleRequest: true,
+ },
skip() {
return this.isEpicBoard;
},
diff --git a/app/assets/javascripts/lib/utils/dom_utils.js b/app/assets/javascripts/lib/utils/dom_utils.js
index bca6978c206..cafee641174 100644
--- a/app/assets/javascripts/lib/utils/dom_utils.js
+++ b/app/assets/javascripts/lib/utils/dom_utils.js
@@ -106,3 +106,15 @@ export const setAttributes = (el, attributes) => {
el.setAttribute(key, attributes[key]);
});
};
+
+/**
+ * Get the height of the wrapper page element
+ * This height can be used to determine where the highest element goes in a page
+ * Useful for gl-drawer's header-height prop
+ * @param {String} contentWrapperClass the content wrapper class
+ * @returns {String} height in px
+ */
+export const getContentWrapperHeight = (contentWrapperClass) => {
+ const wrapperEl = document.querySelector(contentWrapperClass);
+ return wrapperEl ? `${wrapperEl.offsetTop}px` : '';
+};
diff --git a/app/workers/authorized_keys_worker.rb b/app/workers/authorized_keys_worker.rb
index 039fe629a61..77f2ed5f495 100644
--- a/app/workers/authorized_keys_worker.rb
+++ b/app/workers/authorized_keys_worker.rb
@@ -7,8 +7,6 @@ class AuthorizedKeysWorker
sidekiq_options retry: 3
- PERMITTED_ACTIONS = %w[add_key remove_key].freeze
-
feature_category :source_code_management
urgency :high
weight 2
diff --git a/app/workers/gitlab_shell_worker.rb b/app/workers/gitlab_shell_worker.rb
index 1bcaf5a42be..2f396dcdb86 100644
--- a/app/workers/gitlab_shell_worker.rb
+++ b/app/workers/gitlab_shell_worker.rb
@@ -14,18 +14,12 @@ class GitlabShellWorker # rubocop:disable Scalability/IdempotentWorker
loggable_arguments 0
def perform(action, *arg)
- # Gitlab::Shell is being removed but we need to continue to process jobs
- # enqueued in the previous release, so handle them here.
- #
- # See https://gitlab.com/gitlab-org/gitlab/-/issues/25095 for more details
- if AuthorizedKeysWorker::PERMITTED_ACTIONS.include?(action.to_s)
- AuthorizedKeysWorker.new.perform(action, *arg)
-
- return
+ if ::Feature.enabled?(:verify_gitlab_shell_worker_method_names) && Gitlab::Shell::PERMITTED_ACTIONS.exclude?(action)
+ raise(ArgumentError, "#{action} not allowed for #{self.class.name}")
end
Gitlab::GitalyClient::NamespaceService.allow do
- gitlab_shell.__send__(action, *arg) # rubocop:disable GitlabSecurity/PublicSend
+ gitlab_shell.public_send(action, *arg) # rubocop:disable GitlabSecurity/PublicSend
end
end
end
diff --git a/config/feature_flags/development/verify_gitlab_shell_worker_method_names.yml b/config/feature_flags/development/verify_gitlab_shell_worker_method_names.yml
new file mode 100644
index 00000000000..d6b28c28600
--- /dev/null
+++ b/config/feature_flags/development/verify_gitlab_shell_worker_method_names.yml
@@ -0,0 +1,8 @@
+---
+name: verify_gitlab_shell_worker_method_names
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/103783
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/371470
+milestone: '15.6'
+type: development
+group: group::scalability
+default_enabled: false
diff --git a/config/gitlab_loose_foreign_keys.yml b/config/gitlab_loose_foreign_keys.yml
index 9e1bf15dee1..efb14cdea36 100644
--- a/config/gitlab_loose_foreign_keys.yml
+++ b/config/gitlab_loose_foreign_keys.yml
@@ -14,10 +14,6 @@ ci_builds:
- table: ci_runners
column: runner_id
on_delete: async_nullify
-ci_builds_metadata:
- - table: projects
- column: project_id
- on_delete: async_delete
ci_daily_build_group_report_results:
- table: namespaces
column: group_id
diff --git a/config/initializers/database_query_analyzers.rb b/config/initializers/database_query_analyzers.rb
index fcfc75341df..ad6ed20b94d 100644
--- a/config/initializers/database_query_analyzers.rb
+++ b/config/initializers/database_query_analyzers.rb
@@ -7,6 +7,7 @@ Gitlab::Database::QueryAnalyzer.instance.tap do |query_analyzer|
query_analyzer.all_analyzers.tap do |analyzers|
analyzers.append(::Gitlab::Database::QueryAnalyzers::GitlabSchemasMetrics)
analyzers.append(::Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification)
+ analyzers.append(::Gitlab::Database::QueryAnalyzers::Ci::PartitioningRoutingAnalyzer)
if Gitlab.dev_or_test_env?
analyzers.append(::Gitlab::Database::QueryAnalyzers::GitlabSchemasValidateConnection)
diff --git a/config/open_api.yml b/config/open_api.yml
index 96e72819d73..7f02fd23484 100644
--- a/config/open_api.yml
+++ b/config/open_api.yml
@@ -75,6 +75,8 @@ metadata:
description: Operations related to User-starred metrics dashboards
- name: package_files
description: Operations about package files
+ - name: plan_limits
+ description: Operations related to plan limits
- name: project_export
description: Operations related to exporting projects
- name: project_hooks
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index a403c0992fc..4ed4dca8912 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -259,6 +259,8 @@
- 1
- - integrations_slack_event
- 1
+- - integrations_slack_interactivity
+ - 1
- - invalid_gpg_signature_update
- 2
- - issuable_export_csv
diff --git a/db/fixtures/development/17_cycle_analytics.rb b/db/fixtures/development/17_cycle_analytics.rb
index 5c71e1ecdac..4f6bfc5c82a 100644
--- a/db/fixtures/development/17_cycle_analytics.rb
+++ b/db/fixtures/development/17_cycle_analytics.rb
@@ -2,6 +2,7 @@
require './spec/support/sidekiq_middleware'
require './spec/support/helpers/test_env'
+require 'active_support/testing/time_helpers'
# Usage:
#
@@ -18,6 +19,8 @@ require './spec/support/helpers/test_env'
# VSA_SEED_PROJECT_ID=10 FILTER=cycle_analytics SEED_VSA=1 bundle exec rake db:seed_fu
class Gitlab::Seeder::CycleAnalytics
+ include ActiveSupport::Testing::TimeHelpers
+
attr_reader :project, :issues, :merge_requests, :developers
FLAG = 'SEED_VSA'
@@ -133,7 +136,7 @@ class Gitlab::Seeder::CycleAnalytics
def create_issues!
@issue_count.times do
- Timecop.travel start_time + rand(5).days do
+ travel_to(start_time + rand(5).days) do
title = "#{FFaker::Product.brand}-#{suffix}"
@issues << Issue.create!(project: project, title: title, author: developers.sample)
end
diff --git a/doc/.vale/gitlab/Uppercase.yml b/doc/.vale/gitlab/Uppercase.yml
index 72a4e2244f3..f53e1c72dcb 100644
--- a/doc/.vale/gitlab/Uppercase.yml
+++ b/doc/.vale/gitlab/Uppercase.yml
@@ -145,6 +145,7 @@ exceptions:
- NOTE
- NPM
- NTP
+ - OCI
- OKD
- ONLY
- OSS
diff --git a/doc/.vale/gitlab/spelling-exceptions.txt b/doc/.vale/gitlab/spelling-exceptions.txt
index 2a50a076098..0fc7c9703ac 100644
--- a/doc/.vale/gitlab/spelling-exceptions.txt
+++ b/doc/.vale/gitlab/spelling-exceptions.txt
@@ -615,6 +615,7 @@ Silverlight
Sisense
Sitespeed
skippable
+skopeo
Slack
Slackbot
Slony
diff --git a/lefthook.yml b/lefthook.yml
index 03542a437e3..dc2c0b70c6f 100644
--- a/lefthook.yml
+++ b/lefthook.yml
@@ -54,7 +54,7 @@ pre-push:
glob: 'doc/*.md'
run: 'if [ $VALE_WARNINGS ]; then minWarnings=warning; else minWarnings=error; fi; if command -v vale > /dev/null 2>&1; then if ! vale --config .vale.ini --minAlertLevel $minWarnings {files}; then echo "ERROR: Fix any linting errors and make sure you are using the latest version of Vale."; exit 1; fi; else echo "ERROR: Vale not found. For more information, see https://docs.errata.ai/vale/install."; exit 1; fi'
gettext:
- skip: true # This is disabled by default. You can enable this check by adding skip: false in lefhook-local.yml https://github.com/evilmartians/lefthook/blob/master/docs/full_guide.md#skipping-commands
+ skip: true # This is disabled by default. You can enable this check by adding skip: false in lefhook-local.yml https://github.com/evilmartians/lefthook/blob/master/docs/configuration.md#skip
tags: backend frontend view haml
files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD | while read file;do git diff --unified=1 $(git merge-base origin/master HEAD)..HEAD $file | grep -Fqe '_(' && echo $file;done; true
glob: "*.{haml,rb,js,vue}"
diff --git a/lib/api/admin/plan_limits.rb b/lib/api/admin/plan_limits.rb
index 7ce70d85d46..49b41b44a18 100644
--- a/lib/api/admin/plan_limits.rb
+++ b/lib/api/admin/plan_limits.rb
@@ -5,6 +5,8 @@ module API
class PlanLimits < ::API::Base
before { authenticated_as_admin! }
+ PLAN_LIMITS_TAGS = %w[plan_limits].freeze
+
feature_category :not_owned # rubocop:todo Gitlab/AvoidFeatureCategoryNotOwned
helpers do
@@ -17,10 +19,17 @@ module API
end
desc 'Get current plan limits' do
+ detail 'List the current limits of a plan on the GitLab instance.'
success Entities::PlanLimit
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' }
+ ]
+ tags PLAN_LIMITS_TAGS
end
params do
- optional :plan_name, type: String, values: Plan.all_plans, default: Plan::DEFAULT, desc: 'Name of the plan'
+ optional :plan_name, type: String, values: Plan.all_plans, default: Plan::DEFAULT,
+ desc: 'Name of the plan to get the limits from. Default: default.'
end
get "application/plan_limits" do
params = declared_params(include_missing: false)
@@ -29,16 +38,24 @@ module API
present plan.actual_limits, with: Entities::PlanLimit
end
- desc 'Modify plan limits' do
+ desc 'Change plan limits' do
+ detail 'Modify the limits of a plan on the GitLab instance.'
success Entities::PlanLimit
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' }
+ ]
+ tags PLAN_LIMITS_TAGS
end
params do
- requires :plan_name, type: String, values: Plan.all_plans, desc: 'Name of the plan'
+ requires :plan_name, type: String, values: Plan.all_plans, desc: 'Name of the plan to update'
optional :ci_pipeline_size, type: Integer, desc: 'Maximum number of jobs in a single pipeline'
optional :ci_active_jobs, type: Integer, desc: 'Total number of jobs in currently active pipelines'
optional :ci_active_pipelines, type: Integer, desc: 'Maximum number of active pipelines per project'
- optional :ci_project_subscriptions, type: Integer, desc: 'Maximum number of pipeline subscriptions to and from a project'
+ optional :ci_project_subscriptions, type: Integer,
+ desc: 'Maximum number of pipeline subscriptions to and from a project'
optional :ci_pipeline_schedules, type: Integer, desc: 'Maximum number of pipeline schedules'
optional :ci_needs_size_limit, type: Integer, desc: 'Maximum number of DAG dependencies that a job can have'
optional :ci_registered_group_runners, type: Integer, desc: 'Maximum number of runners registered per group'
@@ -50,7 +67,8 @@ module API
optional :npm_max_file_size, type: Integer, desc: 'Maximum NPM package file size in bytes'
optional :nuget_max_file_size, type: Integer, desc: 'Maximum NuGet package file size in bytes'
optional :pypi_max_file_size, type: Integer, desc: 'Maximum PyPI package file size in bytes'
- optional :terraform_module_max_file_size, type: Integer, desc: 'Maximum Terraform Module package file size in bytes'
+ optional :terraform_module_max_file_size, type: Integer,
+ desc: 'Maximum Terraform Module package file size in bytes'
optional :storage_size_limit, type: Integer, desc: 'Maximum storage size for the root namespace in megabytes'
end
put "application/plan_limits" do
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 2b69249f09c..c0d5e84f5b1 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -173,6 +173,7 @@ module API
mount ::API::AccessRequests
mount ::API::Admin::Ci::Variables
mount ::API::Admin::InstanceClusters
+ mount ::API::Admin::PlanLimits
mount ::API::Appearance
mount ::API::Applications
mount ::API::Avatar
@@ -265,7 +266,6 @@ module API
# Keep in alphabetical order
mount ::API::Admin::BatchedBackgroundMigrations
- mount ::API::Admin::PlanLimits
mount ::API::Admin::Sidekiq
mount ::API::AlertManagementAlerts
mount ::API::AwardEmoji
diff --git a/lib/api/entities/plan_limit.rb b/lib/api/entities/plan_limit.rb
index 94e50f19b35..34018f03eb1 100644
--- a/lib/api/entities/plan_limit.rb
+++ b/lib/api/entities/plan_limit.rb
@@ -3,23 +3,23 @@
module API
module Entities
class PlanLimit < Grape::Entity
- expose :ci_pipeline_size
- expose :ci_active_jobs
- expose :ci_active_pipelines
- expose :ci_project_subscriptions
- expose :ci_pipeline_schedules
- expose :ci_needs_size_limit
- expose :ci_registered_group_runners
- expose :ci_registered_project_runners
- expose :conan_max_file_size
- expose :generic_packages_max_file_size
- expose :helm_max_file_size
- expose :maven_max_file_size
- expose :npm_max_file_size
- expose :nuget_max_file_size
- expose :pypi_max_file_size
- expose :terraform_module_max_file_size
- expose :storage_size_limit
+ expose :ci_pipeline_size, documentation: { type: 'integer', example: 0 }
+ expose :ci_active_jobs, documentation: { type: 'integer', example: 0 }
+ expose :ci_active_pipelines, documentation: { type: 'integer', example: 0 }
+ expose :ci_project_subscriptions, documentation: { type: 'integer', example: 2 }
+ expose :ci_pipeline_schedules, documentation: { type: 'integer', example: 10 }
+ expose :ci_needs_size_limit, documentation: { type: 'integer', example: 50 }
+ expose :ci_registered_group_runners, documentation: { type: 'integer', example: 1000 }
+ expose :ci_registered_project_runners, documentation: { type: 'integer', example: 1000 }
+ expose :conan_max_file_size, documentation: { type: 'integer', example: 3221225472 }
+ expose :generic_packages_max_file_size, documentation: { type: 'integer', example: 5368709120 }
+ expose :helm_max_file_size, documentation: { type: 'integer', example: 5242880 }
+ expose :maven_max_file_size, documentation: { type: 'integer', example: 3221225472 }
+ expose :npm_max_file_size, documentation: { type: 'integer', example: 524288000 }
+ expose :nuget_max_file_size, documentation: { type: 'integer', example: 524288000 }
+ expose :pypi_max_file_size, documentation: { type: 'integer', example: 3221225472 }
+ expose :terraform_module_max_file_size, documentation: { type: 'integer', example: 1073741824 }
+ expose :storage_size_limit, documentation: { type: 'integer', example: 15000 }
end
end
end
diff --git a/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer.rb b/lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer.rb
index 055d34b3309..47277182d9a 100644
--- a/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer.rb
+++ b/lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer.rb
@@ -4,47 +4,25 @@ module Gitlab
module Database
module QueryAnalyzers
module Ci
- # The purpose of this analyzer is to detect queries not going through a partitioning routing table
- class PartitioningAnalyzer < Database::QueryAnalyzers::Base
- RoutingTableNotUsedError = Class.new(QueryAnalyzerError)
+ # The purpose of this analyzer is to detect queries missing partition_id clause
+ # when selecting, inserting, updating or deleting data.
+ class PartitioningIdAnalyzer < Database::QueryAnalyzers::Base
PartitionIdMissingError = Class.new(QueryAnalyzerError)
- ENABLED_TABLES = %w[
- ci_builds_metadata
- ].freeze
-
- ROUTING_TABLES = ENABLED_TABLES.map { |table| "p_#{table}" }.freeze
+ ROUTING_TABLES = %w[p_ci_builds_metadata].freeze
class << self
def enabled?
::Feature::FlipperFeature.table_exists? &&
- ::Feature.enabled?(:ci_partitioning_analyze_queries, type: :ops)
+ ::Feature.enabled?(:ci_partitioning_analyze_queries_partition_id_check, type: :ops)
end
def analyze(parsed)
- analyze_legacy_tables_usage(parsed)
- analyze_partition_id_presence(parsed) if partition_id_check_enabled?
+ analyze_partition_id_presence(parsed)
end
private
- def partition_id_check_enabled?
- ::Feature::FlipperFeature.table_exists? &&
- ::Feature.enabled?(:ci_partitioning_analyze_queries_partition_id_check, type: :ops)
- end
-
- def analyze_legacy_tables_usage(parsed)
- detected = ENABLED_TABLES & (parsed.pg.dml_tables + parsed.pg.select_tables)
-
- return if detected.none?
-
- log_and_raise_error(
- RoutingTableNotUsedError.new(
- "Detected non-partitioned table use #{detected.inspect}: #{parsed.sql}"
- )
- )
- end
-
def analyze_partition_id_presence(parsed)
detected = ROUTING_TABLES & (parsed.pg.dml_tables + parsed.pg.select_tables)
return if detected.none?
@@ -56,7 +34,7 @@ module Gitlab
return if partition_id_included?(detected_with_selected_columns)
end
- log_and_raise_error(
+ ::Gitlab::ErrorTracking.track_and_raise_for_dev_exception(
PartitionIdMissingError.new(
"Detected query against a partitioned table without partition id: #{parsed.sql}"
)
@@ -78,10 +56,6 @@ module Gitlab
result.all? { |_routing_table, columns| columns.include?('partition_id') }
end
- def log_and_raise_error(error)
- ::Gitlab::ErrorTracking.track_and_raise_for_dev_exception(error)
- end
-
def insert_query?(parsed)
parsed.sql.start_with?('INSERT')
end
diff --git a/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer.rb b/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer.rb
new file mode 100644
index 00000000000..eb55ebc7619
--- /dev/null
+++ b/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module QueryAnalyzers
+ module Ci
+ # The purpose of this analyzer is to detect queries not going through a partitioning routing table
+ class PartitioningRoutingAnalyzer < Database::QueryAnalyzers::Base
+ RoutingTableNotUsedError = Class.new(QueryAnalyzerError)
+
+ ENABLED_TABLES = %w[ci_builds_metadata].freeze
+
+ class << self
+ def enabled?
+ ::Feature::FlipperFeature.table_exists? &&
+ ::Feature.enabled?(:ci_partitioning_analyze_queries, type: :ops)
+ end
+
+ def analyze(parsed)
+ analyze_legacy_tables_usage(parsed)
+ end
+
+ private
+
+ def analyze_legacy_tables_usage(parsed)
+ detected = ENABLED_TABLES & (parsed.pg.dml_tables + parsed.pg.select_tables)
+
+ return if detected.none?
+
+ ::Gitlab::ErrorTracking.track_and_raise_for_dev_exception(
+ RoutingTableNotUsedError.new("Detected non-partitioned table use #{detected.inspect}: #{parsed.sql}")
+ )
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb
index b167afe589a..bc59d4ce943 100644
--- a/lib/gitlab/shell.rb
+++ b/lib/gitlab/shell.rb
@@ -14,6 +14,11 @@ module Gitlab
class Shell
Error = Class.new(StandardError)
+ PERMITTED_ACTIONS = %w[
+ mv_repository remove_repository add_namespace rm_namespace mv_namespace
+ repository_exists?
+ ].freeze
+
class << self
# Retrieve GitLab Shell secret token
#
diff --git a/lib/gitlab/slash_commands/incident_management/incident_command.rb b/lib/gitlab/slash_commands/incident_management/incident_command.rb
index 13d371151f9..3fa08621777 100644
--- a/lib/gitlab/slash_commands/incident_management/incident_command.rb
+++ b/lib/gitlab/slash_commands/incident_management/incident_command.rb
@@ -15,3 +15,5 @@ module Gitlab
end
end
end
+
+Gitlab::SlashCommands::IncidentManagement::IncidentCommand.prepend_mod
diff --git a/lib/gitlab/slash_commands/incident_management/incident_new.rb b/lib/gitlab/slash_commands/incident_management/incident_new.rb
index ce148f888b8..722fcff151d 100644
--- a/lib/gitlab/slash_commands/incident_management/incident_new.rb
+++ b/lib/gitlab/slash_commands/incident_management/incident_new.rb
@@ -16,12 +16,6 @@ module Gitlab
text == 'incident declare'
end
- def execute(_match)
- response = ServiceResponse.success(message: 'It works!')
-
- presenter.present(response.message)
- end
-
private
def presenter
@@ -31,3 +25,5 @@ module Gitlab
end
end
end
+
+Gitlab::SlashCommands::IncidentManagement::IncidentNew.prepend_mod
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 05a11512583..a2b05faa74f 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -1157,6 +1157,9 @@ msgstr ""
msgid "%{type} only supports %{name} name"
msgstr ""
+msgid "%{url} (optional)"
+msgstr ""
+
msgid "%{userName} (cannot merge)"
msgstr ""
@@ -11643,6 +11646,9 @@ msgstr ""
msgid "Credit card:"
msgstr ""
+msgid "Critical - S1"
+msgstr ""
+
msgid "Critical vulnerabilities present"
msgstr ""
@@ -20083,6 +20089,9 @@ msgstr ""
msgid "Hierarchy|You can start using these items now."
msgstr ""
+msgid "High - S2"
+msgstr ""
+
msgid "High or unknown vulnerabilities present"
msgstr ""
@@ -21328,12 +21337,18 @@ msgstr ""
msgid "Incident Management Limits"
msgstr ""
+msgid "Incident creation cancelled."
+msgstr ""
+
msgid "Incident details"
msgstr ""
msgid "Incident template (optional)."
msgstr ""
+msgid "Incident title"
+msgstr ""
+
msgid "IncidentManagement|%{hours} hours, %{minutes} minutes remaining"
msgstr ""
@@ -24702,6 +24717,9 @@ msgstr ""
msgid "Logs"
msgstr ""
+msgid "Low - S4"
+msgstr ""
+
msgid "Low vulnerabilities present"
msgstr ""
@@ -25308,6 +25326,9 @@ msgstr ""
msgid "Measured in bytes of code. Excludes generated and vendored code."
msgstr ""
+msgid "Medium - S3"
+msgstr ""
+
msgid "Medium timeout"
msgstr ""
@@ -26952,6 +26973,9 @@ msgstr ""
msgid "New identity"
msgstr ""
+msgid "New incident"
+msgstr ""
+
msgid "New issue"
msgstr ""
@@ -30511,6 +30535,9 @@ msgstr ""
msgid "Please click the link in the confirmation email before continuing. It was sent to %{html_tag_strong_start}%{email}%{html_tag_strong_end}."
msgstr ""
+msgid "Please complete the incident creation form."
+msgstr ""
+
msgid "Please complete your profile with email address"
msgstr ""
@@ -37181,6 +37208,9 @@ msgstr ""
msgid "Select reviewer(s)"
msgstr ""
+msgid "Select severity (optional)"
+msgstr ""
+
msgid "Select source"
msgstr ""
@@ -38370,6 +38400,9 @@ msgstr ""
msgid "Something went wrong while closing the epic. Please try again later."
msgstr ""
+msgid "Something went wrong while closing the incident form."
+msgstr ""
+
msgid "Something went wrong while closing the merge request. Please try again later."
msgstr ""
@@ -38439,6 +38472,9 @@ msgstr ""
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
+msgid "Something went wrong while opening the incident form."
+msgstr ""
+
msgid "Something went wrong while promoting the issue to an epic. Please try again."
msgstr ""
@@ -46395,6 +46431,9 @@ msgstr ""
msgid "Write a description or drag your files here…"
msgstr ""
+msgid "Write a description..."
+msgstr ""
+
msgid "Write a description…"
msgstr ""
@@ -46781,6 +46820,9 @@ msgstr ""
msgid "You could not create a new trigger."
msgstr ""
+msgid "You do not have access to any projects for creating incidents."
+msgstr ""
+
msgid "You do not have any subscriptions yet"
msgstr ""
@@ -47512,6 +47554,9 @@ msgstr ""
msgid "ZentaoIntegration|ZenTao issues"
msgstr ""
+msgid "Zoom"
+msgstr ""
+
msgid "Zoom meeting added"
msgstr ""
@@ -47527,6 +47572,9 @@ msgstr ""
msgid "[Redacted]"
msgstr ""
+msgid "[Supports GitLab-flavored markdown, including quick actions]"
+msgstr ""
+
msgid "`end_time` should not exceed one month after `start_time`"
msgstr ""
diff --git a/qa/qa/specs/spec_helper.rb b/qa/qa/specs/spec_helper.rb
index 8fb0ce0ab2f..a4721040683 100644
--- a/qa/qa/specs/spec_helper.rb
+++ b/qa/qa/specs/spec_helper.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require_relative '../../qa'
+require 'active_support/testing/time_helpers'
QA::Specs::QaDeprecationToolkitEnv.configure!
@@ -18,6 +19,7 @@ RSpec.configure(&:disable_monkey_patching!)
require_relative('../../../jh/qa/qa/specs/spec_helper') if GitlabEdition.jh?
RSpec.configure do |config|
+ config.include ActiveSupport::Testing::TimeHelpers
config.include QA::Support::Matchers::EventuallyMatcher
config.include QA::Support::Matchers::HaveMatcher
diff --git a/qa/spec/tools/test_resources_data_processor_spec.rb b/qa/spec/tools/test_resources_data_processor_spec.rb
index 2ae43974a0c..73fc2f6e853 100644
--- a/qa/spec/tools/test_resources_data_processor_spec.rb
+++ b/qa/spec/tools/test_resources_data_processor_spec.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-
require 'active_support/testing/time_helpers'
-
RSpec.describe QA::Tools::TestResourceDataProcessor do
include QA::Support::Helpers::StubEnv
include ActiveSupport::Testing::TimeHelpers
diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb
index c383c4b6f24..ad49a763361 100644
--- a/spec/db/schema_spec.rb
+++ b/spec/db/schema_spec.rb
@@ -14,6 +14,8 @@ RSpec.describe 'Database schema' do
issues: %w[work_item_type_id]
}.with_indifferent_access.freeze
+ TABLE_PARTITIONS = %w[ci_builds_metadata].freeze
+
# List of columns historically missing a FK, don't add more columns
# See: https://docs.gitlab.com/ee/development/database/foreign_keys.html#naming-foreign-keys
IGNORED_FK_COLUMNS = {
@@ -32,7 +34,6 @@ RSpec.describe 'Database schema' do
chat_names: %w[chat_id team_id user_id],
chat_teams: %w[team_id],
ci_builds: %w[erased_by_id trigger_request_id partition_id],
- ci_builds_metadata: %w[partition_id],
p_ci_builds_metadata: %w[partition_id],
ci_job_artifacts: %w[partition_id],
ci_namespace_monthly_usages: %w[namespace_id],
@@ -108,7 +109,7 @@ RSpec.describe 'Database schema' do
}.with_indifferent_access.freeze
context 'for table' do
- ActiveRecord::Base.connection.tables.sort.each do |table|
+ (ActiveRecord::Base.connection.tables - TABLE_PARTITIONS).sort.each do |table|
describe table do
let(:indexes) { connection.indexes(table) }
let(:columns) { connection.columns(table) }
diff --git a/spec/frontend/fixtures/freeze_period.rb b/spec/frontend/fixtures/freeze_period.rb
index dd16bd81b51..5aa466ef015 100644
--- a/spec/frontend/fixtures/freeze_period.rb
+++ b/spec/frontend/fixtures/freeze_period.rb
@@ -16,7 +16,7 @@ RSpec.describe 'Freeze Periods (JavaScript fixtures)' do
around do |example|
freeze_time do
# Mock time to sept 19 (intl. talk like a pirate day)
- Timecop.travel(2020, 9, 19)
+ travel_to(Time.utc(2020, 9, 19))
example.run
end
diff --git a/spec/frontend/lib/utils/dom_utils_spec.js b/spec/frontend/lib/utils/dom_utils_spec.js
index b537e6b2bf8..d6bac935970 100644
--- a/spec/frontend/lib/utils/dom_utils_spec.js
+++ b/spec/frontend/lib/utils/dom_utils_spec.js
@@ -1,8 +1,10 @@
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
+
import {
addClassIfElementExists,
canScrollUp,
canScrollDown,
+ getContentWrapperHeight,
parseBooleanDataAttributes,
isElementVisible,
getParents,
@@ -235,4 +237,30 @@ describe('DOM Utils', () => {
expect(div.getAttribute('title')).toBe('another test');
});
});
+
+ describe('getContentWrapperHeight', () => {
+ const fixture = `
+ <div>
+ <div class="content-wrapper">
+ <div class="content"></div>
+ </div>
+ </div>
+ `;
+
+ beforeEach(() => {
+ setHTMLFixture(fixture);
+ });
+
+ afterEach(() => {
+ resetHTMLFixture();
+ });
+
+ it('returns the height of an element that exists', () => {
+ expect(getContentWrapperHeight('.content-wrapper')).toBe('0px');
+ });
+
+ it('returns an empty string for a class that does not exist', () => {
+ expect(getContentWrapperHeight('.does-not-exist')).toBe('');
+ });
+ });
});
diff --git a/spec/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer_spec.rb b/spec/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer_spec.rb
deleted file mode 100644
index 01990933d0a..00000000000
--- a/spec/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer_spec.rb
+++ /dev/null
@@ -1,163 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Database::QueryAnalyzers::Ci::PartitioningAnalyzer, query_analyzers: false do
- let(:analyzer) { described_class }
-
- before do
- allow(Gitlab::Database::QueryAnalyzer.instance).to receive(:all_analyzers).and_return([analyzer])
- end
-
- context 'when ci_partitioning_analyze_queries is disabled' do
- before do
- stub_feature_flags(ci_partitioning_analyze_queries: false)
- end
-
- it 'does not analyze the query' do
- expect(analyzer).not_to receive(:analyze)
-
- process_sql(Ci::BuildMetadata, "SELECT 1 FROM ci_builds_metadata")
- end
- end
-
- context 'when ci_partitioning_analyze_queries is enabled' do
- context 'when analyzing targeted tables' do
- described_class::ENABLED_TABLES.each do |enabled_table|
- context 'when querying a non routing table' do
- it 'tracks exception' do
- expect(::Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception)
- process_sql(Ci::ApplicationRecord, "SELECT 1 FROM #{enabled_table}")
- end
-
- it 'raises RoutingTableNotUsedError' do
- expect { process_sql(Ci::ApplicationRecord, "SELECT 1 FROM #{enabled_table}") }
- .to raise_error(described_class::RoutingTableNotUsedError)
- end
- end
- end
-
- context 'when updating a record' do
- it 'raises RoutingTableNotUsedError' do
- expect { process_sql(Ci::BuildMetadata, "UPDATE ci_builds_metadata SET id = 1") }
- .to raise_error(described_class::RoutingTableNotUsedError)
- end
- end
-
- context 'when inserting a record' do
- it 'raises RoutingTableNotUsedError' do
- expect { process_sql(Ci::BuildMetadata, "INSERT INTO ci_builds_metadata (id) VALUES(1)") }
- .to raise_error(described_class::RoutingTableNotUsedError)
- end
- end
- end
-
- context 'when analyzing non targeted table' do
- it 'does not raise error' do
- expect { process_sql(Ci::BuildMetadata, "SELECT 1 FROM projects") }.not_to raise_error
- end
- end
-
- context 'when querying a routing table' do
- shared_examples 'a good query' do |sql|
- it 'does not raise error' do
- expect { process_sql(Ci::BuildMetadata, sql) }.not_to raise_error
- end
- end
-
- shared_examples 'a bad query' do |sql|
- it 'raises PartitionIdMissingError' do
- expect { process_sql(Ci::BuildMetadata, sql) }.to raise_error(described_class::PartitionIdMissingError)
- end
- end
-
- context 'when selecting data' do
- it_behaves_like 'a good query', 'SELECT * FROM p_ci_builds_metadata WHERE partition_id = 100'
- end
-
- context 'with a join query' do
- sql = <<~SQL
- SELECT ci_builds.id
- FROM p_ci_builds
- JOIN p_ci_builds_metadata ON p_ci_builds_metadata.build_id = ci_builds.id
- WHERE ci_builds.type = 'Ci::Build'
- AND ci_builds.partition_id = 100
- AND (NOT p_ci_builds_metadata.id IN
- (SELECT p_ci_builds_metadata.id
- FROM p_ci_builds_metadata
- WHERE p_ci_builds_metadata.build_id = ci_builds.id
- AND p_ci_builds_metadata.interruptible = TRUE
- AND p_ci_builds_metadata.partition_id = 100 ));
- SQL
-
- it_behaves_like 'a good query', sql
- end
-
- context 'when removing data' do
- it_behaves_like 'a good query', 'DELETE FROM p_ci_builds_metadata WHERE partition_id = 100'
- end
-
- context 'when updating data' do
- it_behaves_like 'a good query', 'UPDATE p_ci_builds_metadata SET interruptible = false WHERE partition_id = 100'
- end
-
- context 'when inserting a record' do
- it_behaves_like 'a good query', 'INSERT INTO p_ci_builds_metadata (id, partition_id) VALUES(1, 1)'
- end
-
- context 'when partition_id is missing' do
- context 'when inserting a record' do
- it_behaves_like 'a bad query', 'INSERT INTO p_ci_builds_metadata (id) VALUES(1)'
- end
-
- context 'when selecting data' do
- it_behaves_like 'a bad query', 'SELECT * FROM p_ci_builds_metadata WHERE id = 1'
- end
-
- context 'when removing data' do
- it_behaves_like 'a bad query', 'DELETE FROM p_ci_builds_metadata WHERE id = 1'
- end
-
- context 'when updating data' do
- it_behaves_like 'a bad query', 'UPDATE p_ci_builds_metadata SET interruptible = false WHERE id = 1'
- end
-
- context 'with a join query' do
- sql = <<~SQL
- SELECT ci_builds.id
- FROM ci_builds
- JOIN p_ci_builds_metadata ON p_ci_builds_metadata.build_id = ci_builds.id
- WHERE ci_builds.type = 'Ci::Build'
- AND ci_builds.partition_id = 100
- AND (NOT p_ci_builds_metadata.id IN
- (SELECT p_ci_builds_metadata.id
- FROM p_ci_builds_metadata
- WHERE p_ci_builds_metadata.build_id = ci_builds.id
- AND p_ci_builds_metadata.interruptible = TRUE ));
- SQL
-
- it_behaves_like 'a bad query', sql
- end
- end
-
- context 'when ci_partitioning_analyze_queries_partition_id_check is disabled' do
- before do
- stub_feature_flags(ci_partitioning_analyze_queries_partition_id_check: false)
- end
-
- it 'does not check if partition_id is included in the query' do
- expect { process_sql(Ci::BuildMetadata, 'SELECT * from p_ci_builds_metadata') }.not_to raise_error
- end
- end
- end
- end
-
- private
-
- def process_sql(model, sql)
- Gitlab::Database::QueryAnalyzer.instance.within do
- # Skip load balancer and retrieve connection assigned to model
- Gitlab::Database::QueryAnalyzer.instance.send(:process_sql, sql, model.retrieve_connection)
- end
- end
-end
diff --git a/spec/lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer_spec.rb b/spec/lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer_spec.rb
new file mode 100644
index 00000000000..0fe19041b6d
--- /dev/null
+++ b/spec/lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer_spec.rb
@@ -0,0 +1,121 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::QueryAnalyzers::Ci::PartitioningIdAnalyzer, query_analyzers: false do
+ let(:analyzer) { described_class }
+
+ before do
+ allow(Gitlab::Database::QueryAnalyzer.instance).to receive(:all_analyzers).and_return([analyzer])
+ end
+
+ context 'when ci_partitioning_analyze_queries_partition_id_check is disabled' do
+ before do
+ stub_feature_flags(ci_partitioning_analyze_queries_partition_id_check: false)
+ end
+
+ it 'does not analyze the query' do
+ expect(analyzer).not_to receive(:analyze)
+
+ process_sql(Ci::BuildMetadata, "SELECT 1 FROM ci_builds_metadata")
+ end
+ end
+
+ context 'when ci_partitioning_analyze_queries_partition_id_check is enabled' do
+ context 'when querying a routing table' do
+ shared_examples 'a good query' do |sql|
+ it 'does not raise error' do
+ expect { process_sql(Ci::BuildMetadata, sql) }.not_to raise_error
+ end
+ end
+
+ shared_examples 'a bad query' do |sql|
+ it 'raises PartitionIdMissingError' do
+ expect { process_sql(Ci::BuildMetadata, sql) }.to raise_error(described_class::PartitionIdMissingError)
+ end
+ end
+
+ context 'when partition_id is present' do
+ context 'when selecting data' do
+ it_behaves_like 'a good query', 'SELECT * FROM p_ci_builds_metadata WHERE partition_id = 100'
+ end
+
+ context 'with a join query' do
+ sql = <<~SQL
+ SELECT ci_builds.id
+ FROM p_ci_builds
+ JOIN p_ci_builds_metadata ON p_ci_builds_metadata.build_id = ci_builds.id
+ WHERE ci_builds.type = 'Ci::Build'
+ AND ci_builds.partition_id = 100
+ AND (NOT p_ci_builds_metadata.id IN
+ (SELECT p_ci_builds_metadata.id
+ FROM p_ci_builds_metadata
+ WHERE p_ci_builds_metadata.build_id = ci_builds.id
+ AND p_ci_builds_metadata.interruptible = TRUE
+ AND p_ci_builds_metadata.partition_id = 100 ));
+ SQL
+
+ it_behaves_like 'a good query', sql
+ end
+
+ context 'when removing data' do
+ it_behaves_like 'a good query', 'DELETE FROM p_ci_builds_metadata WHERE partition_id = 100'
+ end
+
+ context 'when updating data' do
+ sql = 'UPDATE p_ci_builds_metadata SET interruptible = false WHERE partition_id = 100'
+
+ it_behaves_like 'a good query', sql
+ end
+
+ context 'when inserting a record' do
+ it_behaves_like 'a good query', 'INSERT INTO p_ci_builds_metadata (id, partition_id) VALUES(1, 1)'
+ end
+ end
+
+ context 'when partition_id is missing' do
+ context 'when inserting a record' do
+ it_behaves_like 'a bad query', 'INSERT INTO p_ci_builds_metadata (id) VALUES(1)'
+ end
+
+ context 'when selecting data' do
+ it_behaves_like 'a bad query', 'SELECT * FROM p_ci_builds_metadata WHERE id = 1'
+ end
+
+ context 'when removing data' do
+ it_behaves_like 'a bad query', 'DELETE FROM p_ci_builds_metadata WHERE id = 1'
+ end
+
+ context 'when updating data' do
+ it_behaves_like 'a bad query', 'UPDATE p_ci_builds_metadata SET interruptible = false WHERE id = 1'
+ end
+
+ context 'with a join query' do
+ sql = <<~SQL
+ SELECT ci_builds.id
+ FROM ci_builds
+ JOIN p_ci_builds_metadata ON p_ci_builds_metadata.build_id = ci_builds.id
+ WHERE ci_builds.type = 'Ci::Build'
+ AND ci_builds.partition_id = 100
+ AND (NOT p_ci_builds_metadata.id IN
+ (SELECT p_ci_builds_metadata.id
+ FROM p_ci_builds_metadata
+ WHERE p_ci_builds_metadata.build_id = ci_builds.id
+ AND p_ci_builds_metadata.interruptible = TRUE ));
+ SQL
+
+ it_behaves_like 'a bad query', sql
+ end
+ end
+ end
+ end
+
+ private
+
+ def process_sql(model, sql)
+ Gitlab::Database::QueryAnalyzer.instance.within do
+ # Skip load balancer and retrieve connection assigned to model
+ Gitlab::Database::QueryAnalyzer.instance.send(:process_sql, sql, model.retrieve_connection)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer_spec.rb b/spec/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer_spec.rb
new file mode 100644
index 00000000000..1f86c2ccbb0
--- /dev/null
+++ b/spec/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer_spec.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::QueryAnalyzers::Ci::PartitioningRoutingAnalyzer, query_analyzers: false do
+ let(:analyzer) { described_class }
+
+ before do
+ allow(Gitlab::Database::QueryAnalyzer.instance).to receive(:all_analyzers).and_return([analyzer])
+ end
+
+ context 'when ci_partitioning_analyze_queries is disabled' do
+ before do
+ stub_feature_flags(ci_partitioning_analyze_queries: false)
+ end
+
+ it 'does not analyze the query' do
+ expect(analyzer).not_to receive(:analyze)
+
+ process_sql(Ci::BuildMetadata, "SELECT 1 FROM ci_builds_metadata")
+ end
+ end
+
+ context 'when ci_partitioning_analyze_queries is enabled' do
+ context 'when analyzing targeted tables' do
+ described_class::ENABLED_TABLES.each do |enabled_table|
+ context 'when querying a non routing table' do
+ it 'tracks exception' do
+ expect(::Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception)
+ process_sql(Ci::ApplicationRecord, "SELECT 1 FROM #{enabled_table}")
+ end
+
+ it 'raises RoutingTableNotUsedError' do
+ expect { process_sql(Ci::ApplicationRecord, "SELECT 1 FROM #{enabled_table}") }
+ .to raise_error(described_class::RoutingTableNotUsedError)
+ end
+ end
+ end
+
+ context 'when updating a record' do
+ it 'raises RoutingTableNotUsedError' do
+ expect { process_sql(Ci::BuildMetadata, "UPDATE ci_builds_metadata SET id = 1") }
+ .to raise_error(described_class::RoutingTableNotUsedError)
+ end
+ end
+
+ context 'when inserting a record' do
+ it 'raises RoutingTableNotUsedError' do
+ expect { process_sql(Ci::BuildMetadata, "INSERT INTO ci_builds_metadata (id) VALUES(1)") }
+ .to raise_error(described_class::RoutingTableNotUsedError)
+ end
+ end
+ end
+
+ context 'when analyzing non targeted table' do
+ it 'does not raise error' do
+ expect { process_sql(Ci::BuildMetadata, "SELECT 1 FROM projects") }.not_to raise_error
+ end
+ end
+ end
+
+ private
+
+ def process_sql(model, sql)
+ Gitlab::Database::QueryAnalyzer.instance.within do
+ # Skip load balancer and retrieve connection assigned to model
+ Gitlab::Database::QueryAnalyzer.instance.send(:process_sql, sql, model.retrieve_connection)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/slash_commands/incident_management/incident_new_spec.rb b/spec/lib/gitlab/slash_commands/incident_management/incident_new_spec.rb
deleted file mode 100644
index ee54f29aec7..00000000000
--- a/spec/lib/gitlab/slash_commands/incident_management/incident_new_spec.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::SlashCommands::IncidentManagement::IncidentNew do
- let_it_be(:project) { create(:project) }
- let_it_be(:user) { create(:user) }
- let_it_be(:chat_name) { create(:chat_name, user: user) }
- let_it_be(:regex_match) { described_class.match('declare') }
-
- subject do
- described_class.new(project, chat_name)
- end
-
- describe '#execute' do
- context 'when invoked' do
- it 'sends ephemeral response' do
- response = subject.execute(regex_match)
-
- expect(response[:response_type]).to be(:ephemeral)
- expect(response[:text]).to eq('It works!')
- end
- end
- end
-
- describe '#allowed?' do
- context 'when user has permissions' do
- before do
- project.add_developer(user)
- end
-
- it 'returns true' do
- expect(described_class).to be_allowed(project, user)
- end
- end
-
- context 'when feature flag is disabled' do
- before do
- project.add_developer(user)
- stub_feature_flags(incident_declare_slash_command: false)
- end
-
- it 'returns false in allowed?' do
- expect(described_class).not_to be_allowed(project, user)
- end
- end
- end
-
- describe '#collection' do
- context 'when collection method id called' do
- it 'calls IssuesFinder' do
- expect_next_instance_of(IssuesFinder) do |finder|
- expect(finder).to receive(:execute)
- end
-
- subject.collection
- end
- end
- end
-end
diff --git a/spec/workers/concerns/reenqueuer_spec.rb b/spec/workers/concerns/reenqueuer_spec.rb
index 56db2239bb1..e7287b55af2 100644
--- a/spec/workers/concerns/reenqueuer_spec.rb
+++ b/spec/workers/concerns/reenqueuer_spec.rb
@@ -121,14 +121,7 @@ RSpec.describe Reenqueuer::ReenqueuerSleeper do
# Unit test ensure_minimum_duration
describe '#ensure_minimum_duration' do
around do |example|
- # Allow Timecop.travel without the block form
- Timecop.safe_mode = false
-
- Timecop.freeze do
- example.run
- end
-
- Timecop.safe_mode = true
+ freeze_time { example.run }
end
let(:minimum_duration) { 4.seconds }
@@ -140,31 +133,31 @@ RSpec.describe Reenqueuer::ReenqueuerSleeper do
expect(dummy).to receive(:sleep).with(a_value_within(0.01).of(time_left))
dummy.ensure_minimum_duration(minimum_duration) do
- Timecop.travel(minimum_duration - time_left)
+ travel(minimum_duration - time_left)
end
end
end
context 'when the block completes just before the minimum duration' do
- let(:time_left) { 0.1.seconds }
+ let(:time_left) { 1.second }
it 'sleeps until the minimum duration' do
expect(dummy).to receive(:sleep).with(a_value_within(0.01).of(time_left))
dummy.ensure_minimum_duration(minimum_duration) do
- Timecop.travel(minimum_duration - time_left)
+ travel(minimum_duration - time_left)
end
end
end
context 'when the block completes just after the minimum duration' do
- let(:time_over) { 0.1.seconds }
+ let(:time_over) { 1.second }
it 'does not sleep' do
expect(dummy).not_to receive(:sleep)
dummy.ensure_minimum_duration(minimum_duration) do
- Timecop.travel(minimum_duration + time_over)
+ travel(minimum_duration + time_over)
end
end
end
@@ -176,7 +169,7 @@ RSpec.describe Reenqueuer::ReenqueuerSleeper do
expect(dummy).not_to receive(:sleep)
dummy.ensure_minimum_duration(minimum_duration) do
- Timecop.travel(minimum_duration + time_over)
+ travel(minimum_duration + time_over)
end
end
end
diff --git a/spec/workers/gitlab_shell_worker_spec.rb b/spec/workers/gitlab_shell_worker_spec.rb
index c46ef87333a..a5419291d35 100644
--- a/spec/workers/gitlab_shell_worker_spec.rb
+++ b/spec/workers/gitlab_shell_worker_spec.rb
@@ -2,37 +2,45 @@
require 'spec_helper'
-RSpec.describe GitlabShellWorker do
- let(:worker) { described_class.new }
-
+RSpec.describe GitlabShellWorker, :sidekiq_inline do
describe '#perform' do
- describe '#add_key' do
- it 'delegates to Gitlab::AuthorizedKeys' do
- expect_next_instance_of(Gitlab::AuthorizedKeys) do |instance|
- expect(instance).to receive(:add_key).with('foo', 'bar')
+ Gitlab::Shell::PERMITTED_ACTIONS.each do |action|
+ describe "with the #{action} action" do
+ it 'forwards the message to Gitlab::Shell' do
+ expect_next_instance_of(Gitlab::Shell) do |instance|
+ expect(instance).to respond_to(action)
+ expect(instance).to receive(action).with('foo', 'bar')
+ end
+
+ described_class.perform_async(action, 'foo', 'bar')
end
-
- worker.perform('add_key', 'foo', 'bar')
end
end
- describe '#remove_key' do
- it 'delegates to Gitlab::AuthorizedKeys' do
- expect_next_instance_of(Gitlab::AuthorizedKeys) do |instance|
- expect(instance).to receive(:remove_key).with('foo', 'bar')
+ describe 'all other commands' do
+ context 'when verify_gitlab_shell_worker_method_names is enabled' do
+ it 'raises ArgumentError' do
+ allow_next_instance_of(described_class) do |job_instance|
+ expect(job_instance).not_to receive(:gitlab_shell)
+ end
+
+ expect { described_class.perform_async('foo', 'bar', 'baz') }
+ .to raise_error(ArgumentError, 'foo not allowed for GitlabShellWorker')
end
-
- worker.perform('remove_key', 'foo', 'bar')
end
- end
- describe 'all other commands' do
- it 'delegates them to Gitlab::Shell' do
- expect_next_instance_of(Gitlab::Shell) do |instance|
- expect(instance).to receive(:foo).with('bar', 'baz')
+ context 'when verify_gitlab_shell_worker_method_names is disabled' do
+ before do
+ stub_feature_flags(verify_gitlab_shell_worker_method_names: false)
end
- worker.perform('foo', 'bar', 'baz')
+ it 'forwards the message to Gitlab::Shell' do
+ expect_next_instance_of(Gitlab::Shell) do |instance|
+ expect(instance).to receive('foo').with('bar', 'baz')
+ end
+
+ described_class.perform_async('foo', 'bar', 'baz')
+ end
end
end
end