Disable Style/ArrayCoercion due to safety concern
What does this MR do and why?
Disable Style/ArrayCoercion due to safety concern. Array() may produce unexpected result when a single non-array argument is passed to it.
There are examples in the Rubocop doc showing unexpected values where it does not return an array containing the given object.
Another example is when giving it a single Struct, it returns an array of the Struct's attributes:
Name = Struct.new(:first, :last)
john = Name.new(:john, :doe)
jane = Name.new(:jane, :doe)
Array([john, jane])
=> [#<struct Name first=:john, last=:doe>, #<struct Name first=:jane, last=:doe>]
Array(john)
=> [:john, :doe] # not an array of a single struct
This cop has also been disabled by default in Rubocop.
What could go wrong?
One of the pattern encouraged by this Cop is the use of this method to coerce an array that can be looped over. We have multiple instances in the GitLab code where we use this pattern to coerce a method parameter into an array, so that the method can take in either a single object or an array of objects.
This becomes a problem when a single object is given that causes Array() to return something else other than [object], for example object is a Hash or a Struct.
Some examples of the current use of Array():
ee/app/graphql/ee/mutations/alert_management/http_integration/http_integration_base.rb:41: Array(mappings).each_with_object({}) do |m, h|
ee/lib/gitlab/subscription_portal/clients/graphql.rb:62: future_subscriptions = Array(response['futureSubscriptions']).each do |future_subscription_hash|
ee/spec/services/geo/container_repository_registry_removal_service_spec.rb:20: Array(message).each do |message|
ee/spec/services/geo/file_registry_removal_service_spec.rb:20: Array(message).each do |message|
ee/spec/support/shared_examples/requests/api/members_shared_examples.rb:5: Array(emails).flatten.each do |email|
ee/spec/support/shared_examples/requests/api/members_shared_examples.rb:13: Array(emails).flatten.each do |email|
lib/api/api_guard.rb:36: Array(scopes).each do |scope|
lib/gitlab/ci/artifacts/logger.rb:33: Array(job_artifacts).each do |artifact|
lib/gitlab/ci/artifacts/logger.rb:48: Array(job_artifacts).each do |artifact|
lib/gitlab/ci/yaml_processor.rb:88: Array(includes).each do |included|
lib/gitlab/event_store/store.rb:21: Array(to).each do |event|
lib/gitlab/grape_logging/loggers/exception_logger.rb:31: response_body = Array(response_body) unless response_body.respond_to?(:each)
lib/gitlab/usage/metrics/aggregates/sources/postgres_hll.rb:14: Array(metric_names).each_with_object(Gitlab::Database::PostgresHll::Buckets.new) do |event, buckets|
spec/models/preloaders/merge_request_diff_preloader_spec.rb:13: Array(merge_requests).each(&:merge_request_diff)
spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb:23: Array(flags_to_be_set).each do |flag_to_be_set|
spec/support/helpers/stub_feature_flags.rb:48: Array(actors).each do |actor|
spec/support/protected_branch_helpers.rb:12: Array(option).each { |opt| click_on(opt) }
spec/tasks/gitlab/backup_rake_spec.rb:121: Array(tasks_name).each do |task|
tooling/lib/tooling/kubernetes_client.rb:98: Array(release_name).each do |release|
tooling/lib/tooling/test_map_generator.rb:13: Array(yaml_files).each do |yaml_file|
vendor/gems/error_tracking_open_api/lib/error_tracking_open_api/api_client.rb:307: Array(auth_names).each do |auth_name|