diff --git a/debian/patches/0760-update-grape.patch b/debian/patches/0760-update-grape.patch new file mode 100644 index 0000000000..4293fcaa60 --- /dev/null +++ b/debian/patches/0760-update-grape.patch @@ -0,0 +1,1677 @@ +From e02626b961ce60fcc92757f977dff211e414e572 Mon Sep 17 00:00:00 2001 +From: Stan Hu +Date: Thu, 12 Mar 2020 15:24:13 -0700 +Subject: [PATCH 01/12] Upgrade Grape v1.1.0 to v1.3.1 + +This brings in Ruby 2.7 suport and a number of fixes: +https://github.com/ruby-grape/grape/blob/master/CHANGELOG.md + +Move all inherited Grape::API -> Grape::API::Instance + +Remove use of Virtus since this has been removed from Grape. +--- + Gemfile | 4 +- + Gemfile.lock | 55 +++++++++++-------- + changelogs/unreleased/sh-update-grape-gem.yml | 5 ++ + doc/development/ee_features.md | 12 ++-- + ee/lib/api/analytics/code_review_analytics.rb | 2 +- + ee/lib/api/audit_events.rb | 2 +- + ee/lib/api/conan_packages.rb | 2 +- + ee/lib/api/container_registry_event.rb | 2 +- + ee/lib/api/dependencies.rb | 2 +- + .../api/elasticsearch_indexed_namespaces.rb | 2 +- + ee/lib/api/epic_issues.rb | 2 +- + ee/lib/api/epic_links.rb | 2 +- + ee/lib/api/epics.rb | 2 +- + ee/lib/api/feature_flag_scopes.rb | 2 +- + ee/lib/api/feature_flags.rb | 2 +- + ee/lib/api/geo.rb | 2 +- + ee/lib/api/geo_nodes.rb | 2 +- + ee/lib/api/geo_replication.rb | 2 +- + ee/lib/api/group_hooks.rb | 2 +- + ee/lib/api/group_packages.rb | 2 +- + ee/lib/api/issue_links.rb | 2 +- + ee/lib/api/ldap.rb | 2 +- + ee/lib/api/ldap_group_links.rb | 2 +- + ee/lib/api/license.rb | 2 +- + ee/lib/api/managed_licenses.rb | 2 +- + ee/lib/api/maven_packages.rb | 2 +- + ee/lib/api/merge_request_approval_rules.rb | 2 +- + ee/lib/api/merge_request_approvals.rb | 2 +- + ee/lib/api/merge_trains.rb | 2 +- + ee/lib/api/npm_packages.rb | 2 +- + ee/lib/api/nuget_packages.rb | 2 +- + ee/lib/api/package_files.rb | 2 +- + ee/lib/api/project_aliases.rb | 2 +- + ee/lib/api/project_approval_rules.rb | 2 +- + ee/lib/api/project_approval_settings.rb | 2 +- + ee/lib/api/project_approvals.rb | 2 +- + ee/lib/api/project_mirror.rb | 2 +- + ee/lib/api/project_packages.rb | 2 +- + ee/lib/api/project_push_rule.rb | 2 +- + ee/lib/api/protected_environments.rb | 2 +- + ee/lib/api/scim.rb | 2 +- + ee/lib/api/unleash.rb | 2 +- + ee/lib/api/v3/github.rb | 2 +- + ee/lib/api/visual_review_discussions.rb | 2 +- + ee/lib/api/vulnerabilities.rb | 2 +- + ee/lib/api/vulnerability_findings.rb | 2 +- + ee/lib/api/vulnerability_issue_links.rb | 2 +- + ee/lib/ee/api/boards.rb | 2 +- + ee/lib/ee/api/group_boards.rb | 2 +- + ee/spec/lib/ee/api/helpers_spec.rb | 2 +- + lib/api/access_requests.rb | 2 +- + lib/api/admin/sidekiq.rb | 2 +- + lib/api/api.rb | 2 +- + lib/api/appearance.rb | 2 +- + lib/api/applications.rb | 2 +- + lib/api/avatar.rb | 2 +- + lib/api/award_emoji.rb | 2 +- + lib/api/badges.rb | 2 +- + lib/api/boards.rb | 2 +- + lib/api/branches.rb | 2 +- + lib/api/broadcast_messages.rb | 2 +- + lib/api/commit_statuses.rb | 2 +- + lib/api/commits.rb | 2 +- + lib/api/deploy_keys.rb | 2 +- + lib/api/deploy_tokens.rb | 2 +- + lib/api/deployments.rb | 2 +- + lib/api/discussions.rb | 2 +- + lib/api/environments.rb | 2 +- + lib/api/error_tracking.rb | 2 +- + lib/api/events.rb | 2 +- + lib/api/features.rb | 2 +- + lib/api/files.rb | 2 +- + lib/api/group_boards.rb | 2 +- + lib/api/group_clusters.rb | 2 +- + lib/api/group_container_repositories.rb | 2 +- + lib/api/group_export.rb | 2 +- + lib/api/group_import.rb | 2 +- + lib/api/group_labels.rb | 2 +- + lib/api/group_milestones.rb | 2 +- + lib/api/group_variables.rb | 2 +- + lib/api/groups.rb | 2 +- + lib/api/import_github.rb | 2 +- + lib/api/internal/base.rb | 2 +- + lib/api/internal/pages.rb | 2 +- + lib/api/issues.rb | 2 +- + lib/api/job_artifacts.rb | 2 +- + lib/api/jobs.rb | 2 +- + lib/api/keys.rb | 2 +- + lib/api/labels.rb | 2 +- + lib/api/lint.rb | 2 +- + lib/api/lsif_data.rb | 2 +- + lib/api/markdown.rb | 2 +- + lib/api/members.rb | 2 +- + lib/api/merge_request_diffs.rb | 2 +- + lib/api/merge_requests.rb | 2 +- + lib/api/namespaces.rb | 2 +- + lib/api/notes.rb | 2 +- + lib/api/notification_settings.rb | 2 +- + lib/api/pages.rb | 2 +- + lib/api/pages_domains.rb | 2 +- + lib/api/pagination_params.rb | 2 +- + lib/api/pipeline_schedules.rb | 2 +- + lib/api/pipelines.rb | 2 +- + lib/api/project_clusters.rb | 2 +- + lib/api/project_container_repositories.rb | 2 +- + lib/api/project_events.rb | 2 +- + lib/api/project_export.rb | 2 +- + lib/api/project_hooks.rb | 2 +- + lib/api/project_import.rb | 2 +- + lib/api/project_milestones.rb | 2 +- + lib/api/project_snapshots.rb | 2 +- + lib/api/project_snippets.rb | 2 +- + lib/api/project_statistics.rb | 2 +- + lib/api/project_templates.rb | 2 +- + lib/api/projects.rb | 2 +- + lib/api/protected_branches.rb | 2 +- + lib/api/protected_tags.rb | 2 +- + lib/api/release/links.rb | 2 +- + lib/api/releases.rb | 2 +- + lib/api/remote_mirrors.rb | 2 +- + lib/api/repositories.rb | 2 +- + lib/api/resource_label_events.rb | 2 +- + lib/api/runner.rb | 2 +- + lib/api/runners.rb | 2 +- + lib/api/search.rb | 2 +- + lib/api/services.rb | 2 +- + lib/api/settings.rb | 2 +- + lib/api/sidekiq_metrics.rb | 2 +- + lib/api/snippets.rb | 2 +- + lib/api/statistics.rb | 2 +- + lib/api/submodules.rb | 2 +- + lib/api/subscriptions.rb | 2 +- + lib/api/suggestions.rb | 2 +- + lib/api/system_hooks.rb | 2 +- + lib/api/tags.rb | 2 +- + lib/api/templates.rb | 2 +- + lib/api/todos.rb | 2 +- + lib/api/triggers.rb | 2 +- + lib/api/user_counts.rb | 2 +- + lib/api/users.rb | 2 +- + lib/api/validations/types/workhorse_file.rb | 2 +- + lib/api/variables.rb | 2 +- + lib/api/version.rb | 2 +- + lib/api/wikis.rb | 2 +- + spec/rubocop/cop/code_reuse/worker_spec.rb | 2 +- + 145 files changed, 187 insertions(+), 171 deletions(-) + create mode 100644 changelogs/unreleased/sh-update-grape-gem.yml + +--- a/Gemfile.lock ++++ b/Gemfile.lock +@@ -1,3 +1,15 @@ ++GIT ++ remote: https://github.com/ruby-grape/grape.git ++ revision: cd03bcf1054a2cba2f8c6a31ca2f1563409f728b ++ specs: ++ grape (1.3.2) ++ activesupport ++ builder ++ dry-types (>= 1.1) ++ mustermann-grape (~> 1.0.0) ++ rack (>= 1.3.0) ++ rack-accept ++ + GEM + remote: https://rubygems.org/ + specs: +@@ -103,10 +115,6 @@ + aws-sdk-core (= 2.11.374) + aws-sigv4 (1.1.0) + aws-eventstream (~> 1.0, >= 1.0.2) +- axiom-types (0.1.1) +- descendants_tracker (~> 0.0.4) +- ice_nine (~> 0.11.0) +- thread_safe (~> 0.3, >= 0.3.1) + babosa (1.0.2) + base32 (0.3.2) + batch-loader (1.4.0) +@@ -165,8 +173,6 @@ + nap + open4 (~> 1.3) + coderay (1.1.2) +- coercible (1.0.0) +- descendants_tracker (~> 0.0.1) + colored2 (3.1.2) + commonmarker (0.20.1) + ruby-enum (~> 0.5) +@@ -248,6 +254,28 @@ + doorkeeper-openid_connect (1.6.3) + doorkeeper (>= 5.0, < 5.2) + json-jwt (~> 1.6) ++ dry-configurable (0.11.4) ++ concurrent-ruby (~> 1.0) ++ dry-core (~> 0.4, >= 0.4.7) ++ dry-equalizer (~> 0.2) ++ dry-container (0.7.2) ++ concurrent-ruby (~> 1.0) ++ dry-configurable (~> 0.1, >= 0.1.3) ++ dry-core (0.4.9) ++ concurrent-ruby (~> 1.0) ++ dry-equalizer (0.3.0) ++ dry-inflector (0.2.0) ++ dry-logic (1.0.6) ++ concurrent-ruby (~> 1.0) ++ dry-core (~> 0.2) ++ dry-equalizer (~> 0.2) ++ dry-types (1.4.0) ++ concurrent-ruby (~> 1.0) ++ dry-container (~> 0.3) ++ dry-core (~> 0.4, >= 0.4.4) ++ dry-equalizer (~> 0.3) ++ dry-inflector (~> 0.1, >= 0.1.2) ++ dry-logic (~> 1.0, >= 1.0.2) + ed25519 (1.2.4) + elasticsearch (6.8.0) + elasticsearch-api (= 6.8.0) +@@ -435,19 +463,12 @@ + signet (~> 0.7) + gpgme (2.0.19) + mini_portile2 (~> 2.3) +- grape (1.1.0) +- activesupport +- builder +- mustermann-grape (~> 1.0.0) +- rack (>= 1.3.0) +- rack-accept +- virtus (>= 1.0.0) + grape-entity (0.7.1) + activesupport (>= 4.0) + multi_json (>= 1.3.2) +- grape-path-helpers (1.2.0) ++ grape-path-helpers (1.3.0) + activesupport +- grape (~> 1.0) ++ grape (~> 1.3) + rake (~> 12) + grape_logging (1.8.3) + grape +@@ -640,9 +661,10 @@ + multi_xml (0.6.0) + multipart-post (2.1.1) + murmurhash3 (0.1.6) +- mustermann (1.0.3) +- mustermann-grape (1.0.0) +- mustermann (~> 1.0.0) ++ mustermann (1.1.1) ++ ruby2_keywords (~> 0.0.1) ++ mustermann-grape (1.0.1) ++ mustermann (>= 1.0.0) + nakayoshi_fork (0.0.4) + nap (1.1.0) + nenv (0.3.0) +@@ -1113,11 +1135,6 @@ + activerecord (>= 3.0) + activesupport (>= 3.0) + version_sorter (2.2.4) +- virtus (1.0.5) +- axiom-types (~> 0.1) +- coercible (~> 1.0) +- descendants_tracker (~> 0.0, >= 0.0.3) +- equalizer (~> 0.0, >= 0.0.9) + vmstat (2.3.0) + warden (1.2.8) + rack (>= 2.0.6) +@@ -1247,9 +1264,9 @@ + google-api-client (~> 0.23) + google-protobuf (~> 3.8.0) + gpgme (~> 2.0.19) +- grape (~> 1.1.0) ++ grape! + grape-entity (~> 0.7.1) +- grape-path-helpers (~> 1.2) ++ grape-path-helpers (~> 1.3) + grape_logging (~> 1.7) + graphiql-rails (~> 1.4.10) + graphql (~> 1.9.12) +--- /dev/null ++++ b/changelogs/unreleased/sh-update-grape-gem.yml +@@ -0,0 +1,5 @@ ++--- ++title: Upgrade Grape v1.1.0 to v1.3.1 ++merge_request: 27276 ++author: ++type: other +--- a/doc/development/ee_features.md ++++ b/doc/development/ee_features.md +@@ -516,12 +516,12 @@ + interface first here. + + For example, suppose we have a few more optional params for EE. We can move the +-params out of the `Grape::API` class to a helper module, so we can inject it ++params out of the `Grape::API::Instance` class to a helper module, so we can inject it + before it would be used in the class. + + ```ruby + module API +- class Projects < Grape::API ++ class Projects < Grape::API::Instance + helpers Helpers::ProjectsHelpers + end + end +@@ -582,7 +582,7 @@ + + ```ruby + module API +- class JobArtifacts < Grape::API ++ class JobArtifacts < Grape::API::Instance + # EE::API::JobArtifacts would override the following helpers + helpers do + def authorize_download_artifacts! +@@ -626,7 +626,7 @@ + + ```ruby + module API +- class MergeRequests < Grape::API ++ class MergeRequests < Grape::API::Instance + helpers do + # EE::API::MergeRequests would override the following helpers + def update_merge_request_ee(merge_request) +@@ -695,7 +695,7 @@ + ```ruby + # api/merge_requests/parameters.rb + module API +- class MergeRequests < Grape::API ++ class MergeRequests < Grape::API::Instance + module Parameters + def self.update_params_at_least_one_of + %i[ +@@ -711,7 +711,7 @@ + + # api/merge_requests.rb + module API +- class MergeRequests < Grape::API ++ class MergeRequests < Grape::API::Instance + params do + at_least_one_of(*Parameters.update_params_at_least_one_of) + end +--- a/lib/api/access_requests.rb ++++ b/lib/api/access_requests.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class AccessRequests < Grape::API ++ class AccessRequests < Grape::API::Instance + include PaginationParams + + before { authenticate! } +--- a/lib/api/api.rb ++++ b/lib/api/api.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class API < Grape::API ++ class API < Grape::API::Instance + include APIGuard + + LOG_FILENAME = Rails.root.join("log", "api_json.log") +--- a/lib/api/appearance.rb ++++ b/lib/api/appearance.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Appearance < Grape::API ++ class Appearance < Grape::API::Instance + before { authenticated_as_admin! } + + helpers do +@@ -24,9 +24,9 @@ + optional :title, type: String, desc: 'Instance title on the sign in / sign up page' + optional :description, type: String, desc: 'Markdown text shown on the sign in / sign up page' + # TODO: remove rubocop disable - https://gitlab.com/gitlab-org/gitlab/issues/14960 +- optional :logo, type: File, desc: 'Instance image used on the sign in / sign up page' # rubocop:disable Scalability/FileUploads +- optional :header_logo, type: File, desc: 'Instance image used for the main navigation bar' # rubocop:disable Scalability/FileUploads +- optional :favicon, type: File, desc: 'Instance favicon in .ico/.png format' # rubocop:disable Scalability/FileUploads ++ optional :logo, types: [File, ::API::Validations::Types::WorkhorseFile], desc: 'Instance image used on the sign in / sign up page' # rubocop:disable Scalability/FileUploads ++ optional :header_logo, types: [File, ::API::Validations::Types::WorkhorseFile], desc: 'Instance image used for the main navigation bar' # rubocop:disable Scalability/FileUploads ++ optional :favicon, types: [File, ::API::Validations::Types::WorkhorseFile], desc: 'Instance favicon in .ico/.png format' # rubocop:disable Scalability/FileUploads + optional :new_project_guidelines, type: String, desc: 'Markmarkdown text shown on the new project page' + optional :header_message, type: String, desc: 'Message within the system header bar' + optional :footer_message, type: String, desc: 'Message within the system footer bar' +--- a/lib/api/applications.rb ++++ b/lib/api/applications.rb +@@ -2,7 +2,7 @@ + + module API + # External applications API +- class Applications < Grape::API ++ class Applications < Grape::API::Instance + before { authenticated_as_admin! } + + resource :applications do +--- a/lib/api/avatar.rb ++++ b/lib/api/avatar.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Avatar < Grape::API ++ class Avatar < Grape::API::Instance + resource :avatar do + desc 'Return avatar url for a user' do + success Entities::Avatar +--- a/lib/api/award_emoji.rb ++++ b/lib/api/award_emoji.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class AwardEmoji < Grape::API ++ class AwardEmoji < Grape::API::Instance + include PaginationParams + + before { authenticate! } +--- a/lib/api/badges.rb ++++ b/lib/api/badges.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Badges < Grape::API ++ class Badges < Grape::API::Instance + include PaginationParams + + before { authenticate_non_get! } +--- a/lib/api/boards.rb ++++ b/lib/api/boards.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Boards < Grape::API ++ class Boards < Grape::API::Instance + include BoardsResponses + include PaginationParams + +--- a/lib/api/branches.rb ++++ b/lib/api/branches.rb +@@ -3,7 +3,7 @@ + require 'mime/types' + + module API +- class Branches < Grape::API ++ class Branches < Grape::API::Instance + include PaginationParams + + BRANCH_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(branch: API::NO_SLASH_URL_PART_REGEX) +--- a/lib/api/broadcast_messages.rb ++++ b/lib/api/broadcast_messages.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class BroadcastMessages < Grape::API ++ class BroadcastMessages < Grape::API::Instance + include PaginationParams + + resource :broadcast_messages do +--- a/lib/api/commit_statuses.rb ++++ b/lib/api/commit_statuses.rb +@@ -3,7 +3,7 @@ + require 'mime/types' + + module API +- class CommitStatuses < Grape::API ++ class CommitStatuses < Grape::API::Instance + params do + requires :id, type: String, desc: 'The ID of a project' + end +--- a/lib/api/commits.rb ++++ b/lib/api/commits.rb +@@ -3,7 +3,7 @@ + require 'mime/types' + + module API +- class Commits < Grape::API ++ class Commits < Grape::API::Instance + include PaginationParams + + before do +--- a/lib/api/deploy_keys.rb ++++ b/lib/api/deploy_keys.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class DeployKeys < Grape::API ++ class DeployKeys < Grape::API::Instance + include PaginationParams + + before { authenticate! } +--- a/lib/api/deployments.rb ++++ b/lib/api/deployments.rb +@@ -2,7 +2,7 @@ + + module API + # Deployments RESTful API endpoints +- class Deployments < Grape::API ++ class Deployments < Grape::API::Instance + include PaginationParams + + before { authenticate! } +--- a/lib/api/discussions.rb ++++ b/lib/api/discussions.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Discussions < Grape::API ++ class Discussions < Grape::API::Instance + include PaginationParams + helpers ::API::Helpers::NotesHelpers + helpers ::RendersNotes +--- a/lib/api/environments.rb ++++ b/lib/api/environments.rb +@@ -2,7 +2,7 @@ + + module API + # Environments RESTfull API endpoints +- class Environments < Grape::API ++ class Environments < Grape::API::Instance + include ::API::Helpers::CustomValidators + include PaginationParams + +--- a/lib/api/error_tracking.rb ++++ b/lib/api/error_tracking.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class ErrorTracking < Grape::API ++ class ErrorTracking < Grape::API::Instance + before { authenticate! } + + params do +--- a/lib/api/events.rb ++++ b/lib/api/events.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Events < Grape::API ++ class Events < Grape::API::Instance + include PaginationParams + include APIGuard + helpers ::API::Helpers::EventsHelpers +--- a/lib/api/features.rb ++++ b/lib/api/features.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Features < Grape::API ++ class Features < Grape::API::Instance + before { authenticated_as_admin! } + + helpers do +--- a/lib/api/files.rb ++++ b/lib/api/files.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Files < Grape::API ++ class Files < Grape::API::Instance + include APIGuard + + FILE_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(file_path: API::NO_SLASH_URL_PART_REGEX) +--- a/lib/api/group_boards.rb ++++ b/lib/api/group_boards.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class GroupBoards < Grape::API ++ class GroupBoards < Grape::API::Instance + include BoardsResponses + include PaginationParams + +--- a/lib/api/group_clusters.rb ++++ b/lib/api/group_clusters.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class GroupClusters < Grape::API ++ class GroupClusters < Grape::API::Instance + include PaginationParams + + before { authenticate! } +--- a/lib/api/group_container_repositories.rb ++++ b/lib/api/group_container_repositories.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class GroupContainerRepositories < Grape::API ++ class GroupContainerRepositories < Grape::API::Instance + include PaginationParams + + before { authorize_read_group_container_images! } +--- a/lib/api/group_export.rb ++++ b/lib/api/group_export.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class GroupExport < Grape::API ++ class GroupExport < Grape::API::Instance + before do + not_found! unless Feature.enabled?(:group_import_export, user_group, default_enabled: true) + +--- a/lib/api/group_import.rb ++++ b/lib/api/group_import.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class GroupImport < Grape::API ++ class GroupImport < Grape::API::Instance + MAXIMUM_FILE_SIZE = 50.megabytes.freeze + + helpers do +--- a/lib/api/group_labels.rb ++++ b/lib/api/group_labels.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class GroupLabels < Grape::API ++ class GroupLabels < Grape::API::Instance + include PaginationParams + helpers ::API::Helpers::LabelHelpers + +--- a/lib/api/group_milestones.rb ++++ b/lib/api/group_milestones.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class GroupMilestones < Grape::API ++ class GroupMilestones < Grape::API::Instance + include MilestoneResponses + include PaginationParams + +--- a/lib/api/group_variables.rb ++++ b/lib/api/group_variables.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class GroupVariables < Grape::API ++ class GroupVariables < Grape::API::Instance + include PaginationParams + + before { authenticate! } +--- a/lib/api/groups.rb ++++ b/lib/api/groups.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Groups < Grape::API ++ class Groups < Grape::API::Instance + include PaginationParams + include Helpers::CustomAttributes + +@@ -16,7 +16,7 @@ + + params :group_list_params do + use :statistics_params +- optional :skip_groups, type: Array[Integer], desc: 'Array of group ids to exclude from list' ++ optional :skip_groups, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'Array of group ids to exclude from list' + optional :all_available, type: Boolean, desc: 'Show all group that you have access to' + optional :search, type: String, desc: 'Search for a specific group' + optional :owned, type: Boolean, default: false, desc: 'Limit by owned by authenticated user' +--- a/lib/api/import_github.rb ++++ b/lib/api/import_github.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class ImportGithub < Grape::API ++ class ImportGithub < Grape::API::Instance + rescue_from Octokit::Unauthorized, with: :provider_unauthorized + + helpers do +--- a/lib/api/internal/base.rb ++++ b/lib/api/internal/base.rb +@@ -3,7 +3,7 @@ + module API + # Internal access API + module Internal +- class Base < Grape::API ++ class Base < Grape::API::Instance + before { authenticate_by_gitlab_shell_token! } + + before do +--- a/lib/api/internal/pages.rb ++++ b/lib/api/internal/pages.rb +@@ -3,7 +3,7 @@ + module API + # Pages Internal API + module Internal +- class Pages < Grape::API ++ class Pages < Grape::API::Instance + before do + not_found! unless Feature.enabled?(:pages_internal_api) + authenticate_gitlab_pages_request! +--- a/lib/api/issues.rb ++++ b/lib/api/issues.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Issues < Grape::API ++ class Issues < Grape::API::Instance + include PaginationParams + helpers Helpers::IssuesHelpers + helpers ::Gitlab::IssuableMetadata +@@ -10,9 +10,9 @@ + + helpers do + params :negatable_issue_filter_params do +- optional :labels, type: Array[String], coerce_with: Validations::Types::LabelsList.coerce, desc: 'Comma-separated list of label names' ++ optional :labels, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Comma-separated list of label names' + optional :milestone, type: String, desc: 'Milestone title' +- optional :iids, type: Array[Integer], desc: 'The IID array of issues' ++ optional :iids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'The IID array of issues' + optional :search, type: String, desc: 'Search issues for text present in the title, description, or any combination of these' + optional :in, type: String, desc: '`title`, `description`, or a string joining them with comma' + +@@ -62,10 +62,10 @@ + + params :issue_params do + optional :description, type: String, desc: 'The description of an issue' +- optional :assignee_ids, type: Array[Integer], desc: 'The array of user IDs to assign issue' ++ optional :assignee_ids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'The array of user IDs to assign issue' + optional :assignee_id, type: Integer, desc: '[Deprecated] The ID of a user to assign issue' + optional :milestone_id, type: Integer, desc: 'The ID of a milestone to assign issue' +- optional :labels, type: Array[String], coerce_with: Validations::Types::LabelsList.coerce, desc: 'Comma-separated list of label names' ++ optional :labels, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Comma-separated list of label names' + optional :due_date, type: String, desc: 'Date string in the format YEAR-MONTH-DAY' + optional :confidential, type: Boolean, desc: 'Boolean parameter if the issue should be confidential' + optional :discussion_locked, type: Boolean, desc: " Boolean parameter indicating if the issue's discussion is locked" +--- a/lib/api/job_artifacts.rb ++++ b/lib/api/job_artifacts.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class JobArtifacts < Grape::API ++ class JobArtifacts < Grape::API::Instance + before { authenticate_non_get! } + + # EE::API::JobArtifacts would override the following helpers +--- a/lib/api/jobs.rb ++++ b/lib/api/jobs.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Jobs < Grape::API ++ class Jobs < Grape::API::Instance + include PaginationParams + + before { authenticate! } +--- a/lib/api/keys.rb ++++ b/lib/api/keys.rb +@@ -2,7 +2,7 @@ + + module API + # Keys API +- class Keys < Grape::API ++ class Keys < Grape::API::Instance + before { authenticate! } + + resource :keys do +--- a/lib/api/labels.rb ++++ b/lib/api/labels.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Labels < Grape::API ++ class Labels < Grape::API::Instance + include PaginationParams + helpers ::API::Helpers::LabelHelpers + +--- a/lib/api/lint.rb ++++ b/lib/api/lint.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Lint < Grape::API ++ class Lint < Grape::API::Instance + namespace :ci do + desc 'Validation of .gitlab-ci.yml content' + params do +--- a/lib/api/lsif_data.rb ++++ b/lib/api/lsif_data.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class LsifData < Grape::API ++ class LsifData < Grape::API::Instance + MAX_FILE_SIZE = 10.megabytes + + before do +--- a/lib/api/markdown.rb ++++ b/lib/api/markdown.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Markdown < Grape::API ++ class Markdown < Grape::API::Instance + params do + requires :text, type: String, desc: "The markdown text to render" + optional :gfm, type: Boolean, desc: "Render text using GitLab Flavored Markdown" +--- a/lib/api/members.rb ++++ b/lib/api/members.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Members < Grape::API ++ class Members < Grape::API::Instance + include PaginationParams + + before { authenticate! } +@@ -18,7 +18,7 @@ + end + params do + optional :query, type: String, desc: 'A query string to search for members' +- optional :user_ids, type: Array[Integer], desc: 'Array of user ids to look up for membership' ++ optional :user_ids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'Array of user ids to look up for membership' + optional :show_seat_info, type: Boolean, desc: 'Show seat information for members' + use :optional_filter_params_ee + use :pagination +@@ -37,7 +37,7 @@ + end + params do + optional :query, type: String, desc: 'A query string to search for members' +- optional :user_ids, type: Array[Integer], desc: 'Array of user ids to look up for membership' ++ optional :user_ids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'Array of user ids to look up for membership' + optional :show_seat_info, type: Boolean, desc: 'Show seat information for members' + use :pagination + end +--- a/lib/api/merge_request_diffs.rb ++++ b/lib/api/merge_request_diffs.rb +@@ -2,7 +2,7 @@ + + module API + # MergeRequestDiff API +- class MergeRequestDiffs < Grape::API ++ class MergeRequestDiffs < Grape::API::Instance + include PaginationParams + + before { authenticate! } +--- a/lib/api/merge_requests.rb ++++ b/lib/api/merge_requests.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class MergeRequests < Grape::API ++ class MergeRequests < Grape::API::Instance + include PaginationParams + + CONTEXT_COMMITS_POST_LIMIT = 20 +@@ -177,9 +177,9 @@ + params :optional_params do + optional :description, type: String, desc: 'The description of the merge request' + optional :assignee_id, type: Integer, desc: 'The ID of a user to assign the merge request' +- optional :assignee_ids, type: Array[Integer], desc: 'The array of user IDs to assign issue' ++ optional :assignee_ids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'The array of user IDs to assign issue' + optional :milestone_id, type: Integer, desc: 'The ID of a milestone to assign the merge request' +- optional :labels, type: Array[String], coerce_with: Validations::Types::LabelsList.coerce, desc: 'Comma-separated list of label names' ++ optional :labels, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Comma-separated list of label names' + optional :remove_source_branch, type: Boolean, desc: 'Remove source branch when merging' + optional :allow_collaboration, type: Boolean, desc: 'Allow commits from members who can merge to the target branch' + optional :allow_maintainer_to_push, type: Boolean, as: :allow_collaboration, desc: '[deprecated] See allow_collaboration' +@@ -194,7 +194,7 @@ + end + params do + use :merge_requests_params +- optional :iids, type: Array[Integer], desc: 'The IID array of merge requests' ++ optional :iids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'The IID array of merge requests' + end + get ":id/merge_requests" do + authorize! :read_merge_request, user_project +--- a/lib/api/namespaces.rb ++++ b/lib/api/namespaces.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Namespaces < Grape::API ++ class Namespaces < Grape::API::Instance + include PaginationParams + + before { authenticate! } +--- a/lib/api/notes.rb ++++ b/lib/api/notes.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Notes < Grape::API ++ class Notes < Grape::API::Instance + include PaginationParams + helpers ::API::Helpers::NotesHelpers + +--- a/lib/api/notification_settings.rb ++++ b/lib/api/notification_settings.rb +@@ -2,7 +2,7 @@ + + module API + # notification_settings API +- class NotificationSettings < Grape::API ++ class NotificationSettings < Grape::API::Instance + before { authenticate! } + + helpers ::API::Helpers::MembersHelpers +--- a/lib/api/pages.rb ++++ b/lib/api/pages.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Pages < Grape::API ++ class Pages < Grape::API::Instance + before do + require_pages_config_enabled! + authenticated_with_can_read_all_resources! +--- a/lib/api/pages_domains.rb ++++ b/lib/api/pages_domains.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class PagesDomains < Grape::API ++ class PagesDomains < Grape::API::Instance + include PaginationParams + + PAGES_DOMAINS_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(domain: API::NO_SLASH_URL_PART_REGEX) +--- a/lib/api/pagination_params.rb ++++ b/lib/api/pagination_params.rb +@@ -4,7 +4,7 @@ + # Concern for declare pagination params. + # + # @example +- # class CustomApiResource < Grape::API ++ # class CustomApiResource < Grape::API::Instance + # include PaginationParams + # + # params do +--- a/lib/api/pipeline_schedules.rb ++++ b/lib/api/pipeline_schedules.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class PipelineSchedules < Grape::API ++ class PipelineSchedules < Grape::API::Instance + include PaginationParams + + before { authenticate! } +--- a/lib/api/pipelines.rb ++++ b/lib/api/pipelines.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Pipelines < Grape::API ++ class Pipelines < Grape::API::Instance + include PaginationParams + + before { authenticate_non_get! } +--- a/lib/api/project_clusters.rb ++++ b/lib/api/project_clusters.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class ProjectClusters < Grape::API ++ class ProjectClusters < Grape::API::Instance + include PaginationParams + + before { authenticate! } +--- a/lib/api/project_container_repositories.rb ++++ b/lib/api/project_container_repositories.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class ProjectContainerRepositories < Grape::API ++ class ProjectContainerRepositories < Grape::API::Instance + include PaginationParams + + REPOSITORY_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge( +--- a/lib/api/project_events.rb ++++ b/lib/api/project_events.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class ProjectEvents < Grape::API ++ class ProjectEvents < Grape::API::Instance + include PaginationParams + include APIGuard + helpers ::API::Helpers::EventsHelpers +--- a/lib/api/project_export.rb ++++ b/lib/api/project_export.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class ProjectExport < Grape::API ++ class ProjectExport < Grape::API::Instance + helpers do + def throttled?(action) + rate_limiter.throttled?(action, scope: [current_user, action, user_project]) +--- a/lib/api/project_hooks.rb ++++ b/lib/api/project_hooks.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class ProjectHooks < Grape::API ++ class ProjectHooks < Grape::API::Instance + include PaginationParams + + before { authenticate! } +--- a/lib/api/project_import.rb ++++ b/lib/api/project_import.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class ProjectImport < Grape::API ++ class ProjectImport < Grape::API::Instance + include PaginationParams + + helpers Helpers::ProjectsHelpers +--- a/lib/api/project_milestones.rb ++++ b/lib/api/project_milestones.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class ProjectMilestones < Grape::API ++ class ProjectMilestones < Grape::API::Instance + include PaginationParams + include MilestoneResponses + +--- a/lib/api/project_snapshots.rb ++++ b/lib/api/project_snapshots.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class ProjectSnapshots < Grape::API ++ class ProjectSnapshots < Grape::API::Instance + helpers ::API::Helpers::ProjectSnapshotsHelpers + + before { authorize_read_git_snapshot! } +--- a/lib/api/project_snippets.rb ++++ b/lib/api/project_snippets.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class ProjectSnippets < Grape::API ++ class ProjectSnippets < Grape::API::Instance + include PaginationParams + + before { authenticate! } +--- a/lib/api/project_statistics.rb ++++ b/lib/api/project_statistics.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class ProjectStatistics < Grape::API ++ class ProjectStatistics < Grape::API::Instance + before do + authenticate! + not_found! unless user_project.daily_statistics_enabled? +--- a/lib/api/project_templates.rb ++++ b/lib/api/project_templates.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class ProjectTemplates < Grape::API ++ class ProjectTemplates < Grape::API::Instance + include PaginationParams + + TEMPLATE_TYPES = %w[dockerfiles gitignores gitlab_ci_ymls licenses].freeze +--- a/lib/api/projects.rb ++++ b/lib/api/projects.rb +@@ -3,7 +3,7 @@ + require_dependency 'declarative_policy' + + module API +- class Projects < Grape::API ++ class Projects < Grape::API::Instance + include PaginationParams + include Helpers::CustomAttributes + +@@ -493,7 +493,7 @@ + desc 'Upload a file' + params do + # TODO: remove rubocop disable - https://gitlab.com/gitlab-org/gitlab/issues/14960 +- requires :file, type: File, desc: 'The file to be uploaded' # rubocop:disable Scalability/FileUploads ++ requires :file, types: [File, ::API::Validations::Types::WorkhorseFile], desc: 'The file to be uploaded' # rubocop:disable Scalability/FileUploads + end + post ":id/uploads" do + UploadService.new(user_project, params[:file]).execute.to_h +@@ -504,7 +504,7 @@ + end + params do + optional :search, type: String, desc: 'Return list of users matching the search criteria' +- optional :skip_users, type: Array[Integer], desc: 'Filter out users with the specified IDs' ++ optional :skip_users, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'Filter out users with the specified IDs' + use :pagination + end + get ':id/users' do +--- a/lib/api/protected_branches.rb ++++ b/lib/api/protected_branches.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class ProtectedBranches < Grape::API ++ class ProtectedBranches < Grape::API::Instance + include PaginationParams + + BRANCH_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(name: API::NO_SLASH_URL_PART_REGEX) +--- a/lib/api/protected_tags.rb ++++ b/lib/api/protected_tags.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class ProtectedTags < Grape::API ++ class ProtectedTags < Grape::API::Instance + include PaginationParams + + TAG_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(name: API::NO_SLASH_URL_PART_REGEX) +--- a/lib/api/release/links.rb ++++ b/lib/api/release/links.rb +@@ -2,7 +2,7 @@ + + module API + module Release +- class Links < Grape::API ++ class Links < Grape::API::Instance + include PaginationParams + + RELEASE_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS +--- a/lib/api/releases.rb ++++ b/lib/api/releases.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Releases < Grape::API ++ class Releases < Grape::API::Instance + include PaginationParams + + RELEASE_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS +--- a/lib/api/remote_mirrors.rb ++++ b/lib/api/remote_mirrors.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class RemoteMirrors < Grape::API ++ class RemoteMirrors < Grape::API::Instance + include PaginationParams + + before do +--- a/lib/api/repositories.rb ++++ b/lib/api/repositories.rb +@@ -3,7 +3,7 @@ + require 'mime/types' + + module API +- class Repositories < Grape::API ++ class Repositories < Grape::API::Instance + include PaginationParams + + before { authorize! :download_code, user_project } +@@ -131,7 +131,7 @@ + success Entities::Commit + end + params do +- requires :refs, type: Array[String] ++ requires :refs, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce + end + get ':id/repository/merge_base' do + refs = params[:refs] +--- a/lib/api/resource_label_events.rb ++++ b/lib/api/resource_label_events.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class ResourceLabelEvents < Grape::API ++ class ResourceLabelEvents < Grape::API::Instance + include PaginationParams + helpers ::API::Helpers::NotesHelpers + +--- a/lib/api/runner.rb ++++ b/lib/api/runner.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Runner < Grape::API ++ class Runner < Grape::API::Instance + helpers ::API::Helpers::Runner + + resource :runners do +@@ -18,7 +18,7 @@ + optional :access_level, type: String, values: Ci::Runner.access_levels.keys, + desc: 'The access_level of the runner' + optional :run_untagged, type: Boolean, desc: 'Should Runner handle untagged jobs' +- optional :tag_list, type: Array[String], desc: %q(List of Runner's tags) ++ optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: %q(List of Runner's tags) + optional :maximum_timeout, type: Integer, desc: 'Maximum timeout set when this Runner will handle the job' + end + post '/' do +--- a/lib/api/runners.rb ++++ b/lib/api/runners.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Runners < Grape::API ++ class Runners < Grape::API::Instance + include PaginationParams + + before { authenticate! } +@@ -17,7 +17,7 @@ + desc: 'The type of the runners to show' + optional :status, type: String, values: Ci::Runner::AVAILABLE_STATUSES, + desc: 'The status of the runners to show' +- optional :tag_list, type: Array[String], desc: 'The tags of the runners to show' ++ optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The tags of the runners to show' + use :pagination + end + get do +@@ -40,7 +40,7 @@ + desc: 'The type of the runners to show' + optional :status, type: String, values: Ci::Runner::AVAILABLE_STATUSES, + desc: 'The status of the runners to show' +- optional :tag_list, type: Array[String], desc: 'The tags of the runners to show' ++ optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The tags of the runners to show' + use :pagination + end + get 'all' do +@@ -75,7 +75,7 @@ + requires :id, type: Integer, desc: 'The ID of the runner' + optional :description, type: String, desc: 'The description of the runner' + optional :active, type: Boolean, desc: 'The state of a runner' +- optional :tag_list, type: Array[String], desc: 'The list of tags for a runner' ++ optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The list of tags for a runner' + optional :run_untagged, type: Boolean, desc: 'Flag indicating the runner can execute untagged jobs' + optional :locked, type: Boolean, desc: 'Flag indicating the runner is locked' + optional :access_level, type: String, values: Ci::Runner.access_levels.keys, +@@ -145,7 +145,7 @@ + desc: 'The type of the runners to show' + optional :status, type: String, values: Ci::Runner::AVAILABLE_STATUSES, + desc: 'The status of the runners to show' +- optional :tag_list, type: Array[String], desc: 'The tags of the runners to show' ++ optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The tags of the runners to show' + use :pagination + end + get ':id/runners' do +--- a/lib/api/search.rb ++++ b/lib/api/search.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Search < Grape::API ++ class Search < Grape::API::Instance + include PaginationParams + + before { authenticate! } +--- a/lib/api/services.rb ++++ b/lib/api/services.rb +@@ -1,6 +1,6 @@ + # frozen_string_literal: true + module API +- class Services < Grape::API ++ class Services < Grape::API::Instance + services = Helpers::ServicesHelpers.services + service_classes = Helpers::ServicesHelpers.service_classes + +--- a/lib/api/settings.rb ++++ b/lib/api/settings.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Settings < Grape::API ++ class Settings < Grape::API::Instance + before { authenticated_as_admin! } + + helpers Helpers::SettingsHelpers +--- a/lib/api/sidekiq_metrics.rb ++++ b/lib/api/sidekiq_metrics.rb +@@ -3,7 +3,7 @@ + require 'sidekiq/api' + + module API +- class SidekiqMetrics < Grape::API ++ class SidekiqMetrics < Grape::API::Instance + before { authenticated_as_admin! } + + helpers do +--- a/lib/api/snippets.rb ++++ b/lib/api/snippets.rb +@@ -2,7 +2,7 @@ + + module API + # Snippets API +- class Snippets < Grape::API ++ class Snippets < Grape::API::Instance + include PaginationParams + + before { authenticate! } +--- a/lib/api/statistics.rb ++++ b/lib/api/statistics.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Statistics < Grape::API ++ class Statistics < Grape::API::Instance + before { authenticated_as_admin! } + + COUNTED_ITEMS = [Project, User, Group, ForkNetworkMember, ForkNetwork, Issue, +--- a/lib/api/submodules.rb ++++ b/lib/api/submodules.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Submodules < Grape::API ++ class Submodules < Grape::API::Instance + before { authenticate! } + + helpers do +--- a/lib/api/subscriptions.rb ++++ b/lib/api/subscriptions.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Subscriptions < Grape::API ++ class Subscriptions < Grape::API::Instance + helpers ::API::Helpers::LabelHelpers + + before { authenticate! } +--- a/lib/api/suggestions.rb ++++ b/lib/api/suggestions.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Suggestions < Grape::API ++ class Suggestions < Grape::API::Instance + before { authenticate! } + + resource :suggestions do +--- a/lib/api/system_hooks.rb ++++ b/lib/api/system_hooks.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class SystemHooks < Grape::API ++ class SystemHooks < Grape::API::Instance + include PaginationParams + + before do +--- a/lib/api/tags.rb ++++ b/lib/api/tags.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Tags < Grape::API ++ class Tags < Grape::API::Instance + include PaginationParams + + TAG_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(tag_name: API::NO_SLASH_URL_PART_REGEX) +--- a/lib/api/templates.rb ++++ b/lib/api/templates.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Templates < Grape::API ++ class Templates < Grape::API::Instance + include PaginationParams + + GLOBAL_TEMPLATE_TYPES = { +--- a/lib/api/todos.rb ++++ b/lib/api/todos.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Todos < Grape::API ++ class Todos < Grape::API::Instance + include PaginationParams + + before { authenticate! } +--- a/lib/api/triggers.rb ++++ b/lib/api/triggers.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Triggers < Grape::API ++ class Triggers < Grape::API::Instance + include PaginationParams + + HTTP_GITLAB_EVENT_HEADER = "HTTP_#{WebHookService::GITLAB_EVENT_HEADER}".underscore.upcase +--- a/lib/api/user_counts.rb ++++ b/lib/api/user_counts.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class UserCounts < Grape::API ++ class UserCounts < Grape::API::Instance + resource :user_counts do + desc 'Return the user specific counts' do + detail 'Open MR Count' +--- a/lib/api/users.rb ++++ b/lib/api/users.rb +@@ -51,7 +51,7 @@ + optional :can_create_group, type: Boolean, desc: 'Flag indicating the user can create groups' + optional :external, type: Boolean, desc: 'Flag indicating the user is an external user' + # TODO: remove rubocop disable - https://gitlab.com/gitlab-org/gitlab/issues/14960 +- optional :avatar, type: File, desc: 'Avatar image for user' # rubocop:disable Scalability/FileUploads ++ optional :avatar, types: [File, ::API::Validations::Types::WorkhorseFile], desc: 'Avatar image for user' # rubocop:disable Scalability/FileUploads + optional :theme_id, type: Integer, default: 1, desc: 'The GitLab theme for the user' + optional :color_scheme_id, type: Integer, default: 1, desc: 'The color scheme for the file viewer' + optional :private_profile, type: Boolean, desc: 'Flag indicating the user has a private profile' +--- a/lib/api/validations/types/workhorse_file.rb ++++ b/lib/api/validations/types/workhorse_file.rb +@@ -3,15 +3,14 @@ + module API + module Validations + module Types +- class WorkhorseFile < Virtus::Attribute +- def coerce(input) +- # Processing of multipart file objects +- # is already taken care of by Gitlab::Middleware::Multipart. +- # Nothing to do here. +- input ++ class WorkhorseFile ++ def self.parse(value) ++ raise "#{value.class} is not an UploadedFile type" unless parsed?(value) ++ ++ value + end + +- def value_coerced?(value) ++ def self.parsed?(value) + value.is_a?(::UploadedFile) + end + end +--- a/lib/api/variables.rb ++++ b/lib/api/variables.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Variables < Grape::API ++ class Variables < Grape::API::Instance + include PaginationParams + + before { authenticate! } +--- a/lib/api/version.rb ++++ b/lib/api/version.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Version < Grape::API ++ class Version < Grape::API::Instance + helpers ::API::Helpers::GraphqlHelpers + + before { authenticate! } +--- a/lib/api/wikis.rb ++++ b/lib/api/wikis.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Wikis < Grape::API ++ class Wikis < Grape::API::Instance + helpers do + def commit_params(attrs) + # In order to avoid service disruption this can work with an old workhorse without the acceleration +@@ -117,7 +117,7 @@ + success Entities::WikiAttachment + end + params do +- requires :file, types: [::API::Validations::Types::SafeFile, ::API::Validations::Types::WorkhorseFile], desc: 'The attachment file to be uploaded' ++ requires :file, types: [Rack::Multipart::UploadedFile, ::API::Validations::Types::WorkhorseFile], desc: 'The attachment file to be uploaded' + optional :branch, type: String, desc: 'The name of the branch' + end + post ":id/wikis/attachments" do +--- a/spec/rubocop/cop/code_reuse/worker_spec.rb ++++ b/spec/rubocop/cop/code_reuse/worker_spec.rb +@@ -31,7 +31,7 @@ + .and_return(true) + + expect_offense(<<~SOURCE) +- class Foo < Grape::API ++ class Foo < Grape::API::Instance + resource :projects do + get '/' do + FooWorker.perform_async +--- a/lib/api/api_guard.rb ++++ b/lib/api/api_guard.rb +@@ -148,7 +148,16 @@ + { scope: e.scopes }) + end + +- response.finish ++ finished_response = nil ++ response.finish do |rack_response| ++ # Grape expects a Rack::Response ++ # (https://github.com/ruby-grape/grape/commit/c117bff7d22971675f4b34367d3a98bc31c8fc02), ++ # and we need to retrieve it here: ++ # https://github.com/nov/rack-oauth2/blob/40c9a99fd80486ccb8de0e4869ae384547c0d703/lib/rack/oauth2/server/abstract/error.rb#L28 ++ finished_response = rack_response ++ end ++ ++ finished_response + end + end + end +--- a/lib/api/validations/types/safe_file.rb ++++ /dev/null +@@ -1,15 +0,0 @@ +-# frozen_string_literal: true +- +-# This module overrides the Grape type validator defined in +-# https://github.com/ruby-grape/grape/blob/master/lib/grape/validations/types/file.rb +-module API +- module Validations +- module Types +- class SafeFile < ::Grape::Validations::Types::File +- def value_coerced?(value) +- super && value[:tempfile].is_a?(Tempfile) +- end +- end +- end +- end +-end +--- a/lib/api/milestone_responses.rb ++++ b/lib/api/milestone_responses.rb +@@ -15,7 +15,7 @@ + params :list_params do + optional :state, type: String, values: %w[active closed all], default: 'all', + desc: 'Return "active", "closed", or "all" milestones' +- optional :iids, type: Array[Integer], desc: 'The IIDs of the milestones' ++ optional :iids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'The IIDs of the milestones' + optional :title, type: String, desc: 'The title of the milestones' + optional :search, type: String, desc: 'The search criteria for the title or description of the milestone' + use :pagination +--- /dev/null ++++ b/lib/api/validations/types/comma_separated_to_integer_array.rb +@@ -0,0 +1,15 @@ ++# frozen_string_literal: true ++ ++module API ++ module Validations ++ module Types ++ class CommaSeparatedToIntegerArray < CommaSeparatedToArray ++ def self.coerce ++ lambda do |value| ++ super.call(value).map(&:to_i) ++ end ++ end ++ end ++ end ++ end ++end +--- a/lib/api/helpers/projects_helpers.rb ++++ b/lib/api/helpers/projects_helpers.rb +@@ -45,7 +45,7 @@ + optional :only_allow_merge_if_all_discussions_are_resolved, type: Boolean, desc: 'Only allow to merge if all discussions are resolved' + optional :tag_list, type: Array[String], desc: 'The list of tags for a project' + # TODO: remove rubocop disable - https://gitlab.com/gitlab-org/gitlab/issues/14960 +- optional :avatar, type: File, desc: 'Avatar image for project' # rubocop:disable Scalability/FileUploads ++ optional :avatar, types: [File, ::API::Validations::Types::WorkhorseFile], desc: 'Avatar image for project' # rubocop:disable Scalability/FileUploads + optional :printing_merge_request_link_enabled, type: Boolean, desc: 'Show link to create/view merge request when pushing from the command line' + optional :merge_method, type: String, values: %w(ff rebase_merge merge), desc: 'The merge method used when merging merge requests' + optional :suggestion_commit_message, type: String, desc: 'The commit message used to apply merge request suggestions' +--- a/lib/api/helpers/merge_requests_helpers.rb ++++ b/lib/api/helpers/merge_requests_helpers.rb +@@ -25,7 +25,7 @@ + optional :milestone, type: String, desc: 'Return merge requests for a specific milestone' + optional :labels, + type: Array[String], +- coerce_with: Validations::Types::LabelsList.coerce, ++ coerce_with: Validations::Types::CommaSeparatedToArray.coerce, + desc: 'Comma-separated list of label names' + optional :with_labels_details, type: Boolean, desc: 'Return titles of labels and other details', default: false + optional :created_after, type: DateTime, desc: 'Return merge requests created after the specified time' +--- a/lib/api/validations/types/labels_list.rb ++++ /dev/null +@@ -1,24 +0,0 @@ +-# frozen_string_literal: true +- +-module API +- module Validations +- module Types +- class LabelsList +- def self.coerce +- lambda do |value| +- case value +- when String +- value.split(',').map(&:strip) +- when Array +- value.flat_map { |v| v.to_s.split(',').map(&:strip) } +- when LabelsList +- value +- else +- [] +- end +- end +- end +- end +- end +- end +-end +--- a/lib/api/users.rb ++++ b/lib/api/users.rb +@@ -1,7 +1,7 @@ + # frozen_string_literal: true + + module API +- class Users < Grape::API ++ class Users < Grape::API::Instance + include PaginationParams + include APIGuard + include Helpers::CustomAttributes diff --git a/debian/patches/series b/debian/patches/series index 868c5e3a26..8bb0395120 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -26,3 +26,4 @@ 0730-install-graphql-tag.patch 0740-use-packaged-modules.patch 0750-fix-relative-paths.patch +0760-update-grape.patch