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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib/api
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-05-19 18:44:42 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-05-19 18:44:42 +0300
commit4555e1b21c365ed8303ffb7a3325d773c9b8bf31 (patch)
tree5423a1c7516cffe36384133ade12572cf709398d /lib/api
parente570267f2f6b326480d284e0164a6464ba4081bc (diff)
Add latest changes from gitlab-org/gitlab@13-12-stable-eev13.12.0-rc42
Diffstat (limited to 'lib/api')
-rw-r--r--lib/api/api.rb29
-rw-r--r--lib/api/award_emoji.rb38
-rw-r--r--lib/api/boards.rb2
-rw-r--r--lib/api/branches.rb48
-rw-r--r--lib/api/ci/runner.rb4
-rw-r--r--lib/api/concerns/packages/debian_endpoints.rb133
-rw-r--r--lib/api/debian_group_packages.rb4
-rw-r--r--lib/api/debian_package_endpoints.rb127
-rw-r--r--lib/api/debian_project_packages.rb6
-rw-r--r--lib/api/deploy_tokens.rb31
-rw-r--r--lib/api/deployments.rb2
-rw-r--r--lib/api/entities/application_setting.rb2
-rw-r--r--lib/api/entities/board.rb2
-rw-r--r--lib/api/entities/bulk_imports/export_status.rb14
-rw-r--r--lib/api/entities/ci/job_basic.rb5
-rw-r--r--lib/api/entities/ci/pipeline.rb1
-rw-r--r--lib/api/entities/deploy_token.rb3
-rw-r--r--lib/api/entities/environment.rb39
-rw-r--r--lib/api/entities/group.rb2
-rw-r--r--lib/api/entities/group_detail.rb2
-rw-r--r--lib/api/entities/identity.rb2
-rw-r--r--lib/api/entities/issuable_entity.rb2
-rw-r--r--lib/api/entities/issue.rb2
-rw-r--r--lib/api/entities/issue_basic.rb11
-rw-r--r--lib/api/entities/job_request/response.rb2
-rw-r--r--lib/api/entities/label_basic.rb2
-rw-r--r--lib/api/entities/list.rb2
-rw-r--r--lib/api/entities/member.rb2
-rw-r--r--lib/api/entities/merge_request_basic.rb2
-rw-r--r--lib/api/entities/namespace.rb2
-rw-r--r--lib/api/entities/package.rb1
-rw-r--r--lib/api/entities/package_file.rb2
-rw-r--r--lib/api/entities/project.rb2
-rw-r--r--lib/api/entities/protected_branch.rb2
-rw-r--r--lib/api/entities/protected_ref_access.rb2
-rw-r--r--lib/api/entities/release.rb11
-rw-r--r--lib/api/entities/terraform/module_versions.rb11
-rw-r--r--lib/api/entities/todo.rb2
-rw-r--r--lib/api/entities/user_basic.rb2
-rw-r--r--lib/api/entities/user_credit_card_validations.rb9
-rw-r--r--lib/api/entities/user_details_with_admin.rb2
-rw-r--r--lib/api/entities/user_path.rb2
-rw-r--r--lib/api/entities/user_public.rb2
-rw-r--r--lib/api/entities/user_with_admin.rb2
-rw-r--r--lib/api/environments.rb2
-rw-r--r--lib/api/features.rb2
-rw-r--r--lib/api/generic_packages.rb2
-rw-r--r--lib/api/group_boards.rb2
-rw-r--r--lib/api/group_export.rb37
-rw-r--r--lib/api/group_milestones.rb2
-rw-r--r--lib/api/groups.rb2
-rw-r--r--lib/api/helpers.rb36
-rw-r--r--lib/api/helpers/award_emoji.rb40
-rw-r--r--lib/api/helpers/caching.rb65
-rw-r--r--lib/api/helpers/common_helpers.rb2
-rw-r--r--lib/api/helpers/discussions_helpers.rb2
-rw-r--r--lib/api/helpers/groups_helpers.rb2
-rw-r--r--lib/api/helpers/headers_helpers.rb2
-rw-r--r--lib/api/helpers/internal_helpers.rb2
-rw-r--r--lib/api/helpers/issues_helpers.rb6
-rw-r--r--lib/api/helpers/label_helpers.rb17
-rw-r--r--lib/api/helpers/members_helpers.rb4
-rw-r--r--lib/api/helpers/notes_helpers.rb2
-rw-r--r--lib/api/helpers/performance_bar_helpers.rb6
-rw-r--r--lib/api/helpers/project_snapshots_helpers.rb2
-rw-r--r--lib/api/helpers/projects_helpers.rb2
-rw-r--r--lib/api/helpers/protected_branches_helpers.rb2
-rw-r--r--lib/api/helpers/related_resources_helpers.rb4
-rw-r--r--lib/api/helpers/resource_label_events_helpers.rb2
-rw-r--r--lib/api/helpers/runner.rb6
-rw-r--r--lib/api/helpers/search_helpers.rb2
-rw-r--r--lib/api/helpers/services_helpers.rb57
-rw-r--r--lib/api/helpers/settings_helpers.rb2
-rw-r--r--lib/api/helpers/users_helpers.rb2
-rw-r--r--lib/api/helpers/variables_helpers.rb2
-rw-r--r--lib/api/helpers/wikis_helpers.rb2
-rw-r--r--lib/api/internal/base.rb4
-rw-r--r--lib/api/internal/kubernetes.rb18
-rw-r--r--lib/api/issue_links.rb4
-rw-r--r--lib/api/issues.rb24
-rw-r--r--lib/api/job_artifacts.rb2
-rw-r--r--lib/api/jobs.rb2
-rw-r--r--lib/api/maven_packages.rb14
-rw-r--r--lib/api/members.rb2
-rw-r--r--lib/api/merge_request_approvals.rb6
-rw-r--r--lib/api/merge_requests.rb20
-rw-r--r--lib/api/namespaces.rb2
-rw-r--r--lib/api/package_files.rb23
-rw-r--r--lib/api/project_container_repositories.rb1
-rw-r--r--lib/api/project_import.rb90
-rw-r--r--lib/api/project_milestones.rb2
-rw-r--r--lib/api/project_templates.rb4
-rw-r--r--lib/api/projects.rb7
-rw-r--r--lib/api/protected_branches.rb2
-rw-r--r--lib/api/pypi_packages.rb23
-rw-r--r--lib/api/releases.rb37
-rw-r--r--lib/api/repositories.rb8
-rw-r--r--lib/api/search.rb2
-rw-r--r--lib/api/services.rb13
-rw-r--r--lib/api/settings.rb5
-rw-r--r--lib/api/templates.rb3
-rw-r--r--lib/api/terraform/modules/v1/packages.rb200
-rw-r--r--lib/api/time_tracking_endpoints.rb15
-rw-r--r--lib/api/todos.rb4
-rw-r--r--lib/api/triggers.rb2
-rw-r--r--lib/api/users.rb24
-rw-r--r--lib/api/validations/validators/check_assignees_count.rb2
-rw-r--r--lib/api/validations/validators/file_path.rb2
108 files changed, 1002 insertions, 460 deletions
diff --git a/lib/api/api.rb b/lib/api/api.rb
index a287ffbfcd8..54e5cc5c8d0 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -130,32 +130,6 @@ module API
formatter :json, Gitlab::Json::GrapeFormatter
content_type :json, 'application/json'
- # Remove the `text/plain+deprecated` with `api_always_use_application_json` feature flag
- # There is a small chance some users depend on the old behavior.
- # We this change under a feature flag to see if affects GitLab.com users.
- # The `+deprecated` is added to distinguish content type
- # as defined by `API::API` vs ex. `API::Repositories`
- content_type :txt, 'text/plain+deprecated'
-
- before do
- # the feature flag workaround is only for `.txt`
- api_format = env[Grape::Env::API_FORMAT]
- next unless api_format == :txt
-
- # get all defined content-types for the endpoint
- api_endpoint = env[Grape::Env::API_ENDPOINT]
- content_types = api_endpoint&.namespace_stackable_with_hash(:content_types).to_h
-
- # Only overwrite `text/plain+deprecated`
- if content_types[api_format] == 'text/plain+deprecated'
- if Feature.enabled?(:api_always_use_application_json, default_enabled: :yaml)
- content_type 'application/json'
- else
- content_type 'text/plain'
- end
- end
- end
-
# Ensure the namespace is right, otherwise we might load Grape::API::Helpers
helpers ::API::Helpers
helpers ::API::Helpers::CommonHelpers
@@ -267,6 +241,7 @@ module API
mount ::API::ProjectTemplates
mount ::API::Terraform::State
mount ::API::Terraform::StateVersion
+ mount ::API::Terraform::Modules::V1::Packages
mount ::API::PersonalAccessTokens
mount ::API::ProtectedBranches
mount ::API::ProtectedTags
@@ -323,4 +298,4 @@ module API
end
end
-API::API.prepend_ee_mod
+API::API.prepend_mod
diff --git a/lib/api/award_emoji.rb b/lib/api/award_emoji.rb
index 8ea4f32d3eb..c8485054377 100644
--- a/lib/api/award_emoji.rb
+++ b/lib/api/award_emoji.rb
@@ -4,23 +4,18 @@ module API
class AwardEmoji < ::API::Base
include PaginationParams
+ helpers ::API::Helpers::AwardEmoji
+
before { authenticate! }
- AWARDABLES = [
- { type: 'issue', find_by: :iid, feature_category: :issue_tracking },
- { type: 'merge_request', find_by: :iid, feature_category: :code_review },
- { type: 'snippet', find_by: :id, feature_category: :snippets }
- ].freeze
-
- params do
- requires :id, type: String, desc: 'The ID of a project'
- end
- resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- AWARDABLES.each do |awardable_params|
+
+ Helpers::AwardEmoji.awardables.each do |awardable_params|
+ resource awardable_params[:resource], requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
awardable_string = awardable_params[:type].pluralize
awardable_id_string = "#{awardable_params[:type]}_#{awardable_params[:find_by]}"
params do
- requires :"#{awardable_id_string}", type: Integer, desc: "The ID of an Issue, Merge Request or Snippet"
+ requires :id, type: String, desc: "The ID of a #{awardable_params[:resource] == :projects ? 'project' : 'group'}"
+ requires :"#{awardable_id_string}", type: Integer, desc: Helpers::AwardEmoji.awardable_id_desc
end
[
@@ -104,25 +99,6 @@ module API
awardable.user_can_award?(current_user)
end
- # rubocop: disable CodeReuse/ActiveRecord
- def awardable
- @awardable ||=
- begin
- if params.include?(:note_id)
- note_id = params.delete(:note_id)
-
- awardable.notes.find(note_id)
- elsif params.include?(:issue_iid)
- user_project.issues.find_by!(iid: params[:issue_iid])
- elsif params.include?(:merge_request_iid)
- user_project.merge_requests.find_by!(iid: params[:merge_request_iid])
- else
- user_project.snippets.find(params[:snippet_id])
- end
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
def read_ability(awardable)
case awardable
when Note
diff --git a/lib/api/boards.rb b/lib/api/boards.rb
index 79f4b02f26a..9e829dd5e05 100644
--- a/lib/api/boards.rb
+++ b/lib/api/boards.rb
@@ -5,7 +5,7 @@ module API
include BoardsResponses
include PaginationParams
- prepend_if_ee('EE::API::BoardsResponses') # rubocop: disable Cop/InjectEnterpriseEditionModule
+ prepend_mod_with('API::BoardsResponses') # rubocop: disable Cop/InjectEnterpriseEditionModule
feature_category :boards
diff --git a/lib/api/branches.rb b/lib/api/branches.rb
index 6842e93a4de..1ee120f982a 100644
--- a/lib/api/branches.rb
+++ b/lib/api/branches.rb
@@ -38,22 +38,38 @@ module API
optional :page_token, type: String, desc: 'Name of branch to start the paginaition from'
end
get ':id/repository/branches' do
- user_project.preload_protected_branches
-
- repository = user_project.repository
-
- branches_finder = BranchesFinder.new(repository, declared_params(include_missing: false))
- branches = Gitlab::Pagination::GitalyKeysetPager.new(self, user_project).paginate(branches_finder)
-
- merged_branch_names = repository.merged_branch_names(branches.map(&:name))
-
- present(
- branches,
- with: Entities::Branch,
- current_user: current_user,
- project: user_project,
- merged_branch_names: merged_branch_names
- )
+ ff_enabled = Feature.enabled?(:api_caching_rate_limit_branches, user_project, default_enabled: :yaml)
+
+ cache_action_if(ff_enabled, [user_project, :branches, current_user, declared_params], expires_in: 30.seconds) do
+ user_project.preload_protected_branches
+
+ repository = user_project.repository
+
+ branches_finder = BranchesFinder.new(repository, declared_params(include_missing: false))
+ branches = Gitlab::Pagination::GitalyKeysetPager.new(self, user_project).paginate(branches_finder)
+
+ merged_branch_names = repository.merged_branch_names(branches.map(&:name))
+
+ if Feature.enabled?(:api_caching_branches, user_project, type: :development, default_enabled: :yaml)
+ present_cached(
+ branches,
+ with: Entities::Branch,
+ current_user: current_user,
+ project: user_project,
+ merged_branch_names: merged_branch_names,
+ expires_in: 10.minutes,
+ cache_context: -> (branch) { [current_user&.cache_key, merged_branch_names.include?(branch.name)] }
+ )
+ else
+ present(
+ branches,
+ with: Entities::Branch,
+ current_user: current_user,
+ project: user_project,
+ merged_branch_names: merged_branch_names
+ )
+ end
+ end
end
resource ':id/repository/branches/:branch', requirements: BRANCH_ENDPOINT_REQUIREMENTS do
diff --git a/lib/api/ci/runner.rb b/lib/api/ci/runner.rb
index c5249f1377b..33980b38e2b 100644
--- a/lib/api/ci/runner.rb
+++ b/lib/api/ci/runner.rb
@@ -184,6 +184,8 @@ module API
.new(job, declared_params(include_missing: false))
service.execute.then do |result|
+ track_ci_minutes_usage!(job, current_runner)
+
header 'X-GitLab-Trace-Update-Interval', result.backoff
status result.status
body result.status.to_s
@@ -214,6 +216,8 @@ module API
break error!('416 Range Not Satisfiable', 416, { 'Range' => "0-#{result.stream_size}" })
end
+ track_ci_minutes_usage!(job, current_runner)
+
status result.status
header 'Job-Status', job.status
header 'Range', "0-#{result.stream_size}"
diff --git a/lib/api/concerns/packages/debian_endpoints.rb b/lib/api/concerns/packages/debian_endpoints.rb
new file mode 100644
index 00000000000..6fc7c439464
--- /dev/null
+++ b/lib/api/concerns/packages/debian_endpoints.rb
@@ -0,0 +1,133 @@
+# frozen_string_literal: true
+
+module API
+ module Concerns
+ module Packages
+ module DebianEndpoints
+ extend ActiveSupport::Concern
+
+ DISTRIBUTION_REGEX = %r{[a-zA-Z0-9][a-zA-Z0-9.-]*}.freeze
+ COMPONENT_REGEX = %r{[a-z-]+}.freeze
+ ARCHITECTURE_REGEX = %r{[a-z][a-z0-9]*}.freeze
+ LETTER_REGEX = %r{(lib)?[a-z0-9]}.freeze
+ PACKAGE_REGEX = API::NO_SLASH_URL_PART_REGEX
+ DISTRIBUTION_REQUIREMENTS = {
+ distribution: DISTRIBUTION_REGEX
+ }.freeze
+ COMPONENT_ARCHITECTURE_REQUIREMENTS = {
+ component: COMPONENT_REGEX,
+ architecture: ARCHITECTURE_REGEX
+ }.freeze
+ COMPONENT_LETTER_SOURCE_PACKAGE_REQUIREMENTS = {
+ component: COMPONENT_REGEX,
+ letter: LETTER_REGEX,
+ source_package: PACKAGE_REGEX
+ }.freeze
+ FILE_NAME_REQUIREMENTS = {
+ file_name: API::NO_SLASH_URL_PART_REGEX
+ }.freeze
+
+ included do
+ feature_category :package_registry
+
+ helpers ::API::Helpers::PackagesHelpers
+ helpers ::API::Helpers::Packages::BasicAuthHelpers
+
+ format :txt
+ content_type :txt, 'text/plain'
+
+ rescue_from ArgumentError do |e|
+ render_api_error!(e.message, 400)
+ end
+
+ rescue_from ActiveRecord::RecordInvalid do |e|
+ render_api_error!(e.message, 400)
+ end
+
+ before do
+ require_packages_enabled!
+ end
+
+ namespace 'packages/debian' do
+ params do
+ requires :distribution, type: String, desc: 'The Debian Codename', regexp: Gitlab::Regex.debian_distribution_regex
+ end
+
+ namespace 'dists/*distribution', requirements: DISTRIBUTION_REQUIREMENTS do
+ # GET {projects|groups}/:id/packages/debian/dists/*distribution/Release.gpg
+ desc 'The Release file signature' do
+ detail 'This feature was introduced in GitLab 13.5'
+ end
+
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
+ get 'Release.gpg' do
+ not_found!
+ end
+
+ # GET {projects|groups}/:id/packages/debian/dists/*distribution/Release
+ desc 'The unsigned Release file' do
+ detail 'This feature was introduced in GitLab 13.5'
+ end
+
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
+ get 'Release' do
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
+ 'TODO Release'
+ end
+
+ # GET {projects|groups}/:id/packages/debian/dists/*distribution/InRelease
+ desc 'The signed Release file' do
+ detail 'This feature was introduced in GitLab 13.5'
+ end
+
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
+ get 'InRelease' do
+ not_found!
+ end
+
+ params do
+ requires :component, type: String, desc: 'The Debian Component', regexp: Gitlab::Regex.debian_component_regex
+ requires :architecture, type: String, desc: 'The Debian Architecture', regexp: Gitlab::Regex.debian_architecture_regex
+ end
+
+ namespace ':component/binary-:architecture', requirements: COMPONENT_ARCHITECTURE_REQUIREMENTS do
+ # GET {projects|groups}/:id/packages/debian/dists/*distribution/:component/binary-:architecture/Packages
+ desc 'The binary files index' do
+ detail 'This feature was introduced in GitLab 13.5'
+ end
+
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
+ get 'Packages' do
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
+ 'TODO Packages'
+ end
+ end
+ end
+
+ params do
+ requires :component, type: String, desc: 'The Debian Component', regexp: Gitlab::Regex.debian_component_regex
+ requires :letter, type: String, desc: 'The Debian Classification (first-letter or lib-first-letter)'
+ requires :source_package, type: String, desc: 'The Debian Source Package Name', regexp: Gitlab::Regex.debian_package_name_regex
+ end
+
+ namespace 'pool/:component/:letter/:source_package', requirements: COMPONENT_LETTER_SOURCE_PACKAGE_REQUIREMENTS do
+ # GET {projects|groups}/:id/packages/debian/pool/:component/:letter/:source_package/:file_name
+ params do
+ requires :file_name, type: String, desc: 'The Debian File Name'
+ end
+ desc 'The package' do
+ detail 'This feature was introduced in GitLab 13.5'
+ end
+
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
+ get ':file_name', requirements: FILE_NAME_REQUIREMENTS do
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
+ 'TODO File'
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/debian_group_packages.rb b/lib/api/debian_group_packages.rb
index f138f400601..06edab662bf 100644
--- a/lib/api/debian_group_packages.rb
+++ b/lib/api/debian_group_packages.rb
@@ -15,8 +15,8 @@ module API
authorize_read_package!(user_group)
end
- namespace ':id/packages/debian' do
- include DebianPackageEndpoints
+ namespace ':id/-' do
+ include ::API::Concerns::Packages::DebianEndpoints
end
end
end
diff --git a/lib/api/debian_package_endpoints.rb b/lib/api/debian_package_endpoints.rb
deleted file mode 100644
index e7689b3feff..00000000000
--- a/lib/api/debian_package_endpoints.rb
+++ /dev/null
@@ -1,127 +0,0 @@
-# frozen_string_literal: true
-
-module API
- module DebianPackageEndpoints
- extend ActiveSupport::Concern
-
- DISTRIBUTION_REGEX = %r{[a-zA-Z0-9][a-zA-Z0-9.-]*}.freeze
- COMPONENT_REGEX = %r{[a-z-]+}.freeze
- ARCHITECTURE_REGEX = %r{[a-z][a-z0-9]*}.freeze
- LETTER_REGEX = %r{(lib)?[a-z0-9]}.freeze
- PACKAGE_REGEX = API::NO_SLASH_URL_PART_REGEX
- DISTRIBUTION_REQUIREMENTS = {
- distribution: DISTRIBUTION_REGEX
- }.freeze
- COMPONENT_ARCHITECTURE_REQUIREMENTS = {
- component: COMPONENT_REGEX,
- architecture: ARCHITECTURE_REGEX
- }.freeze
- COMPONENT_LETTER_SOURCE_PACKAGE_REQUIREMENTS = {
- component: COMPONENT_REGEX,
- letter: LETTER_REGEX,
- source_package: PACKAGE_REGEX
- }.freeze
- FILE_NAME_REQUIREMENTS = {
- file_name: API::NO_SLASH_URL_PART_REGEX
- }.freeze
-
- included do
- feature_category :package_registry
-
- helpers ::API::Helpers::PackagesHelpers
- helpers ::API::Helpers::Packages::BasicAuthHelpers
-
- format :txt
- content_type :txt, 'text/plain'
-
- rescue_from ArgumentError do |e|
- render_api_error!(e.message, 400)
- end
-
- rescue_from ActiveRecord::RecordInvalid do |e|
- render_api_error!(e.message, 400)
- end
-
- before do
- require_packages_enabled!
- end
-
- params do
- requires :distribution, type: String, desc: 'The Debian Codename', regexp: Gitlab::Regex.debian_distribution_regex
- end
-
- namespace 'dists/*distribution', requirements: DISTRIBUTION_REQUIREMENTS do
- # GET {projects|groups}/:id/packages/debian/dists/*distribution/Release.gpg
- desc 'The Release file signature' do
- detail 'This feature was introduced in GitLab 13.5'
- end
-
- route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
- get 'Release.gpg' do
- not_found!
- end
-
- # GET {projects|groups}/:id/packages/debian/dists/*distribution/Release
- desc 'The unsigned Release file' do
- detail 'This feature was introduced in GitLab 13.5'
- end
-
- route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
- get 'Release' do
- # https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
- 'TODO Release'
- end
-
- # GET {projects|groups}/:id/packages/debian/dists/*distribution/InRelease
- desc 'The signed Release file' do
- detail 'This feature was introduced in GitLab 13.5'
- end
-
- route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
- get 'InRelease' do
- not_found!
- end
-
- params do
- requires :component, type: String, desc: 'The Debian Component', regexp: Gitlab::Regex.debian_component_regex
- requires :architecture, type: String, desc: 'The Debian Architecture', regexp: Gitlab::Regex.debian_architecture_regex
- end
-
- namespace ':component/binary-:architecture', requirements: COMPONENT_ARCHITECTURE_REQUIREMENTS do
- # GET {projects|groups}/:id/packages/debian/dists/*distribution/:component/binary-:architecture/Packages
- desc 'The binary files index' do
- detail 'This feature was introduced in GitLab 13.5'
- end
-
- route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
- get 'Packages' do
- # https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
- 'TODO Packages'
- end
- end
- end
-
- params do
- requires :component, type: String, desc: 'The Debian Component', regexp: Gitlab::Regex.debian_component_regex
- requires :letter, type: String, desc: 'The Debian Classification (first-letter or lib-first-letter)'
- requires :source_package, type: String, desc: 'The Debian Source Package Name', regexp: Gitlab::Regex.debian_package_name_regex
- end
-
- namespace 'pool/:component/:letter/:source_package', requirements: COMPONENT_LETTER_SOURCE_PACKAGE_REQUIREMENTS do
- # GET {projects|groups}/:id/packages/debian/pool/:component/:letter/:source_package/:file_name
- params do
- requires :file_name, type: String, desc: 'The Debian File Name'
- end
- desc 'The package' do
- detail 'This feature was introduced in GitLab 13.5'
- end
-
- route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
- get ':file_name', requirements: FILE_NAME_REQUIREMENTS do
- # https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
- 'TODO File'
- end
- end
- end
- end
-end
diff --git a/lib/api/debian_project_packages.rb b/lib/api/debian_project_packages.rb
index 8c0db42a448..0ed828fd639 100644
--- a/lib/api/debian_project_packages.rb
+++ b/lib/api/debian_project_packages.rb
@@ -15,14 +15,14 @@ module API
authorize_read_package!
end
- namespace ':id/packages/debian' do
- include DebianPackageEndpoints
+ namespace ':id' do
+ include ::API::Concerns::Packages::DebianEndpoints
params do
requires :file_name, type: String, desc: 'The file name'
end
- namespace ':file_name', requirements: FILE_NAME_REQUIREMENTS do
+ namespace 'packages/debian/:file_name', requirements: FILE_NAME_REQUIREMENTS do
content_type :json, Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE
# PUT {projects|groups}/:id/packages/debian/:file_name
diff --git a/lib/api/deploy_tokens.rb b/lib/api/deploy_tokens.rb
index 30ec4e52b2a..e9beeb18d62 100644
--- a/lib/api/deploy_tokens.rb
+++ b/lib/api/deploy_tokens.rb
@@ -18,6 +18,10 @@ module API
result_hash[:read_repository] = scopes.include?('read_repository')
result_hash
end
+
+ params :filter_params do
+ optional :active, type: Boolean, desc: 'Limit by active status'
+ end
end
desc 'Return all deploy tokens' do
@@ -26,11 +30,18 @@ module API
end
params do
use :pagination
+ use :filter_params
end
get 'deploy_tokens' do
authenticated_as_admin!
- present paginate(DeployToken.all), with: Entities::DeployToken
+ deploy_tokens = ::DeployTokens::TokensFinder.new(
+ current_user,
+ :all,
+ declared_params
+ ).execute
+
+ present paginate(deploy_tokens), with: Entities::DeployToken
end
params do
@@ -39,6 +50,7 @@ module API
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
params do
use :pagination
+ use :filter_params
end
desc 'List deploy tokens for a project' do
detail 'This feature was introduced in GitLab 12.9'
@@ -47,7 +59,13 @@ module API
get ':id/deploy_tokens' do
authorize!(:read_deploy_token, user_project)
- present paginate(user_project.deploy_tokens), with: Entities::DeployToken
+ deploy_tokens = ::DeployTokens::TokensFinder.new(
+ current_user,
+ user_project,
+ declared_params
+ ).execute
+
+ present paginate(deploy_tokens), with: Entities::DeployToken
end
params do
@@ -98,6 +116,7 @@ module API
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
params do
use :pagination
+ use :filter_params
end
desc 'List deploy tokens for a group' do
detail 'This feature was introduced in GitLab 12.9'
@@ -106,7 +125,13 @@ module API
get ':id/deploy_tokens' do
authorize!(:read_deploy_token, user_group)
- present paginate(user_group.deploy_tokens), with: Entities::DeployToken
+ deploy_tokens = ::DeployTokens::TokensFinder.new(
+ current_user,
+ user_group,
+ declared_params
+ ).execute
+
+ present paginate(deploy_tokens), with: Entities::DeployToken
end
params do
diff --git a/lib/api/deployments.rb b/lib/api/deployments.rb
index 0a6ecf2919c..80a50ded522 100644
--- a/lib/api/deployments.rb
+++ b/lib/api/deployments.rb
@@ -41,6 +41,8 @@ module API
.execute.with_api_entity_associations
present paginate(deployments), with: Entities::Deployment
+ rescue DeploymentsFinder::InefficientQueryError => e
+ bad_request!(e.message)
end
desc 'Gets a specific deployment' do
diff --git a/lib/api/entities/application_setting.rb b/lib/api/entities/application_setting.rb
index 2468c1f9b18..f23fce40468 100644
--- a/lib/api/entities/application_setting.rb
+++ b/lib/api/entities/application_setting.rb
@@ -36,4 +36,4 @@ module API
end
end
-API::Entities::ApplicationSetting.prepend_if_ee('EE::API::Entities::ApplicationSetting')
+API::Entities::ApplicationSetting.prepend_mod_with('API::Entities::ApplicationSetting')
diff --git a/lib/api/entities/board.rb b/lib/api/entities/board.rb
index fe0182ad772..ee0bea466e0 100644
--- a/lib/api/entities/board.rb
+++ b/lib/api/entities/board.rb
@@ -16,4 +16,4 @@ module API
end
end
-API::Entities::Board.prepend_if_ee('EE::API::Entities::Board')
+API::Entities::Board.prepend_mod_with('API::Entities::Board')
diff --git a/lib/api/entities/bulk_imports/export_status.rb b/lib/api/entities/bulk_imports/export_status.rb
new file mode 100644
index 00000000000..c9c7f34a16a
--- /dev/null
+++ b/lib/api/entities/bulk_imports/export_status.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ module BulkImports
+ class ExportStatus < Grape::Entity
+ expose :relation
+ expose :status
+ expose :error
+ expose :updated_at
+ end
+ end
+ end
+end
diff --git a/lib/api/entities/ci/job_basic.rb b/lib/api/entities/ci/job_basic.rb
index a29788c7abf..c31340f1ff0 100644
--- a/lib/api/entities/ci/job_basic.rb
+++ b/lib/api/entities/ci/job_basic.rb
@@ -6,7 +6,10 @@ module API
class JobBasic < Grape::Entity
expose :id, :status, :stage, :name, :ref, :tag, :coverage, :allow_failure
expose :created_at, :started_at, :finished_at
- expose :duration
+ expose :duration,
+ documentation: { type: 'Floating', desc: 'Time spent running' }
+ expose :queued_duration,
+ documentation: { type: 'Floating', desc: 'Time spent enqueued' }
expose :user, with: ::API::Entities::User
expose :commit, with: ::API::Entities::Commit
expose :pipeline, with: ::API::Entities::Ci::PipelineBasic
diff --git a/lib/api/entities/ci/pipeline.rb b/lib/api/entities/ci/pipeline.rb
index 3dd3b9c9eff..11336ae070d 100644
--- a/lib/api/entities/ci/pipeline.rb
+++ b/lib/api/entities/ci/pipeline.rb
@@ -9,6 +9,7 @@ module API
expose :user, with: Entities::UserBasic
expose :created_at, :updated_at, :started_at, :finished_at, :committed_at
expose :duration
+ expose :queued_duration
expose :coverage
expose :detailed_status, using: DetailedStatusEntity do |pipeline, options|
pipeline.detailed_status(options[:current_user])
diff --git a/lib/api/entities/deploy_token.rb b/lib/api/entities/deploy_token.rb
index 9c5bf54e299..daee104ba6b 100644
--- a/lib/api/entities/deploy_token.rb
+++ b/lib/api/entities/deploy_token.rb
@@ -4,7 +4,8 @@ module API
module Entities
class DeployToken < Grape::Entity
# exposing :token is a security risk and should be avoided
- expose :id, :name, :username, :expires_at, :scopes
+ expose :id, :name, :username, :expires_at, :scopes, :revoked
+ expose :expired?, as: :expired
end
end
end
diff --git a/lib/api/entities/environment.rb b/lib/api/entities/environment.rb
index cb39ce1b13a..91867f3403d 100644
--- a/lib/api/entities/environment.rb
+++ b/lib/api/entities/environment.rb
@@ -3,9 +3,48 @@
module API
module Entities
class Environment < Entities::EnvironmentBasic
+ include RequestAwareEntity
+ include Gitlab::Utils::StrongMemoize
+
expose :project, using: Entities::BasicProjectDetails
expose :last_deployment, using: Entities::Deployment, if: { last_deployment: true }
expose :state
+
+ expose :enable_advanced_logs_querying, if: -> (*) { can_read_pod_logs? } do |environment|
+ environment.elastic_stack_available?
+ end
+
+ expose :logs_api_path, if: -> (*) { can_read_pod_logs? } do |environment|
+ if environment.elastic_stack_available?
+ elasticsearch_project_logs_path(environment.project, environment_name: environment.name, format: :json)
+ else
+ k8s_project_logs_path(environment.project, environment_name: environment.name, format: :json)
+ end
+ end
+
+ expose :gitlab_managed_apps_logs_path, if: -> (*) { can_read_pod_logs? && cluster } do |environment|
+ ::Clusters::ClusterPresenter.new(cluster, current_user: current_user).gitlab_managed_apps_logs_path # rubocop: disable CodeReuse/Presenter
+ end
+
+ private
+
+ alias_method :environment, :object
+
+ def can_read_pod_logs?
+ strong_memoize(:can_read_pod_logs) do
+ current_user&.can?(:read_pod_logs, environment.project)
+ end
+ end
+
+ def cluster
+ strong_memoize(:cluster) do
+ environment&.last_deployment&.cluster
+ end
+ end
+
+ def current_user
+ options[:current_user]
+ end
end
end
end
diff --git a/lib/api/entities/group.rb b/lib/api/entities/group.rb
index e430eba4880..048b7a3c15a 100644
--- a/lib/api/entities/group.rb
+++ b/lib/api/entities/group.rb
@@ -38,4 +38,4 @@ module API
end
end
-API::Entities::Group.prepend_if_ee('EE::API::Entities::Group', with_descendants: true)
+API::Entities::Group.prepend_mod_with('API::Entities::Group', with_descendants: true)
diff --git a/lib/api/entities/group_detail.rb b/lib/api/entities/group_detail.rb
index 2d9d4ca7992..e63a3fc1334 100644
--- a/lib/api/entities/group_detail.rb
+++ b/lib/api/entities/group_detail.rb
@@ -39,4 +39,4 @@ module API
end
end
-API::Entities::GroupDetail.prepend_if_ee('EE::API::Entities::GroupDetail')
+API::Entities::GroupDetail.prepend_mod_with('API::Entities::GroupDetail')
diff --git a/lib/api/entities/identity.rb b/lib/api/entities/identity.rb
index 52045b6250a..7c8cda8f9c2 100644
--- a/lib/api/entities/identity.rb
+++ b/lib/api/entities/identity.rb
@@ -8,4 +8,4 @@ module API
end
end
-API::Entities::Identity.prepend_if_ee('EE::API::Entities::Identity')
+API::Entities::Identity.prepend_mod_with('API::Entities::Identity')
diff --git a/lib/api/entities/issuable_entity.rb b/lib/api/entities/issuable_entity.rb
index e2c674c0b8b..fd5d6c8137f 100644
--- a/lib/api/entities/issuable_entity.rb
+++ b/lib/api/entities/issuable_entity.rb
@@ -24,7 +24,7 @@ module API
# entity according to the current top-level entity options, such
# as the current_user.
def lazy_issuable_metadata
- BatchLoader.for(object).batch(key: [current_user, :issuable_metadata]) do |models, loader, args|
+ BatchLoader.for(object).batch(key: [current_user, :issuable_metadata], replace_methods: false) do |models, loader, args|
current_user = args[:key].first
issuable_metadata = Gitlab::IssuableMetadata.new(current_user, models)
diff --git a/lib/api/entities/issue.rb b/lib/api/entities/issue.rb
index 82102854394..e2506cc596e 100644
--- a/lib/api/entities/issue.rb
+++ b/lib/api/entities/issue.rb
@@ -48,4 +48,4 @@ module API
end
end
-API::Entities::Issue.prepend_if_ee('EE::API::Entities::Issue')
+API::Entities::Issue.prepend_mod_with('API::Entities::Issue')
diff --git a/lib/api/entities/issue_basic.rb b/lib/api/entities/issue_basic.rb
index cf96c6556ec..d27cc5498bd 100644
--- a/lib/api/entities/issue_basic.rb
+++ b/lib/api/entities/issue_basic.rb
@@ -3,6 +3,10 @@
module API
module Entities
class IssueBasic < IssuableEntity
+ format_with(:upcase) do |item|
+ item.upcase if item.respond_to?(:upcase)
+ end
+
expose :closed_at
expose :closed_by, using: Entities::UserBasic
@@ -16,6 +20,10 @@ module API
expose :milestone, using: Entities::Milestone
expose :assignees, :author, using: Entities::UserBasic
+ expose :issue_type,
+ as: :type,
+ format_with: :upcase,
+ documentation: { type: "String", desc: "One of #{Issue.issue_types.keys.map(&:upcase)}" }
expose :assignee, using: ::API::Entities::UserBasic do |issue|
issue.assignees.first
@@ -28,6 +36,7 @@ module API
expose :due_date
expose :confidential
expose :discussion_locked
+ expose :issue_type
expose :web_url do |issue|
Gitlab::UrlBuilder.build(issue)
@@ -42,4 +51,4 @@ module API
end
end
-API::Entities::IssueBasic.prepend_if_ee('EE::API::Entities::IssueBasic', with_descendants: true)
+API::Entities::IssueBasic.prepend_mod_with('API::Entities::IssueBasic', with_descendants: true)
diff --git a/lib/api/entities/job_request/response.rb b/lib/api/entities/job_request/response.rb
index bf22ea1e6e2..2e8dfc5bde0 100644
--- a/lib/api/entities/job_request/response.rb
+++ b/lib/api/entities/job_request/response.rb
@@ -34,4 +34,4 @@ module API
end
end
-API::Entities::JobRequest::Response.prepend_if_ee('EE::API::Entities::JobRequest::Response')
+API::Entities::JobRequest::Response.prepend_mod_with('API::Entities::JobRequest::Response')
diff --git a/lib/api/entities/label_basic.rb b/lib/api/entities/label_basic.rb
index ed52688638e..00ecea26ec3 100644
--- a/lib/api/entities/label_basic.rb
+++ b/lib/api/entities/label_basic.rb
@@ -3,7 +3,7 @@
module API
module Entities
class LabelBasic < Grape::Entity
- expose :id, :name, :color, :description, :description_html, :text_color
+ expose :id, :name, :color, :description, :description_html, :text_color, :remove_on_close
end
end
end
diff --git a/lib/api/entities/list.rb b/lib/api/entities/list.rb
index 480e722c22c..e9d31827e2f 100644
--- a/lib/api/entities/list.rb
+++ b/lib/api/entities/list.rb
@@ -10,4 +10,4 @@ module API
end
end
-API::Entities::List.prepend_if_ee('EE::API::Entities::List')
+API::Entities::List.prepend_mod_with('API::Entities::List')
diff --git a/lib/api/entities/member.rb b/lib/api/entities/member.rb
index ad62f92e5a0..87f03adba31 100644
--- a/lib/api/entities/member.rb
+++ b/lib/api/entities/member.rb
@@ -11,4 +11,4 @@ module API
end
end
-API::Entities::Member.prepend_if_ee('EE::API::Entities::Member', with_descendants: true)
+API::Entities::Member.prepend_mod_with('API::Entities::Member', with_descendants: true)
diff --git a/lib/api/entities/merge_request_basic.rb b/lib/api/entities/merge_request_basic.rb
index 88c84c494e2..cf8d03bf176 100644
--- a/lib/api/entities/merge_request_basic.rb
+++ b/lib/api/entities/merge_request_basic.rb
@@ -89,4 +89,4 @@ module API
end
end
-API::Entities::MergeRequestBasic.prepend_if_ee('EE::API::Entities::MergeRequestBasic', with_descendants: true)
+API::Entities::MergeRequestBasic.prepend_mod_with('API::Entities::MergeRequestBasic', with_descendants: true)
diff --git a/lib/api/entities/namespace.rb b/lib/api/entities/namespace.rb
index a7e06cc3e02..f11303d41a6 100644
--- a/lib/api/entities/namespace.rb
+++ b/lib/api/entities/namespace.rb
@@ -14,4 +14,4 @@ module API
end
end
-API::Entities::Namespace.prepend_if_ee('EE::API::Entities::Namespace')
+API::Entities::Namespace.prepend_mod_with('API::Entities::Namespace')
diff --git a/lib/api/entities/package.rb b/lib/api/entities/package.rb
index e7153f9bebb..2f60a0bf6bd 100644
--- a/lib/api/entities/package.rb
+++ b/lib/api/entities/package.rb
@@ -22,6 +22,7 @@ module API
expose :version
expose :package_type
+ expose :status
expose :_links do
expose :web_path do |package|
diff --git a/lib/api/entities/package_file.rb b/lib/api/entities/package_file.rb
index 2cc2f62a948..e34a6a7aa1d 100644
--- a/lib/api/entities/package_file.rb
+++ b/lib/api/entities/package_file.rb
@@ -5,7 +5,7 @@ module API
class PackageFile < Grape::Entity
expose :id, :package_id, :created_at
expose :file_name, :size
- expose :file_md5, :file_sha1
+ expose :file_md5, :file_sha1, :file_sha256
expose :pipelines, if: ->(package_file) { package_file.pipelines.present? }, using: Package::Pipeline
end
end
diff --git a/lib/api/entities/project.rb b/lib/api/entities/project.rb
index 690bc5d419d..442013c07dd 100644
--- a/lib/api/entities/project.rb
+++ b/lib/api/entities/project.rb
@@ -147,4 +147,4 @@ module API
end
end
-API::Entities::Project.prepend_if_ee('EE::API::Entities::Project', with_descendants: true)
+API::Entities::Project.prepend_mod_with('API::Entities::Project', with_descendants: true)
diff --git a/lib/api/entities/protected_branch.rb b/lib/api/entities/protected_branch.rb
index e5dbaffb591..ac44d06e69c 100644
--- a/lib/api/entities/protected_branch.rb
+++ b/lib/api/entities/protected_branch.rb
@@ -12,4 +12,4 @@ module API
end
end
-API::Entities::ProtectedBranch.prepend_if_ee('EE::API::Entities::ProtectedBranch')
+API::Entities::ProtectedBranch.prepend_mod_with('API::Entities::ProtectedBranch')
diff --git a/lib/api/entities/protected_ref_access.rb b/lib/api/entities/protected_ref_access.rb
index f0185705b06..443277e23cf 100644
--- a/lib/api/entities/protected_ref_access.rb
+++ b/lib/api/entities/protected_ref_access.rb
@@ -11,4 +11,4 @@ module API
end
end
-API::Entities::ProtectedRefAccess.prepend_if_ee('EE::API::Entities::ProtectedRefAccess')
+API::Entities::ProtectedRefAccess.prepend_mod_with('API::Entities::ProtectedRefAccess')
diff --git a/lib/api/entities/release.rb b/lib/api/entities/release.rb
index f6c3dd5a509..94124352298 100644
--- a/lib/api/entities/release.rb
+++ b/lib/api/entities/release.rb
@@ -8,7 +8,7 @@ module API
expose :name
expose :tag, as: :tag_name, if: ->(_, _) { can_download_code? }
expose :description
- expose :description_html do |entity|
+ expose :description_html, unless: ->(_, _) { remove_description_html? } do |entity|
MarkupHelper.markdown_field(entity, :description, current_user: options[:current_user])
end
expose :created_at
@@ -28,9 +28,7 @@ module API
expose :assets do
expose :assets_count, as: :count
expose :sources, using: Entities::Releases::Source, if: ->(_, _) { can_download_code? }
- expose :links, using: Entities::Releases::Link do |release, options|
- release.links.sorted
- end
+ expose :sorted_links, as: :links, using: Entities::Releases::Link
end
expose :evidences, using: Entities::Releases::Evidence, expose_nil: false, if: ->(_, _) { can_download_code? }
expose :_links do
@@ -47,6 +45,11 @@ module API
def can_read_milestone?
Ability.allowed?(options[:current_user], :read_milestone, object.project)
end
+
+ def remove_description_html?
+ ::Feature.enabled?(:remove_description_html_in_release_api, object.project, default_enabled: :yaml) &&
+ ::Feature.disabled?(:remove_description_html_in_release_api_override, object.project)
+ end
end
end
end
diff --git a/lib/api/entities/terraform/module_versions.rb b/lib/api/entities/terraform/module_versions.rb
new file mode 100644
index 00000000000..75037039117
--- /dev/null
+++ b/lib/api/entities/terraform/module_versions.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ module Terraform
+ class ModuleVersions < Grape::Entity
+ expose :modules
+ end
+ end
+ end
+end
diff --git a/lib/api/entities/todo.rb b/lib/api/entities/todo.rb
index 0acbb4cb704..8d222db488a 100644
--- a/lib/api/entities/todo.rb
+++ b/lib/api/entities/todo.rb
@@ -58,4 +58,4 @@ module API
end
end
-API::Entities::Todo.prepend_if_ee('EE::API::Entities::Todo')
+API::Entities::Todo.prepend_mod_with('API::Entities::Todo')
diff --git a/lib/api/entities/user_basic.rb b/lib/api/entities/user_basic.rb
index 80f3ee7b502..b8ee4e5a6e0 100644
--- a/lib/api/entities/user_basic.rb
+++ b/lib/api/entities/user_basic.rb
@@ -19,4 +19,4 @@ module API
end
end
-API::Entities::UserBasic.prepend_if_ee('EE::API::Entities::UserBasic')
+API::Entities::UserBasic.prepend_mod_with('API::Entities::UserBasic')
diff --git a/lib/api/entities/user_credit_card_validations.rb b/lib/api/entities/user_credit_card_validations.rb
new file mode 100644
index 00000000000..fcd42388b16
--- /dev/null
+++ b/lib/api/entities/user_credit_card_validations.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class UserCreditCardValidations < Grape::Entity
+ expose :user_id, :credit_card_validated_at
+ end
+ end
+end
diff --git a/lib/api/entities/user_details_with_admin.rb b/lib/api/entities/user_details_with_admin.rb
index e48b1da7859..3572b677646 100644
--- a/lib/api/entities/user_details_with_admin.rb
+++ b/lib/api/entities/user_details_with_admin.rb
@@ -11,4 +11,4 @@ module API
end
end
-API::Entities::UserDetailsWithAdmin.prepend_if_ee('EE::API::Entities::UserDetailsWithAdmin')
+API::Entities::UserDetailsWithAdmin.prepend_mod_with('API::Entities::UserDetailsWithAdmin')
diff --git a/lib/api/entities/user_path.rb b/lib/api/entities/user_path.rb
index 3f007659813..ed54857d041 100644
--- a/lib/api/entities/user_path.rb
+++ b/lib/api/entities/user_path.rb
@@ -13,4 +13,4 @@ module API
end
end
-API::Entities::UserPath.prepend_if_ee('EE::API::Entities::UserPath')
+API::Entities::UserPath.prepend_mod_with('API::Entities::UserPath')
diff --git a/lib/api/entities/user_public.rb b/lib/api/entities/user_public.rb
index 685adb1dd10..78f088d3c1a 100644
--- a/lib/api/entities/user_public.rb
+++ b/lib/api/entities/user_public.rb
@@ -19,4 +19,4 @@ module API
end
end
-API::Entities::UserPublic.prepend_if_ee('EE::API::Entities::UserPublic', with_descendants: true)
+API::Entities::UserPublic.prepend_mod_with('API::Entities::UserPublic', with_descendants: true)
diff --git a/lib/api/entities/user_with_admin.rb b/lib/api/entities/user_with_admin.rb
index ab7bc738ff8..e148a5c45b5 100644
--- a/lib/api/entities/user_with_admin.rb
+++ b/lib/api/entities/user_with_admin.rb
@@ -9,4 +9,4 @@ module API
end
end
-API::Entities::UserWithAdmin.prepend_if_ee('EE::API::Entities::UserWithAdmin')
+API::Entities::UserWithAdmin.prepend_mod_with('API::Entities::UserWithAdmin')
diff --git a/lib/api/environments.rb b/lib/api/environments.rb
index b606b2e814d..57e548183b0 100644
--- a/lib/api/environments.rb
+++ b/lib/api/environments.rb
@@ -26,7 +26,7 @@ module API
get ':id/environments' do
authorize! :read_environment, user_project
- environments = ::EnvironmentsFinder.new(user_project, current_user, params).execute
+ environments = ::Environments::EnvironmentsFinder.new(user_project, current_user, params).execute
present paginate(environments), with: Entities::Environment, current_user: current_user
end
diff --git a/lib/api/features.rb b/lib/api/features.rb
index 57bd7c38ad2..2ce2f7c518f 100644
--- a/lib/api/features.rb
+++ b/lib/api/features.rb
@@ -120,4 +120,4 @@ module API
end
end
-API::Features.prepend_if_ee('EE::API::Features')
+API::Features.prepend_mod_with('API::Features')
diff --git a/lib/api/generic_packages.rb b/lib/api/generic_packages.rb
index cce55fa92d9..d0680ad7bc5 100644
--- a/lib/api/generic_packages.rb
+++ b/lib/api/generic_packages.rb
@@ -74,6 +74,8 @@ module API
Gitlab::ErrorTracking.track_exception(e, extra: { file_name: params[:file_name], project_id: project.id })
forbidden!
+ rescue ::Packages::DuplicatePackageError
+ bad_request!('Duplicate package is not allowed')
end
desc 'Download package file' do
diff --git a/lib/api/group_boards.rb b/lib/api/group_boards.rb
index 90632048354..92869f8fbba 100644
--- a/lib/api/group_boards.rb
+++ b/lib/api/group_boards.rb
@@ -5,7 +5,7 @@ module API
include BoardsResponses
include PaginationParams
- prepend_if_ee('EE::API::BoardsResponses') # rubocop: disable Cop/InjectEnterpriseEditionModule
+ prepend_mod_with('API::BoardsResponses') # rubocop: disable Cop/InjectEnterpriseEditionModule
feature_category :boards
diff --git a/lib/api/group_export.rb b/lib/api/group_export.rb
index 29ffbea687a..6134515032f 100644
--- a/lib/api/group_export.rb
+++ b/lib/api/group_export.rb
@@ -43,6 +43,43 @@ module API
render_api_error!(message: 'Group export could not be started.')
end
end
+
+ desc 'Start relations export' do
+ detail 'This feature was introduced in GitLab 13.12'
+ end
+ post ':id/export_relations' do
+ response = ::BulkImports::ExportService.new(portable: user_group, user: current_user).execute
+
+ if response.success?
+ accepted!
+ else
+ render_api_error!(message: 'Group relations export could not be started.')
+ end
+ end
+
+ desc 'Download relations export' do
+ detail 'This feature was introduced in GitLab 13.12'
+ end
+ params do
+ requires :relation, type: String, desc: 'Group relation name'
+ end
+ get ':id/export_relations/download' do
+ export = user_group.bulk_import_exports.find_by_relation(params[:relation])
+ file = export&.upload&.export_file
+
+ if file
+ present_carrierwave_file!(file)
+ else
+ render_api_error!('404 Not found', 404)
+ end
+ end
+
+ desc 'Relations export status' do
+ detail 'This feature was introduced in GitLab 13.12'
+ end
+ get ':id/export_relations/status' do
+ present user_group.bulk_import_exports, with: Entities::BulkImports::ExportStatus
+ end
end
end
end
diff --git a/lib/api/group_milestones.rb b/lib/api/group_milestones.rb
index dfffd3b1209..061d0410a9c 100644
--- a/lib/api/group_milestones.rb
+++ b/lib/api/group_milestones.rb
@@ -96,4 +96,4 @@ module API
end
end
-API::GroupMilestones.prepend_if_ee('EE::API::GroupMilestones')
+API::GroupMilestones.prepend_mod_with('API::GroupMilestones')
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index 912813d5bb7..1a604e70bf1 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -401,4 +401,4 @@ module API
end
end
-API::Groups.prepend_if_ee('EE::API::Groups')
+API::Groups.prepend_mod_with('API::Groups')
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 2d8a4f60e2a..632717e1b73 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -124,12 +124,22 @@ module API
def find_project!(id)
project = find_project(id)
+ return forbidden! unless authorized_project_scope?(project)
+
return project if can?(current_user, :read_project, project)
return unauthorized! if authenticate_non_public?
not_found!('Project')
end
+ def authorized_project_scope?(project)
+ return true unless job_token_authentication?
+ return true unless route_authentication_setting[:job_token_scope] == :project
+
+ ::Feature.enabled?(:ci_job_token_scope, project, default_enabled: :yaml) &&
+ current_authenticated_job.project == project
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def find_group(id)
if id.to_s =~ /^\d+$/
@@ -308,7 +318,7 @@ module API
def verify_workhorse_api!
Gitlab::Workhorse.verify_api_request!(request.headers)
- rescue => e
+ rescue StandardError => e
Gitlab::ErrorTracking.track_exception(e)
forbidden!
@@ -549,7 +559,7 @@ module API
return unless Feature.enabled?(feature_name)
Gitlab::UsageDataCounters.count(event_name)
- rescue => error
+ rescue StandardError => error
Gitlab::AppLogger.warn("Redis tracking event failed for event: #{event_name}, message: #{error.message}")
end
@@ -559,7 +569,7 @@ module API
return unless values.present?
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(event_name, values: values)
- rescue => error
+ rescue StandardError => error
Gitlab::AppLogger.warn("Redis tracking event failed for event: #{event_name}, message: #{error.message}")
end
@@ -582,18 +592,26 @@ module API
def project_finder_params_ce
finder_params = project_finder_params_visibility_ce
+
+ finder_params.merge!(
+ params
+ .slice(:search,
+ :custom_attributes,
+ :last_activity_after,
+ :last_activity_before,
+ :repository_storage)
+ .symbolize_keys
+ .compact
+ )
+
finder_params[:with_issues_enabled] = true if params[:with_issues_enabled].present?
finder_params[:with_merge_requests_enabled] = true if params[:with_merge_requests_enabled].present?
finder_params[:without_deleted] = true
- finder_params[:search] = params[:search] if params[:search]
finder_params[:search_namespaces] = true if params[:search_namespaces].present?
finder_params[:user] = params.delete(:user) if params[:user]
- finder_params[:custom_attributes] = params[:custom_attributes] if params[:custom_attributes]
finder_params[:id_after] = sanitize_id_param(params[:id_after]) if params[:id_after]
finder_params[:id_before] = sanitize_id_param(params[:id_before]) if params[:id_before]
- finder_params[:last_activity_after] = params[:last_activity_after] if params[:last_activity_after]
- finder_params[:last_activity_before] = params[:last_activity_before] if params[:last_activity_before]
- finder_params[:repository_storage] = params[:repository_storage] if params[:repository_storage]
+ finder_params[:tag] = params[:topic] if params[:topic].present?
finder_params
end
@@ -700,4 +718,4 @@ module API
end
end
-API::Helpers.prepend_if_ee('EE::API::Helpers')
+API::Helpers.prepend_mod_with('API::Helpers')
diff --git a/lib/api/helpers/award_emoji.rb b/lib/api/helpers/award_emoji.rb
new file mode 100644
index 00000000000..5b659c4dde7
--- /dev/null
+++ b/lib/api/helpers/award_emoji.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+module API
+ module Helpers
+ module AwardEmoji
+ def self.awardables
+ [
+ { type: 'issue', resource: :projects, find_by: :iid, feature_category: :issue_tracking },
+ { type: 'merge_request', resource: :projects, find_by: :iid, feature_category: :code_review },
+ { type: 'snippet', resource: :projects, find_by: :id, feature_category: :snippets }
+ ]
+ end
+
+ def self.awardable_id_desc
+ "The ID of an Issue, Merge Request or Snippet"
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def awardable
+ @awardable ||=
+ begin
+ if params.include?(:note_id)
+ note_id = params.delete(:note_id)
+
+ awardable.notes.find(note_id)
+ elsif params.include?(:issue_iid)
+ user_project.issues.find_by!(iid: params[:issue_iid])
+ elsif params.include?(:merge_request_iid)
+ user_project.merge_requests.find_by!(iid: params[:merge_request_iid])
+ elsif params.include?(:snippet_id)
+ user_project.snippets.find(params[:snippet_id])
+ end
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+ end
+ end
+end
+
+API::Helpers::AwardEmoji.prepend_mod_with('API::Helpers::AwardEmoji')
diff --git a/lib/api/helpers/caching.rb b/lib/api/helpers/caching.rb
index d0f22109879..f24ac7302c1 100644
--- a/lib/api/helpers/caching.rb
+++ b/lib/api/helpers/caching.rb
@@ -11,6 +11,11 @@ module API
# @return [ActiveSupport::Duration]
DEFAULT_EXPIRY = 1.day
+ # @return [Hash]
+ DEFAULT_CACHE_OPTIONS = {
+ race_condition_ttl: 5.seconds
+ }.freeze
+
# @return [ActiveSupport::Cache::Store]
def cache
Rails.cache
@@ -40,7 +45,7 @@ module API
# @param expires_in [ActiveSupport::Duration, Integer] an expiry time for the cache entry
# @param presenter_args [Hash] keyword arguments to be passed to the entity
# @return [Gitlab::Json::PrecompiledJson]
- def present_cached(obj_or_collection, with:, cache_context: -> (_) { current_user.cache_key }, expires_in: DEFAULT_EXPIRY, **presenter_args)
+ def present_cached(obj_or_collection, with:, cache_context: -> (_) { current_user&.cache_key }, expires_in: DEFAULT_EXPIRY, **presenter_args)
json =
if obj_or_collection.is_a?(Enumerable)
cached_collection(
@@ -63,8 +68,59 @@ module API
body Gitlab::Json::PrecompiledJson.new(json)
end
+ # Action caching implementation
+ #
+ # This allows you to wrap an entire API endpoint call in a cache, useful
+ # for short TTL caches to effectively rate-limit an endpoint. The block
+ # will be converted to JSON and cached, and returns a
+ # `Gitlab::Json::PrecompiledJson` object which will be exported without
+ # secondary conversion.
+ #
+ # @param key [Object] any object that can be converted into a cache key
+ # @param expires_in [ActiveSupport::Duration, Integer] an expiry time for the cache entry
+ # @return [Gitlab::Json::PrecompiledJson]
+ def cache_action(key, **cache_opts)
+ json = cache.fetch(key, **apply_default_cache_options(cache_opts)) do
+ response = yield
+
+ if response.is_a?(Gitlab::Json::PrecompiledJson)
+ response.to_s
+ else
+ Gitlab::Json.dump(response.as_json)
+ end
+ end
+
+ body Gitlab::Json::PrecompiledJson.new(json)
+ end
+
+ # Conditionally cache an action
+ #
+ # Perform a `cache_action` only if the conditional passes
+ def cache_action_if(conditional, *opts, **kwargs)
+ if conditional
+ cache_action(*opts, **kwargs) do
+ yield
+ end
+ else
+ yield
+ end
+ end
+
+ # Conditionally cache an action
+ #
+ # Perform a `cache_action` unless the conditional passes
+ def cache_action_unless(conditional, *opts, **kwargs)
+ cache_action_if(!conditional, *opts, **kwargs) do
+ yield
+ end
+ end
+
private
+ def apply_default_cache_options(opts = {})
+ DEFAULT_CACHE_OPTIONS.merge(opts)
+ end
+
# Optionally uses a `Proc` to add context to a cache key
#
# @param object [Object] must respond to #cache_key
@@ -119,8 +175,11 @@ module API
objs.flatten!
map = multi_key_map(objs, context: context)
- cache.fetch_multi(*map.keys, **kwargs) do |key|
- yield map[key]
+ # TODO: `contextual_cache_key` should be constructed based on the guideline https://docs.gitlab.com/ee/development/redis.html#multi-key-commands.
+ Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
+ cache.fetch_multi(*map.keys, **kwargs) do |key|
+ yield map[key]
+ end
end
end
diff --git a/lib/api/helpers/common_helpers.rb b/lib/api/helpers/common_helpers.rb
index 8940cf87f82..02942820982 100644
--- a/lib/api/helpers/common_helpers.rb
+++ b/lib/api/helpers/common_helpers.rb
@@ -40,4 +40,4 @@ module API
end
end
-API::Helpers::CommonHelpers.prepend_if_ee('EE::API::Helpers::CommonHelpers')
+API::Helpers::CommonHelpers.prepend_mod_with('API::Helpers::CommonHelpers')
diff --git a/lib/api/helpers/discussions_helpers.rb b/lib/api/helpers/discussions_helpers.rb
index 3c0db1d0ea9..cb2feeda1e1 100644
--- a/lib/api/helpers/discussions_helpers.rb
+++ b/lib/api/helpers/discussions_helpers.rb
@@ -17,4 +17,4 @@ module API
end
end
-API::Helpers::DiscussionsHelpers.prepend_if_ee('EE::API::Helpers::DiscussionsHelpers')
+API::Helpers::DiscussionsHelpers.prepend_mod_with('API::Helpers::DiscussionsHelpers')
diff --git a/lib/api/helpers/groups_helpers.rb b/lib/api/helpers/groups_helpers.rb
index ba07a70ee32..5c5109f3d21 100644
--- a/lib/api/helpers/groups_helpers.rb
+++ b/lib/api/helpers/groups_helpers.rb
@@ -48,4 +48,4 @@ module API
end
end
-API::Helpers::GroupsHelpers.prepend_if_ee('EE::API::Helpers::GroupsHelpers')
+API::Helpers::GroupsHelpers.prepend_mod_with('API::Helpers::GroupsHelpers')
diff --git a/lib/api/helpers/headers_helpers.rb b/lib/api/helpers/headers_helpers.rb
index 908c57bb04e..56445ccbd0d 100644
--- a/lib/api/helpers/headers_helpers.rb
+++ b/lib/api/helpers/headers_helpers.rb
@@ -8,7 +8,7 @@ module API
def set_http_headers(header_data)
header_data.each do |key, value|
if value.is_a?(Enumerable)
- raise ArgumentError.new("Header value should be a string")
+ raise ArgumentError, "Header value should be a string"
end
header "X-Gitlab-#{key.to_s.split('_').collect(&:capitalize).join('-')}", value.to_s
diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb
index 9a1ff2ba8ce..e03f029a6ef 100644
--- a/lib/api/helpers/internal_helpers.rb
+++ b/lib/api/helpers/internal_helpers.rb
@@ -65,7 +65,7 @@ module API
result = Gitlab::Redis::SharedState.with { |redis| redis.ping }
result == 'PONG'
- rescue => e
+ rescue StandardError => e
Gitlab::AppLogger.warn("GitLab: An unexpected error occurred in pinging to Redis: #{e}")
false
end
diff --git a/lib/api/helpers/issues_helpers.rb b/lib/api/helpers/issues_helpers.rb
index 2b1ed479692..b1954f8ece9 100644
--- a/lib/api/helpers/issues_helpers.rb
+++ b/lib/api/helpers/issues_helpers.rb
@@ -28,7 +28,8 @@ module API
:remove_labels,
:milestone_id,
:state_event,
- :title
+ :title,
+ :issue_type
]
end
@@ -47,6 +48,7 @@ module API
args[:not][:label_name] ||= args[:not]&.delete(:labels)
args[:scope] = args[:scope].underscore if args[:scope]
args[:sort] = "#{args[:order_by]}_#{args[:sort]}"
+ args[:issue_types] ||= args.delete(:issue_type)
IssuesFinder.new(current_user, args)
end
@@ -74,4 +76,4 @@ module API
end
end
-API::Helpers::IssuesHelpers.prepend_if_ee('EE::API::Helpers::IssuesHelpers')
+API::Helpers::IssuesHelpers.prepend_mod_with('API::Helpers::IssuesHelpers')
diff --git a/lib/api/helpers/label_helpers.rb b/lib/api/helpers/label_helpers.rb
index 4018f2dec21..796b8928243 100644
--- a/lib/api/helpers/label_helpers.rb
+++ b/lib/api/helpers/label_helpers.rb
@@ -5,27 +5,34 @@ module API
module LabelHelpers
extend Grape::API::Helpers
+ params :optional_label_params do
+ optional :description, type: String, desc: 'The description of the label'
+ optional :remove_on_close, type: Boolean, desc: 'Whether the label should be removed from an issue when the issue is closed'
+ end
+
params :label_create_params do
requires :name, type: String, desc: 'The name of the label to be created'
requires :color, type: String, desc: "The color of the label given in 6-digit hex notation with leading '#' sign (e.g. #FFAABB) or one of the allowed CSS color names"
- optional :description, type: String, desc: 'The description of label to be created'
+
+ use :optional_label_params
end
params :label_update_params do
optional :new_name, type: String, desc: 'The new name of the label'
optional :color, type: String, desc: "The new color of the label given in 6-digit hex notation with leading '#' sign (e.g. #FFAABB) or one of the allowed CSS color names"
- optional :description, type: String, desc: 'The new description of label'
+
+ use :optional_label_params
end
params :project_label_update_params do
use :label_update_params
optional :priority, type: Integer, desc: 'The priority of the label', allow_blank: true
- at_least_one_of :new_name, :color, :description, :priority
+ at_least_one_of :new_name, :color, :description, :priority, :remove_on_close
end
params :group_label_update_params do
use :label_update_params
- at_least_one_of :new_name, :color, :description
+ at_least_one_of :new_name, :color, :description, :remove_on_close
end
def find_label(parent, id_or_title, params = { include_ancestor_groups: true })
@@ -117,7 +124,7 @@ module API
else
render_api_error!('Failed to promote project label to group label', 400)
end
- rescue => error
+ rescue StandardError => error
render_api_error!(error.to_s, 400)
end
end
diff --git a/lib/api/helpers/members_helpers.rb b/lib/api/helpers/members_helpers.rb
index 2de077b5a3b..bd0c2501220 100644
--- a/lib/api/helpers/members_helpers.rb
+++ b/lib/api/helpers/members_helpers.rb
@@ -18,7 +18,7 @@ module API
# rubocop: disable CodeReuse/ActiveRecord
def retrieve_members(source, params:, deep: false)
- members = deep ? find_all_members(source) : source_members(source).where.not(user_id: nil)
+ members = deep ? find_all_members(source) : source_members(source).connected_to_user
members = members.includes(:user)
members = members.references(:user).merge(User.search(params[:query])) if params[:query].present?
members = members.where(user_id: params[:user_ids]) if params[:user_ids].present?
@@ -65,4 +65,4 @@ module API
end
end
-API::Helpers::MembersHelpers.prepend_if_ee('EE::API::Helpers::MembersHelpers')
+API::Helpers::MembersHelpers.prepend_mod_with('API::Helpers::MembersHelpers')
diff --git a/lib/api/helpers/notes_helpers.rb b/lib/api/helpers/notes_helpers.rb
index cb938bc8a14..356e4a98c97 100644
--- a/lib/api/helpers/notes_helpers.rb
+++ b/lib/api/helpers/notes_helpers.rb
@@ -151,4 +151,4 @@ module API
end
end
-API::Helpers::NotesHelpers.prepend_if_ee('EE::API::Helpers::NotesHelpers')
+API::Helpers::NotesHelpers.prepend_mod_with('API::Helpers::NotesHelpers')
diff --git a/lib/api/helpers/performance_bar_helpers.rb b/lib/api/helpers/performance_bar_helpers.rb
index 8430e889dff..0b7fb4308fc 100644
--- a/lib/api/helpers/performance_bar_helpers.rb
+++ b/lib/api/helpers/performance_bar_helpers.rb
@@ -4,17 +4,17 @@ module API
module Helpers
module PerformanceBarHelpers
def set_peek_enabled_for_current_request
- Gitlab::SafeRequestStore.fetch(:peek_enabled) { perf_bar_cookie_enabled? && perf_bar_enabled_for_user? }
+ Gitlab::SafeRequestStore.fetch(:peek_enabled) { perf_bar_cookie_enabled? && perf_bar_allowed_for_user? }
end
def perf_bar_cookie_enabled?
cookies[:perf_bar_enabled] == 'true'
end
- def perf_bar_enabled_for_user?
+ def perf_bar_allowed_for_user?
# We cannot use `current_user` here because that method raises an exception when the user
# is unauthorized and some API endpoints require that `current_user` is not called.
- Gitlab::PerformanceBar.enabled_for_user?(find_user_from_sources)
+ Gitlab::PerformanceBar.allowed_for_user?(find_user_from_sources)
end
end
end
diff --git a/lib/api/helpers/project_snapshots_helpers.rb b/lib/api/helpers/project_snapshots_helpers.rb
index e708dbf0156..0b10641571a 100644
--- a/lib/api/helpers/project_snapshots_helpers.rb
+++ b/lib/api/helpers/project_snapshots_helpers.rb
@@ -3,7 +3,7 @@
module API
module Helpers
module ProjectSnapshotsHelpers
- prepend_if_ee('::EE::API::Helpers::ProjectSnapshotsHelpers') # rubocop: disable Cop/InjectEnterpriseEditionModule
+ prepend_mod_with('API::Helpers::ProjectSnapshotsHelpers') # rubocop: disable Cop/InjectEnterpriseEditionModule
def authorize_read_git_snapshot!
authenticated_with_can_read_all_resources!
diff --git a/lib/api/helpers/projects_helpers.rb b/lib/api/helpers/projects_helpers.rb
index cf2bcace33b..d9c0b4f67c8 100644
--- a/lib/api/helpers/projects_helpers.rb
+++ b/lib/api/helpers/projects_helpers.rb
@@ -170,4 +170,4 @@ module API
end
end
-API::Helpers::ProjectsHelpers.prepend_if_ee('EE::API::Helpers::ProjectsHelpers')
+API::Helpers::ProjectsHelpers.prepend_mod_with('API::Helpers::ProjectsHelpers')
diff --git a/lib/api/helpers/protected_branches_helpers.rb b/lib/api/helpers/protected_branches_helpers.rb
index 970a3687214..4a968ad1d60 100644
--- a/lib/api/helpers/protected_branches_helpers.rb
+++ b/lib/api/helpers/protected_branches_helpers.rb
@@ -12,4 +12,4 @@ module API
end
end
-API::Helpers::ProtectedBranchesHelpers.prepend_if_ee('EE::API::Helpers::ProtectedBranchesHelpers')
+API::Helpers::ProtectedBranchesHelpers.prepend_mod_with('API::Helpers::ProtectedBranchesHelpers')
diff --git a/lib/api/helpers/related_resources_helpers.rb b/lib/api/helpers/related_resources_helpers.rb
index 9cdde25fe4e..d0eda68bf52 100644
--- a/lib/api/helpers/related_resources_helpers.rb
+++ b/lib/api/helpers/related_resources_helpers.rb
@@ -23,10 +23,10 @@ module API
# Using a blank component at the beginning of the join we ensure
# that the resulted path will start with '/'. If the resulted path
- # does not start with '/', URI::Generic#build will fail
+ # does not start with '/', URI::Generic#new will fail
path_with_script_name = File.join('', [script_name, path].select(&:present?))
- URI::Generic.build(scheme: protocol, host: host, port: port, path: path_with_script_name).to_s
+ URI::Generic.new(protocol, nil, host, port, nil, path_with_script_name, nil, nil, nil, URI::RFC3986_PARSER, true).to_s
end
private
diff --git a/lib/api/helpers/resource_label_events_helpers.rb b/lib/api/helpers/resource_label_events_helpers.rb
index ad2733baffc..7e641130062 100644
--- a/lib/api/helpers/resource_label_events_helpers.rb
+++ b/lib/api/helpers/resource_label_events_helpers.rb
@@ -15,4 +15,4 @@ module API
end
end
-API::Helpers::ResourceLabelEventsHelpers.prepend_if_ee('EE::API::Helpers::ResourceLabelEventsHelpers')
+API::Helpers::ResourceLabelEventsHelpers.prepend_mod_with('API::Helpers::ResourceLabelEventsHelpers')
diff --git a/lib/api/helpers/runner.rb b/lib/api/helpers/runner.rb
index 688cd2da994..6f25cf507bc 100644
--- a/lib/api/helpers/runner.rb
+++ b/lib/api/helpers/runner.rb
@@ -5,7 +5,7 @@ module API
module Runner
include Gitlab::Utils::StrongMemoize
- prepend_if_ee('EE::API::Helpers::Runner') # rubocop: disable Cop/InjectEnterpriseEditionModule
+ prepend_mod_with('API::Helpers::Runner') # rubocop: disable Cop/InjectEnterpriseEditionModule
JOB_TOKEN_HEADER = 'HTTP_JOB_TOKEN'
JOB_TOKEN_PARAM = :token
@@ -87,6 +87,10 @@ module API
project: -> { current_job.project }
)
end
+
+ def track_ci_minutes_usage!(_build, _runner)
+ # noop: overridden in EE
+ end
end
end
end
diff --git a/lib/api/helpers/search_helpers.rb b/lib/api/helpers/search_helpers.rb
index cb5f92fa62a..66321306496 100644
--- a/lib/api/helpers/search_helpers.rb
+++ b/lib/api/helpers/search_helpers.rb
@@ -25,4 +25,4 @@ module API
end
end
-API::Helpers::SearchHelpers.prepend_if_ee('EE::API::Helpers::SearchHelpers')
+API::Helpers::SearchHelpers.prepend_mod_with('API::Helpers::SearchHelpers')
diff --git a/lib/api/helpers/services_helpers.rb b/lib/api/helpers/services_helpers.rb
index 2f2ad88c942..d123db8e3df 100644
--- a/lib/api/helpers/services_helpers.rb
+++ b/lib/api/helpers/services_helpers.rb
@@ -420,44 +420,6 @@ module API
},
chat_notification_events
].flatten,
- 'hipchat' => [
- {
- required: true,
- name: :token,
- type: String,
- desc: 'The room token'
- },
- {
- required: false,
- name: :room,
- type: String,
- desc: 'The room name or ID'
- },
- {
- required: false,
- name: :color,
- type: String,
- desc: 'The room color'
- },
- {
- required: false,
- name: :notify,
- type: Boolean,
- desc: 'Enable notifications'
- },
- {
- required: false,
- name: :api_version,
- type: String,
- desc: 'Leave blank for default (v2)'
- },
- {
- required: false,
- name: :server,
- type: String,
- desc: 'Leave blank for default. https://hipchat.example.com'
- }
- ],
'irker' => [
{
required: true,
@@ -803,7 +765,7 @@ module API
required: true,
name: :webhook,
type: String,
- desc: 'The Webex Teams webhook. e.g. https://api.ciscospark.com/v1/webhooks/incoming/…'
+ desc: 'The Webex Teams webhook. For example, https://api.ciscospark.com/v1/webhooks/incoming/...'
},
chat_notification_events
].flatten
@@ -812,23 +774,22 @@ module API
def self.service_classes
[
- ::AsanaService,
- ::AssemblaService,
- ::BambooService,
+ ::Integrations::Asana,
+ ::Integrations::Assembla,
+ ::Integrations::Bamboo,
+ ::Integrations::Campfire,
+ ::Integrations::Confluence,
+ ::Integrations::Datadog,
+ ::Integrations::EmailsOnPush,
::BugzillaService,
::BuildkiteService,
- ::ConfluenceService,
- ::CampfireService,
::CustomIssueTrackerService,
- ::DatadogService,
::DiscordService,
::DroneCiService,
- ::EmailsOnPushService,
::EwmService,
::ExternalWikiService,
::FlowdockService,
::HangoutsChatService,
- ::HipchatService,
::IrkerService,
::JenkinsService,
::JiraService,
@@ -858,4 +819,4 @@ module API
end
end
-API::Helpers::ServicesHelpers.prepend_if_ee('EE::API::Helpers::ServicesHelpers')
+API::Helpers::ServicesHelpers.prepend_mod_with('API::Helpers::ServicesHelpers')
diff --git a/lib/api/helpers/settings_helpers.rb b/lib/api/helpers/settings_helpers.rb
index 451e578fdd6..a3ea1057bc8 100644
--- a/lib/api/helpers/settings_helpers.rb
+++ b/lib/api/helpers/settings_helpers.rb
@@ -19,4 +19,4 @@ module API
end
end
-API::Helpers::SettingsHelpers.prepend_if_ee('EE::API::Helpers::SettingsHelpers')
+API::Helpers::SettingsHelpers.prepend_mod_with('API::Helpers::SettingsHelpers')
diff --git a/lib/api/helpers/users_helpers.rb b/lib/api/helpers/users_helpers.rb
index 2d7b22e66b3..1a019283bc6 100644
--- a/lib/api/helpers/users_helpers.rb
+++ b/lib/api/helpers/users_helpers.rb
@@ -22,4 +22,4 @@ module API
end
end
-API::Helpers::UsersHelpers.prepend_if_ee('EE::API::Helpers::UsersHelpers')
+API::Helpers::UsersHelpers.prepend_mod_with('API::Helpers::UsersHelpers')
diff --git a/lib/api/helpers/variables_helpers.rb b/lib/api/helpers/variables_helpers.rb
index e2b3372fc33..edbdcb257e7 100644
--- a/lib/api/helpers/variables_helpers.rb
+++ b/lib/api/helpers/variables_helpers.rb
@@ -24,4 +24,4 @@ module API
end
end
-API::Helpers::VariablesHelpers.prepend_if_ee('EE::API::Helpers::VariablesHelpers')
+API::Helpers::VariablesHelpers.prepend_mod_with('API::Helpers::VariablesHelpers')
diff --git a/lib/api/helpers/wikis_helpers.rb b/lib/api/helpers/wikis_helpers.rb
index 49da1e317ab..4a14dc1f40a 100644
--- a/lib/api/helpers/wikis_helpers.rb
+++ b/lib/api/helpers/wikis_helpers.rb
@@ -32,4 +32,4 @@ module API
end
end
-API::Helpers::WikisHelpers.prepend_if_ee('EE::API::Helpers::WikisHelpers')
+API::Helpers::WikisHelpers.prepend_mod_with('API::Helpers::WikisHelpers')
diff --git a/lib/api/internal/base.rb b/lib/api/internal/base.rb
index 4dcfc0cf7eb..e16149185c9 100644
--- a/lib/api/internal/base.rb
+++ b/lib/api/internal/base.rb
@@ -158,7 +158,7 @@ module API
status 200
unless actor.key_or_user
- raise ActiveRecord::RecordNotFound.new('User not found!')
+ raise ActiveRecord::RecordNotFound, 'User not found!'
end
actor.update_last_used_at!
@@ -336,4 +336,4 @@ module API
end
end
-API::Internal::Base.prepend_if_ee('EE::API::Internal::Base')
+API::Internal::Base.prepend_mod_with('API::Internal::Base')
diff --git a/lib/api/internal/kubernetes.rb b/lib/api/internal/kubernetes.rb
index af2c53dd778..c28e2181873 100644
--- a/lib/api/internal/kubernetes.rb
+++ b/lib/api/internal/kubernetes.rb
@@ -107,18 +107,18 @@ module API
detail 'Updates usage metrics for agent'
end
params do
- requires :gitops_sync_count, type: Integer, desc: 'The count to increment the gitops_sync metric by'
+ optional :gitops_sync_count, type: Integer, desc: 'The count to increment the gitops_sync metric by'
+ optional :k8s_api_proxy_request_count, type: Integer, desc: 'The count to increment the k8s_api_proxy_request_count metric by'
end
post '/' do
- gitops_sync_count = params[:gitops_sync_count]
+ events = params.slice(:gitops_sync_count, :k8s_api_proxy_request_count)
+ events.transform_keys! { |event| event.to_s.chomp('_count') }
- if gitops_sync_count < 0
- bad_request!('gitops_sync_count must be greater than or equal to zero')
- else
- Gitlab::UsageDataCounters::KubernetesAgentCounter.increment_gitops_sync(gitops_sync_count)
+ Gitlab::UsageDataCounters::KubernetesAgentCounter.increment_event_counts(events)
- no_content!
- end
+ no_content!
+ rescue ArgumentError => e
+ bad_request!(e.message)
end
end
end
@@ -126,4 +126,4 @@ module API
end
end
-API::Internal::Kubernetes.prepend_if_ee('EE::API::Internal::Kubernetes')
+API::Internal::Kubernetes.prepend_mod_with('API::Internal::Kubernetes')
diff --git a/lib/api/issue_links.rb b/lib/api/issue_links.rb
index 1cd5bde224b..0b4f4e06d0b 100644
--- a/lib/api/issue_links.rb
+++ b/lib/api/issue_links.rb
@@ -21,12 +21,12 @@ module API
related_issues = source_issue.related_issues(current_user) do |issues|
issues.with_api_entity_associations.preload_awardable
end
- related_issues.each { |issue| issue.lazy_subscription(current_user, user_project) } # preload subscriptions
present related_issues,
with: Entities::RelatedIssue,
current_user: current_user,
- project: user_project
+ project: user_project,
+ include_subscribed: false
end
desc 'Relate issues' do
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index c844655f0b3..355b5ed3a1f 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -74,6 +74,7 @@ module API
desc: 'Return issues sorted in `asc` or `desc` order.'
optional :due_date, type: String, values: %w[0 overdue week month next_month_and_previous_two_weeks] << '',
desc: 'Return issues that have no due date (`0`), or whose due date is this week, this month, between two weeks ago and next month, or which are overdue. Accepts: `overdue`, `week`, `month`, `next_month_and_previous_two_weeks`, `0`'
+ optional :issue_type, type: String, values: Issue.issue_types.keys, desc: "The type of the issue. Accepts: #{Issue.issue_types.keys.join(', ')}"
use :issues_stats_params
use :pagination
@@ -90,6 +91,7 @@ module API
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"
+ optional :issue_type, type: String, values: Issue.issue_types.keys, desc: "The type of the issue. Accepts: #{Issue.issue_types.keys.join(', ')}"
use :optional_issue_params_ee
end
@@ -253,9 +255,9 @@ module API
issue_params = convert_parameters_from_legacy_format(issue_params)
begin
- issue = ::Issues::CreateService.new(user_project,
- current_user,
- issue_params.merge(request: request, api: true)).execute
+ issue = ::Issues::CreateService.new(project: user_project,
+ current_user: current_user,
+ params: issue_params.merge(request: request, api: true)).execute
if issue.spam?
render_api_error!({ error: 'Spam detected' }, 400)
@@ -296,9 +298,9 @@ module API
update_params = convert_parameters_from_legacy_format(update_params)
- issue = ::Issues::UpdateService.new(user_project,
- current_user,
- update_params).execute(issue)
+ issue = ::Issues::UpdateService.new(project: user_project,
+ current_user: current_user,
+ params: update_params).execute(issue)
render_spam_error! if issue.spam?
@@ -326,7 +328,7 @@ module API
authorize! :update_issue, issue
- if ::Issues::ReorderService.new(user_project, current_user, params).execute(issue)
+ if ::Issues::ReorderService.new(project: user_project, current_user: current_user, params: params).execute(issue)
present issue, with: Entities::Issue, current_user: current_user, project: user_project
else
render_api_error!({ error: 'Unprocessable Entity' }, 422)
@@ -352,7 +354,7 @@ module API
not_found!('Project') unless new_project
begin
- issue = ::Issues::MoveService.new(user_project, current_user).execute(issue, new_project)
+ issue = ::Issues::MoveService.new(project: user_project, current_user: current_user).execute(issue, new_project)
present issue, with: Entities::Issue, current_user: current_user, project: user_project
rescue ::Issues::MoveService::MoveError => error
render_api_error!(error.message, 400)
@@ -372,7 +374,7 @@ module API
authorize!(:destroy_issue, issue)
destroy_conditionally!(issue) do |issue|
- Issuable::DestroyService.new(user_project, current_user).execute(issue)
+ Issuable::DestroyService.new(project: user_project, current_user: current_user).execute(issue)
end
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -386,7 +388,7 @@ module API
get ':id/issues/:issue_iid/related_merge_requests' do
issue = find_project_issue(params[:issue_iid])
- merge_requests = ::Issues::ReferencedMergeRequestsService.new(user_project, current_user)
+ merge_requests = ::Issues::ReferencedMergeRequestsService.new(project: user_project, current_user: current_user)
.execute(issue)
.first
@@ -446,4 +448,4 @@ module API
end
end
-API::Issues.prepend_if_ee('EE::API::Issues')
+API::Issues.prepend_mod_with('API::Issues')
diff --git a/lib/api/job_artifacts.rb b/lib/api/job_artifacts.rb
index 3dec0a29181..37199279205 100644
--- a/lib/api/job_artifacts.rb
+++ b/lib/api/job_artifacts.rb
@@ -13,7 +13,7 @@ module API
end
end
- prepend_if_ee('EE::API::JobArtifacts') # rubocop: disable Cop/InjectEnterpriseEditionModule
+ prepend_mod_with('API::JobArtifacts') # rubocop: disable Cop/InjectEnterpriseEditionModule
params do
requires :id, type: String, desc: 'The ID of a project'
diff --git a/lib/api/jobs.rb b/lib/api/jobs.rb
index 54951f9bd01..cf65bfdfd0e 100644
--- a/lib/api/jobs.rb
+++ b/lib/api/jobs.rb
@@ -202,4 +202,4 @@ module API
end
end
-API::Jobs.prepend_if_ee('EE::API::Jobs')
+API::Jobs.prepend_mod_with('API::Jobs')
diff --git a/lib/api/maven_packages.rb b/lib/api/maven_packages.rb
index bd1d984719e..22f7b07809b 100644
--- a/lib/api/maven_packages.rb
+++ b/lib/api/maven_packages.rb
@@ -25,7 +25,7 @@ module API
helpers do
def path_exists?(path)
# return true when FF disabled so that processing the request is not stopped
- return true unless Feature.enabled?(:check_maven_path_first)
+ return true unless Feature.enabled?(:check_maven_path_first, default_enabled: :yaml)
return false if path.blank?
Packages::Maven::Metadatum.with_path(path)
@@ -88,17 +88,13 @@ module API
end
def fetch_package(file_name:, project: nil, group: nil)
- order_by_package_file = false
- if Feature.enabled?(:maven_packages_group_level_improvements, default_enabled: :yaml)
- order_by_package_file = file_name.include?(::Packages::Maven::Metadata.filename) &&
- !params[:path].include?(::Packages::Maven::FindOrCreatePackageService::SNAPSHOT_TERM)
- end
+ order_by_package_file = file_name.include?(::Packages::Maven::Metadata.filename) &&
+ !params[:path].include?(::Packages::Maven::FindOrCreatePackageService::SNAPSHOT_TERM)
::Packages::Maven::PackageFinder.new(
- params[:path],
current_user,
- project: project,
- group: group,
+ project || group,
+ path: params[:path],
order_by_package_file: order_by_package_file
).execute!
end
diff --git a/lib/api/members.rb b/lib/api/members.rb
index aaf0e3e1927..a1a733ea7ae 100644
--- a/lib/api/members.rb
+++ b/lib/api/members.rb
@@ -175,4 +175,4 @@ module API
end
end
-API::Members.prepend_if_ee('EE::API::Members')
+API::Members.prepend_mod_with('API::Members')
diff --git a/lib/api/merge_request_approvals.rb b/lib/api/merge_request_approvals.rb
index 0cdfd8f94b4..83150bb51ca 100644
--- a/lib/api/merge_request_approvals.rb
+++ b/lib/api/merge_request_approvals.rb
@@ -54,7 +54,7 @@ module API
success =
::MergeRequests::ApprovalService
- .new(user_project, current_user, params)
+ .new(project: user_project, current_user: current_user, params: params)
.execute(merge_request)
unauthorized! unless success
@@ -67,7 +67,7 @@ module API
merge_request = find_merge_request_with_access(params[:merge_request_iid], :approve_merge_request)
success = ::MergeRequests::RemoveApprovalService
- .new(user_project, current_user)
+ .new(project: user_project, current_user: current_user)
.execute(merge_request)
not_found! unless success
@@ -79,4 +79,4 @@ module API
end
end
-API::MergeRequestApprovals.prepend_if_ee('EE::API::MergeRequestApprovals')
+API::MergeRequestApprovals.prepend_mod_with('API::MergeRequestApprovals')
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 613de514ffa..931d2322c98 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -52,7 +52,7 @@ module API
]
end
- prepend_if_ee('EE::API::MergeRequests') # rubocop: disable Cop/InjectEnterpriseEditionModule
+ prepend_mod_with('API::MergeRequests') # rubocop: disable Cop/InjectEnterpriseEditionModule
helpers do
# rubocop: disable CodeReuse/ActiveRecord
@@ -201,7 +201,11 @@ module API
options = serializer_options_for(merge_requests).merge(project: user_project)
options[:project] = user_project
- present merge_requests, options
+ if Feature.enabled?(:api_caching_merge_requests, user_project, type: :development, default_enabled: :yaml)
+ present_cached merge_requests, expires_in: 10.minutes, **options
+ else
+ present merge_requests, options
+ end
end
desc 'Create a merge request' do
@@ -224,7 +228,7 @@ module API
mr_params[:force_remove_source_branch] = mr_params.delete(:remove_source_branch)
mr_params = convert_parameters_from_legacy_format(mr_params)
- merge_request = ::MergeRequests::CreateService.new(user_project, current_user, mr_params).execute
+ merge_request = ::MergeRequests::CreateService.new(project: user_project, current_user: current_user, params: mr_params).execute
handle_merge_request_errors!(merge_request)
@@ -243,7 +247,7 @@ module API
authorize!(:destroy_merge_request, merge_request)
destroy_conditionally!(merge_request) do |merge_request|
- Issuable::DestroyService.new(user_project, current_user).execute(merge_request)
+ Issuable::DestroyService.new(project: user_project, current_user: current_user).execute(merge_request)
end
end
@@ -335,7 +339,7 @@ module API
authorize!(:update_merge_request, merge_request)
project = merge_request.target_project
- result = ::MergeRequests::AddContextService.new(project, current_user, merge_request: merge_request, commits: commit_ids).execute
+ result = ::MergeRequests::AddContextService.new(project: project, current_user: current_user, params: { merge_request: merge_request, commits: commit_ids }).execute
if result.instance_of?(Array)
present result, with: Entities::Commit
@@ -398,7 +402,7 @@ module API
end
post ':id/merge_requests/:merge_request_iid/pipelines', feature_category: :continuous_integration do
pipeline = ::MergeRequests::CreatePipelineService
- .new(user_project, current_user, allow_duplicate: true)
+ .new(project: user_project, current_user: current_user, params: { allow_duplicate: true })
.execute(find_merge_request_with_access(params[:merge_request_iid]))
if pipeline.nil?
@@ -439,7 +443,7 @@ module API
::MergeRequests::UpdateService
end
- merge_request = service.new(user_project, current_user, mr_params).execute(merge_request)
+ merge_request = service.new(project: user_project, current_user: current_user, params: mr_params).execute(merge_request)
handle_merge_request_errors!(merge_request)
@@ -489,7 +493,7 @@ module API
if immediately_mergeable
::MergeRequests::MergeService
- .new(merge_request.target_project, current_user, merge_params)
+ .new(project: merge_request.target_project, current_user: current_user, params: merge_params)
.execute(merge_request)
elsif automatically_mergeable
AutoMergeService.new(merge_request.target_project, current_user, merge_params)
diff --git a/lib/api/namespaces.rb b/lib/api/namespaces.rb
index 465d2f23e9d..9d41c2f148f 100644
--- a/lib/api/namespaces.rb
+++ b/lib/api/namespaces.rb
@@ -19,7 +19,7 @@ module API
end
end
- prepend_if_ee('EE::API::Namespaces') # rubocop: disable Cop/InjectEnterpriseEditionModule
+ prepend_mod_with('API::Namespaces') # rubocop: disable Cop/InjectEnterpriseEditionModule
resource :namespaces do
desc 'Get a namespaces list' do
diff --git a/lib/api/package_files.rb b/lib/api/package_files.rb
index 4a33f3e8af2..6d0c1f44a36 100644
--- a/lib/api/package_files.rb
+++ b/lib/api/package_files.rb
@@ -30,6 +30,29 @@ module API
present paginate(package.package_files), with: ::API::Entities::PackageFile
end
+
+ desc 'Remove a package file' do
+ detail 'This feature was introduced in GitLab 13.12'
+ end
+ params do
+ requires :package_file_id, type: Integer, desc: 'The ID of a package file'
+ end
+ delete ':id/packages/:package_id/package_files/:package_file_id' do
+ authorize_destroy_package!(user_project)
+
+ # We want to make sure the file belongs to the declared package
+ # so we look up the package before looking up the file.
+ package = ::Packages::PackageFinder
+ .new(user_project, params[:package_id]).execute
+
+ not_found! unless package
+
+ package_file = package.package_files.find_by_id(params[:package_file_id])
+
+ not_found! unless package_file
+
+ destroy_conditionally!(package_file)
+ end
end
end
end
diff --git a/lib/api/project_container_repositories.rb b/lib/api/project_container_repositories.rb
index 3125de88de5..2580f7adbc9 100644
--- a/lib/api/project_container_repositories.rb
+++ b/lib/api/project_container_repositories.rb
@@ -15,6 +15,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
end
+ route_setting :authentication, job_token_allowed: true, job_token_scope: :project
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a project container repositories' do
detail 'This feature was introduced in GitLab 11.8.'
diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb
index 5f3a574eeee..039f7b4be41 100644
--- a/lib/api/project_import.rb
+++ b/lib/api/project_import.rb
@@ -14,6 +14,21 @@ module API
def import_params
declared_params(include_missing: false)
end
+
+ def namespace_from(params, current_user)
+ if params[:namespace]
+ find_namespace!(params[:namespace])
+ else
+ current_user.namespace
+ end
+ end
+
+ def filtered_override_params(params)
+ override_params = params.delete(:override_params)
+ filter_attributes_using_license!(override_params) if override_params
+
+ override_params
+ end
end
before do
@@ -67,34 +82,25 @@ module API
check_rate_limit! :project_import, [current_user, :project_import]
- Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/20823')
+ Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/21041')
validate_file!
- namespace = if import_params[:namespace]
- find_namespace!(import_params[:namespace])
- else
- current_user.namespace
- end
-
- project_params = {
- path: import_params[:path],
- namespace_id: namespace.id,
- name: import_params[:name],
- file: import_params[:file],
- overwrite: import_params[:overwrite]
- }
-
- override_params = import_params.delete(:override_params)
- filter_attributes_using_license!(override_params) if override_params
-
- project = ::Projects::GitlabProjectsImportService.new(
- current_user, project_params, override_params
+ response = ::Import::GitlabProjects::CreateProjectFromUploadedFileService.new(
+ current_user,
+ path: import_params[:path],
+ namespace: namespace_from(import_params, current_user),
+ name: import_params[:name],
+ file: import_params[:file],
+ overwrite: import_params[:overwrite],
+ override: filtered_override_params(import_params)
).execute
- render_api_error!(project.errors.full_messages&.first, 400) unless project.saved?
-
- present project, with: Entities::ProjectImportStatus
+ if response.success?
+ present(response.payload, with: Entities::ProjectImportStatus)
+ else
+ render_api_error!(response.message, response.http_status)
+ end
end
params do
@@ -107,6 +113,44 @@ module API
get ':id/import' do
present user_project, with: Entities::ProjectImportStatus
end
+
+ params do
+ requires :url, type: String, desc: 'The URL for the file.'
+ requires :path, type: String, desc: 'The new project path and name'
+ optional :name, type: String, desc: 'The name of the project to be imported. Defaults to the path of the project if not provided.'
+ optional :namespace, type: String, desc: "The ID or name of the namespace that the project will be imported into. Defaults to the current user's namespace."
+ optional :overwrite, type: Boolean, default: false, desc: 'If there is a project in the same namespace and with the same name overwrite it'
+ optional :override_params,
+ type: Hash,
+ desc: 'New project params to override values in the export' do
+ use :optional_project_params
+ end
+ end
+ desc 'Create a new project import using a remote object storage path' do
+ detail 'This feature was introduced in GitLab 13.2.'
+ success Entities::ProjectImportStatus
+ end
+ post 'remote-import' do
+ not_found! unless ::Feature.enabled?(:import_project_from_remote_file)
+
+ check_rate_limit! :project_import, [current_user, :project_import]
+
+ response = ::Import::GitlabProjects::CreateProjectFromRemoteFileService.new(
+ current_user,
+ path: import_params[:path],
+ namespace: namespace_from(import_params, current_user),
+ name: import_params[:name],
+ remote_import_url: import_params[:url],
+ overwrite: import_params[:overwrite],
+ override: filtered_override_params(import_params)
+ ).execute
+
+ if response.success?
+ present(response.payload, with: Entities::ProjectImportStatus)
+ else
+ render_api_error!(response.message, response.http_status)
+ end
+ end
end
end
end
diff --git a/lib/api/project_milestones.rb b/lib/api/project_milestones.rb
index 8675de33923..107311ea446 100644
--- a/lib/api/project_milestones.rb
+++ b/lib/api/project_milestones.rb
@@ -117,4 +117,4 @@ module API
end
end
-API::ProjectMilestones.prepend_if_ee('EE::API::ProjectMilestones')
+API::ProjectMilestones.prepend_mod_with('API::ProjectMilestones')
diff --git a/lib/api/project_templates.rb b/lib/api/project_templates.rb
index fdfdc244cbe..5d6f67ccbae 100644
--- a/lib/api/project_templates.rb
+++ b/lib/api/project_templates.rb
@@ -4,7 +4,7 @@ module API
class ProjectTemplates < ::API::Base
include PaginationParams
- TEMPLATE_TYPES = %w[dockerfiles gitignores gitlab_ci_ymls gitlab_ci_syntax_ymls licenses metrics_dashboard_ymls issues merge_requests].freeze
+ TEMPLATE_TYPES = %w[dockerfiles gitignores gitlab_ci_ymls licenses metrics_dashboard_ymls issues merge_requests].freeze
# The regex is needed to ensure a period (e.g. agpl-3.0)
# isn't confused with a format type. We also need to allow encoded
# values (e.g. C%2B%2B for C++), so allow % and + as well.
@@ -16,7 +16,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
- requires :type, type: String, values: TEMPLATE_TYPES, desc: 'The type (dockerfiles|gitignores|gitlab_ci_ymls|gitlab_ci_syntax_ymls|licenses|metrics_dashboard_ymls|issues|merge_requests) of the template'
+ requires :type, type: String, values: TEMPLATE_TYPES, desc: 'The type (dockerfiles|gitignores|gitlab_ci_ymls|licenses|metrics_dashboard_ymls|issues|merge_requests) of the template'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a list of templates available to this project' do
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 92f6970e6fc..4e8786fbe1f 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require_dependency 'declarative_policy'
-
module API
class Projects < ::API::Base
include PaginationParams
@@ -119,6 +117,7 @@ module API
optional :last_activity_after, type: DateTime, desc: 'Limit results to projects with last_activity after specified time. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ'
optional :last_activity_before, type: DateTime, desc: 'Limit results to projects with last_activity before specified time. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ'
optional :repository_storage, type: String, desc: 'Which storage shard the repository is on. Available only to admins'
+ optional :topic, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'Comma-separated list of topics. Limit results to projects having all topics'
use :optional_filter_params_ee
end
@@ -619,6 +618,8 @@ module API
optional :skip_groups, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'Array of group ids to exclude from list'
optional :with_shared, type: Boolean, default: false,
desc: 'Include shared groups'
+ optional :shared_visible_only, type: Boolean, default: false,
+ desc: 'Limit to shared groups user has access to'
optional :shared_min_access_level, type: Integer, values: Gitlab::Access.all_values,
desc: 'Limit returned shared groups by minimum access level to the project'
use :pagination
@@ -663,4 +664,4 @@ module API
end
end
-API::Projects.prepend_if_ee('EE::API::Projects')
+API::Projects.prepend_mod_with('API::Projects')
diff --git a/lib/api/protected_branches.rb b/lib/api/protected_branches.rb
index 802dfdec511..3cebc308f51 100644
--- a/lib/api/protected_branches.rb
+++ b/lib/api/protected_branches.rb
@@ -104,4 +104,4 @@ module API
end
end
-API::ProtectedBranches.prepend_if_ee('EE::API::ProtectedBranches')
+API::ProtectedBranches.prepend_mod_with('API::ProtectedBranches')
diff --git a/lib/api/pypi_packages.rb b/lib/api/pypi_packages.rb
index 658c6d13847..73b2f658825 100644
--- a/lib/api/pypi_packages.rb
+++ b/lib/api/pypi_packages.rb
@@ -24,25 +24,6 @@ module API
render_api_error!(e.message, 400)
end
- helpers do
- def packages_finder(project = authorized_user_project)
- project
- .packages
- .pypi
- .has_version
- .processed
- end
-
- def find_package_versions
- packages = packages_finder
- .with_normalized_pypi_name(params[:package_name])
-
- not_found!('Package') if packages.empty?
-
- packages
- end
- end
-
before do
require_packages_enabled!
end
@@ -71,7 +52,7 @@ module API
project = unauthorized_user_project!
filename = "#{params[:file_identifier]}.#{params[:format]}"
- package = packages_finder(project).by_file_name_and_sha256(filename, params[:sha256])
+ package = Packages::Pypi::PackageFinder.new(current_user, project, { filename: filename, sha256: params[:sha256] }).execute
package_file = ::Packages::PackageFileFinder.new(package, filename, with_file_name_like: false).execute
track_package_event('pull_package', :pypi)
@@ -95,7 +76,7 @@ module API
track_package_event('list_package', :pypi)
- packages = find_package_versions
+ packages = Packages::Pypi::PackagesFinder.new(current_user, authorized_user_project, { package_name: params[:package_name] }).execute!
presenter = ::Packages::Pypi::PackagePresenter.new(packages, authorized_user_project)
# Adjusts grape output format
diff --git a/lib/api/releases.rb b/lib/api/releases.rb
index c20e618efd1..c65a23e334f 100644
--- a/lib/api/releases.rb
+++ b/lib/api/releases.rb
@@ -6,9 +6,12 @@ module API
RELEASE_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
.merge(tag_name: API::NO_SLASH_URL_PART_REGEX)
+ RELEASE_CLI_USER_AGENT = 'GitLab-release-cli'
before { authorize_read_releases! }
+ after { track_release_event }
+
feature_category :release_orchestration
params do
@@ -17,6 +20,7 @@ module API
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a project releases' do
detail 'This feature was introduced in GitLab 11.7.'
+ named 'get_releases'
success Entities::Release
end
params do
@@ -29,11 +33,22 @@ module API
get ':id/releases' do
releases = ::ReleasesFinder.new(user_project, current_user, declared_params.slice(:order_by, :sort)).execute
- present paginate(releases), with: Entities::Release, current_user: current_user
+ # We cache the serialized payload per user in order to avoid repeated renderings.
+ # Since the cached result could contain sensitive information,
+ # it will expire in a short interval.
+ present_cached paginate(releases),
+ with: Entities::Release,
+ # `current_user` could be absent if the releases are publicly accesible.
+ # We should not use `cache_key` for the user because the version/updated_at
+ # context is unnecessary here.
+ cache_context: -> (_) { "user:{#{current_user&.id}}" },
+ expires_in: 5.minutes,
+ current_user: current_user
end
desc 'Get a single project release' do
detail 'This feature was introduced in GitLab 11.7.'
+ named 'get_release'
success Entities::Release
end
params do
@@ -47,6 +62,7 @@ module API
desc 'Create a new release' do
detail 'This feature was introduced in GitLab 11.7.'
+ named 'create_release'
success Entities::Release
end
params do
@@ -84,6 +100,7 @@ module API
desc 'Update a release' do
detail 'This feature was introduced in GitLab 11.7.'
+ named 'update_release'
success Entities::Release
end
params do
@@ -112,6 +129,7 @@ module API
desc 'Delete a release' do
detail 'This feature was introduced in GitLab 11.7.'
+ named 'delete_release'
success Entities::Release
end
params do
@@ -176,8 +194,23 @@ module API
def log_release_milestones_updated_audit_event
# extended in EE
end
+
+ def release_cli?
+ request.env['HTTP_USER_AGENT']&.include?(RELEASE_CLI_USER_AGENT) == true
+ end
+
+ def event_context
+ {
+ release_cli: release_cli?
+ }
+ end
+
+ def track_release_event
+ Gitlab::Tracking.event(options[:for].name, options[:route_options][:named],
+ project: user_project, user: current_user, **event_context)
+ end
end
end
end
-API::Releases.prepend_if_ee('EE::API::Releases')
+API::Releases.prepend_mod_with('API::Releases')
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index 033cc6744b0..a5234828de3 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -37,7 +37,7 @@ module API
begin
@blob = Gitlab::Git::Blob.raw(@repo, params[:sha])
@blob.load_all_data!(@repo)
- rescue
+ rescue StandardError
not_found! 'Blob'
end
@@ -106,7 +106,7 @@ module API
not_acceptable! if Gitlab::HotlinkingDetector.intercept_hotlinking?(request)
send_git_archive user_project.repository, ref: params[:sha], format: params[:format], append_sha: true
- rescue
+ rescue StandardError
not_found!('File')
end
@@ -152,7 +152,7 @@ module API
get ':id/repository/contributors' do
contributors = ::Kaminari.paginate_array(user_project.repository.contributors(order_by: params[:order_by], sort: params[:sort]))
present paginate(contributors), with: Entities::Contributor
- rescue
+ rescue StandardError
not_found!
end
@@ -224,7 +224,7 @@ module API
desc: 'The commit message to use when committing the changelog'
end
post ':id/repository/changelog' do
- branch = params[:branch] || user_project.default_branch_or_master
+ branch = params[:branch] || user_project.default_branch_or_main
access = Gitlab::UserAccess.new(current_user, container: user_project)
unless access.can_push_to_branch?(branch)
diff --git a/lib/api/search.rb b/lib/api/search.rb
index 8fabf379d49..3c5801366a8 100644
--- a/lib/api/search.rb
+++ b/lib/api/search.rb
@@ -138,4 +138,4 @@ module API
end
end
-API::Search.prepend_if_ee('EE::API::Search')
+API::Search.prepend_mod_with('API::Search')
diff --git a/lib/api/services.rb b/lib/api/services.rb
index cfcae13e518..8a7abe721dd 100644
--- a/lib/api/services.rb
+++ b/lib/api/services.rb
@@ -72,7 +72,7 @@ module API
success Entities::ProjectServiceBasic
end
get ":id/services" do
- services = user_project.services.active
+ services = user_project.integrations.active
present services, with: Entities::ProjectServiceBasic
end
@@ -125,15 +125,18 @@ module API
requires :service_slug, type: String, values: SERVICES.keys, desc: 'The name of the service'
end
get ":id/services/:service_slug" do
- service = user_project.find_or_initialize_service(params[:service_slug].underscore)
- present service, with: Entities::ProjectService
+ integration = user_project.find_or_initialize_service(params[:service_slug].underscore)
+
+ not_found!('Service') unless integration&.persisted?
+
+ present integration, with: Entities::ProjectService
end
end
TRIGGER_SERVICES.each do |service_slug, settings|
helpers do
def slash_command_service(project, service_slug, params)
- project.services.active.find do |service|
+ project.integrations.active.find do |service|
service.try(:token) == params[:token] && service.to_param == service_slug.underscore
end
end
@@ -172,4 +175,4 @@ module API
end
end
-API::Services.prepend_if_ee('EE::API::Services')
+API::Services.prepend_mod_with('API::Services')
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index 95d0c525ced..372bc7b3d8f 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -154,6 +154,7 @@ module API
optional :spam_check_endpoint_enabled, type: Boolean, desc: 'Enable Spam Check via external API endpoint'
given spam_check_endpoint_enabled: ->(val) { val } do
requires :spam_check_endpoint_url, type: String, desc: 'The URL of the external Spam Check service endpoint'
+ requires :spam_check_api_key, type: String, desc: 'The API key used by GitLab for accessing the Spam Check service endpoint'
end
optional :terminal_max_session_time, type: Integer, desc: 'Maximum time for web terminal websocket connection (in seconds). Set to 0 for unlimited time.'
optional :usage_ping_enabled, type: Boolean, desc: 'Every week GitLab will report license usage back to GitLab, Inc.'
@@ -169,6 +170,8 @@ module API
optional :raw_blob_request_limit, type: Integer, desc: "Maximum number of requests per minute for each raw path. Set to 0 for unlimited requests per minute."
optional :wiki_page_max_content_bytes, type: Integer, desc: "Maximum wiki page content size in bytes"
optional :require_admin_approval_after_user_signup, type: Boolean, desc: 'Require explicit admin approval for new signups'
+ optional :whats_new_variant, type: String, values: ApplicationSetting.whats_new_variants.keys, desc: "What's new variant, possible values: `all_tiers`, `current_tier`, and `disabled`."
+ optional :floc_enabled, type: Grape::API::Boolean, desc: 'Enable FloC (Federated Learning of Cohorts)'
ApplicationSetting::SUPPORTED_KEY_TYPES.each do |type|
optional :"#{type}_key_restriction",
@@ -232,4 +235,4 @@ module API
end
end
-API::Settings.prepend_if_ee('EE::API::Settings')
+API::Settings.prepend_mod_with('API::Settings')
diff --git a/lib/api/templates.rb b/lib/api/templates.rb
index bc1e427bcaa..b7fb35eac03 100644
--- a/lib/api/templates.rb
+++ b/lib/api/templates.rb
@@ -13,9 +13,6 @@ module API
gitlab_ci_ymls: {
gitlab_version: 8.9
},
- gitlab_ci_syntax_ymls: {
- gitlab_version: 13.8
- },
dockerfiles: {
gitlab_version: 8.15
}
diff --git a/lib/api/terraform/modules/v1/packages.rb b/lib/api/terraform/modules/v1/packages.rb
new file mode 100644
index 00000000000..34e77e09800
--- /dev/null
+++ b/lib/api/terraform/modules/v1/packages.rb
@@ -0,0 +1,200 @@
+# frozen_string_literal: true
+
+module API
+ module Terraform
+ module Modules
+ module V1
+ class Packages < ::API::Base
+ include ::API::Helpers::Authentication
+ helpers ::API::Helpers::PackagesHelpers
+ helpers ::API::Helpers::Packages::BasicAuthHelpers
+
+ SEMVER_REGEX = Gitlab::Regex.semver_regex
+
+ TERRAFORM_MODULE_REQUIREMENTS = {
+ module_namespace: API::NO_SLASH_URL_PART_REGEX,
+ module_name: API::NO_SLASH_URL_PART_REGEX,
+ module_system: API::NO_SLASH_URL_PART_REGEX
+ }.freeze
+
+ TERRAFORM_MODULE_VERSION_REQUIREMENTS = {
+ module_version: SEMVER_REGEX
+ }.freeze
+
+ feature_category :package_registry
+
+ after_validation do
+ require_packages_enabled!
+ end
+
+ helpers do
+ params :module_name do
+ requires :module_name, type: String, desc: "", regexp: API::NO_SLASH_URL_PART_REGEX
+ requires :module_system, type: String, regexp: API::NO_SLASH_URL_PART_REGEX
+ end
+
+ params :module_version do
+ requires :module_version, type: String, desc: 'Module version', regexp: SEMVER_REGEX
+ end
+
+ def module_namespace
+ strong_memoize(:module_namespace) do
+ find_namespace(params[:module_namespace])
+ end
+ end
+
+ def finder_params
+ {
+ package_type: :terraform_module,
+ package_name: "#{params[:module_name]}/#{params[:module_system]}"
+ }.tap do |finder_params|
+ finder_params[:package_version] = params[:module_version] if params.has_key?(:module_version)
+ end
+ end
+
+ def packages
+ strong_memoize(:packages) do
+ ::Packages::GroupPackagesFinder.new(
+ current_user,
+ module_namespace,
+ finder_params
+ ).execute
+ end
+ end
+
+ def package
+ strong_memoize(:package) do
+ packages.first
+ end
+ end
+
+ def package_file
+ strong_memoize(:package_file) do
+ package.package_files.first
+ end
+ end
+ end
+
+ params do
+ requires :module_namespace, type: String, desc: "Group's ID or slug", regexp: API::NO_SLASH_URL_PART_REGEX
+ includes :module_name
+ end
+
+ namespace 'packages/terraform/modules/v1/:module_namespace/:module_name/:module_system', requirements: TERRAFORM_MODULE_REQUIREMENTS do
+ authenticate_with do |accept|
+ accept.token_types(:personal_access_token, :deploy_token, :job_token)
+ .sent_through(:http_bearer_token)
+ end
+
+ after_validation do
+ authorize_read_package!(package || module_namespace)
+ end
+
+ get 'versions' do
+ presenter = ::Terraform::ModulesPresenter.new(packages, params[:module_system])
+ present presenter, with: ::API::Entities::Terraform::ModuleVersions
+ end
+
+ params do
+ includes :module_version
+ end
+
+ namespace '*module_version', requirements: TERRAFORM_MODULE_VERSION_REQUIREMENTS do
+ after_validation do
+ not_found! unless package && package_file
+ end
+
+ get 'download' do
+ module_file_path = api_v4_packages_terraform_modules_v1_module_version_file_path(
+ module_namespace: params[:module_namespace],
+ module_name: params[:module_name],
+ module_system: params[:module_system],
+ module_version: params[:module_version]
+ )
+
+ jwt_token = Gitlab::TerraformRegistryToken.from_token(token_from_namespace_inheritable).encoded
+
+ header 'X-Terraform-Get', module_file_path.sub(%r{module_version/file$}, "#{params[:module_version]}/file?token=#{jwt_token}&archive=tgz")
+ status :no_content
+ end
+
+ namespace 'file' do
+ authenticate_with do |accept|
+ accept.token_types(:deploy_token_from_jwt, :job_token_from_jwt, :personal_access_token_from_jwt).sent_through(:token_param)
+ end
+
+ get do
+ track_package_event('pull_package', :terraform_module)
+
+ present_carrierwave_file!(package_file.file)
+ end
+ end
+ end
+ end
+
+ params do
+ requires :id, type: String, desc: 'The ID or full path of a project'
+ includes :module_name
+ includes :module_version
+ end
+
+ resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ namespace ':id/packages/terraform/modules/:module_name/:module_system/*module_version/file' do
+ authenticate_with do |accept|
+ accept.token_types(:deploy_token).sent_through(:http_deploy_token_header)
+ accept.token_types(:job_token).sent_through(:http_job_token_header)
+ accept.token_types(:personal_access_token).sent_through(:http_private_token_header)
+ end
+
+ desc 'Workhorse authorize Terraform Module package file' do
+ detail 'This feature was introduced in GitLab 13.11'
+ end
+
+ put 'authorize' do
+ authorize_workhorse!(
+ subject: authorized_user_project,
+ maximum_size: authorized_user_project.actual_limits.terraform_module_max_file_size
+ )
+ end
+
+ desc 'Upload Terraform Module package file' do
+ detail 'This feature was introduced in GitLab 13.11'
+ end
+
+ params do
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ end
+
+ put do
+ authorize_upload!(authorized_user_project)
+ bad_request!('File is too large') if authorized_user_project.actual_limits.exceeded?(:terraform_module_max_file_size, params[:file].size)
+
+ create_package_file_params = {
+ module_name: params['module_name'],
+ module_system: params['module_system'],
+ module_version: params['module_version'],
+ file: params['file'],
+ build: current_authenticated_job
+ }
+
+ result = ::Packages::TerraformModule::CreatePackageService
+ .new(authorized_user_project, current_user, create_package_file_params)
+ .execute
+
+ render_api_error!(result[:message], result[:http_status]) if result[:status] == :error
+
+ track_package_event('push_package', :terraform_module)
+
+ created!
+ rescue ObjectStorage::RemoteStoreError => e
+ Gitlab::ErrorTracking.track_exception(e, extra: { file_name: params[:file_name], project_id: authorized_user_project.id })
+
+ forbidden!
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/time_tracking_endpoints.rb b/lib/api/time_tracking_endpoints.rb
index da234fb5277..969122d7906 100644
--- a/lib/api/time_tracking_endpoints.rb
+++ b/lib/api/time_tracking_endpoints.rb
@@ -37,7 +37,7 @@ module API
custom_params = declared_params(include_missing: false)
custom_params.merge!(attrs)
- issuable = update_service.new(user_project, current_user, custom_params).execute(load_issuable)
+ issuable = update_service.new(project: user_project, current_user: current_user, params: custom_params).execute(load_issuable)
if issuable.valid?
present issuable, with: Entities::IssuableTimeStats
else
@@ -85,10 +85,15 @@ module API
post ":id/#{issuable_collection_name}/:#{issuable_key}/add_spent_time" do
authorize! admin_issuable_key, load_issuable
- update_issuable(spend_time: {
- duration: Gitlab::TimeTrackingFormatter.parse(params.delete(:duration)),
- user_id: current_user.id
- })
+ update_params = {
+ spend_time: {
+ duration: Gitlab::TimeTrackingFormatter.parse(params.delete(:duration)),
+ user_id: current_user.id
+ }
+ }
+ update_params[:use_specialized_service] = true if issuable_name == 'merge_request'
+
+ update_issuable(update_params)
end
desc "Reset spent time for a project #{issuable_name}"
diff --git a/lib/api/todos.rb b/lib/api/todos.rb
index afc1525cbe2..a001313a11f 100644
--- a/lib/api/todos.rb
+++ b/lib/api/todos.rb
@@ -79,7 +79,7 @@ module API
next unless collection
targets = collection.map(&:target)
- options[type] = { issuable_metadata: Gitlab::IssuableMetadata.new(current_user, targets).data }
+ options[type] = { issuable_metadata: Gitlab::IssuableMetadata.new(current_user, targets).data, include_subscribed: false }
end
end
end
@@ -124,4 +124,4 @@ module API
end
end
-API::Todos.prepend_if_ee('EE::API::Todos')
+API::Todos.prepend_mod_with('API::Todos')
diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb
index 84c51e5aeac..a359083a9d2 100644
--- a/lib/api/triggers.rb
+++ b/lib/api/triggers.rb
@@ -37,7 +37,7 @@ module API
result = ::Ci::PipelineTriggerService.new(project, nil, params).execute
not_found! unless result
- if result[:http_status]
+ if result.error?
render_api_error!(result[:message], result[:http_status])
else
present result[:pipeline], with: Entities::Ci::Pipeline
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 078ba7542a3..565a3544da2 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -996,6 +996,30 @@ module API
present paginate(current_user.emails), with: Entities::Email
end
+ desc "Update a user's credit_card_validation" do
+ success Entities::UserCreditCardValidations
+ end
+ params do
+ requires :user_id, type: String, desc: 'The ID or username of the user'
+ requires :credit_card_validated_at, type: DateTime, desc: 'The time when the user\'s credit card was validated'
+ end
+ put ":user_id/credit_card_validation", feature_category: :users do
+ authenticated_as_admin!
+
+ user = find_user(params[:user_id])
+ not_found!('User') unless user
+
+ attrs = declared_params(include_missing: false)
+
+ service = ::Users::UpsertCreditCardValidationService.new(attrs).execute
+
+ if service.success?
+ present user.credit_card_validation, with: Entities::UserCreditCardValidations
+ else
+ render_api_error!('400 Bad Request', 400)
+ end
+ end
+
desc "Update the current user's preferences" do
success Entities::UserPreferences
detail 'This feature was introduced in GitLab 13.10.'
diff --git a/lib/api/validations/validators/check_assignees_count.rb b/lib/api/validations/validators/check_assignees_count.rb
index 92ada159b46..15f48c09a4f 100644
--- a/lib/api/validations/validators/check_assignees_count.rb
+++ b/lib/api/validations/validators/check_assignees_count.rb
@@ -34,4 +34,4 @@ module API
end
end
-API::Validations::Validators::CheckAssigneesCount.prepend_if_ee('EE::API::Validations::Validators::CheckAssigneesCount')
+API::Validations::Validators::CheckAssigneesCount.prepend_mod_with('API::Validations::Validators::CheckAssigneesCount')
diff --git a/lib/api/validations/validators/file_path.rb b/lib/api/validations/validators/file_path.rb
index a6a3c692fd6..246c445658f 100644
--- a/lib/api/validations/validators/file_path.rb
+++ b/lib/api/validations/validators/file_path.rb
@@ -10,7 +10,7 @@ module API
path = params[attr_name]
path = Gitlab::Utils.check_path_traversal!(path)
Gitlab::Utils.check_allowed_absolute_path!(path, path_allowlist)
- rescue
+ rescue StandardError
raise Grape::Exceptions::Validation.new(
params: [@scope.full_name(attr_name)],
message: "should be a valid file path"