summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-08-04 21:09:04 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-08-04 21:09:04 +0000
commit155fb78b9a3017640b527bc41c9096642ca11aca (patch)
tree56a8fa90237548d86968da021ccc772245fa7667
parentf5a72705e46f835812ffcc51658eecb08fbdf050 (diff)
downloadgitlab-ce-155fb78b9a3017640b527bc41c9096642ca11aca.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/feature_flags/components/strategies/flexible_rollout.vue8
-rw-r--r--app/models/namespaces/traversal/linear.rb19
-rw-r--r--app/models/namespaces/traversal/linear_scopes.rb59
-rw-r--r--app/models/namespaces/traversal/recursive.rb1
-rw-r--r--app/models/namespaces/traversal/recursive_scopes.rb25
-rw-r--r--app/models/operations/feature_flags/strategy.rb2
-rw-r--r--app/models/project_feature.rb2
-rw-r--r--db/migrate/20210722150102_operations_feature_flags_correct_flexible_rollout_values.rb29
-rw-r--r--db/schema_migrations/202107221501021
-rw-r--r--package.json4
-rw-r--r--qa/qa/resource/issue.rb7
-rw-r--r--qa/qa/resource/merge_request.rb7
-rw-r--r--qa/qa/resource/project.rb29
-rw-r--r--qa/qa/runtime/api/request.rb6
-rw-r--r--qa/qa/specs/features/api/1_manage/import_large_github_repo_spec.rb20
-rw-r--r--qa/qa/support/api.rb24
-rw-r--r--qa/qa/support/repeater.rb26
-rw-r--r--qa/qa/support/retrier.rb20
-rw-r--r--qa/spec/support/retrier_spec.rb10
-rw-r--r--spec/controllers/projects/feature_flags_controller_spec.rb8
-rw-r--r--spec/factories/projects.rb16
-rw-r--r--spec/frontend/feature_flags/components/strategies/flexible_rollout_spec.js5
-rw-r--r--spec/frontend/feature_flags/mock_data.js2
-rw-r--r--spec/migrations/20210722150102_operations_feature_flags_correct_flexible_rollout_values_spec.rb66
-rw-r--r--spec/models/namespace_spec.rb16
-rw-r--r--spec/models/operations/feature_flags/strategy_spec.rb22
-rw-r--r--spec/models/project_feature_spec.rb24
-rw-r--r--spec/models/project_spec.rb3
-rw-r--r--spec/requests/api/feature_flags_spec.rb12
-rw-r--r--spec/support/shared_examples/namespaces/linear_traversal_examples.rb23
-rw-r--r--spec/support/shared_examples/namespaces/traversal_scope_examples.rb51
-rw-r--r--yarn.lock24
32 files changed, 304 insertions, 267 deletions
diff --git a/app/assets/javascripts/feature_flags/components/strategies/flexible_rollout.vue b/app/assets/javascripts/feature_flags/components/strategies/flexible_rollout.vue
index 4daf8b4e6bf..858c30649bb 100644
--- a/app/assets/javascripts/feature_flags/components/strategies/flexible_rollout.vue
+++ b/app/assets/javascripts/feature_flags/components/strategies/flexible_rollout.vue
@@ -25,19 +25,19 @@ export default {
},
stickinessOptions: [
{
- value: 'DEFAULT',
+ value: 'default',
text: __('Available ID'),
},
{
- value: 'USERID',
+ value: 'userId',
text: __('User ID'),
},
{
- value: 'SESSIONID',
+ value: 'sessionId',
text: __('Session ID'),
},
{
- value: 'RANDOM',
+ value: 'random',
text: __('Random'),
},
],
diff --git a/app/models/namespaces/traversal/linear.rb b/app/models/namespaces/traversal/linear.rb
index 79df466fd64..3d78f384634 100644
--- a/app/models/namespaces/traversal/linear.rb
+++ b/app/models/namespaces/traversal/linear.rb
@@ -37,7 +37,6 @@ module Namespaces
module Traversal
module Linear
extend ActiveSupport::Concern
- include LinearScopes
UnboundedSearch = Class.new(StandardError)
@@ -45,6 +44,14 @@ module Namespaces
before_update :lock_both_roots, if: -> { sync_traversal_ids? && parent_id_changed? }
after_create :sync_traversal_ids, if: -> { sync_traversal_ids? }
after_update :sync_traversal_ids, if: -> { sync_traversal_ids? && saved_change_to_parent_id? }
+
+ scope :traversal_ids_contains, ->(ids) { where("traversal_ids @> (?)", ids) }
+ # When filtering namespaces by the traversal_ids column to compile a
+ # list of namespace IDs, it's much faster to reference the ID in
+ # traversal_ids than the primary key ID column.
+ # WARNING This scope must be used behind a linear query feature flag
+ # such as `use_traversal_ids`.
+ scope :as_ids, -> { select('traversal_ids[array_length(traversal_ids, 1)] AS id') }
end
def sync_traversal_ids?
@@ -157,14 +164,20 @@ module Namespaces
Namespace.lock.select(:id).where(id: roots).order(id: :asc).load
end
+ # Make sure we drop the STI `type = 'Group'` condition for better performance.
+ # Logically equivalent so long as hierarchies remain homogeneous.
+ def without_sti_condition
+ self.class.unscope(where: :type)
+ end
+
# Search this namespace's lineage. Bound inclusively by top node.
def lineage(top: nil, bottom: nil, hierarchy_order: nil)
raise UnboundedSearch, 'Must bound search by either top or bottom' unless top || bottom
- skope = self.class.without_sti_condition
+ skope = without_sti_condition
if top
- skope = skope.where("traversal_ids @> ('{?}')", top.id)
+ skope = skope.traversal_ids_contains("{#{top.id}}")
end
if bottom
diff --git a/app/models/namespaces/traversal/linear_scopes.rb b/app/models/namespaces/traversal/linear_scopes.rb
deleted file mode 100644
index f352497e6de..00000000000
--- a/app/models/namespaces/traversal/linear_scopes.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-# frozen_string_literal: true
-
-module Namespaces
- module Traversal
- module LinearScopes
- extend ActiveSupport::Concern
-
- class_methods do
- # When filtering namespaces by the traversal_ids column to compile a
- # list of namespace IDs, it can be faster to reference the ID in
- # traversal_ids than the primary key ID column.
- def as_ids
- return super unless use_traversal_ids?
-
- select('namespaces.traversal_ids[array_length(namespaces.traversal_ids, 1)] AS id')
- end
-
- def self_and_descendants
- return super unless use_traversal_ids?
-
- without_dups = self_and_descendants_with_duplicates
- .select('DISTINCT on(namespaces.id) namespaces.*')
-
- # Wrap the `SELECT DISTINCT on(....)` with a normal query so we
- # retain expected Rails behavior. Otherwise count and other
- # aggregates won't work.
- unscoped.without_sti_condition.from(without_dups, :namespaces)
- end
-
- def self_and_descendant_ids
- return super unless use_traversal_ids?
-
- self_and_descendants_with_duplicates.select('DISTINCT namespaces.id')
- end
-
- # Make sure we drop the STI `type = 'Group'` condition for better performance.
- # Logically equivalent so long as hierarchies remain homogeneous.
- def without_sti_condition
- unscope(where: :type)
- end
-
- private
-
- def use_traversal_ids?
- Feature.enabled?(:use_traversal_ids, default_enabled: :yaml)
- end
-
- def self_and_descendants_with_duplicates
- base_ids = select(:id)
-
- unscoped
- .without_sti_condition
- .from("namespaces, (#{base_ids.to_sql}) base")
- .where('namespaces.traversal_ids @> ARRAY[base.id]')
- end
- end
- end
- end
-end
diff --git a/app/models/namespaces/traversal/recursive.rb b/app/models/namespaces/traversal/recursive.rb
index c1ada715d6d..d9e8743aa50 100644
--- a/app/models/namespaces/traversal/recursive.rb
+++ b/app/models/namespaces/traversal/recursive.rb
@@ -4,7 +4,6 @@ module Namespaces
module Traversal
module Recursive
extend ActiveSupport::Concern
- include RecursiveScopes
def root_ancestor
return self if parent.nil?
diff --git a/app/models/namespaces/traversal/recursive_scopes.rb b/app/models/namespaces/traversal/recursive_scopes.rb
deleted file mode 100644
index 0dcb23b6567..00000000000
--- a/app/models/namespaces/traversal/recursive_scopes.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-
-module Namespaces
- module Traversal
- module RecursiveScopes
- extend ActiveSupport::Concern
-
- class_methods do
- def as_ids
- select('id')
- end
-
- def self_and_descendants
- Gitlab::ObjectHierarchy.new(all).base_and_descendants
- end
- alias_method :recursive_self_and_descendants, :self_and_descendants
-
- def self_and_descendant_ids
- self_and_descendants.as_ids
- end
- alias_method :recursive_self_and_descendant_ids, :self_and_descendant_ids
- end
- end
- end
-end
diff --git a/app/models/operations/feature_flags/strategy.rb b/app/models/operations/feature_flags/strategy.rb
index c70e10c72d5..ed9400dde8f 100644
--- a/app/models/operations/feature_flags/strategy.rb
+++ b/app/models/operations/feature_flags/strategy.rb
@@ -16,7 +16,7 @@ module Operations
STRATEGY_USERWITHID => ['userIds'].freeze
}.freeze
USERID_MAX_LENGTH = 256
- STICKINESS_SETTINGS = %w[DEFAULT USERID SESSIONID RANDOM].freeze
+ STICKINESS_SETTINGS = %w[default userId sessionId random].freeze
self.table_name = 'operations_strategies'
diff --git a/app/models/project_feature.rb b/app/models/project_feature.rb
index 94db683267d..11dd10007e9 100644
--- a/app/models/project_feature.rb
+++ b/app/models/project_feature.rb
@@ -79,7 +79,7 @@ class ProjectFeature < ApplicationRecord
end
end
- default_value_for(:container_registry_access_level, allows_nil: false) do |feature|
+ default_value_for(:container_registry_access_level) do |feature|
if gitlab_config_features.container_registry
ENABLED
else
diff --git a/db/migrate/20210722150102_operations_feature_flags_correct_flexible_rollout_values.rb b/db/migrate/20210722150102_operations_feature_flags_correct_flexible_rollout_values.rb
new file mode 100644
index 00000000000..974559239d7
--- /dev/null
+++ b/db/migrate/20210722150102_operations_feature_flags_correct_flexible_rollout_values.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+class OperationsFeatureFlagsCorrectFlexibleRolloutValues < ActiveRecord::Migration[6.1]
+ STICKINESS = { "USERID" => "userId", "RANDOM" => "random", "SESSIONID" => "sessionId", "DEFAULT" => "default" }.freeze
+
+ def up
+ STICKINESS.each do |before, after|
+ update_statement = <<-SQL
+ UPDATE operations_strategies
+ SET parameters = parameters || jsonb_build_object('stickiness', '#{quote_string(after)}')
+ WHERE name = 'flexibleRollout' AND parameters->>'stickiness' = '#{quote_string(before)}'
+ SQL
+
+ execute(update_statement)
+ end
+ end
+
+ def down
+ STICKINESS.each do |before, after|
+ update_statement = <<-SQL
+ UPDATE operations_strategies
+ SET parameters = parameters || jsonb_build_object('stickiness', '#{quote_string(before)}')
+ WHERE name = 'flexibleRollout' AND parameters->>'stickiness' = '#{quote_string(after)}'
+ SQL
+
+ execute(update_statement)
+ end
+ end
+end
diff --git a/db/schema_migrations/20210722150102 b/db/schema_migrations/20210722150102
new file mode 100644
index 00000000000..42f6cfb3b7e
--- /dev/null
+++ b/db/schema_migrations/20210722150102
@@ -0,0 +1 @@
+cea8e51f6917be9ad43280fba9f8e7d9b9db1f508e249d9f5df792e43c0b8313 \ No newline at end of file
diff --git a/package.json b/package.json
index 0f00ac90862..e9119753584 100644
--- a/package.json
+++ b/package.json
@@ -212,7 +212,7 @@
"babel-plugin-istanbul": "^6.0.0",
"chalk": "^2.4.1",
"cheerio": "^1.0.0-rc.9",
- "commander": "^2.18.0",
+ "commander": "^2.20.3",
"custom-jquery-matchers": "^2.1.0",
"docdash": "^1.0.2",
"eslint": "7.31.0",
@@ -264,7 +264,7 @@
"webpack-dev-server": "^3.11.2",
"xhr-mock": "^2.5.1",
"yarn-check-webpack-plugin": "^1.2.0",
- "yarn-deduplicate": "^1.1.1"
+ "yarn-deduplicate": "^3.1.0"
},
"blockedDependencies": {
"bootstrap-vue": "https://docs.gitlab.com/ee/development/fe_guide/dependencies.html#bootstrapvue"
diff --git a/qa/qa/resource/issue.rb b/qa/qa/resource/issue.rb
index 2144e619c70..c45ab7593b6 100644
--- a/qa/qa/resource/issue.rb
+++ b/qa/qa/resource/issue.rb
@@ -84,10 +84,13 @@ module QA
# Get issue comments
#
# @return [Array]
- def comments(auto_paginate: false)
+ def comments(auto_paginate: false, attempts: 0)
return parse_body(api_get_from(api_comments_path)) unless auto_paginate
- auto_paginated_response(Runtime::API::Request.new(api_client, api_comments_path, per_page: '100').url)
+ auto_paginated_response(
+ Runtime::API::Request.new(api_client, api_comments_path, per_page: '100').url,
+ attempts: attempts
+ )
end
end
end
diff --git a/qa/qa/resource/merge_request.rb b/qa/qa/resource/merge_request.rb
index 419893f0b11..e09a4b5860d 100644
--- a/qa/qa/resource/merge_request.rb
+++ b/qa/qa/resource/merge_request.rb
@@ -160,10 +160,13 @@ module QA
# Get MR comments
#
# @return [Array]
- def comments(auto_paginate: false)
+ def comments(auto_paginate: false, attempts: 0)
return parse_body(api_get_from(api_comments_path)) unless auto_paginate
- auto_paginated_response(Runtime::API::Request.new(api_client, api_comments_path, per_page: '100').url)
+ auto_paginated_response(
+ Runtime::API::Request.new(api_client, api_comments_path, per_page: '100').url,
+ attempts: attempts
+ )
end
private
diff --git a/qa/qa/resource/project.rb b/qa/qa/resource/project.rb
index c9aa2a80187..16af37f0a29 100644
--- a/qa/qa/resource/project.rb
+++ b/qa/qa/resource/project.rb
@@ -264,21 +264,24 @@ module QA
result = parse_body(response)
- Runtime::Logger.error("Import failed: #{result[:import_error]}") if result[:import_status] == "failed"
+ if result[:import_status] == "failed"
+ Runtime::Logger.error("Import failed: #{result[:import_error]}")
+ Runtime::Logger.error("Failed relations: #{result[:failed_relations]}")
+ end
result[:import_status]
end
- def commits(auto_paginate: false)
+ def commits(auto_paginate: false, attempts: 0)
return parse_body(api_get_from(api_commits_path)) unless auto_paginate
- auto_paginated_response(request_url(api_commits_path, per_page: '100'))
+ auto_paginated_response(request_url(api_commits_path, per_page: '100'), attempts: attempts)
end
- def merge_requests(auto_paginate: false)
+ def merge_requests(auto_paginate: false, attempts: 0)
return parse_body(api_get_from(api_merge_requests_path)) unless auto_paginate
- auto_paginated_response(request_url(api_merge_requests_path, per_page: '100'))
+ auto_paginated_response(request_url(api_merge_requests_path, per_page: '100'), attempts: attempts)
end
def merge_request_with_title(title)
@@ -302,10 +305,10 @@ module QA
parse_body(response)
end
- def repository_branches(auto_paginate: false)
+ def repository_branches(auto_paginate: false, attempts: 0)
return parse_body(api_get_from(api_repository_branches_path)) unless auto_paginate
- auto_paginated_response(request_url(api_repository_branches_path, per_page: '100'))
+ auto_paginated_response(request_url(api_repository_branches_path, per_page: '100'), attempts: attempts)
end
def repository_tags
@@ -328,22 +331,22 @@ module QA
parse_body(response)
end
- def issues(auto_paginate: false)
+ def issues(auto_paginate: false, attempts: 0)
return parse_body(api_get_from(api_issues_path)) unless auto_paginate
- auto_paginated_response(request_url(api_issues_path, per_page: '100'))
+ auto_paginated_response(request_url(api_issues_path, per_page: '100'), attempts: attempts)
end
- def labels(auto_paginate: false)
+ def labels(auto_paginate: false, attempts: 0)
return parse_body(api_get_from(api_labels_path)) unless auto_paginate
- auto_paginated_response(request_url(api_labels_path, per_page: '100'))
+ auto_paginated_response(request_url(api_labels_path, per_page: '100'), attempts: attempts)
end
- def milestones(auto_paginate: false)
+ def milestones(auto_paginate: false, attempts: 0)
return parse_body(api_get_from(api_milestones_path)) unless auto_paginate
- auto_paginated_response(request_url(api_milestones_path, per_page: '100'))
+ auto_paginated_response(request_url(api_milestones_path, per_page: '100'), attempts: attempts)
end
def wikis
diff --git a/qa/qa/runtime/api/request.rb b/qa/qa/runtime/api/request.rb
index 28bae541cb8..c1df5e84f6c 100644
--- a/qa/qa/runtime/api/request.rb
+++ b/qa/qa/runtime/api/request.rb
@@ -6,6 +6,10 @@ module QA
class Request
API_VERSION = 'v4'
+ def self.masked_url(url)
+ url.sub(/private_token=.*/, "private_token=[****]")
+ end
+
def initialize(api_client, path, **query_string)
query_string[:private_token] ||= api_client.personal_access_token unless query_string[:oauth_access_token]
request_path = request_path(path, **query_string)
@@ -13,7 +17,7 @@ module QA
end
def mask_url
- @session_address.address.sub(/private_token=.*/, "private_token=[****]")
+ QA::Runtime::API::Request.masked_url(url)
end
def url
diff --git a/qa/qa/specs/features/api/1_manage/import_large_github_repo_spec.rb b/qa/qa/specs/features/api/1_manage/import_large_github_repo_spec.rb
index 52051ddab02..bc1e67f93e0 100644
--- a/qa/qa/specs/features/api/1_manage/import_large_github_repo_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/import_large_github_repo_spec.rb
@@ -135,10 +135,12 @@ module QA
imported_project # import the project
fetch_github_objects # fetch all objects right after import has started
- expect { imported_project.reload!.import_status }.to eventually_eq('finished').within(
- duration: 3600,
- interval: 30
- )
+ import_status = lambda do
+ imported_project.reload!.import_status.tap do |status|
+ raise "Import of '#{imported_project.name}' failed!" if status == 'failed'
+ end
+ end
+ expect(import_status).to eventually_eq('finished').within(duration: 3600, interval: 30)
@import_time = Time.now - start
aggregate_failures do
@@ -264,7 +266,7 @@ module QA
def gl_commits
@gl_commits ||= begin
logger.debug("= Fetching commits =")
- imported_project.commits(auto_paginate: true).map { |c| c[:id] }
+ imported_project.commits(auto_paginate: true, attempts: 2).map { |c| c[:id] }
end
end
@@ -294,7 +296,7 @@ module QA
def mrs
@mrs ||= begin
logger.debug("= Fetching merge requests =")
- imported_mrs = imported_project.merge_requests(auto_paginate: true)
+ imported_mrs = imported_project.merge_requests(auto_paginate: true, attempts: 2)
logger.debug("= Transforming merge request objects for comparison =")
imported_mrs.each_with_object({}) do |mr, hash|
resource = Resource::MergeRequest.init do |resource|
@@ -305,7 +307,7 @@ module QA
hash[mr[:title]] = {
body: mr[:description],
- comments: resource.comments(auto_paginate: true)
+ comments: resource.comments(auto_paginate: true, attempts: 2)
# remove system notes
.reject { |c| c[:system] || c[:body].match?(/^(\*\*Review:\*\*)|(\*Merged by:).*/) }
.map { |c| sanitize(c[:body]) }
@@ -320,7 +322,7 @@ module QA
def gl_issues
@gl_issues ||= begin
logger.debug("= Fetching issues =")
- imported_issues = imported_project.issues(auto_paginate: true)
+ imported_issues = imported_project.issues(auto_paginate: true, attempts: 2)
logger.debug("= Transforming issue objects for comparison =")
imported_issues.each_with_object({}) do |issue, hash|
resource = Resource::Issue.init do |issue_resource|
@@ -331,7 +333,7 @@ module QA
hash[issue[:title]] = {
body: issue[:description],
- comments: resource.comments(auto_paginate: true).map { |c| sanitize(c[:body]) }
+ comments: resource.comments(auto_paginate: true, attempts: 2).map { |c| sanitize(c[:body]) }
}
end
end
diff --git a/qa/qa/support/api.rb b/qa/qa/support/api.rb
index 1493feeeed7..579227b4f7a 100644
--- a/qa/qa/support/api.rb
+++ b/qa/qa/support/api.rb
@@ -79,16 +79,27 @@ module QA
error.response
end
- def auto_paginated_response(url)
+ def auto_paginated_response(url, attempts: 0)
pages = []
- with_paginated_response_body(url) { |response| pages << response }
+ with_paginated_response_body(url, attempts: attempts) { |response| pages << response }
pages.flatten
end
- def with_paginated_response_body(url)
+ def with_paginated_response_body(url, attempts: 0)
+ not_ok_error = lambda do |resp|
+ raise "Failed to GET #{QA::Runtime::API::Request.masked_url(url)} - (#{resp.code}): `#{resp}`."
+ end
+
loop do
- response = get(url)
+ response = if attempts > 0
+ Retrier.retry_on_exception(max_attempts: attempts, log: false) do
+ get(url).tap { |resp| not_ok_error.call(resp) if resp.code != HTTP_STATUS_OK }
+ end
+ else
+ get(url).tap { |resp| not_ok_error.call(resp) if resp.code != HTTP_STATUS_OK }
+ end
+
page, pages = response.headers.values_at(:x_page, :x_total_pages)
api_endpoint = url.match(%r{v4/(\S+)\?})[1]
@@ -104,7 +115,10 @@ module QA
end
def pagination_links(response)
- response.headers[:link].split(',').map do |link|
+ link = response.headers[:link]
+ return unless link
+
+ link.split(',').map do |link|
match = link.match(/<(?<url>.*)>; rel="(?<rel>\w+)"/)
break nil unless match
diff --git a/qa/qa/support/repeater.rb b/qa/qa/support/repeater.rb
index 6f8c4a59566..b3a2472d702 100644
--- a/qa/qa/support/repeater.rb
+++ b/qa/qa/support/repeater.rb
@@ -11,7 +11,15 @@ module QA
RetriesExceededError = Class.new(RepeaterConditionExceededError)
WaitExceededError = Class.new(RepeaterConditionExceededError)
- def repeat_until(max_attempts: nil, max_duration: nil, reload_page: nil, sleep_interval: 0, raise_on_failure: true, retry_on_exception: false, log: true)
+ def repeat_until(
+ max_attempts: nil,
+ max_duration: nil,
+ reload_page: nil,
+ sleep_interval: 0,
+ raise_on_failure: true,
+ retry_on_exception: false,
+ log: true
+ )
attempts = 0
start = Time.now
@@ -29,17 +37,19 @@ module QA
raise unless retry_on_exception
attempts += 1
- if remaining_attempts?(attempts, max_attempts) && remaining_time?(start, max_duration)
- sleep_and_reload_if_needed(sleep_interval, reload_page)
+ raise unless remaining_attempts?(attempts, max_attempts) && remaining_time?(start, max_duration)
- retry
- else
- raise
- end
+ sleep_and_reload_if_needed(sleep_interval, reload_page)
+ retry
end
if raise_on_failure
- raise RetriesExceededError, "Retry condition not met after #{max_attempts} #{'attempt'.pluralize(max_attempts)}" unless remaining_attempts?(attempts, max_attempts)
+ unless remaining_attempts?(attempts, max_attempts)
+ raise(
+ RetriesExceededError,
+ "Retry condition not met after #{max_attempts} #{'attempt'.pluralize(max_attempts)}"
+ )
+ end
raise WaitExceededError, "Wait condition not met after #{max_duration} #{'second'.pluralize(max_duration)}"
end
diff --git a/qa/qa/support/retrier.rb b/qa/qa/support/retrier.rb
index 25dbb42cf6f..fde8ac263ca 100644
--- a/qa/qa/support/retrier.rb
+++ b/qa/qa/support/retrier.rb
@@ -7,21 +7,21 @@ module QA
module_function
- def retry_on_exception(max_attempts: 3, reload_page: nil, sleep_interval: 0.5)
- QA::Runtime::Logger.debug(
- <<~MSG.tr("\n", ' ')
- with retry_on_exception: max_attempts: #{max_attempts};
- reload_page: #{reload_page};
- sleep_interval: #{sleep_interval}
- MSG
- )
+ def retry_on_exception(max_attempts: 3, reload_page: nil, sleep_interval: 0.5, log: true)
+ if log
+ msg = ["with retry_on_exception: max_attempts: #{max_attempts}"]
+ msg << "reload_page: #{reload_page}" if reload_page
+ msg << "sleep_interval: #{sleep_interval}"
+ QA::Runtime::Logger.debug(msg.join('; '))
+ end
result = nil
repeat_until(
max_attempts: max_attempts,
reload_page: reload_page,
sleep_interval: sleep_interval,
- retry_on_exception: true
+ retry_on_exception: true,
+ log: log
) do
result = yield
@@ -29,7 +29,7 @@ module QA
# We set it to `true` so that it doesn't repeat if there's no exception
true
end
- QA::Runtime::Logger.debug("ended retry_on_exception")
+ QA::Runtime::Logger.debug("ended retry_on_exception") if log
result
end
diff --git a/qa/spec/support/retrier_spec.rb b/qa/spec/support/retrier_spec.rb
index 6f052519516..4e27915553c 100644
--- a/qa/spec/support/retrier_spec.rb
+++ b/qa/spec/support/retrier_spec.rb
@@ -70,8 +70,9 @@ RSpec.describe QA::Support::Retrier do
describe '.retry_on_exception' do
context 'when the condition is true' do
it 'logs max_attempts, reload_page, and sleep_interval parameters' do
- expect { subject.retry_on_exception(max_attempts: 1, reload_page: nil, sleep_interval: 0) { true } }
- .to output(/with retry_on_exception: max_attempts: 1; reload_page: ; sleep_interval: 0/).to_stdout_from_any_process
+ message = /with retry_on_exception: max_attempts: 1; reload_page: true; sleep_interval: 0/
+ expect { subject.retry_on_exception(max_attempts: 1, reload_page: true, sleep_interval: 0) { true } }
+ .to output(message).to_stdout_from_any_process
end
it 'logs the end' do
@@ -82,8 +83,9 @@ RSpec.describe QA::Support::Retrier do
context 'when the condition is false' do
it 'logs the start' do
- expect { subject.retry_on_exception(max_attempts: 1, reload_page: nil, sleep_interval: 0) { false } }
- .to output(/with retry_on_exception: max_attempts: 1; reload_page: ; sleep_interval: 0/).to_stdout_from_any_process
+ message = /with retry_on_exception: max_attempts: 1; reload_page: true; sleep_interval: 0/
+ expect { subject.retry_on_exception(max_attempts: 1, reload_page: true, sleep_interval: 0) { false } }
+ .to output(message).to_stdout_from_any_process
end
it 'logs the end' do
diff --git a/spec/controllers/projects/feature_flags_controller_spec.rb b/spec/controllers/projects/feature_flags_controller_spec.rb
index f809dd31b3b..e038b247eff 100644
--- a/spec/controllers/projects/feature_flags_controller_spec.rb
+++ b/spec/controllers/projects/feature_flags_controller_spec.rb
@@ -652,7 +652,7 @@ RSpec.describe Projects::FeatureFlagsController do
version: 'new_version_flag',
strategies_attributes: [{
name: 'flexibleRollout',
- parameters: { groupId: 'default', rollout: '15', stickiness: 'DEFAULT' },
+ parameters: { groupId: 'default', rollout: '15', stickiness: 'default' },
scopes_attributes: [{ environment_scope: 'production' }]
}]
}
@@ -666,7 +666,7 @@ RSpec.describe Projects::FeatureFlagsController do
strategy_json = json_response['strategies'].first
expect(strategy_json['name']).to eq('flexibleRollout')
- expect(strategy_json['parameters']).to eq({ 'groupId' => 'default', 'rollout' => '15', 'stickiness' => 'DEFAULT' })
+ expect(strategy_json['parameters']).to eq({ 'groupId' => 'default', 'rollout' => '15', 'stickiness' => 'default' })
expect(strategy_json['scopes'].count).to eq(1)
scope_json = strategy_json['scopes'].first
@@ -938,7 +938,7 @@ RSpec.describe Projects::FeatureFlagsController do
it 'creates a flexibleRollout strategy' do
put_request(new_version_flag, strategies_attributes: [{
name: 'flexibleRollout',
- parameters: { groupId: 'default', rollout: '30', stickiness: 'DEFAULT' }
+ parameters: { groupId: 'default', rollout: '30', stickiness: 'default' }
}])
expect(response).to have_gitlab_http_status(:ok)
@@ -948,7 +948,7 @@ RSpec.describe Projects::FeatureFlagsController do
expect(strategy_json['parameters']).to eq({
'groupId' => 'default',
'rollout' => '30',
- 'stickiness' => 'DEFAULT'
+ 'stickiness' => 'default'
})
expect(strategy_json['scopes']).to eq([])
end
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index d18369b8023..7f330681a82 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -51,7 +51,7 @@ FactoryBot.define do
ci_job_token_scope_enabled { nil }
end
- before(:create) do |project, evaluator|
+ after(:build) do |project, evaluator|
# Builds and MRs can't have higher visibility level than repository access level.
builds_access_level = [evaluator.builds_access_level, evaluator.repository_access_level].min
merge_requests_access_level = [evaluator.merge_requests_access_level, evaluator.repository_access_level].min
@@ -67,21 +67,11 @@ FactoryBot.define do
pages_access_level: evaluator.pages_access_level,
metrics_dashboard_access_level: evaluator.metrics_dashboard_access_level,
operations_access_level: evaluator.operations_access_level,
- analytics_access_level: evaluator.analytics_access_level
+ analytics_access_level: evaluator.analytics_access_level,
+ container_registry_access_level: evaluator.container_registry_access_level
}
project.build_project_feature(hash)
-
- # This is not included in the `hash` above because the default_value_for in
- # the ProjectFeature model overrides the value set by `build_project_feature` when
- # evaluator.container_registry_access_level == ProjectFeature::DISABLED.
- #
- # This is because the default_value_for gem uses the <column>_changed? method
- # to determine if the default value should be applied. For new records,
- # <column>_changed? returns false if the value of the column is the same as
- # the database default.
- # See https://github.com/FooBarWidget/default_value_for/blob/release-3.4.0/lib/default_value_for.rb#L158.
- project.project_feature.container_registry_access_level = evaluator.container_registry_access_level
end
after(:create) do |project, evaluator|
diff --git a/spec/frontend/feature_flags/components/strategies/flexible_rollout_spec.js b/spec/frontend/feature_flags/components/strategies/flexible_rollout_spec.js
index 02216370b79..07aa456e69e 100644
--- a/spec/frontend/feature_flags/components/strategies/flexible_rollout_spec.js
+++ b/spec/frontend/feature_flags/components/strategies/flexible_rollout_spec.js
@@ -66,15 +66,14 @@ describe('feature_flags/components/strategies/flexible_rollout.vue', () => {
});
it('emits a change when the stickiness value changes', async () => {
- stickinessSelect.setValue('USERID');
- await wrapper.vm.$nextTick();
+ await stickinessSelect.setValue('userId');
expect(wrapper.emitted('change')).toEqual([
[
{
parameters: {
rollout: flexibleRolloutStrategy.parameters.rollout,
groupId: PERCENT_ROLLOUT_GROUP_ID,
- stickiness: 'USERID',
+ stickiness: 'userId',
},
},
],
diff --git a/spec/frontend/feature_flags/mock_data.js b/spec/frontend/feature_flags/mock_data.js
index b5f09ac1957..4c40c2acf01 100644
--- a/spec/frontend/feature_flags/mock_data.js
+++ b/spec/frontend/feature_flags/mock_data.js
@@ -76,7 +76,7 @@ export const percentRolloutStrategy = {
export const flexibleRolloutStrategy = {
name: ROLLOUT_STRATEGY_FLEXIBLE_ROLLOUT,
- parameters: { rollout: '50', groupId: 'default', stickiness: 'DEFAULT' },
+ parameters: { rollout: '50', groupId: 'default', stickiness: 'default' },
scopes: [],
};
diff --git a/spec/migrations/20210722150102_operations_feature_flags_correct_flexible_rollout_values_spec.rb b/spec/migrations/20210722150102_operations_feature_flags_correct_flexible_rollout_values_spec.rb
new file mode 100644
index 00000000000..130ad45ffc1
--- /dev/null
+++ b/spec/migrations/20210722150102_operations_feature_flags_correct_flexible_rollout_values_spec.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!('operations_feature_flags_correct_flexible_rollout_values')
+
+RSpec.describe OperationsFeatureFlagsCorrectFlexibleRolloutValues, :migration do
+ let_it_be(:strategies) { table(:operations_strategies) }
+
+ let(:namespace) { table(:namespaces).create!(name: 'feature_flag', path: 'feature_flag') }
+ let(:project) { table(:projects).create!(namespace_id: namespace.id) }
+ let(:feature_flag) { table(:operations_feature_flags).create!(project_id: project.id, active: true, name: 'foo', iid: 1) }
+
+ describe "#up" do
+ described_class::STICKINESS.each do |old, new|
+ it "corrects parameters for flexible rollout stickiness #{old}" do
+ reversible_migration do |migration|
+ parameters = { groupId: "default", rollout: "100", stickiness: old }
+ strategy = create_strategy(parameters)
+
+ migration.before -> {
+ expect(strategy.reload.parameters).to eq({ "groupId" => "default", "rollout" => "100", "stickiness" => old })
+ }
+
+ migration.after -> {
+ expect(strategy.reload.parameters).to eq({ "groupId" => "default", "rollout" => "100", "stickiness" => new })
+ }
+ end
+ end
+ end
+
+ it 'ignores other strategies' do
+ reversible_migration do |migration|
+ parameters = { "groupId" => "default", "rollout" => "100", "stickiness" => "USERID" }
+ strategy = create_strategy(parameters, name: 'default')
+
+ migration.before -> {
+ expect(strategy.reload.parameters).to eq(parameters)
+ }
+
+ migration.after -> {
+ expect(strategy.reload.parameters).to eq(parameters)
+ }
+ end
+ end
+
+ it 'ignores other stickiness' do
+ reversible_migration do |migration|
+ parameters = { "groupId" => "default", "rollout" => "100", "stickiness" => "FOO" }
+ strategy = create_strategy(parameters)
+
+ migration.before -> {
+ expect(strategy.reload.parameters).to eq(parameters)
+ }
+
+ migration.after -> {
+ expect(strategy.reload.parameters).to eq(parameters)
+ }
+ end
+ end
+ end
+
+ def create_strategy(params, name: 'flexibleRollout')
+ strategies.create!(name: name, parameters: params, feature_flag_id: feature_flag.id)
+ end
+end
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index e2700378f5f..b945fa34ebb 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -208,23 +208,9 @@ RSpec.describe Namespace do
it { is_expected.to include_module(Gitlab::VisibilityLevel) }
it { is_expected.to include_module(Namespaces::Traversal::Recursive) }
it { is_expected.to include_module(Namespaces::Traversal::Linear) }
- it { is_expected.to include_module(Namespaces::Traversal::RecursiveScopes) }
- it { is_expected.to include_module(Namespaces::Traversal::LinearScopes) }
end
- context 'traversal scopes' do
- context 'recursive' do
- before do
- stub_feature_flags(use_traversal_ids: false)
- end
-
- it_behaves_like 'namespace traversal scopes'
- end
-
- context 'linear' do
- it_behaves_like 'namespace traversal scopes'
- end
- end
+ it_behaves_like 'linear namespace traversal'
context 'traversal_ids on create' do
context 'default traversal_ids' do
diff --git a/spec/models/operations/feature_flags/strategy_spec.rb b/spec/models/operations/feature_flags/strategy_spec.rb
index 0ecb49e75f3..9289e3beab5 100644
--- a/spec/models/operations/feature_flags/strategy_spec.rb
+++ b/spec/models/operations/feature_flags/strategy_spec.rb
@@ -112,7 +112,7 @@ RSpec.describe Operations::FeatureFlags::Strategy do
end
context 'when the strategy name is flexibleRollout' do
- valid_parameters = { rollout: '40', groupId: 'mygroup', stickiness: 'DEFAULT' }
+ valid_parameters = { rollout: '40', groupId: 'mygroup', stickiness: 'default' }
where(invalid_parameters: [
nil,
{},
@@ -133,7 +133,7 @@ RSpec.describe Operations::FeatureFlags::Strategy do
[
[:rollout, '10'],
- [:stickiness, 'DEFAULT'],
+ [:stickiness, 'default'],
[:groupId, 'mygroup']
].permutation(3).each do |parameters|
it "allows the parameters in the order #{parameters.map { |p| p.first }.join(', ')}" do
@@ -151,7 +151,7 @@ RSpec.describe Operations::FeatureFlags::Strategy do
"\n", "\t", "\n10", "20\n", "\n100", "100\n", "\n ", nil])
with_them do
it 'must be a string value between 0 and 100 inclusive and without a percentage sign' do
- parameters = { stickiness: 'DEFAULT', groupId: 'mygroup', rollout: invalid_value }
+ parameters = { stickiness: 'default', groupId: 'mygroup', rollout: invalid_value }
strategy = described_class.create(feature_flag: feature_flag,
name: 'flexibleRollout',
parameters: parameters)
@@ -165,7 +165,7 @@ RSpec.describe Operations::FeatureFlags::Strategy do
where(valid_value: %w[0 1 10 38 100 93])
with_them do
it 'must be a string value between 0 and 100 inclusive and without a percentage sign' do
- parameters = { stickiness: 'DEFAULT', groupId: 'mygroup', rollout: valid_value }
+ parameters = { stickiness: 'default', groupId: 'mygroup', rollout: valid_value }
strategy = described_class.create(feature_flag: feature_flag,
name: 'flexibleRollout',
parameters: parameters)
@@ -180,7 +180,7 @@ RSpec.describe Operations::FeatureFlags::Strategy do
'!bad', '.bad', 'Bad', 'bad1', "", " ", "b" * 33, "ba_d", "ba\nd"])
with_them do
it 'must be a string value of up to 32 lowercase characters' do
- parameters = { stickiness: 'DEFAULT', groupId: invalid_value, rollout: '40' }
+ parameters = { stickiness: 'default', groupId: invalid_value, rollout: '40' }
strategy = described_class.create(feature_flag: feature_flag,
name: 'flexibleRollout',
parameters: parameters)
@@ -192,7 +192,7 @@ RSpec.describe Operations::FeatureFlags::Strategy do
where(valid_value: ["somegroup", "anothergroup", "okay", "g", "a" * 32])
with_them do
it 'must be a string value of up to 32 lowercase characters' do
- parameters = { stickiness: 'DEFAULT', groupId: valid_value, rollout: '40' }
+ parameters = { stickiness: 'default', groupId: valid_value, rollout: '40' }
strategy = described_class.create(feature_flag: feature_flag,
name: 'flexibleRollout',
parameters: parameters)
@@ -203,7 +203,7 @@ RSpec.describe Operations::FeatureFlags::Strategy do
end
describe 'stickiness' do
- where(invalid_value: [nil, " ", "default", "DEFAULT\n", "UserId", "USER", "USERID "])
+ where(invalid_value: [nil, " ", "DEFAULT", "DEFAULT\n", "UserId", "USER", "USERID "])
with_them do
it 'must be a string representing a supported stickiness setting' do
parameters = { stickiness: invalid_value, groupId: 'mygroup', rollout: '40' }
@@ -212,12 +212,12 @@ RSpec.describe Operations::FeatureFlags::Strategy do
parameters: parameters)
expect(strategy.errors[:parameters]).to eq([
- 'stickiness parameter must be DEFAULT, USERID, SESSIONID, or RANDOM'
+ 'stickiness parameter must be default, userId, sessionId, or random'
])
end
end
- where(valid_value: %w[DEFAULT USERID SESSIONID RANDOM])
+ where(valid_value: %w[default userId sessionId random])
with_them do
it 'must be a string representing a supported stickiness setting' do
parameters = { stickiness: valid_value, groupId: 'mygroup', rollout: '40' }
@@ -425,7 +425,7 @@ RSpec.describe Operations::FeatureFlags::Strategy do
user_list: user_list,
parameters: { groupId: 'default',
rollout: '10',
- stickiness: 'DEFAULT' })
+ stickiness: 'default' })
expect(strategy.errors[:user_list]).to eq(['must be blank'])
end
@@ -435,7 +435,7 @@ RSpec.describe Operations::FeatureFlags::Strategy do
name: 'flexibleRollout',
parameters: { groupId: 'default',
rollout: '10',
- stickiness: 'DEFAULT' })
+ stickiness: 'default' })
expect(strategy.errors[:user_list]).to be_empty
end
diff --git a/spec/models/project_feature_spec.rb b/spec/models/project_feature_spec.rb
index 0ef5a2046ba..0e276191af1 100644
--- a/spec/models/project_feature_spec.rb
+++ b/spec/models/project_feature_spec.rb
@@ -218,5 +218,29 @@ RSpec.describe ProjectFeature do
end
end
end
+
+ context 'test build factory' do
+ let(:project) { build(:project, container_registry_access_level: level) }
+
+ subject { project.container_registry_access_level }
+
+ context 'private' do
+ let(:level) { ProjectFeature::PRIVATE }
+
+ it { is_expected.to eq(level) }
+ end
+
+ context 'enabled' do
+ let(:level) { ProjectFeature::ENABLED }
+
+ it { is_expected.to eq(level) }
+ end
+
+ context 'disabled' do
+ let(:level) { ProjectFeature::DISABLED }
+
+ it { is_expected.to eq(level) }
+ end
+ end
end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 66d650b4f84..72c45de402e 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -318,7 +318,8 @@ RSpec.describe Project, factory_default: :keep do
end
it 'validates presence of project_feature' do
- project = build(:project, project_feature: nil)
+ project = build(:project)
+ project.project_feature = nil
expect(project).not_to be_valid
end
diff --git a/spec/requests/api/feature_flags_spec.rb b/spec/requests/api/feature_flags_spec.rb
index 8edf8825fb2..8c8c6803a38 100644
--- a/spec/requests/api/feature_flags_spec.rb
+++ b/spec/requests/api/feature_flags_spec.rb
@@ -417,7 +417,7 @@ RSpec.describe API::FeatureFlags do
version: 'new_version_flag',
strategies: [{
name: 'flexibleRollout',
- parameters: { groupId: 'default', rollout: '50', stickiness: 'DEFAULT' },
+ parameters: { groupId: 'default', rollout: '50', stickiness: 'default' },
scopes: [{
environment_scope: 'staging'
}]
@@ -434,7 +434,7 @@ RSpec.describe API::FeatureFlags do
expect(feature_flag.version).to eq('new_version_flag')
expect(feature_flag.strategies.map { |s| s.slice(:name, :parameters).deep_symbolize_keys }).to eq([{
name: 'flexibleRollout',
- parameters: { groupId: 'default', rollout: '50', stickiness: 'DEFAULT' }
+ parameters: { groupId: 'default', rollout: '50', stickiness: 'default' }
}])
expect(feature_flag.strategies.first.scopes.map { |s| s.slice(:environment_scope).deep_symbolize_keys }).to eq([{
environment_scope: 'staging'
@@ -630,7 +630,7 @@ RSpec.describe API::FeatureFlags do
strategies: [{
id: strategy.id,
name: 'flexibleRollout',
- parameters: { groupId: 'default', rollout: '10', stickiness: 'DEFAULT' }
+ parameters: { groupId: 'default', rollout: '10', stickiness: 'default' }
}]
}
@@ -642,7 +642,7 @@ RSpec.describe API::FeatureFlags do
expect(result).to eq([{
id: strategy.id,
name: 'flexibleRollout',
- parameters: { groupId: 'default', rollout: '10', stickiness: 'DEFAULT' }
+ parameters: { groupId: 'default', rollout: '10', stickiness: 'default' }
}])
end
@@ -677,7 +677,7 @@ RSpec.describe API::FeatureFlags do
params = {
strategies: [{
name: 'flexibleRollout',
- parameters: { groupId: 'default', rollout: '10', stickiness: 'DEFAULT' }
+ parameters: { groupId: 'default', rollout: '10', stickiness: 'default' }
}]
}
@@ -694,7 +694,7 @@ RSpec.describe API::FeatureFlags do
parameters: {}
}, {
name: 'flexibleRollout',
- parameters: { groupId: 'default', rollout: '10', stickiness: 'DEFAULT' }
+ parameters: { groupId: 'default', rollout: '10', stickiness: 'default' }
}])
end
diff --git a/spec/support/shared_examples/namespaces/linear_traversal_examples.rb b/spec/support/shared_examples/namespaces/linear_traversal_examples.rb
new file mode 100644
index 00000000000..2fd90c36953
--- /dev/null
+++ b/spec/support/shared_examples/namespaces/linear_traversal_examples.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+# Traversal examples common to linear and recursive methods are in
+# spec/support/shared_examples/namespaces/traversal_examples.rb
+
+RSpec.shared_examples 'linear namespace traversal' do
+ context 'when use_traversal_ids feature flag is enabled' do
+ before do
+ stub_feature_flags(use_traversal_ids: true)
+ end
+
+ context 'scopes' do
+ describe '.as_ids' do
+ let_it_be(:namespace1) { create(:group) }
+ let_it_be(:namespace2) { create(:group) }
+
+ subject { Namespace.where(id: [namespace1, namespace2]).as_ids.pluck(:id) }
+
+ it { is_expected.to contain_exactly(namespace1.id, namespace2.id) }
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/namespaces/traversal_scope_examples.rb b/spec/support/shared_examples/namespaces/traversal_scope_examples.rb
deleted file mode 100644
index bc17d104034..00000000000
--- a/spec/support/shared_examples/namespaces/traversal_scope_examples.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.shared_examples 'namespace traversal scopes' do
- # Hierarchy 1
- let_it_be(:group_1) { create(:group) }
- let_it_be(:nested_group_1) { create(:group, parent: group_1) }
- let_it_be(:deep_nested_group_1) { create(:group, parent: nested_group_1) }
-
- # Hierarchy 2
- let_it_be(:group_2) { create(:group) }
- let_it_be(:nested_group_2) { create(:group, parent: group_2) }
- let_it_be(:deep_nested_group_2) { create(:group, parent: nested_group_2) }
-
- # All groups
- let_it_be(:groups) do
- [
- group_1, nested_group_1, deep_nested_group_1,
- group_2, nested_group_2, deep_nested_group_2
- ]
- end
-
- describe '.as_ids' do
- subject { described_class.where(id: [group_1, group_2]).as_ids.pluck(:id) }
-
- it { is_expected.to contain_exactly(group_1.id, group_2.id) }
- end
-
- describe '.without_sti_condition' do
- subject { described_class.without_sti_condition }
-
- it { expect(subject.where_values_hash).not_to have_key(:type) }
- end
-
- describe '.self_and_descendants' do
- subject { described_class.where(id: [nested_group_1, nested_group_2]).self_and_descendants }
-
- it { is_expected.to contain_exactly(nested_group_1, deep_nested_group_1, nested_group_2, deep_nested_group_2) }
-
- context 'with duplicate descendants' do
- subject { described_class.where(id: [group_1, group_2, nested_group_1]).self_and_descendants }
-
- it { is_expected.to match_array(groups) }
- end
- end
-
- describe '.self_and_descendant_ids' do
- subject { described_class.where(id: [nested_group_1, nested_group_2]).self_and_descendant_ids.pluck(:id) }
-
- it { is_expected.to contain_exactly(nested_group_1.id, deep_nested_group_1.id, nested_group_2.id, deep_nested_group_2.id) }
- end
-end
diff --git a/yarn.lock b/yarn.lock
index cd8511bbd2f..7870aa23b58 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3418,12 +3418,12 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
dependencies:
delayed-stream "~1.0.0"
-commander@2, commander@^2.10.0, commander@^2.18.0, commander@^2.19.0, commander@^2.20.0, commander@~2.20.0:
- version "2.20.0"
- resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
- integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
+commander@2, commander@^2.19.0, commander@^2.20.0, commander@^2.20.3, commander@~2.20.0:
+ version "2.20.3"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
+ integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
-commander@^6.0.0, commander@^6.2.0, commander@~6.2.1:
+commander@^6.0.0, commander@^6.1.0, commander@^6.2.0, commander@~6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c"
integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==
@@ -10560,7 +10560,7 @@ semver-diff@^3.1.1:
dependencies:
semver "^6.3.0"
-"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1:
+"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
@@ -12882,14 +12882,14 @@ yarn-check-webpack-plugin@^1.2.0:
dependencies:
chalk "^2.4.2"
-yarn-deduplicate@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/yarn-deduplicate/-/yarn-deduplicate-1.1.1.tgz#19b4a87654b66f55bf3a4bd6b153b4e4ab1b6e6d"
- integrity sha512-2FDJ1dFmtvqhRmfja89ohYzpaheCYg7BFBSyaUq+kxK0y61C9oHv1XaQovCWGJtP2WU8PksQOgzMVV7oQOobzw==
+yarn-deduplicate@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/yarn-deduplicate/-/yarn-deduplicate-3.1.0.tgz#3018d93e95f855f236a215b591fe8bc4bcabba3e"
+ integrity sha512-q2VZ6ThNzQpGfNpkPrkmV7x5HT9MOhCUsTxVTzyyZB0eSXz1NTodHn+r29DlLb+peKk8iXxzdUVhQG9pI7moFw==
dependencies:
"@yarnpkg/lockfile" "^1.1.0"
- commander "^2.10.0"
- semver "^5.3.0"
+ commander "^6.1.0"
+ semver "^7.3.2"
yeast@0.1.2:
version "0.1.2"