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>2023-07-19 17:16:28 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-07-19 17:16:28 +0300
commite4384360a16dd9a19d4d2d25d0ef1f2b862ed2a6 (patch)
tree2fcdfa7dcdb9db8f5208b2562f4b4e803d671243 /lib/api
parentffda4e7bcac36987f936b4ba515995a6698698f0 (diff)
Add latest changes from gitlab-org/gitlab@16-2-stable-eev16.2.0-rc42
Diffstat (limited to 'lib/api')
-rw-r--r--lib/api/api.rb1
-rw-r--r--lib/api/award_emoji.rb4
-rw-r--r--lib/api/badges.rb4
-rw-r--r--lib/api/ci/pipeline_schedules.rb44
-rw-r--r--lib/api/ci/variables.rb2
-rw-r--r--lib/api/concerns/packages/debian_package_endpoints.rb19
-rw-r--r--lib/api/concerns/packages/npm_endpoints.rb29
-rw-r--r--lib/api/debian_project_packages.rb2
-rw-r--r--lib/api/deployments.rb9
-rw-r--r--lib/api/entities/blob.rb7
-rw-r--r--lib/api/entities/bulk_imports/export_batch_status.rb15
-rw-r--r--lib/api/entities/bulk_imports/export_status.rb4
-rw-r--r--lib/api/entities/ci/runner.rb1
-rw-r--r--lib/api/entities/ci/variable.rb2
-rw-r--r--lib/api/entities/dictionary/table.rb2
-rw-r--r--lib/api/entities/group.rb1
-rw-r--r--lib/api/entities/plan_limit.rb5
-rw-r--r--lib/api/entities/project_hook.rb1
-rw-r--r--lib/api/entities/protected_ref_access.rb7
-rw-r--r--lib/api/environments.rb8
-rw-r--r--lib/api/files.rb15
-rw-r--r--lib/api/group_export.rb45
-rw-r--r--lib/api/group_variables.rb3
-rw-r--r--lib/api/helpers.rb13
-rw-r--r--lib/api/helpers/custom_attributes.rb2
-rw-r--r--lib/api/helpers/integrations_helpers.rb58
-rw-r--r--lib/api/helpers/members_helpers.rb1
-rw-r--r--lib/api/helpers/packages/maven.rb22
-rw-r--r--lib/api/helpers/packages/npm.rb27
-rw-r--r--lib/api/helpers/projects_helpers.rb7
-rw-r--r--lib/api/helpers/remote_mirrors_helpers.rb2
-rw-r--r--lib/api/import_github.rb10
-rw-r--r--lib/api/internal/kubernetes.rb37
-rw-r--r--lib/api/lint.rb28
-rw-r--r--lib/api/markdown.rb5
-rw-r--r--lib/api/maven_packages.rb6
-rw-r--r--lib/api/merge_requests.rb14
-rw-r--r--lib/api/ml_model_packages.rb37
-rw-r--r--lib/api/npm_instance_packages.rb4
-rw-r--r--lib/api/npm_project_packages.rb5
-rw-r--r--lib/api/package_files.rb3
-rw-r--r--lib/api/project_export.rb50
-rw-r--r--lib/api/project_hooks.rb1
-rw-r--r--lib/api/project_packages.rb3
-rw-r--r--lib/api/projects.rb23
-rw-r--r--lib/api/remote_mirrors.rb4
-rw-r--r--lib/api/search.rb10
-rw-r--r--lib/api/settings.rb7
-rw-r--r--lib/api/usage_data.rb32
-rw-r--r--lib/api/user_runners.rb72
-rw-r--r--lib/api/users.rb61
51 files changed, 541 insertions, 233 deletions
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 090fbaa7f93..7da5f21b21f 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -316,6 +316,7 @@ module API
mount ::API::UsageDataQueries
mount ::API::Users
mount ::API::UserCounts
+ mount ::API::UserRunners
mount ::API::Wikis
add_open_api_documentation!
diff --git a/lib/api/award_emoji.rb b/lib/api/award_emoji.rb
index f7a39db7249..aa7468723b7 100644
--- a/lib/api/award_emoji.rb
+++ b/lib/api/award_emoji.rb
@@ -82,7 +82,9 @@ module API
unauthorized! unless award.user == current_user || current_user&.can_admin_all_resources?
- destroy_conditionally!(award)
+ destroy_conditionally!(award) do
+ AwardEmojis::DestroyService.new(awardable, award.name, award.user).execute
+ end
end
end
end
diff --git a/lib/api/badges.rb b/lib/api/badges.rb
index 84c9f780a53..62eecdbd5e5 100644
--- a/lib/api/badges.rb
+++ b/lib/api/badges.rb
@@ -22,7 +22,9 @@ module API
%w[group project].each do |source_type|
params do
- requires :id, type: String, desc: "The ID of a #{source_type}"
+ requires :id,
+ type: String,
+ desc: "The ID or URL-encoded path of the #{source_type} owned by the authenticated user."
end
resource source_type.pluralize, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc "Gets a list of #{source_type} badges viewable by the authenticated user." do
diff --git a/lib/api/ci/pipeline_schedules.rb b/lib/api/ci/pipeline_schedules.rb
index e27ec24fb44..1606d5ba649 100644
--- a/lib/api/ci/pipeline_schedules.rb
+++ b/lib/api/ci/pipeline_schedules.rb
@@ -90,14 +90,28 @@ module API
post ':id/pipeline_schedules' do
authorize! :create_pipeline_schedule, user_project
- pipeline_schedule = ::Ci::CreatePipelineScheduleService
- .new(user_project, current_user, declared_params(include_missing: false))
- .execute
+ if ::Feature.enabled?(:ci_refactoring_pipeline_schedule_create_service, @project)
+ response = ::Ci::PipelineSchedules::CreateService
+ .new(user_project, current_user, declared_params(include_missing: false))
+ .execute
- if pipeline_schedule.persisted?
- present pipeline_schedule, with: Entities::Ci::PipelineScheduleDetails
+ pipeline_schedule = response.payload
+
+ if response.success?
+ present pipeline_schedule, with: Entities::Ci::PipelineScheduleDetails
+ else
+ render_validation_error!(pipeline_schedule)
+ end
else
- render_validation_error!(pipeline_schedule)
+ pipeline_schedule = ::Ci::CreatePipelineScheduleService
+ .new(user_project, current_user, declared_params(include_missing: false))
+ .execute
+
+ if pipeline_schedule.persisted?
+ present pipeline_schedule, with: Entities::Ci::PipelineScheduleDetails
+ else
+ render_validation_error!(pipeline_schedule)
+ end
end
end
@@ -121,10 +135,22 @@ module API
put ':id/pipeline_schedules/:pipeline_schedule_id' do
authorize! :update_pipeline_schedule, pipeline_schedule
- if pipeline_schedule.update(declared_params(include_missing: false))
- present pipeline_schedule, with: Entities::Ci::PipelineScheduleDetails
+ if ::Feature.enabled?(:ci_refactoring_pipeline_schedule_create_service, @project)
+ response = ::Ci::PipelineSchedules::UpdateService
+ .new(pipeline_schedule, current_user, declared_params(include_missing: false))
+ .execute
+
+ if response.success?
+ present pipeline_schedule, with: Entities::Ci::PipelineScheduleDetails
+ else
+ render_validation_error!(pipeline_schedule)
+ end
else
- render_validation_error!(pipeline_schedule)
+ if pipeline_schedule.update(declared_params(include_missing: false)) # rubocop:disable Style/IfInsideElse
+ present pipeline_schedule, with: Entities::Ci::PipelineScheduleDetails
+ else
+ render_validation_error!(pipeline_schedule)
+ end
end
end
diff --git a/lib/api/ci/variables.rb b/lib/api/ci/variables.rb
index f5331eb75da..49a6ec279fb 100644
--- a/lib/api/ci/variables.rb
+++ b/lib/api/ci/variables.rb
@@ -63,6 +63,7 @@ module API
optional :raw, type: Boolean, desc: 'Whether the variable will be expanded'
optional :variable_type, type: String, values: ::Ci::Variable.variable_types.keys, desc: 'The type of the variable. Default: env_var'
optional :environment_scope, type: String, desc: 'The environment_scope of the variable'
+ optional :description, type: String, desc: 'The description of the variable'
end
post ':id/variables' do
variable = ::Ci::ChangeVariableService.new(
@@ -95,6 +96,7 @@ module API
optional :filter, type: Hash, desc: 'Available filters: [environment_scope]. Example: filter[environment_scope]=production' do
optional :environment_scope, type: String, desc: 'The environment scope of a variable'
end
+ optional :description, type: String, desc: 'The description of the variable'
end
# rubocop: disable CodeReuse/ActiveRecord
put ':id/variables/:key' do
diff --git a/lib/api/concerns/packages/debian_package_endpoints.rb b/lib/api/concerns/packages/debian_package_endpoints.rb
index 25c97932e31..45290cb3e44 100644
--- a/lib/api/concerns/packages/debian_package_endpoints.rb
+++ b/lib/api/concerns/packages/debian_package_endpoints.rb
@@ -13,7 +13,6 @@ module API
component: ::Packages::Debian::COMPONENT_REGEX,
architecture: ::Packages::Debian::ARCHITECTURE_REGEX
}.freeze
- LIST_PACKAGE = 'list_package'
included do
feature_category :package_registry
@@ -41,8 +40,6 @@ module API
package_file = distribution_from!(project).package_files.with_file_name(params[:file_name]).last!
- track_debian_package_event 'pull_package'
-
present_package_file!(package_file)
end
@@ -73,22 +70,8 @@ module API
no_content! # empty component files are not always persisted in DB
end
- track_debian_package_event LIST_PACKAGE
-
present_carrierwave_file!(component_file.file)
end
-
- def track_debian_package_event(action)
- if project_or_group.is_a?(Project)
- project = project_or_group
- namespace = project_or_group.namespace
- else
- project = nil
- namespace = project_or_group
- end
-
- track_package_event(action, :debian, project: project, namespace: namespace, user: current_user)
- end
end
rescue_from ArgumentError do |e|
@@ -146,7 +129,6 @@ module API
get 'Release' do
distribution = distribution_from!(project_or_group)
- track_debian_package_event LIST_PACKAGE
present_carrierwave_file!(distribution.file)
end
@@ -166,7 +148,6 @@ module API
get 'InRelease' do
distribution = distribution_from!(project_or_group)
- track_debian_package_event LIST_PACKAGE
present_carrierwave_file!(distribution.signed_file)
end
diff --git a/lib/api/concerns/packages/npm_endpoints.rb b/lib/api/concerns/packages/npm_endpoints.rb
index 74ad3bb296f..ec20440f013 100644
--- a/lib/api/concerns/packages/npm_endpoints.rb
+++ b/lib/api/concerns/packages/npm_endpoints.rb
@@ -21,12 +21,18 @@ module API
included do
helpers ::API::Helpers::Packages::DependencyProxyHelpers
+ rescue_from ActiveRecord::RecordInvalid do |e|
+ render_structured_api_error!({ message: e.message, error: e.message }, 400)
+ end
+
before do
require_packages_enabled!
authenticate_non_get!
end
helpers do
+ include Gitlab::Utils::StrongMemoize
+
params :package_name do
requires :package_name, type: String, file_path: true, desc: 'Package name',
documentation: { example: 'mypackage' }
@@ -51,6 +57,12 @@ module API
def generate_metadata_service(packages)
::Packages::Npm::GenerateMetadataService.new(params[:package_name], packages)
end
+
+ def metadata_cache
+ ::Packages::Npm::MetadataCache
+ .find_by_package_name_and_project_id(params[:package_name], project.id)
+ end
+ strong_memoize_attr :metadata_cache
end
params do
@@ -80,7 +92,7 @@ module API
packages = ::Packages::Npm::PackageFinder.new(package_name, project: project)
.execute
- not_found! if packages.empty?
+ not_found!('Package') if packages.empty?
track_package_event(:list_tags, :npm, project: project, namespace: project.namespace)
@@ -122,6 +134,8 @@ module API
track_package_event(:create_tag, :npm, project: project, namespace: project.namespace)
+ enqueue_sync_metadata_cache_worker(project, package_name)
+
::Packages::Npm::CreateTagService.new(package, tag).execute
no_content!
@@ -156,6 +170,8 @@ module API
track_package_event(:delete_tag, :npm, project: project, namespace: project.namespace)
+ enqueue_sync_metadata_cache_worker(project, package_name)
+
::Packages::RemoveTagService.new(package_tag).execute
no_content!
@@ -202,6 +218,17 @@ module API
not_found!('Packages') if packages.empty?
+ if endpoint_scope == :project && Feature.enabled?(:npm_metadata_cache, project)
+ if metadata_cache&.file&.exists?
+ metadata_cache.touch_last_downloaded_at
+ present_carrierwave_file!(metadata_cache.file)
+
+ break
+ end
+
+ enqueue_sync_metadata_cache_worker(project, package_name)
+ end
+
present ::Packages::Npm::PackagePresenter.new(generate_metadata_service(packages).execute),
with: ::API::Entities::NpmPackage
end
diff --git a/lib/api/debian_project_packages.rb b/lib/api/debian_project_packages.rb
index e1531847b87..a2b2d781797 100644
--- a/lib/api/debian_project_packages.rb
+++ b/lib/api/debian_project_packages.rb
@@ -111,8 +111,6 @@ module API
::Packages::Debian::CreatePackageFileService.new(package: package, current_user: current_user, params: file_params).execute
- track_debian_package_event 'push_package'
-
created!
rescue ObjectStorage::RemoteStoreError => e
Gitlab::ErrorTracking.track_exception(e, extra: { file_name: params[:file_name], project_id: project_or_group.id })
diff --git a/lib/api/deployments.rb b/lib/api/deployments.rb
index 3a0eea677b8..8161c2b850f 100644
--- a/lib/api/deployments.rb
+++ b/lib/api/deployments.rb
@@ -68,6 +68,7 @@ module API
desc: 'The status to filter deployments by. One of `created`, `running`, `success`, `failed`, `canceled`, or `blocked`'
end
+ route_setting :authentication, job_token_allowed: true
get ':id/deployments' do
authorize! :read_deployment, user_project
@@ -92,6 +93,7 @@ module API
params do
requires :deployment_id, type: Integer, desc: 'The ID of the deployment'
end
+ route_setting :authentication, job_token_allowed: true
get ':id/deployments/:deployment_id' do
authorize! :read_deployment, user_project
@@ -129,9 +131,10 @@ module API
requires :status,
type: String,
- desc: 'The status to filter deployments by. One of `running`, `success`, `failed`, or `canceled`',
+ desc: 'The status of the deployment that is created. One of `running`, `success`, `failed`, or `canceled`',
values: %w[running success failed canceled]
end
+ route_setting :authentication, job_token_allowed: true
post ':id/deployments' do
authorize!(:create_deployment, user_project)
authorize!(:create_environment, user_project)
@@ -175,6 +178,7 @@ module API
desc: 'The new status of the deployment. One of `running`, `success`, `failed`, or `canceled`',
values: %w[running success failed canceled]
end
+ route_setting :authentication, job_token_allowed: true
put ':id/deployments/:deployment_id' do
authorize!(:read_deployment, user_project)
@@ -207,6 +211,7 @@ module API
params do
requires :deployment_id, type: Integer, desc: 'The ID of the deployment'
end
+ route_setting :authentication, job_token_allowed: true
delete ':id/deployments/:deployment_id' do
deployment = user_project.deployments.find(params[:deployment_id])
@@ -240,7 +245,7 @@ module API
use :merge_requests_base_params
end
-
+ route_setting :authentication, job_token_allowed: true
get ':id/deployments/:deployment_id/merge_requests' do
authorize! :read_deployment, user_project
diff --git a/lib/api/entities/blob.rb b/lib/api/entities/blob.rb
index 12700d99865..b4206679ac9 100644
--- a/lib/api/entities/blob.rb
+++ b/lib/api/entities/blob.rb
@@ -15,6 +15,13 @@ module API
expose :ref
expose :startline
expose :project_id
+ expose :group_id, if: ->(object) { object.is_a?(Gitlab::Search::FoundWikiPage) }
+
+ private
+
+ def group_id
+ object.group&.id
+ end
end
end
end
diff --git a/lib/api/entities/bulk_imports/export_batch_status.rb b/lib/api/entities/bulk_imports/export_batch_status.rb
new file mode 100644
index 00000000000..6e4a2fc8f93
--- /dev/null
+++ b/lib/api/entities/bulk_imports/export_batch_status.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ module BulkImports
+ class ExportBatchStatus < Grape::Entity
+ expose :status, documentation: { type: 'string', example: 'started', values: %w[started finished failed] }
+ expose :batch_number, documentation: { type: 'integer', example: 1 }
+ expose :objects_count, documentation: { type: 'integer', example: 100 }
+ expose :error, documentation: { type: 'string', example: 'Error message' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ end
+ end
+ end
+end
diff --git a/lib/api/entities/bulk_imports/export_status.rb b/lib/api/entities/bulk_imports/export_status.rb
index fee983c6fd8..1e5ee6ec210 100644
--- a/lib/api/entities/bulk_imports/export_status.rb
+++ b/lib/api/entities/bulk_imports/export_status.rb
@@ -8,6 +8,10 @@ module API
expose :status, documentation: { type: 'string', example: 'started', values: %w[started finished failed] }
expose :error, documentation: { type: 'string', example: 'Error message' }
expose :updated_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ expose :batched, documentation: { type: 'boolean', example: true }
+ expose :batches_count, documentation: { type: 'integer', example: 2 }
+ expose :total_objects_count, documentation: { type: 'integer', example: 100 }
+ expose :batches, if: ->(export, _options) { export.batched? }, using: ExportBatchStatus
end
end
end
diff --git a/lib/api/entities/ci/runner.rb b/lib/api/entities/ci/runner.rb
index 9361709b6ed..441e1dc1117 100644
--- a/lib/api/entities/ci/runner.rb
+++ b/lib/api/entities/ci/runner.rb
@@ -6,6 +6,7 @@ module API
class Runner < Grape::Entity
expose :id, documentation: { type: 'integer', example: 8 }
expose :description, documentation: { type: 'string', example: 'test-1-20150125' }
+ # TODO: return null in 17.0 and remove in v5 https://gitlab.com/gitlab-org/gitlab/-/issues/415159
expose :ip_address, documentation: { type: 'string', example: '127.0.0.1' }
# TODO Remove in v5 in favor of `paused` for REST calls, see https://gitlab.com/gitlab-org/gitlab/-/issues/375709
expose :active, documentation: { type: 'boolean', example: true }
diff --git a/lib/api/entities/ci/variable.rb b/lib/api/entities/ci/variable.rb
index 47597cb77be..4336f82fb5e 100644
--- a/lib/api/entities/ci/variable.rb
+++ b/lib/api/entities/ci/variable.rb
@@ -14,6 +14,8 @@ module API
expose :raw?, as: :raw, if: -> (entity, _) { entity.respond_to?(:raw?) }, documentation: { type: 'boolean' }
expose :environment_scope, if: -> (entity, _) { entity.respond_to?(:environment_scope) },
documentation: { type: 'string', example: '*' }
+ expose :description, if: -> (entity, _) { entity.respond_to?(:description) },
+ documentation: { type: 'string', example: 'This variable is being used for ...' }
end
end
end
diff --git a/lib/api/entities/dictionary/table.rb b/lib/api/entities/dictionary/table.rb
index 8d4e3fb959d..93e82d34b14 100644
--- a/lib/api/entities/dictionary/table.rb
+++ b/lib/api/entities/dictionary/table.rb
@@ -5,7 +5,7 @@ module API
module Dictionary
class Table < Grape::Entity
expose :table_name, documentation: { type: :string, example: 'users' }
- expose :feature_categories, documentation: { type: :array, example: ['database'] }
+ expose :feature_categories, documentation: { type: :string, is_array: true, example: 'database' }
end
end
end
diff --git a/lib/api/entities/group.rb b/lib/api/entities/group.rb
index 246fb819890..9296617dac9 100644
--- a/lib/api/entities/group.rb
+++ b/lib/api/entities/group.rb
@@ -21,6 +21,7 @@ module API
expose :full_name, :full_path
expose :created_at
expose :parent_id
+ expose :shared_runners_setting
expose :custom_attributes, using: 'API::Entities::CustomAttribute', if: :with_custom_attributes
diff --git a/lib/api/entities/plan_limit.rb b/lib/api/entities/plan_limit.rb
index 753c595d65f..27b24a60305 100644
--- a/lib/api/entities/plan_limit.rb
+++ b/lib/api/entities/plan_limit.rb
@@ -14,6 +14,11 @@ module API
expose :enforcement_limit, documentation: { type: 'integer', example: 15000 }
expose :generic_packages_max_file_size, documentation: { type: 'integer', example: 5368709120 }
expose :helm_max_file_size, documentation: { type: 'integer', example: 5242880 }
+ expose :limits_history, documentation: {
+ type: 'object',
+ example: '{"enforcement_limit"=>[{"timestamp"=>1686909124, "user_id"=>1, "username"=>"x", "value"=>5}],
+ "notification_limit"=>[{"timestamp"=>1686909124, "user_id"=>2, "username"=>"y", "value"=>7}]}'
+ }
expose :maven_max_file_size, documentation: { type: 'integer', example: 3221225472 }
expose :notification_limit, documentation: { type: 'integer', example: 15000 }
expose :npm_max_file_size, documentation: { type: 'integer', example: 524288000 }
diff --git a/lib/api/entities/project_hook.rb b/lib/api/entities/project_hook.rb
index bffb057abed..b85d2747226 100644
--- a/lib/api/entities/project_hook.rb
+++ b/lib/api/entities/project_hook.rb
@@ -14,6 +14,7 @@ module API
expose :job_events, documentation: { type: 'boolean' }
expose :releases_events, documentation: { type: 'boolean' }
expose :push_events_branch_filter, documentation: { type: 'string', example: 'my-branch-*' }
+ expose :emoji_events, documentation: { type: 'boolean' }
end
end
end
diff --git a/lib/api/entities/protected_ref_access.rb b/lib/api/entities/protected_ref_access.rb
index 28e0ef540d5..3cac91ccddc 100644
--- a/lib/api/entities/protected_ref_access.rb
+++ b/lib/api/entities/protected_ref_access.rb
@@ -5,12 +5,9 @@ module API
class ProtectedRefAccess < Grape::Entity
expose :id, documentation: { type: 'integer', example: 1 }
expose :access_level, documentation: { type: 'integer', example: 40 }
- expose :access_level_description,
- documentation: { type: 'string', example: 'Maintainers' } do |protected_ref_access|
- protected_ref_access.humanize
- end
+ expose :humanize, as: :access_level_description, documentation: { type: 'string', example: 'Maintainers' }
expose :deploy_key_id, documentation: { type: 'integer', example: 1 },
- if: ->(access) { access.has_attribute?(:deploy_key_id) && access.deploy_key_id }
+ if: ->(access) { access.has_attribute?(:deploy_key_id) }
end
end
end
diff --git a/lib/api/environments.rb b/lib/api/environments.rb
index bb261079d2a..b94391359ed 100644
--- a/lib/api/environments.rb
+++ b/lib/api/environments.rb
@@ -38,6 +38,7 @@ module API
desc: 'List all environments that match a specific state. Accepted values: `available`, `stopping`, or `stopped`. If no state value given, returns all environments'
mutually_exclusive :name, :search, message: 'cannot be used together'
end
+ route_setting :authentication, job_token_allowed: true
get ':id/environments' do
authorize! :read_environment, user_project
@@ -66,6 +67,7 @@ module API
optional :slug, absence: { message: "is automatically generated and cannot be changed" }, documentation: { hidden: true }
optional :tier, type: String, values: Environment.tiers.keys, desc: 'The tier of the new environment. Allowed values are `production`, `staging`, `testing`, `development`, and `other`'
end
+ route_setting :authentication, job_token_allowed: true
post ':id/environments' do
authorize! :create_environment, user_project
@@ -94,6 +96,7 @@ module API
optional :slug, absence: { message: "is automatically generated and cannot be changed" }, documentation: { hidden: true }
optional :tier, type: String, values: Environment.tiers.keys, desc: 'The tier of the new environment. Allowed values are `production`, `staging`, `testing`, `development`, and `other`'
end
+ route_setting :authentication, job_token_allowed: true
put ':id/environments/:environment_id' do
authorize! :update_environment, user_project
@@ -126,6 +129,7 @@ module API
optional :limit, type: Integer, desc: "Maximum number of environments to delete. Defaults to 100", default: 100, values: 1..1000
optional :dry_run, type: Boolean, desc: "Defaults to true for safety reasons. It performs a dry run where no actual deletion will be performed. Set to false to actually delete the environment", default: true
end
+ route_setting :authentication, job_token_allowed: true
delete ":id/environments/review_apps" do
authorize! :read_environment, user_project
@@ -156,6 +160,7 @@ module API
params do
requires :environment_id, type: Integer, desc: 'The ID of the environment'
end
+ route_setting :authentication, job_token_allowed: true
delete ':id/environments/:environment_id' do
authorize! :read_environment, user_project
@@ -178,6 +183,7 @@ module API
requires :environment_id, type: Integer, desc: 'The ID of the environment'
optional :force, type: Boolean, default: false, desc: 'Force environment to stop without executing `on_stop` actions'
end
+ route_setting :authentication, job_token_allowed: true
post ':id/environments/:environment_id/stop' do
authorize! :read_environment, user_project
@@ -202,6 +208,7 @@ module API
type: DateTime,
desc: 'Stop all environments that were last modified or deployed to before this date.'
end
+ route_setting :authentication, job_token_allowed: true
post ':id/environments/stop_stale' do
authorize! :stop_environment, user_project
@@ -229,6 +236,7 @@ module API
params do
requires :environment_id, type: Integer, desc: 'The ID of the environment'
end
+ route_setting :authentication, job_token_allowed: true
get ':id/environments/:environment_id' do
authorize! :read_environment, user_project
diff --git a/lib/api/files.rb b/lib/api/files.rb
index 45e935d7ea2..c140cec658d 100644
--- a/lib/api/files.rb
+++ b/lib/api/files.rb
@@ -49,7 +49,14 @@ module API
end
def content_sha
- cache_client.fetch("blob_content_sha256:#{user_project.full_path}:#{@blob.id}") do
+ cache_client.fetch(
+ "blob_content_sha256:#{user_project.full_path}:#{@blob.id}",
+ nil,
+ {
+ cache_identifier: 'API::Files#content_sha',
+ backing_resource: :gitaly
+ }
+ ) do
@blob.load_all_data!
Digest::SHA256.hexdigest(@blob.data)
@@ -57,10 +64,8 @@ module API
end
def cache_client
- Gitlab::Cache::Client.build_with_metadata(
- cache_identifier: 'API::Files#content_sha',
- feature_category: :source_code_management,
- backing_resource: :gitaly
+ @cache_client ||= Gitlab::Cache::Client.new(
+ Gitlab::Cache::Metrics.new(Gitlab::Cache::Metadata.new(feature_category: :source_code_management))
)
end
diff --git a/lib/api/group_export.rb b/lib/api/group_export.rb
index 37dfbfdb925..4cac707ff66 100644
--- a/lib/api/group_export.rb
+++ b/lib/api/group_export.rb
@@ -80,8 +80,13 @@ module API
{ code: 503, message: 'Service unavailable' }
]
end
+ params do
+ optional :batched, type: Boolean, desc: 'Whether to export in batches'
+ end
post ':id/export_relations' do
- response = ::BulkImports::ExportService.new(portable: user_group, user: current_user).execute
+ response = ::BulkImports::ExportService
+ .new(portable: user_group, user: current_user, batched: params[:batched])
+ .execute
if response.success?
accepted!
@@ -104,15 +109,32 @@ module API
end
params do
requires :relation, type: String, desc: 'Group relation name'
+ optional :batched, type: Boolean, desc: 'Whether to download in batches'
+ optional :batch_number, type: Integer, desc: 'Batch number to download'
+
+ all_or_none_of :batched, :batch_number
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)
+ break render_api_error!('Export not found', 404) unless export
+
+ if params[:batched]
+ batch = export.batches.find_by_batch_number(params[:batch_number])
+ batch_file = batch&.upload&.export_file
+
+ break render_api_error!('Export is not batched', 400) unless export.batched?
+ break render_api_error!('Batch not found', 404) unless batch
+ break render_api_error!('Batch file not found', 404) unless batch_file
+
+ present_carrierwave_file!(batch_file)
else
- render_api_error!('404 Not found', 404)
+ file = export&.upload&.export_file
+
+ break render_api_error!('Export is batched', 400) if export.batched?
+ break render_api_error!('Export file not found', 404) unless file
+
+ present_carrierwave_file!(file)
end
end
@@ -128,8 +150,19 @@ module API
{ code: 503, message: 'Service unavailable' }
]
end
+ params do
+ optional :relation, type: String, desc: 'Group relation name'
+ end
get ':id/export_relations/status' do
- present user_group.bulk_import_exports, with: Entities::BulkImports::ExportStatus
+ if params[:relation]
+ export = user_group.bulk_import_exports.find_by_relation(params[:relation])
+
+ break render_api_error!('Export not found', 404) unless export
+
+ present export, with: Entities::BulkImports::ExportStatus
+ else
+ present user_group.bulk_import_exports, with: Entities::BulkImports::ExportStatus
+ end
end
end
end
diff --git a/lib/api/group_variables.rb b/lib/api/group_variables.rb
index 295bee475c3..f320fa06394 100644
--- a/lib/api/group_variables.rb
+++ b/lib/api/group_variables.rb
@@ -59,6 +59,8 @@ module API
optional :raw, type: String, desc: 'Whether the variable will be expanded'
optional :variable_type, type: String, values: ::Ci::GroupVariable.variable_types.keys, desc: 'The type of the variable. Default: env_var'
optional :environment_scope, type: String, desc: 'The environment scope of a variable'
+ optional :description, type: String, desc: 'The description of the variable'
+
use :optional_group_variable_params_ee
end
post ':id/variables' do
@@ -94,6 +96,7 @@ module API
optional :raw, type: String, desc: 'Whether the variable will be expanded'
optional :variable_type, type: String, values: ::Ci::GroupVariable.variable_types.keys, desc: 'The type of the variable. Default: env_var'
optional :environment_scope, type: String, desc: 'The environment scope of a variable'
+ optional :description, type: String, desc: 'The description of the variable'
use :optional_group_variable_params_ee
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index df080c8e666..b616f1b35b3 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -657,6 +657,19 @@ module API
Gitlab::AppLogger.warn("Redis tracking event failed for event: #{event_name}, message: #{error.message}")
end
+ def track_event(event_name, user_id:, namespace_id: nil, project_id: nil)
+ return unless user_id.present?
+
+ Gitlab::InternalEvents.track_event(
+ event_name,
+ user_id: user_id,
+ namespace_id: namespace_id,
+ project_id: project_id
+ )
+ rescue StandardError => error
+ Gitlab::AppLogger.warn("Internal Event tracking event failed for event: #{event_name}, message: #{error.message}")
+ end
+
def order_by_similarity?(allow_unauthorized: true)
params[:order_by] == 'similarity' && params[:search].present? && (allow_unauthorized || current_user.present?)
end
diff --git a/lib/api/helpers/custom_attributes.rb b/lib/api/helpers/custom_attributes.rb
index 88208226c40..fc3f42f0d58 100644
--- a/lib/api/helpers/custom_attributes.rb
+++ b/lib/api/helpers/custom_attributes.rb
@@ -8,7 +8,7 @@ module API
included do
helpers do
params :with_custom_attributes do
- optional :with_custom_attributes, type: Boolean, default: false, desc: 'Include custom attributes in the response'
+ optional :with_custom_attributes, type: ::Grape::API::Boolean, default: false, desc: 'Include custom attributes in the response'
optional :custom_attributes, type: Hash,
desc: 'Filter with custom attributes'
diff --git a/lib/api/helpers/integrations_helpers.rb b/lib/api/helpers/integrations_helpers.rb
index 850cc61af2c..09dd69ef03b 100644
--- a/lib/api/helpers/integrations_helpers.rb
+++ b/lib/api/helpers/integrations_helpers.rb
@@ -41,7 +41,7 @@ module API
{
required: false,
name: :notify_only_broken_pipelines,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Send notifications for broken pipelines'
}
].freeze
@@ -129,85 +129,85 @@ module API
{
required: false,
name: :commit_events,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable notifications for commit_events'
},
{
required: false,
name: :push_events,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable notifications for push_events'
},
{
required: false,
name: :issues_events,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable notifications for issues_events'
},
{
required: false,
name: :incident_events,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable notifications for incident_events'
},
{
required: false,
name: :alert_events,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable notifications for alert_events'
},
{
required: false,
name: :confidential_issues_events,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable notifications for confidential_issues_events'
},
{
required: false,
name: :merge_requests_events,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable notifications for merge_requests_events'
},
{
required: false,
name: :note_events,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable notifications for note_events'
},
{
required: false,
name: :confidential_note_events,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable notifications for confidential_note_events'
},
{
required: false,
name: :tag_push_events,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable notifications for tag_push_events'
},
{
required: false,
name: :deployment_events,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable notifications for deployment_events'
},
{
required: false,
name: :job_events,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable notifications for job_events'
},
{
required: false,
name: :pipeline_events,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable notifications for pipeline_events'
},
{
required: false,
name: :wiki_page_events,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable notifications for wiki_page_events'
}
].freeze
@@ -243,7 +243,7 @@ module API
{
required: false,
name: :app_store_protected_refs,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Only enable for protected refs'
}
],
@@ -285,7 +285,7 @@ module API
{
required: false,
name: :enable_ssl_verification,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable SSL verification'
},
{
@@ -343,7 +343,7 @@ module API
{
required: false,
name: :enable_ssl_verification,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'DEPRECATED: This parameter has no effect since SSL verification will always be enabled'
}
],
@@ -417,7 +417,7 @@ module API
{
required: false,
name: :archive_trace_events,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'When enabled, job logs will be collected by Datadog and shown along pipeline execution traces'
},
{
@@ -471,7 +471,7 @@ module API
{
required: false,
name: :enable_ssl_verification,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable SSL verification'
}
],
@@ -485,13 +485,13 @@ module API
{
required: false,
name: :disable_diffs,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Disable code diffs'
},
{
required: false,
name: :send_from_committer_email,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Send from committer'
},
{
@@ -598,7 +598,7 @@ module API
{
required: false,
name: :colorize_messages,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Colorize messages'
}
],
@@ -612,7 +612,7 @@ module API
{
required: false,
name: :enable_ssl_verification,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable SSL verification'
},
{
@@ -668,7 +668,7 @@ module API
{
required: false,
name: :jira_issue_transition_automatic,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable automatic issue transitions'
},
{
@@ -692,7 +692,7 @@ module API
{
required: false,
name: :comment_on_event_enabled,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable comments inside Jira issues on each GitLab event (commit / merge request)'
}
],
@@ -750,13 +750,13 @@ module API
{
required: false,
name: :notify_only_broken_pipelines,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Notify only broken pipelines'
},
{
required: false,
name: :notify_only_default_branch,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Send notifications only for the default branch'
},
{
@@ -946,7 +946,7 @@ module API
{
required: false,
name: :enable_ssl_verification,
- type: Boolean,
+ type: ::Grape::API::Boolean,
desc: 'Enable SSL verification'
},
{
diff --git a/lib/api/helpers/members_helpers.rb b/lib/api/helpers/members_helpers.rb
index b3c79486465..a82aed507fd 100644
--- a/lib/api/helpers/members_helpers.rb
+++ b/lib/api/helpers/members_helpers.rb
@@ -29,6 +29,7 @@ module API
# rubocop: disable CodeReuse/ActiveRecord
def retrieve_members(source, params:, deep: false)
members = deep ? find_all_members(source) : source_members(source).connected_to_user
+ members = members.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417456")
members = members.includes(:user)
members = members.references(:user).merge(User.search(params[:query], use_minimum_char_limit: false)) if params[:query].present?
members = members.where(user_id: params[:user_ids]) if params[:user_ids].present?
diff --git a/lib/api/helpers/packages/maven.rb b/lib/api/helpers/packages/maven.rb
new file mode 100644
index 00000000000..694a1ec6436
--- /dev/null
+++ b/lib/api/helpers/packages/maven.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module API
+ module Helpers
+ module Packages
+ module Maven
+ extend Grape::API::Helpers
+
+ params :path_and_file_name do
+ requires :path,
+ type: String,
+ desc: 'Package path',
+ documentation: { example: 'foo/bar/mypkg/1.0-SNAPSHOT' }
+ requires :file_name,
+ type: String,
+ desc: 'Package file name',
+ documentation: { example: 'mypkg-1.0-SNAPSHOT.jar' }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/helpers/packages/npm.rb b/lib/api/helpers/packages/npm.rb
index be7f57fda0c..a80122c5309 100644
--- a/lib/api/helpers/packages/npm.rb
+++ b/lib/api/helpers/packages/npm.rb
@@ -6,6 +6,7 @@ module API
module Npm
include Gitlab::Utils::StrongMemoize
include ::API::Helpers::PackagesHelpers
+ extend ::Gitlab::Utils::Override
NPM_ENDPOINT_REQUIREMENTS = {
package_name: API::NO_SLASH_URL_PART_REGEX
@@ -55,8 +56,7 @@ module API
when :group
finder = ::Packages::Npm::PackageFinder.new(
params[:package_name],
- namespace: group,
- last_of_each_version: false
+ namespace: group
)
finder.last&.project_id
@@ -77,8 +77,7 @@ module API
finder = ::Packages::Npm::PackageFinder.new(
package_name,
- namespace: namespace,
- last_of_each_version: false
+ namespace: namespace
)
finder.last&.project_id
@@ -86,6 +85,12 @@ module API
end
strong_memoize_attr :project_id_or_nil
+ def enqueue_sync_metadata_cache_worker(project, package_name)
+ return unless Feature.enabled?(:npm_metadata_cache, project)
+
+ ::Packages::Npm::CreateMetadataCacheWorker.perform_async(project.id, package_name)
+ end
+
private
def top_namespace_from(package_name)
@@ -101,6 +106,20 @@ module API
group
end
strong_memoize_attr :group
+
+ override :not_found!
+ def not_found!(resource = nil)
+ reason = "#{resource} not found"
+ message = "404 #{reason}".titleize
+ render_structured_api_error!({ message: message, error: reason }, 404)
+ end
+
+ override :bad_request_missing_attribute!
+ def bad_request_missing_attribute!(attribute)
+ reason = "\"#{attribute}\" not given"
+ message = "400 Bad request - #{reason}"
+ render_structured_api_error!({ message: message, error: reason }, 400)
+ end
end
end
end
diff --git a/lib/api/helpers/projects_helpers.rb b/lib/api/helpers/projects_helpers.rb
index b96e8efba61..642963768f8 100644
--- a/lib/api/helpers/projects_helpers.rb
+++ b/lib/api/helpers/projects_helpers.rb
@@ -15,7 +15,6 @@ module API
optional :auto_cancel_pending_pipelines, type: String, values: %w(disabled enabled), desc: 'Auto-cancel pending pipelines'
optional :ci_config_path, type: String, desc: 'The path to CI config file. Defaults to `.gitlab-ci.yml`'
optional :service_desk_enabled, type: Boolean, desc: 'Disable or enable the service desk'
- optional :keep_latest_artifact, type: Boolean, desc: 'Indicates if the latest artifact should be kept for this project.'
# TODO: remove in API v5, replaced by *_access_level
optional :issues_enabled, type: Boolean, desc: 'Flag indication if the issue tracker is enabled'
@@ -71,7 +70,6 @@ module API
optional :squash_commit_template, type: String, desc: 'Template used to create squash commit message'
optional :issue_branch_template, type: String, desc: 'Template used to create a branch from an issue'
optional :initialize_with_readme, type: Boolean, desc: "Initialize a project with a README.md"
- optional :ci_default_git_depth, type: Integer, desc: 'Default number of revisions for shallow cloning'
optional :auto_devops_enabled, type: Boolean, desc: 'Flag indication if Auto DevOps is enabled'
optional :auto_devops_deploy_strategy, type: String, values: %w(continuous manual timed_incremental), desc: 'Auto Deploy strategy'
optional :autoclose_referenced_issues, type: Boolean, desc: 'Flag indication if referenced issues auto-closing is enabled'
@@ -101,6 +99,8 @@ module API
end
params :optional_update_params_ce do
+ optional :ci_default_git_depth, type: Integer, desc: 'Default number of revisions for shallow cloning'
+ optional :keep_latest_artifact, type: Boolean, desc: 'Indicates if the latest artifact should be kept for this project.'
optional :ci_forward_deployment_enabled, type: Boolean, desc: 'Prevent older deployment jobs that are still pending'
optional :ci_allow_fork_pipelines_to_run_in_parent_project, type: Boolean, desc: 'Allow fork merge request pipelines to run in parent project'
optional :ci_separated_caches, type: Boolean, desc: 'Enable or disable separated caches based on branch protection.'
@@ -205,9 +205,6 @@ module API
def filter_attributes_using_license!(attrs)
end
- def filter_attributes_under_feature_flag!(attrs, project)
- end
-
def validate_git_import_url!(import_url)
return if import_url.blank?
diff --git a/lib/api/helpers/remote_mirrors_helpers.rb b/lib/api/helpers/remote_mirrors_helpers.rb
index efd81a5ac5a..2c00f7cdb14 100644
--- a/lib/api/helpers/remote_mirrors_helpers.rb
+++ b/lib/api/helpers/remote_mirrors_helpers.rb
@@ -18,7 +18,7 @@ module API
use :mirror_branches_setting_ee
end
- def verify_mirror_branches_setting(attrs, project); end
+ def verify_mirror_branches_setting(attrs); end
end
end
end
diff --git a/lib/api/import_github.rb b/lib/api/import_github.rb
index 6550808a563..ab7ac6624a8 100644
--- a/lib/api/import_github.rb
+++ b/lib/api/import_github.rb
@@ -20,7 +20,10 @@ module API
end
def access_params
- { github_access_token: params[:personal_access_token] }
+ {
+ github_access_token: params[:personal_access_token],
+ additional_access_tokens: params[:additional_access_tokens]
+ }
end
def client_options
@@ -59,6 +62,11 @@ module API
requires :target_namespace, type: String, allow_blank: false, desc: 'Namespace or group to import repository into'
optional :github_hostname, type: String, desc: 'Custom GitHub enterprise hostname'
optional :optional_stages, type: Hash, desc: 'Optional stages of import to be performed'
+ optional :additional_access_tokens,
+ type: Array[String],
+ coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
+ desc: 'Additional list of personal access tokens',
+ documentation: { example: 'foo,bar' }
end
post 'import/github' do
result = Import::GithubService.new(client, current_user, params).execute(access_params, provider)
diff --git a/lib/api/internal/kubernetes.rb b/lib/api/internal/kubernetes.rb
index 5592207c4b5..8783a8dd57c 100644
--- a/lib/api/internal/kubernetes.rb
+++ b/lib/api/internal/kubernetes.rb
@@ -29,21 +29,13 @@ module API
end
def gitaly_info(project)
- shard = repo_type.repository_for(project).shard
- {
- address: Gitlab::GitalyClient.address(shard),
- token: Gitlab::GitalyClient.token(shard),
- features: Feature::Gitaly.server_feature_flags
- }
+ gitaly_features = Feature::Gitaly.server_feature_flags
+
+ Gitlab::GitalyClient.connection_data(project.repository_storage).merge(features: gitaly_features)
end
def gitaly_repository(project)
- {
- storage_name: project.repository_storage,
- relative_path: project.disk_path + '.git',
- gl_repository: repo_type.identifier_for_container(project),
- gl_project_path: repo_type.repository_for(project).full_path
- }
+ project.repository.gitaly_repository.to_h
end
def check_feature_enabled
@@ -61,7 +53,12 @@ module API
end
def increment_unique_events
- events = params[:unique_counters]&.slice(:agent_users_using_ci_tunnel)
+ events = params[:unique_counters]&.slice(
+ :agent_users_using_ci_tunnel,
+ :k8s_api_proxy_requests_unique_users_via_ci_access, :k8s_api_proxy_requests_unique_agents_via_ci_access,
+ :k8s_api_proxy_requests_unique_users_via_user_access, :k8s_api_proxy_requests_unique_agents_via_user_access,
+ :flux_git_push_notified_unique_projects
+ )
events&.each do |event, entity_ids|
increment_unique_values(event, entity_ids)
@@ -69,7 +66,10 @@ module API
end
def increment_count_events
- events = params[:counters]&.slice(:gitops_sync, :k8s_api_proxy_request, :flux_git_push_notifications_total)
+ events = params[:counters]&.slice(
+ :gitops_sync, :k8s_api_proxy_request, :flux_git_push_notifications_total,
+ :k8s_api_proxy_requests_via_ci_access, :k8s_api_proxy_requests_via_user_access
+ )
Gitlab::UsageDataCounters::KubernetesAgentCounter.increment_event_counts(events)
end
@@ -185,7 +185,7 @@ module API
# Load agent
agent = ::Clusters::Agent.find(params[:agent_id])
- unauthorized!('Feature disabled for agent') unless ::Gitlab::Kas::UserAccess.enabled_for?(agent)
+ unauthorized!('Feature disabled for agent') unless ::Gitlab::Kas::UserAccess.enabled?
service_response = ::Clusters::Agents::AuthorizeProxyUserService.new(user, agent).execute
render_api_error!(service_response[:message], service_response[:reason]) unless service_response.success?
@@ -203,10 +203,17 @@ module API
optional :gitops_sync, type: Integer, desc: 'The count to increment the gitops_sync metric by'
optional :k8s_api_proxy_request, type: Integer, desc: 'The count to increment the k8s_api_proxy_request metric by'
optional :flux_git_push_notifications_total, type: Integer, desc: 'The count to increment the flux_git_push_notifications_total metrics by'
+ optional :k8s_api_proxy_requests_via_ci_access, type: Integer, desc: 'The count to increment the k8s_api_proxy_requests_via_ci_access metric by'
+ optional :k8s_api_proxy_requests_via_user_access, type: Integer, desc: 'The count to increment the k8s_api_proxy_requests_via_user_access metric by'
end
optional :unique_counters, type: Hash do
optional :agent_users_using_ci_tunnel, type: Array[Integer], desc: 'An array of user ids that have interacted with CI Tunnel'
+ optional :k8s_api_proxy_requests_unique_users_via_ci_access, type: Array[Integer], desc: 'An array of users that have interacted with the CI tunnel via `ci_access`'
+ optional :k8s_api_proxy_requests_unique_agents_via_ci_access, type: Array[Integer], desc: 'An array of agents that have interacted with the CI tunnel via `ci_access`'
+ optional :k8s_api_proxy_requests_unique_users_via_user_access, type: Array[Integer], desc: 'An array of users that have interacted with the CI tunnel via `user_access`'
+ optional :k8s_api_proxy_requests_unique_agents_via_user_access, type: Array[Integer], desc: 'An array of agents that have interacted with the CI tunnel via `user_access`'
+ optional :flux_git_push_notified_unique_projects, type: Array[Integer], desc: 'An array of projects that have been notified to reconcile their Flux workloads'
end
end
post '/', feature_category: :deployment_management do
diff --git a/lib/api/lint.rb b/lib/api/lint.rb
index dee04b6bb00..71965fc05c9 100644
--- a/lib/api/lint.rb
+++ b/lib/api/lint.rb
@@ -4,34 +4,6 @@ module API
class Lint < ::API::Base
feature_category :pipeline_composition
- helpers do
- def can_lint_ci?
- signup_unrestricted = Gitlab::CurrentSettings.signup_enabled? && !Gitlab::CurrentSettings.signup_limited?
- internal_user = current_user.present? && !current_user.external?
- is_developer = current_user.present? && current_user.projects.any? { |p| p.member?(current_user, Gitlab::Access::DEVELOPER) }
-
- signup_unrestricted || internal_user || is_developer
- end
- end
-
- namespace :ci do
- desc 'REMOVED: Validates the .gitlab-ci.yml content' do
- detail 'Checks if CI/CD YAML configuration is valid'
- success code: 200, model: Entities::Ci::Lint::Result
- tags %w[ci_lint]
- end
- params do
- requires :content, type: String, desc: 'The CI/CD configuration content'
- optional :include_merged_yaml, type: Boolean, desc: 'If the expanded CI/CD configuration should be included in the response'
- optional :include_jobs, type: Boolean, desc: 'If the list of jobs should be included in the response. This is
- false by default'
- end
-
- post '/lint', urgency: :low do
- render_api_error!('410 Gone', 410)
- end
- end
-
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Validates a CI YAML configuration with a namespace' do
detail 'Checks if a project’s latest (HEAD of the project’s default branch) .gitlab-ci.yml configuration is
diff --git a/lib/api/markdown.rb b/lib/api/markdown.rb
index 5ef60ab0b94..08b172cd608 100644
--- a/lib/api/markdown.rb
+++ b/lib/api/markdown.rb
@@ -40,10 +40,7 @@ module API
context[:skip_project_check] = true
end
- # Disable comments in markdown for IE browsers because comments in IE
- # could allow script execution.
- browser = Browser.new(headers['User-Agent'])
- context[:allow_comments] = !browser.ie?
+ context[:allow_comments] = false
present({ html: Banzai.render_and_post_process(params[:text], context) }, with: Entities::Markdown)
end
diff --git a/lib/api/maven_packages.rb b/lib/api/maven_packages.rb
index 241cd93f380..eccc55ed158 100644
--- a/lib/api/maven_packages.rb
+++ b/lib/api/maven_packages.rb
@@ -23,14 +23,10 @@ module API
helpers ::API::Helpers::PackagesHelpers
helpers ::API::Helpers::Packages::DependencyProxyHelpers
+ helpers ::API::Helpers::Packages::Maven
helpers ::API::Helpers::Packages::Maven::BasicAuthHelpers
helpers do
- params :path_and_file_name do
- requires :path, type: String, desc: 'Package path', documentation: { example: 'foo/bar/mypkg/1.0-SNAPSHOT' }
- requires :file_name, type: String, desc: 'Package file name', documentation: { example: 'mypkg-1.0-SNAPSHOT.jar' }
- end
-
def path_exists?(path)
return false if path.blank?
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index c29a7eee923..ff9d0e2c371 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -124,6 +124,10 @@ module API
merge_requests.each { |mr| mr.check_mergeability(async: true) }
end
+ def batch_process_mergeability_checks(merge_requests)
+ ::MergeRequests::MergeabilityCheckBatchService.new(merge_requests, current_user).execute
+ end
+
params :merge_requests_params do
use :merge_requests_base_params
use :optional_merge_requests_search_params
@@ -177,8 +181,16 @@ module API
get ":id/merge_requests", feature_category: :code_review_workflow, urgency: :low do
validate_search_rate_limit! if declared_params[:search].present?
merge_requests = find_merge_requests(group_id: user_group.id, include_subgroups: true)
+ options = serializer_options_for(merge_requests).merge(group: user_group)
+
+ if !options[:skip_merge_status_recheck] && ::Feature.enabled?(:batched_api_mergeability_checks, user_group)
+ batch_process_mergeability_checks(merge_requests)
+
+ # NOTE: skipping individual mergeability checks in the presenter
+ options[:skip_merge_status_recheck] = true
+ end
- present merge_requests, serializer_options_for(merge_requests).merge(group: user_group)
+ present merge_requests, options
end
end
diff --git a/lib/api/ml_model_packages.rb b/lib/api/ml_model_packages.rb
index fec72b03ffd..35d231d9fe1 100644
--- a/lib/api/ml_model_packages.rb
+++ b/lib/api/ml_model_packages.rb
@@ -6,7 +6,7 @@ module API
include ::API::Helpers::Authentication
ML_MODEL_PACKAGES_REQUIREMENTS = {
- package_name: API::NO_SLASH_URL_PART_REGEX,
+ model_name: API::NO_SLASH_URL_PART_REGEX,
file_name: API::NO_SLASH_URL_PART_REGEX
}.freeze
@@ -47,15 +47,15 @@ module API
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
namespace ':id/packages/ml_models' do
params do
- requires :package_name, type: String, desc: 'Package name', regexp: Gitlab::Regex.ml_model_name_regex,
+ requires :model_name, type: String, desc: 'Model name', regexp: Gitlab::Regex.ml_model_name_regex,
file_path: true
- requires :package_version, type: String, desc: 'Package version',
+ requires :model_version, type: String, desc: 'Model version',
regexp: Gitlab::Regex.ml_model_version_regex
requires :file_name, type: String, desc: 'Package file name',
regexp: Gitlab::Regex.ml_model_file_name_regex, file_path: true
optional :status, type: String, values: ALLOWED_STATUSES, desc: 'Package status'
end
- namespace ':package_name/*package_version/:file_name', requirements: ML_MODEL_PACKAGES_REQUIREMENTS do
+ namespace ':model_name/*model_version/:file_name', requirements: ML_MODEL_PACKAGES_REQUIREMENTS do
desc 'Workhorse authorize model package file' do
detail 'Introduced in GitLab 16.1'
success code: 200
@@ -71,7 +71,7 @@ module API
end
desc 'Workhorse upload model package file' do
- detail 'Introduced in GitLab 16.1'
+ detail 'Introduced in GitLab 16.2'
success code: 201
failure [
{ code: 401, message: 'Unauthorized' },
@@ -91,7 +91,12 @@ module API
bad_request!('File is too large') if max_file_size_exceeded?
- create_package_file_params = declared(params).merge(build: current_authenticated_job)
+ create_package_file_params = declared(params).merge(
+ build: current_authenticated_job,
+ package_name: params[:model_name],
+ package_version: params[:model_version]
+ )
+
package_file = ::Packages::MlModel::CreatePackageFileService
.new(project, current_user, create_package_file_params)
.execute
@@ -104,6 +109,26 @@ module API
forbidden!
end
+
+ desc 'Download an ml_model package file' do
+ detail 'This feature was introduced in GitLab 16.2'
+ success code: 200
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not Found' }
+ ]
+ tags %w[ml_model_registry]
+ end
+ get do
+ authorize_read_package!(project)
+
+ package = ::Packages::MlModel::PackageFinder.new(project)
+ .execute!(params[:model_name], params[:model_version])
+ package_file = ::Packages::PackageFileFinder.new(package, params[:file_name]).execute!
+
+ present_package_file!(package_file)
+ end
end
end
end
diff --git a/lib/api/npm_instance_packages.rb b/lib/api/npm_instance_packages.rb
index 8215296b617..ea92818e76c 100644
--- a/lib/api/npm_instance_packages.rb
+++ b/lib/api/npm_instance_packages.rb
@@ -6,10 +6,6 @@ module API
feature_category :package_registry
urgency :low
- rescue_from ActiveRecord::RecordInvalid do |e|
- render_api_error!(e.message, 400)
- end
-
helpers do
def endpoint_scope
:instance
diff --git a/lib/api/npm_project_packages.rb b/lib/api/npm_project_packages.rb
index 61409909b06..e1d0455b1e2 100644
--- a/lib/api/npm_project_packages.rb
+++ b/lib/api/npm_project_packages.rb
@@ -7,7 +7,7 @@ module API
urgency :low
rescue_from ActiveRecord::RecordInvalid do |e|
- render_api_error!(e.message, 400)
+ render_structured_api_error!({ message: e.message, error: e.message }, 400)
end
helpers do
@@ -78,8 +78,9 @@ module API
.new(project, current_user, params.merge(build: current_authenticated_job)).execute
if created_package[:status] == :error
- render_api_error!(created_package[:message], created_package[:http_status])
+ render_structured_api_error!({ message: created_package[:message], error: created_package[:message] }, created_package[:http_status])
else
+ enqueue_sync_metadata_cache_worker(project, created_package.name)
track_package_event('push_package', :npm, category: 'API::NpmPackages', project: project, namespace: project.namespace)
created_package
end
diff --git a/lib/api/package_files.rb b/lib/api/package_files.rb
index 7ff49f326d9..6a02769519f 100644
--- a/lib/api/package_files.rb
+++ b/lib/api/package_files.rb
@@ -14,6 +14,7 @@ module API
urgency :low
helpers ::API::Helpers::PackagesHelpers
+ helpers ::API::Helpers::Packages::Npm
params do
requires :id, types: [String, Integer], desc: 'ID or URL-encoded path of the project'
@@ -70,6 +71,8 @@ module API
destroy_conditionally!(package_file) do |package_file|
package_file.pending_destruction!
+
+ enqueue_sync_metadata_cache_worker(user_project, package.name) if package.npm?
end
end
end
diff --git a/lib/api/project_export.rb b/lib/api/project_export.rb
index 19e5ed3f9e0..8a72ec051dc 100644
--- a/lib/api/project_export.rb
+++ b/lib/api/project_export.rb
@@ -127,8 +127,13 @@ module API
]
tags ['project_export']
end
+ params do
+ optional :batched, type: Boolean, desc: 'Whether to export in batches'
+ end
post ':id/export_relations' do
- response = ::BulkImports::ExportService.new(portable: user_project, user: current_user).execute
+ response = ::BulkImports::ExportService
+ .new(portable: user_project, user: current_user, batched: params[:batched])
+ .execute
if response.success?
accepted!
@@ -152,19 +157,33 @@ module API
produces %w[application/octet-stream application/json]
end
params do
- requires :relation,
- type: String,
- project_portable: true,
- desc: 'Project relation name'
+ requires :relation, type: String, project_portable: true, desc: 'Project relation name'
+ optional :batched, type: Boolean, desc: 'Whether to download in batches'
+ optional :batch_number, type: Integer, desc: 'Batch number to download'
+
+ all_or_none_of :batched, :batch_number
end
get ':id/export_relations/download' do
export = user_project.bulk_import_exports.find_by_relation(params[:relation])
- file = export&.upload&.export_file
- if file
- present_carrierwave_file!(file)
+ break render_api_error!('Export not found', 404) unless export
+
+ if params[:batched]
+ batch = export.batches.find_by_batch_number(params[:batch_number])
+ batch_file = batch&.upload&.export_file
+
+ break render_api_error!('Export is not batched', 400) unless export.batched?
+ break render_api_error!('Batch not found', 404) unless batch
+ break render_api_error!('Batch file not found', 404) unless batch_file
+
+ present_carrierwave_file!(batch_file)
else
- render_api_error!('404 Not found', 404)
+ file = export&.upload&.export_file
+
+ break render_api_error!('Export is batched', 400) if export.batched?
+ break render_api_error!('Export file not found', 404) unless file
+
+ present_carrierwave_file!(file)
end
end
@@ -180,8 +199,19 @@ module API
]
tags ['project_export']
end
+ params do
+ optional :relation, type: String, desc: 'Project relation name'
+ end
get ':id/export_relations/status' do
- present user_project.bulk_import_exports, with: Entities::BulkImports::ExportStatus
+ if params[:relation]
+ export = user_project.bulk_import_exports.find_by_relation(params[:relation])
+
+ break render_api_error!('Export not found', 404) unless export
+
+ present export, with: Entities::BulkImports::ExportStatus
+ else
+ present user_project.bulk_import_exports, with: Entities::BulkImports::ExportStatus
+ end
end
end
end
diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb
index db97f4988e1..c9cba397f5c 100644
--- a/lib/api/project_hooks.rb
+++ b/lib/api/project_hooks.rb
@@ -31,6 +31,7 @@ module API
optional :wiki_page_events, type: Boolean, desc: "Trigger hook on wiki events"
optional :deployment_events, type: Boolean, desc: "Trigger hook on deployment events"
optional :releases_events, type: Boolean, desc: "Trigger hook on release events"
+ optional :emoji_events, type: Boolean, desc: "Trigger hook on emoji events"
optional :enable_ssl_verification, type: Boolean, desc: "Do SSL verification when triggering the hook"
optional :token, type: String, desc: "Secret token to validate received payloads; this will not be returned in the response"
optional :push_events_branch_filter, type: String, desc: "Trigger hook on specified branch only"
diff --git a/lib/api/project_packages.rb b/lib/api/project_packages.rb
index 43bd15931ef..2aa6858e41d 100644
--- a/lib/api/project_packages.rb
+++ b/lib/api/project_packages.rb
@@ -15,6 +15,7 @@ module API
urgency :low
helpers ::API::Helpers::PackagesHelpers
+ helpers ::API::Helpers::Packages::Npm
helpers do
def package
strong_memoize(:package) do # rubocop:disable Gitlab/StrongMemoizeAttr
@@ -133,6 +134,8 @@ module API
destroy_conditionally!(package) do |package|
::Packages::MarkPackageForDestructionService.new(container: package, current_user: current_user).execute
+
+ enqueue_sync_metadata_cache_worker(user_project, package.name) if package.npm?
end
end
end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 7ec9f72e0b2..468f284f136 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -251,6 +251,28 @@ module API
present_projects load_projects
end
+ desc 'Get projects that a user has contributed to' do
+ success code: 200, model: Entities::BasicProjectDetails
+ failure [{ code: 404, message: '404 User Not Found' }]
+ tags %w[projects]
+ is_array true
+ end
+ params do
+ requires :user_id, type: String, desc: 'The ID or username of the user'
+ use :sort_params
+ use :pagination
+
+ optional :simple, type: Boolean, default: false,
+ desc: 'Return only the ID, URL, name, and path of each project'
+ end
+ get ":user_id/contributed_projects", feature_category: :groups_and_projects, urgency: :low do
+ user = find_user(params[:user_id])
+ not_found!('User') unless user
+
+ contributed_projects = ContributedProjectsFinder.new(user).execute(current_user).joined(user)
+ present_projects contributed_projects
+ end
+
desc 'Get projects starred by a user' do
success code: 200, model: Entities::BasicProjectDetails
failure [{ code: 404, message: '404 User Not Found' }]
@@ -534,7 +556,6 @@ module API
attrs = translate_params_for_compatibility(attrs)
attrs = add_import_params(attrs)
filter_attributes_using_license!(attrs)
- filter_attributes_under_feature_flag!(attrs, user_project)
verify_update_project_attrs!(user_project, attrs)
user_project.remove_avatar! if attrs.key?(:avatar) && attrs[:avatar].nil?
diff --git a/lib/api/remote_mirrors.rb b/lib/api/remote_mirrors.rb
index c3c7d9370e0..5346476ed0d 100644
--- a/lib/api/remote_mirrors.rb
+++ b/lib/api/remote_mirrors.rb
@@ -67,7 +67,7 @@ module API
end
post ':id/remote_mirrors' do
create_params = declared_params(include_missing: false)
- verify_mirror_branches_setting(create_params, user_project)
+ verify_mirror_branches_setting(create_params)
new_mirror = user_project.remote_mirrors.create(create_params)
if new_mirror.persisted?
@@ -99,7 +99,7 @@ module API
mirror_params = declared_params(include_missing: false)
mirror_params[:id] = mirror_params.delete(:mirror_id)
- verify_mirror_branches_setting(mirror_params, user_project)
+ verify_mirror_branches_setting(mirror_params)
update_params = { remote_mirrors_attributes: mirror_params }
result = ::Projects::UpdateService
diff --git a/lib/api/search.rb b/lib/api/search.rb
index 954c3cd9f9e..b14fce13f5e 100644
--- a/lib/api/search.rb
+++ b/lib/api/search.rb
@@ -59,6 +59,8 @@ module API
end
def search(additional_params = {})
+ return Kaminari.paginate_array([]) if @project.present? && !project_scope_allowed?
+
search_service = search_service(additional_params)
if search_service.global_search? && !search_service.global_search_enabled_for_scope?
forbidden!('Global Search is disabled for this scope')
@@ -95,6 +97,10 @@ module API
)
end
+ def project_scope_allowed?
+ ::Search::Navigation.new(user: current_user, project: @project).tab_enabled_for_project?(params[:scope].to_sym)
+ end
+
def snippets?
%w(snippet_titles).include?(params[:scope]).to_s
end
@@ -108,9 +114,7 @@ module API
end
def verify_search_scope!(resource:)
- # In EE we have additional validation requirements for searches.
- # Defining this method here as a noop allows us to easily extend it in
- # EE, without having to modify this file directly.
+ # no-op
end
def search_type(additional_params = {})
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index 5d20444cb54..b12ca48829b 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -203,6 +203,13 @@ module API
optional :allow_runner_registration_token, type: Boolean, desc: 'Allow registering runners using a registration token'
optional :ci_max_includes, type: Integer, desc: 'Maximum number of includes per pipeline'
optional :security_policy_global_group_approvers_enabled, type: Boolean, desc: 'Query scan result policy approval groups globally'
+ optional :slack_app_enabled, type: Grape::API::Boolean, desc: 'Enable the GitLab for Slack app'
+ given slack_app_enabled: -> (val) { val } do
+ requires :slack_app_id, type: String, desc: 'The client ID of the GitLab for Slack app'
+ requires :slack_app_secret, type: String, desc: 'The client secret of the GitLab for Slack app. Used for authenticating OAuth requests from the app'
+ requires :slack_app_signing_secret, type: String, desc: 'The signing secret of the GitLab for Slack app. Used for authenticating API requests from the app'
+ requires :slack_app_verification_token, type: String, desc: 'The verification token of the GitLab for Slack app. This method of authentication is deprecated by Slack and used only for authenticating slash commands from the app'
+ end
Gitlab::SSHPublicKey.supported_types.each do |type|
optional :"#{type}_key_restriction",
diff --git a/lib/api/usage_data.rb b/lib/api/usage_data.rb
index 3e2023d769f..0a343093c33 100644
--- a/lib/api/usage_data.rb
+++ b/lib/api/usage_data.rb
@@ -53,6 +53,38 @@ module API
status :ok
end
+ desc 'Track gitlab internal events' do
+ detail 'This feature was introduced in GitLab 16.2.'
+ success code: 200
+ failure [
+ { code: 403, message: 'Invalid CSRF token is provided' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[usage_data]
+ end
+ params do
+ requires :event, type: String, desc: 'The event name that should be tracked',
+ documentation: { example: 'i_quickactions_page' }
+ optional :namespace_id, type: Integer, desc: 'Namespace ID',
+ documentation: { example: 1234 }
+ optional :project_id, type: Integer, desc: 'Project ID',
+ documentation: { example: 1234 }
+ end
+ post 'track_event', urgency: :low do
+ event_name = params[:event]
+ namespace_id = params[:namespace_id]
+ project_id = params[:project_id]
+
+ track_event(
+ event_name,
+ user_id: current_user.id,
+ namespace_id: namespace_id,
+ project_id: project_id
+ )
+
+ status :ok
+ end
+
desc 'Get a list of all metric definitions' do
detail 'This feature was introduced in GitLab 13.11.'
success code: 200
diff --git a/lib/api/user_runners.rb b/lib/api/user_runners.rb
new file mode 100644
index 00000000000..edbd0214bb8
--- /dev/null
+++ b/lib/api/user_runners.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+module API
+ class UserRunners < ::API::Base
+ include APIGuard
+
+ resource :user do
+ before do
+ authenticate!
+ end
+
+ allow_access_with_scope :create_runner, if: ->(request) { request.post? }
+
+ desc 'Create a runner owned by currently authenticated user' do
+ detail 'Create a new runner'
+ success Entities::Ci::RunnerRegistrationDetails
+ failure [[400, 'Bad Request'], [403, 'Forbidden']]
+ tags %w[user runners]
+ end
+ params do
+ requires :runner_type, type: String, values: ::Ci::Runner.runner_types.keys,
+ desc: %q(Specifies the scope of the runner)
+ given runner_type: ->(runner_type) { runner_type == 'group_type' } do
+ requires :group_id, type: Integer,
+ desc: 'The ID of the group that the runner is created in',
+ documentation: { example: 1 }
+ end
+ given runner_type: ->(runner_type) { runner_type == 'project_type' } do
+ requires :project_id, type: Integer,
+ desc: 'The ID of the project that the runner is created in',
+ documentation: { example: 1 }
+ end
+ optional :description, type: String, desc: %q(Description of the runner)
+ optional :maintenance_note, type: String,
+ desc: %q(Free-form maintenance notes for the runner (1024 characters))
+ optional :paused, type: Boolean, desc: 'Specifies if the runner should ignore new jobs (defaults to false)'
+ optional :locked, type: Boolean,
+ desc: 'Specifies if the runner should be locked for the current project (defaults to false)'
+ optional :access_level, type: String, values: ::Ci::Runner.access_levels.keys,
+ desc: 'The access level of the runner'
+ optional :run_untagged, type: Boolean,
+ desc: 'Specifies if the runner should handle untagged jobs (defaults to true)'
+ optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
+ desc: %q(A list of runner tags)
+ optional :maximum_timeout, type: Integer,
+ desc: 'Maximum timeout that limits the amount of time (in seconds) that runners can run jobs'
+ end
+ post 'runners', urgency: :low, feature_category: :runner_fleet do
+ attributes = attributes_for_keys(
+ %i[runner_type group_id project_id description maintenance_note paused locked run_untagged tag_list
+ access_level maximum_timeout]
+ )
+
+ case attributes[:runner_type]
+ when 'group_type'
+ attributes[:scope] = ::Group.find_by_id(attributes.delete(:group_id))
+ when 'project_type'
+ attributes[:scope] = ::Project.find_by_id(attributes.delete(:project_id))
+ end
+
+ result = ::Ci::Runners::CreateRunnerService.new(user: current_user, params: attributes).execute
+ if result.error?
+ message = result.errors.to_sentence
+ forbidden!(message) if result.reason == :forbidden
+ bad_request!(message)
+ end
+
+ present result.payload[:runner], with: Entities::Ci::RunnerRegistrationDetails
+ end
+ end
+ end
+end
diff --git a/lib/api/users.rb b/lib/api/users.rb
index ff36a4cfe95..fff0e9fee06 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -6,7 +6,7 @@ module API
include APIGuard
include Helpers::CustomAttributes
- allow_access_with_scope :read_user, if: -> (request) { request.get? || request.head? }
+ allow_access_with_scope :read_user, if: ->(request) { request.get? || request.head? }
feature_category :user_profile,
%w[
@@ -134,7 +134,7 @@ module API
entity = current_user&.can_read_all_resources? ? Entities::UserWithAdmin : Entities::UserBasic
if entity == Entities::UserWithAdmin
- users = users.preload(:identities, :webauthn_registrations, :namespace, :followers, :followees, :user_preference)
+ users = users.preload(:identities, :webauthn_registrations, :namespace, :followers, :followees, :user_preference, :user_detail)
end
users, options = with_custom_attributes(users, { with: entity, current_user: current_user })
@@ -1369,63 +1369,6 @@ module API
get 'status', feature_category: :user_profile do
present current_user.status || {}, with: Entities::UserStatus
end
-
- desc 'Create a runner owned by currently authenticated user' do
- detail 'Create a new runner'
- success Entities::Ci::RunnerRegistrationDetails
- failure [[400, 'Bad Request'], [403, 'Forbidden']]
- tags %w[user runners]
- end
- params do
- requires :runner_type, type: String, values: ::Ci::Runner.runner_types.keys,
- desc: %q(Specifies the scope of the runner)
- given runner_type: ->(runner_type) { runner_type == 'group_type' } do
- requires :group_id, type: Integer,
- desc: 'The ID of the group that the runner is created in',
- documentation: { example: 1 }
- end
- given runner_type: ->(runner_type) { runner_type == 'project_type' } do
- requires :project_id, type: Integer,
- desc: 'The ID of the project that the runner is created in',
- documentation: { example: 1 }
- end
- optional :description, type: String, desc: %q(Description of the runner)
- optional :maintenance_note, type: String,
- desc: %q(Free-form maintenance notes for the runner (1024 characters))
- optional :paused, type: Boolean, desc: 'Specifies if the runner should ignore new jobs (defaults to false)'
- optional :locked, type: Boolean,
- desc: 'Specifies if the runner should be locked for the current project (defaults to false)'
- optional :access_level, type: String, values: ::Ci::Runner.access_levels.keys,
- desc: 'The access level of the runner'
- optional :run_untagged, type: Boolean,
- desc: 'Specifies if the runner should handle untagged jobs (defaults to true)'
- optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
- desc: %q(A list of runner tags)
- optional :maximum_timeout, type: Integer,
- desc: 'Maximum timeout that limits the amount of time (in seconds) that runners can run jobs'
- end
- post 'runners', urgency: :low, feature_category: :runner_fleet do
- attributes = attributes_for_keys(
- %i[runner_type group_id project_id description maintenance_note paused locked run_untagged tag_list
- access_level maximum_timeout]
- )
-
- case attributes[:runner_type]
- when 'group_type'
- attributes[:scope] = ::Group.find_by_id(attributes.delete(:group_id))
- when 'project_type'
- attributes[:scope] = ::Project.find_by_id(attributes.delete(:project_id))
- end
-
- result = ::Ci::Runners::CreateRunnerService.new(user: current_user, params: attributes).execute
- if result.error?
- message = result.errors.to_sentence
- forbidden!(message) if result.reason == :forbidden
- bad_request!(message)
- end
-
- present result.payload[:runner], with: Entities::Ci::RunnerRegistrationDetails
- end
end
end
end