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:
Diffstat (limited to 'lib/api')
-rw-r--r--lib/api/access_requests.rb39
-rw-r--r--lib/api/admin/ci/variables.rb49
-rw-r--r--lib/api/admin/instance_clusters.rb52
-rw-r--r--lib/api/admin/plan_limits.rb28
-rw-r--r--lib/api/alert_management_alerts.rb2
-rw-r--r--lib/api/api.rb185
-rw-r--r--lib/api/appearance.rb1
-rw-r--r--lib/api/applications.rb21
-rw-r--r--lib/api/badges.rb9
-rw-r--r--lib/api/boards.rb2
-rw-r--r--lib/api/branches.rb45
-rw-r--r--lib/api/bulk_imports.rb48
-rw-r--r--lib/api/ci/helpers/runner.rb30
-rw-r--r--lib/api/ci/job_artifacts.rb6
-rw-r--r--lib/api/ci/jobs.rb94
-rw-r--r--lib/api/ci/pipeline_schedules.rb144
-rw-r--r--lib/api/ci/pipelines.rb151
-rw-r--r--lib/api/ci/resource_groups.rb54
-rw-r--r--lib/api/ci/runner.rb75
-rw-r--r--lib/api/ci/runners.rb292
-rw-r--r--lib/api/ci/secure_files.rb4
-rw-r--r--lib/api/ci/triggers.rb66
-rw-r--r--lib/api/ci/variables.rb39
-rw-r--r--lib/api/clusters/agent_tokens.rb20
-rw-r--r--lib/api/clusters/agents.rb22
-rw-r--r--lib/api/commit_statuses.rb55
-rw-r--r--lib/api/commits.rb204
-rw-r--r--lib/api/concerns/packages/conan_endpoints.rb6
-rw-r--r--lib/api/container_registry_event.rb14
-rw-r--r--lib/api/container_repositories.rb2
-rw-r--r--lib/api/debian_project_packages.rb4
-rw-r--r--lib/api/dependency_proxy.rb13
-rw-r--r--lib/api/deploy_keys.rb75
-rw-r--r--lib/api/deploy_tokens.rb100
-rw-r--r--lib/api/deployments.rb113
-rw-r--r--lib/api/discussions.rb95
-rw-r--r--lib/api/entities/application.rb10
-rw-r--r--lib/api/entities/application_statistics.rb32
-rw-r--r--lib/api/entities/application_with_secret.rb3
-rw-r--r--lib/api/entities/basic_project_details.rb23
-rw-r--r--lib/api/entities/basic_ref.rb3
-rw-r--r--lib/api/entities/basic_release_details.rb12
-rw-r--r--lib/api/entities/basic_repository_storage_move.rb10
-rw-r--r--lib/api/entities/basic_snippet.rb26
-rw-r--r--lib/api/entities/branch.rb44
-rw-r--r--lib/api/entities/bulk_import.rb12
-rw-r--r--lib/api/entities/bulk_imports/entity.rb28
-rw-r--r--lib/api/entities/bulk_imports/entity_failure.rb18
-rw-r--r--lib/api/entities/bulk_imports/export_status.rb8
-rw-r--r--lib/api/entities/ci/job.rb13
-rw-r--r--lib/api/entities/ci/job_artifact.rb7
-rw-r--r--lib/api/entities/ci/job_artifact_file.rb4
-rw-r--r--lib/api/entities/ci/job_basic.rb27
-rw-r--r--lib/api/entities/ci/lint/result.rb17
-rw-r--r--lib/api/entities/ci/pipeline.rb18
-rw-r--r--lib/api/entities/ci/pipeline_basic.rb17
-rw-r--r--lib/api/entities/ci/pipeline_schedule.rb12
-rw-r--r--lib/api/entities/ci/resource_group.rb6
-rw-r--r--lib/api/entities/ci/runner.rb22
-rw-r--r--lib/api/entities/ci/secure_file.rb2
-rw-r--r--lib/api/entities/ci/variable.rb14
-rw-r--r--lib/api/entities/commit.rb27
-rw-r--r--lib/api/entities/commit_detail.rb6
-rw-r--r--lib/api/entities/commit_note.rb20
-rw-r--r--lib/api/entities/commit_signature.rb4
-rw-r--r--lib/api/entities/commit_stats.rb4
-rw-r--r--lib/api/entities/commit_status.rb18
-rw-r--r--lib/api/entities/compare.rb13
-rw-r--r--lib/api/entities/container_registry.rb14
-rw-r--r--lib/api/entities/contributor.rb6
-rw-r--r--lib/api/entities/custom_attribute.rb4
-rw-r--r--lib/api/entities/deploy_key.rb12
-rw-r--r--lib/api/entities/deploy_keys_project.rb2
-rw-r--r--lib/api/entities/deploy_token.rb9
-rw-r--r--lib/api/entities/deploy_token_with_token.rb2
-rw-r--r--lib/api/entities/deployment.rb9
-rw-r--r--lib/api/entities/diff.rb16
-rw-r--r--lib/api/entities/entity_helpers.rb4
-rw-r--r--lib/api/entities/environment.rb4
-rw-r--r--lib/api/entities/environment_basic.rb7
-rw-r--r--lib/api/entities/error_tracking.rb18
-rw-r--r--lib/api/entities/feature.rb4
-rw-r--r--lib/api/entities/feature_flag.rb12
-rw-r--r--lib/api/entities/feature_flag/scope.rb4
-rw-r--r--lib/api/entities/feature_flag/strategy.rb6
-rw-r--r--lib/api/entities/feature_flag/user_list.rb14
-rw-r--r--lib/api/entities/feature_gate.rb4
-rw-r--r--lib/api/entities/freeze_period.rb8
-rw-r--r--lib/api/entities/go_module_version.rb4
-rw-r--r--lib/api/entities/hook.rb16
-rw-r--r--lib/api/entities/issuable_entity.rb14
-rw-r--r--lib/api/entities/issue_basic.rb16
-rw-r--r--lib/api/entities/license.rb25
-rw-r--r--lib/api/entities/license_basic.rb6
-rw-r--r--lib/api/entities/markdown.rb9
-rw-r--r--lib/api/entities/merge_request_approvals.rb6
-rw-r--r--lib/api/entities/merge_request_basic.rb7
-rw-r--r--lib/api/entities/merge_request_simple.rb7
-rw-r--r--lib/api/entities/metadata.rb9
-rw-r--r--lib/api/entities/metrics/dashboard/annotation.rb14
-rw-r--r--lib/api/entities/metrics/user_starred_dashboard.rb5
-rw-r--r--lib/api/entities/ml/mlflow/run.rb2
-rw-r--r--lib/api/entities/ml/mlflow/run_info.rb2
-rw-r--r--lib/api/entities/ml/mlflow/update_run.rb8
-rw-r--r--lib/api/entities/package.rb29
-rw-r--r--lib/api/entities/package_file.rb11
-rw-r--r--lib/api/entities/personal_access_token.rb13
-rw-r--r--lib/api/entities/plan_limit.rb34
-rw-r--r--lib/api/entities/project.rb159
-rw-r--r--lib/api/entities/project_daily_fetches.rb4
-rw-r--r--lib/api/entities/project_daily_statistics.rb4
-rw-r--r--lib/api/entities/project_export_status.rb14
-rw-r--r--lib/api/entities/project_group_link.rb6
-rw-r--r--lib/api/entities/project_hook.rb15
-rw-r--r--lib/api/entities/project_identity.rb11
-rw-r--r--lib/api/entities/project_import_failed_relation.rb11
-rw-r--r--lib/api/entities/project_import_status.rb16
-rw-r--r--lib/api/entities/project_integration.rb2
-rw-r--r--lib/api/entities/project_integration_basic.rb25
-rw-r--r--lib/api/entities/project_repository_storage.rb10
-rw-r--r--lib/api/entities/project_with_access.rb36
-rw-r--r--lib/api/entities/protected_branch.rb10
-rw-r--r--lib/api/entities/protected_ref_access.rb10
-rw-r--r--lib/api/entities/protected_tag.rb2
-rw-r--r--lib/api/entities/pull_mirror.rb19
-rw-r--r--lib/api/entities/release.rb18
-rw-r--r--lib/api/entities/releases/evidence.rb6
-rw-r--r--lib/api/entities/releases/link.rb20
-rw-r--r--lib/api/entities/releases/source.rb4
-rw-r--r--lib/api/entities/remote_mirror.rb20
-rw-r--r--lib/api/entities/resource_access_token.rb7
-rw-r--r--lib/api/entities/resource_milestone_event.rb12
-rw-r--r--lib/api/entities/snippet.rb8
-rw-r--r--lib/api/entities/snippets/repository_storage_move.rb2
-rw-r--r--lib/api/entities/ssh_key.rb11
-rw-r--r--lib/api/entities/tag.rb6
-rw-r--r--lib/api/entities/tag_release.rb4
-rw-r--r--lib/api/entities/templates_list.rb4
-rw-r--r--lib/api/entities/tree_object.rb7
-rw-r--r--lib/api/entities/trigger.rb10
-rw-r--r--lib/api/entities/user_agent_detail.rb6
-rw-r--r--lib/api/entities/user_associations_count.rb23
-rw-r--r--lib/api/entities/user_basic.rb19
-rw-r--r--lib/api/entities/user_counts.rb25
-rw-r--r--lib/api/entities/user_public.rb24
-rw-r--r--lib/api/entities/user_safe.rb5
-rw-r--r--lib/api/entities/wiki_attachment.rb14
-rw-r--r--lib/api/entities/wiki_page.rb6
-rw-r--r--lib/api/entities/wiki_page_basic.rb6
-rw-r--r--lib/api/entities/x509_certificate.rb17
-rw-r--r--lib/api/entities/x509_issuer.rb11
-rw-r--r--lib/api/entities/x509_signature.rb2
-rw-r--r--lib/api/environments.rb102
-rw-r--r--lib/api/error_tracking/client_keys.rb23
-rw-r--r--lib/api/error_tracking/collector.rb4
-rw-r--r--lib/api/error_tracking/project_settings.rb30
-rw-r--r--lib/api/feature_flags.rb77
-rw-r--r--lib/api/feature_flags_user_lists.rb56
-rw-r--r--lib/api/features.rb45
-rw-r--r--lib/api/files.rb77
-rw-r--r--lib/api/freeze_periods.rb64
-rw-r--r--lib/api/generic_packages.rb4
-rw-r--r--lib/api/geo.rb7
-rwxr-xr-xlib/api/go_proxy.rb52
-rw-r--r--lib/api/group_avatar.rb4
-rw-r--r--lib/api/group_clusters.rb42
-rw-r--r--lib/api/group_container_repositories.rb13
-rw-r--r--lib/api/group_export.rb45
-rw-r--r--lib/api/group_import.rb11
-rw-r--r--lib/api/group_packages.rb19
-rw-r--r--lib/api/group_variables.rb38
-rw-r--r--lib/api/helpers.rb13
-rw-r--r--lib/api/helpers/internal_helpers.rb7
-rw-r--r--lib/api/helpers/label_helpers.rb5
-rw-r--r--lib/api/helpers/merge_requests_helpers.rb5
-rw-r--r--lib/api/helpers/packages/dependency_proxy_helpers.rb2
-rw-r--r--lib/api/helpers/packages/npm.rb2
-rw-r--r--lib/api/helpers/packages_helpers.rb30
-rw-r--r--lib/api/helpers/projects_helpers.rb4
-rw-r--r--lib/api/helpers/users_helpers.rb7
-rw-r--r--lib/api/helpers/web_hooks_helpers.rb6
-rw-r--r--lib/api/import_bitbucket_server.rb8
-rw-r--r--lib/api/import_github.rb24
-rw-r--r--lib/api/integrations.rb51
-rw-r--r--lib/api/internal/kubernetes.rb28
-rw-r--r--lib/api/internal/pages.rb1
-rw-r--r--lib/api/invitations.rb20
-rw-r--r--lib/api/issue_links.rb55
-rw-r--r--lib/api/issues.rb2
-rw-r--r--lib/api/keys.rb12
-rw-r--r--lib/api/labels.rb2
-rw-r--r--lib/api/lint.rb43
-rw-r--r--lib/api/markdown.rb16
-rw-r--r--lib/api/maven_packages.rb14
-rw-r--r--lib/api/merge_request_approvals.rb28
-rw-r--r--lib/api/merge_request_diffs.rb11
-rw-r--r--lib/api/merge_requests.rb2
-rw-r--r--lib/api/metadata.rb57
-rw-r--r--lib/api/metrics/dashboard/annotations.rb25
-rw-r--r--lib/api/metrics/user_starred_dashboards.rb22
-rw-r--r--lib/api/ml/mlflow.rb24
-rw-r--r--lib/api/npm_project_packages.rb2
-rw-r--r--lib/api/nuget_project_packages.rb4
-rw-r--r--lib/api/package_files.rb22
-rw-r--r--lib/api/pages.rb2
-rw-r--r--lib/api/pages_domains.rb2
-rw-r--r--lib/api/pagination_params.rb5
-rw-r--r--lib/api/personal_access_tokens.rb60
-rw-r--r--lib/api/personal_access_tokens/self_information.rb18
-rw-r--r--lib/api/project_clusters.rb49
-rw-r--r--lib/api/project_container_repositories.rb8
-rw-r--r--lib/api/project_debian_distributions.rb2
-rw-r--r--lib/api/project_events.rb9
-rw-r--r--lib/api/project_export.rb61
-rw-r--r--lib/api/project_hooks.rb45
-rw-r--r--lib/api/project_import.rb48
-rw-r--r--lib/api/project_milestones.rb2
-rw-r--r--lib/api/project_packages.rb2
-rw-r--r--lib/api/project_repository_storage_moves.rb17
-rw-r--r--lib/api/project_snapshots.rb5
-rw-r--r--lib/api/project_snippets.rb52
-rw-r--r--lib/api/project_statistics.rb12
-rw-r--r--lib/api/project_templates.rb27
-rw-r--r--lib/api/projects.rb7
-rw-r--r--lib/api/projects_relation_builder.rb4
-rw-r--r--lib/api/protected_branches.rb72
-rw-r--r--lib/api/protected_tags.rb46
-rw-r--r--lib/api/pypi_packages.rb33
-rw-r--r--lib/api/release/links.rb75
-rw-r--r--lib/api/releases.rb197
-rw-r--r--lib/api/remote_mirrors.rb58
-rw-r--r--lib/api/repositories.rb76
-rw-r--r--lib/api/resource_access_tokens.rb35
-rw-r--r--lib/api/resource_milestone_events.rb17
-rw-r--r--lib/api/rpm_project_packages.rb27
-rw-r--r--lib/api/rubygem_packages.rb2
-rw-r--r--lib/api/search.rb8
-rw-r--r--lib/api/settings.rb1
-rw-r--r--lib/api/snippet_repository_storage_moves.rb15
-rw-r--r--lib/api/snippets.rb46
-rw-r--r--lib/api/statistics.rb2
-rw-r--r--lib/api/submodules.rb31
-rw-r--r--lib/api/suggestions.rb6
-rw-r--r--lib/api/system_hooks.rb54
-rw-r--r--lib/api/tags.rb45
-rw-r--r--lib/api/terraform/modules/v1/packages.rb72
-rw-r--r--lib/api/terraform/state.rb76
-rw-r--r--lib/api/terraform/state_version.rb22
-rw-r--r--lib/api/topics.rb10
-rw-r--r--lib/api/unleash.rb34
-rw-r--r--lib/api/user_counts.rb9
-rw-r--r--lib/api/users.rb57
-rw-r--r--lib/api/v3/github.rb2
-rw-r--r--lib/api/validations/validators/email_or_email_list.rb7
-rw-r--r--lib/api/wikis.rb34
255 files changed, 4699 insertions, 1860 deletions
diff --git a/lib/api/access_requests.rb b/lib/api/access_requests.rb
index 74f6515f07f..38a9856ca58 100644
--- a/lib/api/access_requests.rb
+++ b/lib/api/access_requests.rb
@@ -19,6 +19,7 @@ module API
desc "Gets a list of access requests for a #{source_type}." do
detail 'This feature was introduced in GitLab 8.11.'
success Entities::AccessRequester
+ tags %w[access_requests]
end
params do
use :pagination
@@ -37,6 +38,24 @@ module API
desc "Requests access for the authenticated user to a #{source_type}." do
detail 'This feature was introduced in GitLab 8.11.'
success Entities::AccessRequester
+ success [
+ {
+ code: 200,
+ model: Entities::AccessRequester,
+ message: 'successful operation',
+ examples: {
+ successfull_response: {
+ "id" => 1,
+ "username" => "raymond_smith",
+ "name" => "Raymond Smith",
+ "state" => "active",
+ "created_at" => "2012-10-22T14:13:35Z",
+ "access_level" => 20
+ }
+ }
+ }
+ ]
+ tags %w[access_requests]
end
post ":id/access_requests" do
source = find_source(source_type, params[:id])
@@ -51,7 +70,24 @@ module API
desc 'Approves an access request for the given user.' do
detail 'This feature was introduced in GitLab 8.11.'
- success Entities::Member
+ success [
+ {
+ code: 200,
+ model: Entities::AccessRequester,
+ message: 'successful operation',
+ examples: {
+ successfull_response: {
+ "id" => 1,
+ "username" => "raymond_smith",
+ "name" => "Raymond Smith",
+ "state" => "active",
+ "created_at" => "2012-10-22T14:13:35Z",
+ "access_level" => 20
+ }
+ }
+ }
+ ]
+ tags %w[access_requests]
end
params do
requires :user_id, type: Integer, desc: 'The user ID of the access requester'
@@ -74,6 +110,7 @@ module API
desc 'Denies an access request for the given user.' do
detail 'This feature was introduced in GitLab 8.11.'
+ tags %w[access_requests]
end
params do
requires :user_id, type: Integer, desc: 'The user ID of the access requester'
diff --git a/lib/api/admin/ci/variables.rb b/lib/api/admin/ci/variables.rb
index 0462878c90c..bc351e27f99 100644
--- a/lib/api/admin/ci/variables.rb
+++ b/lib/api/admin/ci/variables.rb
@@ -13,8 +13,9 @@ module API
namespace 'admin' do
namespace 'ci' do
namespace 'variables' do
- desc 'Get instance-level variables' do
+ desc 'List all instance-level variables' do
success Entities::Ci::Variable
+ tags %w[ci_variables]
end
params do
use :pagination
@@ -25,11 +26,13 @@ module API
present paginate(variables), with: Entities::Ci::Variable
end
- desc 'Get a specific variable from a group' do
+ desc 'Get the details of a specific instance-level variable' do
success Entities::Ci::Variable
+ failure [{ code: 404, message: 'Instance Variable Not Found' }]
+ tags %w[ci_variables]
end
params do
- requires :key, type: String, desc: 'The key of the variable'
+ requires :key, type: String, desc: 'The key of a variable'
end
get ':key' do
key = params[:key]
@@ -42,28 +45,35 @@ module API
desc 'Create a new instance-level variable' do
success Entities::Ci::Variable
+ failure [{ code: 400, message: '400 Bad Request' }]
+ tags %w[ci_variables]
end
+ route_setting :log_safety, { safe: %w[key], unsafe: %w[value] }
params do
requires :key,
type: String,
- desc: 'The key of the variable'
+ desc: 'The key of the variable. Max 255 characters'
requires :value,
type: String,
- desc: 'The value of the variable'
+ desc: 'The value of a variable'
optional :protected,
- type: String,
+ type: Boolean,
desc: 'Whether the variable is protected'
optional :masked,
- type: String,
+ type: Boolean,
desc: 'Whether the variable is masked'
+ optional :raw,
+ type: Boolean,
+ desc: 'Whether the variable will be expanded'
+
optional :variable_type,
type: String,
values: ::Ci::InstanceVariable.variable_types.keys,
- desc: 'The type of variable, must be one of env_var or file. Defaults to env_var'
+ desc: 'The type of a variable. Available types are: env_var (default) and file'
end
post '/' do
variable_params = declared_params(include_missing: false)
@@ -77,30 +87,37 @@ module API
end
end
- desc 'Update an existing instance-variable' do
+ desc 'Update an instance-level variable' do
success Entities::Ci::Variable
+ failure [{ code: 404, message: 'Instance Variable Not Found' }]
+ tags %w[ci_variables]
end
+ route_setting :log_safety, { safe: %w[key], unsafe: %w[value] }
params do
optional :key,
type: String,
- desc: 'The key of the variable'
+ desc: 'The key of a variable'
optional :value,
type: String,
- desc: 'The value of the variable'
+ desc: 'The value of a variable'
optional :protected,
- type: String,
+ type: Boolean,
desc: 'Whether the variable is protected'
optional :masked,
- type: String,
+ type: Boolean,
desc: 'Whether the variable is masked'
+ optional :raw,
+ type: Boolean,
+ desc: 'Whether the variable will be expanded'
+
optional :variable_type,
type: String,
values: ::Ci::InstanceVariable.variable_types.keys,
- desc: 'The type of variable, must be one of env_var or file'
+ desc: 'The type of a variable. Available types are: env_var (default) and file'
end
put ':key' do
variable = ::Ci::InstanceVariable.find_by_key(params[:key])
@@ -118,9 +135,11 @@ module API
desc 'Delete an existing instance-level variable' do
success Entities::Ci::Variable
+ failure [{ code: 404, message: 'Instance Variable Not Found' }]
+ tags %w[ci_variables]
end
params do
- requires :key, type: String, desc: 'The key of the variable'
+ requires :key, type: String, desc: 'The key of a variable'
end
delete ':key' do
variable = ::Ci::InstanceVariable.find_by_key(params[:key])
diff --git a/lib/api/admin/instance_clusters.rb b/lib/api/admin/instance_clusters.rb
index 7163225777a..f848103d9a0 100644
--- a/lib/api/admin/instance_clusters.rb
+++ b/lib/api/admin/instance_clusters.rb
@@ -14,16 +14,28 @@ module API
end
namespace 'admin' do
- desc "Get list of all instance clusters" do
- detail "This feature was introduced in GitLab 13.2."
+ desc 'List instance clusters' do
+ detail 'This feature was introduced in GitLab 13.2. Returns a list of instance clusters.'
+ success Entities::Cluster
+ failure [
+ { code: 403, message: 'Forbidden' }
+ ]
+ is_array true
+ tags %w[clusters]
end
get '/clusters' do
authorize! :read_cluster, clusterable_instance
present paginate(clusters_for_current_user), with: Entities::Cluster
end
- desc "Get a single instance cluster" do
- detail "This feature was introduced in GitLab 13.2."
+ desc 'Get a single instance cluster' do
+ detail 'This feature was introduced in GitLab 13.2. Returns a single instance cluster.'
+ success Entities::Cluster
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: "The cluster ID"
@@ -34,8 +46,15 @@ module API
present cluster, with: Entities::Cluster
end
- desc "Add an instance cluster" do
- detail "This feature was introduced in GitLab 13.2."
+ desc 'Add existing instance cluster' do
+ detail 'This feature was introduced in GitLab 13.2. Adds an existing Kubernetes instance cluster.'
+ success Entities::Cluster
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :name, type: String, desc: 'Cluster name'
@@ -67,8 +86,15 @@ module API
end
end
- desc "Update an instance cluster" do
- detail "This feature was introduced in GitLab 13.2."
+ desc 'Edit instance cluster' do
+ detail 'This feature was introduced in GitLab 13.2. Updates an existing instance cluster.'
+ success Entities::Cluster
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The cluster ID'
@@ -98,8 +124,14 @@ module API
end
end
- desc "Remove a cluster" do
- detail "This feature was introduced in GitLab 13.2."
+ desc 'Delete instance cluster' do
+ detail 'This feature was introduced in GitLab 13.2. Deletes an existing instance cluster. Does not remove existing resources within the connected Kubernetes cluster.'
+ success Entities::Cluster
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: "The cluster ID"
diff --git a/lib/api/admin/plan_limits.rb b/lib/api/admin/plan_limits.rb
index 7ce70d85d46..49b41b44a18 100644
--- a/lib/api/admin/plan_limits.rb
+++ b/lib/api/admin/plan_limits.rb
@@ -5,6 +5,8 @@ module API
class PlanLimits < ::API::Base
before { authenticated_as_admin! }
+ PLAN_LIMITS_TAGS = %w[plan_limits].freeze
+
feature_category :not_owned # rubocop:todo Gitlab/AvoidFeatureCategoryNotOwned
helpers do
@@ -17,10 +19,17 @@ module API
end
desc 'Get current plan limits' do
+ detail 'List the current limits of a plan on the GitLab instance.'
success Entities::PlanLimit
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' }
+ ]
+ tags PLAN_LIMITS_TAGS
end
params do
- optional :plan_name, type: String, values: Plan.all_plans, default: Plan::DEFAULT, desc: 'Name of the plan'
+ optional :plan_name, type: String, values: Plan.all_plans, default: Plan::DEFAULT,
+ desc: 'Name of the plan to get the limits from. Default: default.'
end
get "application/plan_limits" do
params = declared_params(include_missing: false)
@@ -29,16 +38,24 @@ module API
present plan.actual_limits, with: Entities::PlanLimit
end
- desc 'Modify plan limits' do
+ desc 'Change plan limits' do
+ detail 'Modify the limits of a plan on the GitLab instance.'
success Entities::PlanLimit
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' }
+ ]
+ tags PLAN_LIMITS_TAGS
end
params do
- requires :plan_name, type: String, values: Plan.all_plans, desc: 'Name of the plan'
+ requires :plan_name, type: String, values: Plan.all_plans, desc: 'Name of the plan to update'
optional :ci_pipeline_size, type: Integer, desc: 'Maximum number of jobs in a single pipeline'
optional :ci_active_jobs, type: Integer, desc: 'Total number of jobs in currently active pipelines'
optional :ci_active_pipelines, type: Integer, desc: 'Maximum number of active pipelines per project'
- optional :ci_project_subscriptions, type: Integer, desc: 'Maximum number of pipeline subscriptions to and from a project'
+ optional :ci_project_subscriptions, type: Integer,
+ desc: 'Maximum number of pipeline subscriptions to and from a project'
optional :ci_pipeline_schedules, type: Integer, desc: 'Maximum number of pipeline schedules'
optional :ci_needs_size_limit, type: Integer, desc: 'Maximum number of DAG dependencies that a job can have'
optional :ci_registered_group_runners, type: Integer, desc: 'Maximum number of runners registered per group'
@@ -50,7 +67,8 @@ module API
optional :npm_max_file_size, type: Integer, desc: 'Maximum NPM package file size in bytes'
optional :nuget_max_file_size, type: Integer, desc: 'Maximum NuGet package file size in bytes'
optional :pypi_max_file_size, type: Integer, desc: 'Maximum PyPI package file size in bytes'
- optional :terraform_module_max_file_size, type: Integer, desc: 'Maximum Terraform Module package file size in bytes'
+ optional :terraform_module_max_file_size, type: Integer,
+ desc: 'Maximum Terraform Module package file size in bytes'
optional :storage_size_limit, type: Integer, desc: 'Maximum storage size for the root namespace in megabytes'
end
put "application/plan_limits" do
diff --git a/lib/api/alert_management_alerts.rb b/lib/api/alert_management_alerts.rb
index f03f133f6f7..f57b7d00c81 100644
--- a/lib/api/alert_management_alerts.rb
+++ b/lib/api/alert_management_alerts.rb
@@ -6,7 +6,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
requires :alert_iid, type: Integer, desc: 'The IID of the Alert'
end
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 933c3f69075..ffb0cdf8991 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -13,13 +13,14 @@ module API
USER_REQUIREMENTS = { user_id: NO_SLASH_URL_PART_REGEX }.freeze
LOG_FILTERS = ::Rails.application.config.filter_parameters + [/^output$/]
LOG_FORMATTER = Gitlab::GrapeLogging::Formatters::LogrageWithTimestamp.new
+ LOGGER = Logger.new(LOG_FILENAME)
insert_before Grape::Middleware::Error,
GrapeLogging::Middleware::RequestLogger,
- logger: Logger.new(LOG_FILENAME),
+ logger: LOGGER,
formatter: LOG_FORMATTER,
include: [
- GrapeLogging::Loggers::FilterParameters.new(LOG_FILTERS),
+ Gitlab::GrapeLogging::Loggers::FilterParameters.new(LOG_FILTERS),
Gitlab::GrapeLogging::Loggers::ClientEnvLogger.new,
Gitlab::GrapeLogging::Loggers::RouteLogger.new,
Gitlab::GrapeLogging::Loggers::UserLogger.new,
@@ -168,42 +169,111 @@ module API
# Mount endpoints to include in the OpenAPI V2 documentation here
namespace do
+ # Keep in alphabetical order
+ mount ::API::AccessRequests
+ mount ::API::Admin::Ci::Variables
+ mount ::API::Admin::InstanceClusters
+ mount ::API::Admin::PlanLimits
+ mount ::API::Appearance
+ mount ::API::Applications
+ mount ::API::Avatar
+ mount ::API::Badges
+ mount ::API::Branches
+ mount ::API::BroadcastMessages
+ mount ::API::BulkImports
+ mount ::API::Ci::Jobs
+ mount ::API::Ci::ResourceGroups
+ mount ::API::Ci::Runner
+ mount ::API::Ci::Runners
+ mount ::API::Ci::Pipelines
+ mount ::API::Ci::PipelineSchedules
+ mount ::API::Ci::Triggers
+ mount ::API::Ci::Variables
+ mount ::API::Clusters::AgentTokens
+ mount ::API::Clusters::Agents
+ mount ::API::Commits
+ mount ::API::CommitStatuses
+ mount ::API::DependencyProxy
+ mount ::API::DeployKeys
+ mount ::API::DeployTokens
+ mount ::API::Deployments
+ mount ::API::Environments
+ mount ::API::ErrorTracking::ClientKeys
+ mount ::API::ErrorTracking::ProjectSettings
+ mount ::API::FeatureFlags
+ mount ::API::FeatureFlagsUserLists
+ mount ::API::Features
+ mount ::API::Files
+ mount ::API::FreezePeriods
+ mount ::API::Geo
+ mount ::API::GoProxy
+ mount ::API::GroupAvatar
+ mount ::API::GroupClusters
+ mount ::API::GroupContainerRepositories
+ mount ::API::GroupExport
+ mount ::API::GroupImport
+ mount ::API::GroupPackages
+ mount ::API::GroupVariables
+ mount ::API::ImportBitbucketServer
+ mount ::API::ImportGithub
+ mount ::API::Integrations
+ mount ::API::Invitations
+ mount ::API::IssueLinks
+ mount ::API::Keys
+ mount ::API::Lint
+ mount ::API::Markdown
+ mount ::API::MergeRequestApprovals
+ mount ::API::MergeRequestDiffs
mount ::API::Metadata
+ mount ::API::Metrics::Dashboard::Annotations
+ mount ::API::Metrics::UserStarredDashboards
+ mount ::API::PackageFiles
+ mount ::API::PersonalAccessTokens::SelfInformation
+ mount ::API::PersonalAccessTokens
+ mount ::API::ProjectClusters
+ mount ::API::ProjectEvents
+ mount ::API::ProjectExport
+ mount ::API::ProjectHooks
+ mount ::API::ProjectImport
+ mount ::API::ProjectRepositoryStorageMoves
+ mount ::API::ProjectSnippets
+ mount ::API::ProjectSnapshots
+ mount ::API::ProjectStatistics
+ mount ::API::ProjectTemplates
+ mount ::API::ProtectedBranches
+ mount ::API::ProtectedTags
+ mount ::API::Releases
+ mount ::API::Release::Links
+ mount ::API::RemoteMirrors
+ mount ::API::Repositories
+ mount ::API::ResourceAccessTokens
+ mount ::API::ResourceMilestoneEvents
+ mount ::API::Snippets
+ mount ::API::SnippetRepositoryStorageMoves
+ mount ::API::Statistics
+ mount ::API::Submodules
+ mount ::API::Suggestions
+ mount ::API::SystemHooks
+ mount ::API::Tags
+ mount ::API::Terraform::Modules::V1::Packages
+ mount ::API::Terraform::State
+ mount ::API::Terraform::StateVersion
+ mount ::API::Topics
+ mount ::API::Unleash
+ mount ::API::UserCounts
+ mount ::API::Wikis
add_open_api_documentation!
end
# Keep in alphabetical order
- mount ::API::AccessRequests
mount ::API::Admin::BatchedBackgroundMigrations
- mount ::API::Admin::Ci::Variables
- mount ::API::Admin::InstanceClusters
- mount ::API::Admin::PlanLimits
mount ::API::Admin::Sidekiq
mount ::API::AlertManagementAlerts
- mount ::API::Appearance
- mount ::API::Applications
- mount ::API::Avatar
mount ::API::AwardEmoji
- mount ::API::Badges
mount ::API::Boards
- mount ::API::Branches
- mount ::API::BroadcastMessages
- mount ::API::BulkImports
mount ::API::Ci::JobArtifacts
- mount ::API::Ci::Jobs
- mount ::API::Ci::PipelineSchedules
- mount ::API::Ci::Pipelines
- mount ::API::Ci::ResourceGroups
- mount ::API::Ci::Runner
- mount ::API::Ci::Runners
mount ::API::Ci::SecureFiles
- mount ::API::Ci::Triggers
- mount ::API::Ci::Variables
- mount ::API::Clusters::Agents
- mount ::API::Clusters::AgentTokens
- mount ::API::CommitStatuses
- mount ::API::Commits
mount ::API::ComposerPackages
mount ::API::ConanInstancePackages
mount ::API::ConanProjectPackages
@@ -211,55 +281,22 @@ module API
mount ::API::ContainerRepositories
mount ::API::DebianGroupPackages
mount ::API::DebianProjectPackages
- mount ::API::DependencyProxy
- mount ::API::DeployKeys
- mount ::API::DeployTokens
- mount ::API::Deployments
mount ::API::Discussions
- mount ::API::Environments
- mount ::API::ErrorTracking::ClientKeys
mount ::API::ErrorTracking::Collector
- mount ::API::ErrorTracking::ProjectSettings
mount ::API::Events
- mount ::API::FeatureFlags
- mount ::API::FeatureFlagsUserLists
- mount ::API::Features
- mount ::API::Files
- mount ::API::FreezePeriods
mount ::API::GenericPackages
- mount ::API::Geo
- mount ::API::GoProxy
- mount ::API::GroupAvatar
mount ::API::GroupBoards
- mount ::API::GroupClusters
- mount ::API::GroupContainerRepositories
mount ::API::GroupDebianDistributions
- mount ::API::GroupExport
- mount ::API::GroupImport
mount ::API::GroupLabels
mount ::API::GroupMilestones
- mount ::API::GroupPackages
- mount ::API::GroupVariables
mount ::API::Groups
mount ::API::HelmPackages
- mount ::API::ImportBitbucketServer
- mount ::API::ImportGithub
- mount ::API::Integrations
mount ::API::Integrations::JiraConnect::Subscriptions
- mount ::API::Invitations
- mount ::API::IssueLinks
mount ::API::Issues
- mount ::API::Keys
mount ::API::Labels
- mount ::API::Lint
- mount ::API::Markdown
mount ::API::MavenPackages
mount ::API::Members
- mount ::API::MergeRequestApprovals
- mount ::API::MergeRequestDiffs
mount ::API::MergeRequests
- mount ::API::Metrics::Dashboard::Annotations
- mount ::API::Metrics::UserStarredDashboards
mount ::API::Namespaces
mount ::API::Notes
mount ::API::NotificationSettings
@@ -267,63 +304,31 @@ module API
mount ::API::NpmProjectPackages
mount ::API::NugetGroupPackages
mount ::API::NugetProjectPackages
- mount ::API::PackageFiles
mount ::API::Pages
mount ::API::PagesDomains
- mount ::API::PersonalAccessTokens::SelfInformation
- mount ::API::PersonalAccessTokens
- mount ::API::ProjectClusters
mount ::API::ProjectContainerRepositories
mount ::API::ProjectDebianDistributions
mount ::API::ProjectEvents
- mount ::API::ProjectExport
- mount ::API::ProjectHooks
- mount ::API::ProjectImport
mount ::API::ProjectMilestones
mount ::API::ProjectPackages
- mount ::API::ProjectRepositoryStorageMoves
- mount ::API::ProjectSnapshots
- mount ::API::ProjectSnippets
- mount ::API::ProjectStatistics
- mount ::API::ProjectTemplates
mount ::API::Projects
- mount ::API::ProtectedBranches
mount ::API::ProtectedTags
mount ::API::PypiPackages
- mount ::API::Release::Links
- mount ::API::Releases
- mount ::API::RemoteMirrors
- mount ::API::Repositories
- mount ::API::ResourceAccessTokens
mount ::API::ResourceLabelEvents
- mount ::API::ResourceMilestoneEvents
mount ::API::ResourceStateEvents
mount ::API::RpmProjectPackages
mount ::API::RubygemPackages
mount ::API::Search
mount ::API::Settings
mount ::API::SidekiqMetrics
- mount ::API::SnippetRepositoryStorageMoves
- mount ::API::Snippets
- mount ::API::Statistics
- mount ::API::Submodules
mount ::API::Subscriptions
- mount ::API::Suggestions
- mount ::API::SystemHooks
mount ::API::Tags
mount ::API::Templates
- mount ::API::Terraform::Modules::V1::Packages
- mount ::API::Terraform::State
- mount ::API::Terraform::StateVersion
mount ::API::Todos
- mount ::API::Topics
- mount ::API::Unleash
mount ::API::UsageData
mount ::API::UsageDataNonSqlMetrics
mount ::API::UsageDataQueries
- mount ::API::UserCounts
mount ::API::Users
- mount ::API::Wikis
mount ::API::Ml::Mlflow
end
diff --git a/lib/api/appearance.rb b/lib/api/appearance.rb
index e599abf4aaf..69f1521ef2a 100644
--- a/lib/api/appearance.rb
+++ b/lib/api/appearance.rb
@@ -22,6 +22,7 @@ module API
desc 'Modify appearance' do
success Entities::Appearance
+ consumes ['multipart/form-data']
end
params do
optional :title, type: String, desc: 'Instance title on the sign in / sign up page'
diff --git a/lib/api/applications.rb b/lib/api/applications.rb
index 4048215160f..6fc9408a570 100644
--- a/lib/api/applications.rb
+++ b/lib/api/applications.rb
@@ -10,17 +10,21 @@ module API
resource :applications do
desc 'Create a new application' do
detail 'This feature was introduced in GitLab 10.5'
- success Entities::ApplicationWithSecret
+ success code: 200, model: Entities::ApplicationWithSecret
end
params do
- requires :name, type: String, desc: 'Application name'
- requires :redirect_uri, type: String, desc: 'Application redirect URI'
- requires :scopes, type: String, desc: 'Application scopes', allow_blank: false
+ requires :name, type: String, desc: 'Name of the application.', documentation: { example: 'MyApplication' }
+ requires :redirect_uri, type: String, desc: 'Redirect URI of the application.', documentation: { example: 'https://redirect.uri' }
+ requires :scopes, type: String,
+ desc: 'Scopes of the application. You can specify multiple scopes by separating\
+ each scope using a space',
+ allow_blank: false
optional :confidential,
type: Boolean,
default: true,
- desc: 'Application will be used where the client secret is confidential'
+ desc: 'The application is used where the client secret can be kept confidential. Native mobile apps \
+ and Single Page Apps are considered non-confidential. Defaults to true if not supplied'
end
post do
application = Doorkeeper::Application.new(declared_params)
@@ -33,14 +37,19 @@ module API
end
desc 'Get applications' do
+ detail 'List all registered applications'
success Entities::Application
+ is_array true
end
get do
applications = ApplicationsFinder.new.execute
present applications, with: Entities::Application
end
- desc 'Delete an application'
+ desc 'Delete an application' do
+ detail 'Delete a specific application'
+ success code: 204
+ end
params do
requires :id, type: Integer, desc: 'The ID of the application (not the application_id)'
end
diff --git a/lib/api/badges.rb b/lib/api/badges.rb
index 0a3f247ffd6..020ba53b9ee 100644
--- a/lib/api/badges.rb
+++ b/lib/api/badges.rb
@@ -28,6 +28,8 @@ module API
desc "Gets a list of #{source_type} badges viewable by the authenticated user." do
detail 'This feature was introduced in GitLab 10.6.'
success Entities::Badge
+ is_array true
+ tags %w[badges]
end
params do
use :pagination
@@ -46,6 +48,7 @@ module API
desc "Preview a badge from a #{source_type}." do
detail 'This feature was introduced in GitLab 10.6.'
success Entities::BasicBadgeDetails
+ tags %w[badges]
end
params do
requires :link_url, type: String, desc: 'URL of the badge link'
@@ -69,6 +72,7 @@ module API
desc "Gets a badge of a #{source_type}." do
detail 'This feature was introduced in GitLab 10.6.'
success Entities::Badge
+ tags %w[badges]
end
params do
requires :badge_id, type: Integer, desc: 'The badge ID'
@@ -86,6 +90,7 @@ module API
desc "Adds a badge to a #{source_type}." do
detail 'This feature was introduced in GitLab 10.6.'
success Entities::Badge
+ tags %w[badges]
end
params do
requires :link_url, type: String, desc: 'URL of the badge link'
@@ -107,6 +112,7 @@ module API
desc "Updates a badge of a #{source_type}." do
detail 'This feature was introduced in GitLab 10.6.'
success Entities::Badge
+ tags %w[badges]
end
params do
optional :link_url, type: String, desc: 'URL of the badge link'
@@ -127,8 +133,9 @@ module API
end
end
- desc 'Removes a badge from a project or group.' do
+ desc "Removes a badge from the #{source_type}." do
detail 'This feature was introduced in GitLab 10.6.'
+ tags %w[badges]
end
params do
requires :badge_id, type: Integer, desc: 'The badge ID'
diff --git a/lib/api/boards.rb b/lib/api/boards.rb
index 6e3005ce676..0e0f6441da7 100644
--- a/lib/api/boards.rb
+++ b/lib/api/boards.rb
@@ -19,7 +19,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
segment ':id/boards' do
diff --git a/lib/api/branches.rb b/lib/api/branches.rb
index 7e6b0214c03..845e42c2ed8 100644
--- a/lib/api/branches.rb
+++ b/lib/api/branches.rb
@@ -14,7 +14,7 @@ module API
before do
require_repository_enabled!
- authorize! :download_code, user_project
+ authorize! :read_code, user_project
end
rescue_from Gitlab::Git::Repository::NoRepository do
@@ -29,17 +29,21 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a project repository branches' do
success Entities::Branch
+ success code: 200, model: Entities::Branch
+ failure [{ code: 404, message: '404 Project Not Found' }]
+ tags %w[branches]
+ is_array true
end
params do
use :pagination
use :filter_params
- optional :page_token, type: String, desc: 'Name of branch to start the paginaition from'
+ optional :page_token, type: String, desc: 'Name of branch to start the pagination from'
end
get ':id/repository/branches', urgency: :low do
cache_action([user_project, :branches, current_user, declared_params], expires_in: 30.seconds) do
@@ -65,15 +69,23 @@ module API
end
resource ':id/repository/branches/:branch', requirements: BRANCH_ENDPOINT_REQUIREMENTS do
- desc 'Get a single branch' do
- success Entities::Branch
- end
params do
requires :branch, type: String, desc: 'The name of the branch'
end
+ desc 'Check if a branch exists' do
+ success [{ code: 204, message: 'No Content' }]
+ failure [{ code: 404, message: 'Not Found' }]
+ tags %w[branches]
+ end
head do
user_project.repository.branch_exists?(params[:branch]) ? no_content! : not_found!
end
+ desc 'Get a single repository branch' do
+ success Entities::Branch
+ success code: 200, model: Entities::Branch
+ failure [{ code: 404, message: 'Branch Not Found' }, { code: 404, message: 'Project Not Found' }]
+ tags %w[branches]
+ end
get '/', urgency: :low do
branch = find_branch!(params[:branch])
@@ -87,6 +99,9 @@ module API
# but it works with the changed data model to infer `developers_can_merge` and `developers_can_push`.
desc 'Protect a single branch' do
success Entities::Branch
+ success code: 200, model: Entities::Branch
+ failure [{ code: 404, message: '404 Branch Not Found' }]
+ tags %w[branches]
end
params do
requires :branch, type: String, desc: 'The name of the branch', allow_blank: false
@@ -126,6 +141,9 @@ module API
# Note: This API will be deprecated in favor of the protected branches API.
desc 'Unprotect a single branch' do
success Entities::Branch
+ success code: 200, model: Entities::Branch
+ failure [{ code: 404, message: '404 Project Not Found' }, { code: 404, message: '404 Branch Not Found' }]
+ tags %w[branches]
end
params do
requires :branch, type: String, desc: 'The name of the branch', allow_blank: false
@@ -145,6 +163,9 @@ module API
desc 'Create branch' do
success Entities::Branch
+ success code: 201, model: Entities::Branch
+ failure [{ code: 400, message: 'Failed to create branch' }, { code: 400, message: 'Branch already exists' }]
+ tags %w[branches]
end
params do
requires :branch, type: String, desc: 'The name of the branch', allow_blank: false
@@ -166,7 +187,11 @@ module API
end
end
- desc 'Delete a branch'
+ desc 'Delete a branch' do
+ success code: 204
+ failure [{ code: 404, message: 'Branch Not Found' }]
+ tags %w[branches]
+ end
params do
requires :branch, type: String, desc: 'The name of the branch', allow_blank: false
end
@@ -187,7 +212,11 @@ module API
end
end
- desc 'Delete all merged branches'
+ desc 'Delete all merged branches' do
+ success code: 202, message: '202 Accepted'
+ failure [{ code: 404, message: '404 Project Not Found' }]
+ tags %w[branches]
+ end
delete ':id/repository/merged_branches' do
::Branches::DeleteMergedService.new(user_project, current_user).async_execute
diff --git a/lib/api/bulk_imports.rb b/lib/api/bulk_imports.rb
index c54632919be..a28db321348 100644
--- a/lib/api/bulk_imports.rb
+++ b/lib/api/bulk_imports.rb
@@ -41,7 +41,15 @@ module API
resource :bulk_imports do
desc 'Start a new GitLab Migration' do
detail 'This feature was introduced in GitLab 14.2.'
- success Entities::BulkImport
+ success code: 200, model: Entities::BulkImport
+ consumes ['application/x-www-form-urlencoded']
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
params do
requires :configuration, type: Hash, desc: 'The source GitLab instance configuration' do
@@ -88,7 +96,13 @@ module API
desc 'List all GitLab Migrations' do
detail 'This feature was introduced in GitLab 14.1.'
- success Entities::BulkImport
+ is_array true
+ success code: 200, model: Entities::BulkImport
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
params do
use :pagination
@@ -103,7 +117,13 @@ module API
desc "List all GitLab Migrations' entities" do
detail 'This feature was introduced in GitLab 14.1.'
- success Entities::BulkImports::Entity
+ is_array true
+ success code: 200, model: Entities::BulkImports::Entity
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
params do
use :pagination
@@ -123,7 +143,12 @@ module API
desc 'Get GitLab Migration details' do
detail 'This feature was introduced in GitLab 14.1.'
- success Entities::BulkImport
+ success code: 200, model: Entities::BulkImport
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
params do
requires :import_id, type: Integer, desc: "The ID of user's GitLab Migration"
@@ -134,7 +159,13 @@ module API
desc "List GitLab Migration entities" do
detail 'This feature was introduced in GitLab 14.1.'
- success Entities::BulkImports::Entity
+ is_array true
+ success code: 200, model: Entities::BulkImports::Entity
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
params do
requires :import_id, type: Integer, desc: "The ID of user's GitLab Migration"
@@ -148,7 +179,12 @@ module API
desc 'Get GitLab Migration entity details' do
detail 'This feature was introduced in GitLab 14.1.'
- success Entities::BulkImports::Entity
+ success code: 200, model: Entities::BulkImports::Entity
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
params do
requires :import_id, type: Integer, desc: "The ID of user's GitLab Migration"
diff --git a/lib/api/ci/helpers/runner.rb b/lib/api/ci/helpers/runner.rb
index 269f2fa7ddc..be4d82bc500 100644
--- a/lib/api/ci/helpers/runner.rb
+++ b/lib/api/ci/helpers/runner.rb
@@ -53,7 +53,7 @@ module API
# HTTP status codes to terminate the job on GitLab Runner:
# - 403
- def authenticate_job!(require_running: true, heartbeat_runner: false)
+ def authenticate_job!(heartbeat_runner: false)
job = current_job
# 404 is not returned here because we want to terminate the job if it's
@@ -66,10 +66,7 @@ module API
forbidden!('Project has been deleted!') if job.project.nil? || job.project.pending_delete?
forbidden!('Job has been erased!') if job.erased?
-
- if require_running
- job_forbidden!(job, 'Job is not running') unless job.running?
- end
+ job_forbidden!(job, 'Job is not running') unless job.running?
# Only some requests (like updating the job or patching the trace) should trigger
# runner heartbeat. Operations like artifacts uploading are executed in context of
@@ -87,9 +84,9 @@ module API
end
def authenticate_job_via_dependent_job!
- forbidden! unless current_authenticated_job
+ authenticate!
forbidden! unless current_job
- forbidden! unless can?(current_authenticated_job.user, :read_build, current_job)
+ forbidden! unless can?(current_user, :read_build, current_job)
end
def current_job
@@ -106,21 +103,6 @@ module API
end
end
- # TODO: Replace this with `#current_authenticated_job from API::Helpers`
- # after the feature flag `ci_authenticate_running_job_token_for_artifacts`
- # is removed.
- #
- # For the time being, this needs to be overridden because the API
- # GET api/v4/jobs/:id/artifacts
- # needs to allow requests using token whose job is not running.
- #
- # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83713#note_942368526
- def current_authenticated_job
- strong_memoize(:current_authenticated_job) do
- ::Ci::AuthJobFinder.new(token: job_token).execute
- end
- end
-
# The token used by runner to authenticate a request.
# In most cases, the runner uses the token belonging to the requested job.
# However, when requesting for job artifacts, the runner would use
@@ -151,10 +133,6 @@ module API
{ config: attributes_for_keys(%w(gpus), params.dig('info', 'config')) }
end
- def request_using_running_job_token?
- current_job.present? && current_authenticated_job.present? && current_job != current_authenticated_job
- end
-
def metrics
strong_memoize(:metrics) { ::Gitlab::Ci::Runner::Metrics.new }
end
diff --git a/lib/api/ci/job_artifacts.rb b/lib/api/ci/job_artifacts.rb
index 37c7cc73c46..352ad04c982 100644
--- a/lib/api/ci/job_artifacts.rb
+++ b/lib/api/ci/job_artifacts.rb
@@ -19,7 +19,7 @@ module API
prepend_mod_with('API::Ci::JobArtifacts') # rubocop: disable Cop/InjectEnterpriseEditionModule
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Download the artifacts archive from a job' do
@@ -38,7 +38,7 @@ module API
latest_build = user_project.latest_successful_build_for_ref!(params[:job], params[:ref_name])
authorize_read_job_artifacts!(latest_build)
- present_artifacts_file!(latest_build.artifacts_file, project: latest_build.project)
+ present_artifacts_file!(latest_build.artifacts_file)
end
desc 'Download a specific file from artifacts archive from a ref' do
@@ -80,7 +80,7 @@ module API
build = find_build!(params[:job_id])
authorize_read_job_artifacts!(build)
- present_artifacts_file!(build.artifacts_file, project: build.project)
+ present_artifacts_file!(build.artifacts_file)
end
desc 'Download a specific file from artifacts archive' do
diff --git a/lib/api/ci/jobs.rb b/lib/api/ci/jobs.rb
index 6049993bf6f..9e41e1c0d8f 100644
--- a/lib/api/ci/jobs.rb
+++ b/lib/api/ci/jobs.rb
@@ -11,12 +11,12 @@ module API
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
helpers do
params :optional_scope do
- optional :scope, types: [String, Array[String]], desc: 'The scope of builds to show',
+ optional :scope, type: Array[String], desc: 'The scope of builds to show',
values: ::CommitStatus::AVAILABLE_STATUSES,
coerce_with: ->(scope) {
case scope
@@ -29,12 +29,19 @@ module API
else
['unknown']
end
- }
+ },
+ documentation: { example: %w[pending running] }
end
end
desc 'Get a projects jobs' do
- success Entities::Ci::Job
+ success code: 200, model: Entities::Ci::Job
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
end
params do
use :optional_scope
@@ -53,10 +60,15 @@ module API
# rubocop: enable CodeReuse/ActiveRecord
desc 'Get a specific job of a project' do
- success Entities::Ci::Job
+ success code: 200, model: Entities::Ci::Job
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :job_id, type: Integer, desc: 'The ID of a job'
+ requires :job_id, type: Integer, desc: 'The ID of a job', documentation: { example: 88 }
end
get ':id/jobs/:job_id', urgency: :low, feature_category: :continuous_integration do
authorize_read_builds!
@@ -69,9 +81,16 @@ module API
# TODO: We should use `present_disk_file!` and leave this implementation for backward compatibility (when build trace
# is saved in the DB instead of file). But before that, we need to consider how to replace the value of
# `runners_token` with some mask (like `xxxxxx`) when sending trace file directly by workhorse.
- desc 'Get a trace of a specific job of a project'
+ desc 'Get a trace of a specific job of a project' do
+ success code: 200, model: Entities::Ci::Job
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ end
params do
- requires :job_id, type: Integer, desc: 'The ID of a job'
+ requires :job_id, type: Integer, desc: 'The ID of a job', documentation: { example: 88 }
end
get ':id/jobs/:job_id/trace', urgency: :low, feature_category: :continuous_integration do
authorize_read_builds!
@@ -90,10 +109,15 @@ module API
end
desc 'Cancel a specific job of a project' do
- success Entities::Ci::Job
+ success code: 201, model: Entities::Ci::Job
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :job_id, type: Integer, desc: 'The ID of a job'
+ requires :job_id, type: Integer, desc: 'The ID of a job', documentation: { example: 88 }
end
post ':id/jobs/:job_id/cancel', urgency: :low, feature_category: :continuous_integration do
authorize_update_builds!
@@ -107,10 +131,15 @@ module API
end
desc 'Retry a specific build of a project' do
- success Entities::Ci::Job
+ success code: 201, model: Entities::Ci::Job
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :job_id, type: Integer, desc: 'The ID of a build'
+ requires :job_id, type: Integer, desc: 'The ID of a build', documentation: { example: 88 }
end
post ':id/jobs/:job_id/retry', urgency: :low, feature_category: :continuous_integration do
authorize_update_builds!
@@ -128,10 +157,16 @@ module API
end
desc 'Erase job (remove artifacts and the trace)' do
- success Entities::Ci::Job
+ success code: 201, model: Entities::Ci::Job
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 409, message: 'Conflict' }
+ ]
end
params do
- requires :job_id, type: Integer, desc: 'The ID of a build'
+ requires :job_id, type: Integer, desc: 'The ID of a build', documentation: { example: 88 }
end
post ':id/jobs/:job_id/erase', urgency: :low, feature_category: :continuous_integration do
authorize_update_builds!
@@ -148,15 +183,21 @@ module API
end
desc 'Trigger an actionable job (manual, delayed, etc)' do
- success Entities::Ci::JobBasic
detail 'This feature was added in GitLab 8.11'
+ success code: 200, model: Entities::Ci::JobBasic
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :job_id, type: Integer, desc: 'The ID of a Job'
+ requires :job_id, type: Integer, desc: 'The ID of a Job', documentation: { example: 88 }
optional :job_variables_attributes,
type: Array, desc: 'User defined variables that will be included when running the job' do
- requires :key, type: String, desc: 'The name of the variable'
- requires :value, type: String, desc: 'The value of the variable'
+ requires :key, type: String, desc: 'The name of the variable', documentation: { example: 'foo' }
+ requires :value, type: String, desc: 'The value of the variable', documentation: { example: 'bar' }
end
end
@@ -183,7 +224,12 @@ module API
resource :job do
desc 'Get current job using job token' do
- success Entities::Ci::Job
+ success code: 200, model: Entities::Ci::Job
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
end
route_setting :authentication, job_token_allowed: true
get '', feature_category: :continuous_integration, urgency: :low do
@@ -194,6 +240,12 @@ module API
desc 'Get current agents' do
detail 'Retrieves a list of agents for the given job token'
+ success code: 200, model: Entities::Ci::Job
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
end
route_setting :authentication, job_token_allowed: true
get '/allowed_agents', urgency: :low, feature_category: :kubernetes_management do
@@ -210,7 +262,7 @@ module API
.select { |_role, role_access_level| role_access_level <= user_access_level }
.map(&:first)
- environment = if persisted_environment = current_authenticated_job.persisted_environment
+ environment = if persisted_environment = current_authenticated_job.actual_persisted_environment
{ tier: persisted_environment.tier, slug: persisted_environment.slug }
end
@@ -244,6 +296,8 @@ module API
# current_authenticated_job will be nil if user is using
# a valid authentication (like PRIVATE-TOKEN) that is not CI_JOB_TOKEN
not_found!('Job') unless current_authenticated_job
+
+ ::Gitlab::ApplicationContext.push(job: current_authenticated_job)
end
end
end
diff --git a/lib/api/ci/pipeline_schedules.rb b/lib/api/ci/pipeline_schedules.rb
index 886c3509c51..afb3754f2ae 100644
--- a/lib/api/ci/pipeline_schedules.rb
+++ b/lib/api/ci/pipeline_schedules.rb
@@ -11,16 +11,24 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project',
+ documentation: { example: 18 }
end
resource :projects, requirements: ::API::API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get all pipeline schedules' do
- success Entities::Ci::PipelineSchedule
+ success code: 200, model: Entities::Ci::PipelineSchedule
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
end
params do
use :pagination
optional :scope, type: String, values: %w[active inactive],
- desc: 'The scope of pipeline schedules'
+ desc: 'The scope of pipeline schedules',
+ documentation: { example: 'active' }
end
# rubocop: disable CodeReuse/ActiveRecord
get ':id/pipeline_schedules' do
@@ -33,34 +41,51 @@ module API
# rubocop: enable CodeReuse/ActiveRecord
desc 'Get a single pipeline schedule' do
- success Entities::Ci::PipelineScheduleDetails
+ success code: 200, model: Entities::Ci::PipelineScheduleDetails
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id'
+ requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id', documentation: { example: 13 }
end
get ':id/pipeline_schedules/:pipeline_schedule_id' do
present pipeline_schedule, with: Entities::Ci::PipelineScheduleDetails, user: current_user
end
desc 'Get all pipelines triggered from a pipeline schedule' do
- success Entities::Ci::PipelineBasic
+ success code: 200, model: Entities::Ci::PipelineBasic
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
end
params do
- requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule ID'
+ requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule ID', documentation: { example: 13 }
end
get ':id/pipeline_schedules/:pipeline_schedule_id/pipelines' do
present paginate(pipeline_schedule.pipelines), with: Entities::Ci::PipelineBasic
end
desc 'Create a new pipeline schedule' do
- success Entities::Ci::PipelineScheduleDetails
+ success code: 201, model: Entities::Ci::PipelineScheduleDetails
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :description, type: String, desc: 'The description of pipeline schedule'
- requires :ref, type: String, desc: 'The branch/tag name will be triggered', allow_blank: false
- requires :cron, type: String, desc: 'The cron'
- optional :cron_timezone, type: String, default: 'UTC', desc: 'The timezone'
- optional :active, type: Boolean, default: true, desc: 'The activation of pipeline schedule'
+ requires :description, type: String, desc: 'The description of pipeline schedule', documentation: { example: 'Test schedule pipeline' }
+ requires :ref, type: String, desc: 'The branch/tag name will be triggered', allow_blank: false, documentation: { example: 'develop' }
+ requires :cron, type: String, desc: 'The cron', documentation: { example: '* * * * *' }
+ optional :cron_timezone, type: String, default: 'UTC', desc: 'The timezone', documentation: { example: 'Asia/Tokyo' }
+ optional :active, type: Boolean, default: true, desc: 'The activation of pipeline schedule', documentation: { example: true }
end
post ':id/pipeline_schedules' do
authorize! :create_pipeline_schedule, user_project
@@ -77,15 +102,21 @@ module API
end
desc 'Edit a pipeline schedule' do
- success Entities::Ci::PipelineScheduleDetails
+ success code: 200, model: Entities::Ci::PipelineScheduleDetails
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id'
- optional :description, type: String, desc: 'The description of pipeline schedule'
- optional :ref, type: String, desc: 'The branch/tag name will be triggered'
- optional :cron, type: String, desc: 'The cron'
- optional :cron_timezone, type: String, desc: 'The timezone'
- optional :active, type: Boolean, desc: 'The activation of pipeline schedule'
+ requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id', documentation: { example: 13 }
+ optional :description, type: String, desc: 'The description of pipeline schedule', documentation: { example: 'Test schedule pipeline' }
+ optional :ref, type: String, desc: 'The branch/tag name will be triggered', documentation: { example: 'develop' }
+ optional :cron, type: String, desc: 'The cron', documentation: { example: '* * * * *' }
+ optional :cron_timezone, type: String, desc: 'The timezone', documentation: { example: 'Asia/Tokyo' }
+ optional :active, type: Boolean, desc: 'The activation of pipeline schedule', documentation: { example: true }
end
put ':id/pipeline_schedules/:pipeline_schedule_id' do
authorize! :update_pipeline_schedule, pipeline_schedule
@@ -98,10 +129,16 @@ module API
end
desc 'Take ownership of a pipeline schedule' do
- success Entities::Ci::PipelineScheduleDetails
+ success code: 201, model: Entities::Ci::PipelineScheduleDetails
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id'
+ requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id', documentation: { example: 13 }
end
post ':id/pipeline_schedules/:pipeline_schedule_id/take_ownership' do
authorize! :take_ownership_pipeline_schedule, pipeline_schedule
@@ -114,10 +151,16 @@ module API
end
desc 'Delete a pipeline schedule' do
- success Entities::Ci::PipelineScheduleDetails
+ success code: 204
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 412, message: 'Precondition Failed' }
+ ]
end
params do
- requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id'
+ requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id', documentation: { example: 13 }
end
delete ':id/pipeline_schedules/:pipeline_schedule_id' do
authorize! :admin_pipeline_schedule, pipeline_schedule
@@ -127,9 +170,15 @@ module API
desc 'Play a scheduled pipeline immediately' do
detail 'This feature was added in GitLab 12.8'
+ success code: 201
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id'
+ requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id', documentation: { example: 13 }
end
post ':id/pipeline_schedules/:pipeline_schedule_id/play' do
authorize! :play_pipeline_schedule, pipeline_schedule
@@ -145,13 +194,20 @@ module API
end
desc 'Create a new pipeline schedule variable' do
- success Entities::Ci::Variable
+ success code: 201, model: Entities::Ci::Variable
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id'
- requires :key, type: String, desc: 'The key of the variable'
- requires :value, type: String, desc: 'The value of the variable'
- optional :variable_type, type: String, values: ::Ci::PipelineScheduleVariable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file. Defaults to env_var'
+ requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id', documentation: { example: 13 }
+ requires :key, type: String, desc: 'The key of the variable', documentation: { example: 'NEW_VARIABLE' }
+ requires :value, type: String, desc: 'The value of the variable', documentation: { example: 'new value' }
+ optional :variable_type, type: String, values: ::Ci::PipelineScheduleVariable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file. Defaults to env_var',
+ documentation: { default: 'env_var' }
end
post ':id/pipeline_schedules/:pipeline_schedule_id/variables' do
authorize! :update_pipeline_schedule, pipeline_schedule
@@ -166,13 +222,20 @@ module API
end
desc 'Edit a pipeline schedule variable' do
- success Entities::Ci::Variable
+ success code: 200, model: Entities::Ci::Variable
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id'
- requires :key, type: String, desc: 'The key of the variable'
- optional :value, type: String, desc: 'The value of the variable'
- optional :variable_type, type: String, values: ::Ci::PipelineScheduleVariable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file'
+ requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id', documentation: { example: 13 }
+ requires :key, type: String, desc: 'The key of the variable', documentation: { example: 'NEW_VARIABLE' }
+ optional :value, type: String, desc: 'The value of the variable', documentation: { example: 'new value' }
+ optional :variable_type, type: String, values: ::Ci::PipelineScheduleVariable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file',
+ documentation: { default: 'env_var' }
end
put ':id/pipeline_schedules/:pipeline_schedule_id/variables/:key' do
authorize! :update_pipeline_schedule, pipeline_schedule
@@ -185,11 +248,16 @@ module API
end
desc 'Delete a pipeline schedule variable' do
- success Entities::Ci::Variable
+ success code: 202, model: Entities::Ci::Variable
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id'
- requires :key, type: String, desc: 'The key of the variable'
+ requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id', documentation: { example: 13 }
+ requires :key, type: String, desc: 'The key of the variable', documentation: { example: 'NEW_VARIABLE' }
end
delete ':id/pipeline_schedules/:pipeline_schedule_id/variables/:key' do
authorize! :admin_pipeline_schedule, pipeline_schedule
diff --git a/lib/api/ci/pipelines.rb b/lib/api/ci/pipelines.rb
index 72a81330e71..c055512e54e 100644
--- a/lib/api/ci/pipelines.rb
+++ b/lib/api/ci/pipelines.rb
@@ -10,12 +10,17 @@ module API
before { authenticate_non_get! }
params do
- requires :id, type: String, desc: 'The project ID'
+ requires :id, type: String, desc: 'The project ID or URL-encoded path', documentation: { example: 11 }
end
resource :projects, requirements: ::API::API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get all Pipelines of the project' do
detail 'This feature was introduced in GitLab 8.11.'
- success Entities::Ci::PipelineBasic
+ success status: 200, model: Entities::Ci::PipelineBasic
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' }
+ ]
+ is_array true
end
helpers do
@@ -31,27 +36,39 @@ module API
else
['unknown']
end
- }
+ },
+ documentation: { example: %w[pending running] }
end
end
params do
use :pagination
optional :scope, type: String, values: %w[running pending finished branches tags],
- desc: 'The scope of pipelines'
+ desc: 'The scope of pipelines',
+ documentation: { example: 'pending' }
optional :status, type: String, values: ::Ci::HasStatus::AVAILABLE_STATUSES,
- desc: 'The status of pipelines'
- optional :ref, type: String, desc: 'The ref of pipelines'
- optional :sha, type: String, desc: 'The sha of pipelines'
- optional :yaml_errors, type: Boolean, desc: 'Returns pipelines with invalid configurations'
- optional :username, type: String, desc: 'The username of the user who triggered pipelines'
- optional :updated_before, type: DateTime, desc: 'Return pipelines updated before the specified datetime. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ'
- optional :updated_after, type: DateTime, desc: 'Return pipelines updated after the specified datetime. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ'
+ desc: 'The status of pipelines',
+ documentation: { example: 'pending' }
+ optional :ref, type: String, desc: 'The ref of pipelines',
+ documentation: { example: 'develop' }
+ optional :sha, type: String, desc: 'The sha of pipelines',
+ documentation: { example: 'a91957a858320c0e17f3a0eca7cfacbff50ea29a' }
+ optional :yaml_errors, type: Boolean, desc: 'Returns pipelines with invalid configurations',
+ documentation: { example: false }
+ optional :username, type: String, desc: 'The username of the user who triggered pipelines',
+ documentation: { example: 'root' }
+ optional :updated_before, type: DateTime, desc: 'Return pipelines updated before the specified datetime. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ',
+ documentation: { example: '2015-12-24T15:51:21.880Z' }
+ optional :updated_after, type: DateTime, desc: 'Return pipelines updated after the specified datetime. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ',
+ documentation: { example: '2015-12-24T15:51:21.880Z' }
optional :order_by, type: String, values: ::Ci::PipelinesFinder::ALLOWED_INDEXED_COLUMNS, default: 'id',
- desc: 'Order pipelines'
+ desc: 'Order pipelines',
+ documentation: { example: 'status' }
optional :sort, type: String, values: %w[asc desc], default: 'desc',
- desc: 'Sort pipelines'
- optional :source, type: String, values: ::Ci::Pipeline.sources.keys
+ desc: 'Sort pipelines',
+ documentation: { example: 'asc' }
+ optional :source, type: String, values: ::Ci::Pipeline.sources.keys,
+ documentation: { example: 'push' }
end
get ':id/pipelines', urgency: :low, feature_category: :continuous_integration do
authorize! :read_pipeline, user_project
@@ -63,11 +80,22 @@ module API
desc 'Create a new pipeline' do
detail 'This feature was introduced in GitLab 8.14'
- success Entities::Ci::Pipeline
+ success status: 201, model: Entities::Ci::Pipeline
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :ref, type: String, desc: 'Reference'
- optional :variables, Array, desc: 'Array of variables available in the pipeline'
+ requires :ref, type: String, desc: 'Reference',
+ documentation: { example: 'develop' }
+ optional :variables, type: Array, desc: 'Array of variables available in the pipeline' do
+ optional :key, type: String, desc: 'The key of the variable', documentation: { example: 'UPLOAD_TO_S3' }
+ optional :value, type: String, desc: 'The value of the variable', documentation: { example: 'true' }
+ optional :variable_type, type: String, values: ::Ci::PipelineVariable.variable_types.keys, default: 'env_var', desc: 'The type of variable, must be one of env_var or file. Defaults to env_var'
+ end
end
post ':id/pipeline', urgency: :low, feature_category: :continuous_integration do
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/20711')
@@ -89,12 +117,18 @@ module API
end
end
- desc 'Gets a the latest pipeline for the project branch' do
+ desc 'Gets the latest pipeline for the project branch' do
detail 'This feature was introduced in GitLab 12.3'
- success Entities::Ci::Pipeline
+ success status: 200, model: Entities::Ci::Pipeline
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- optional :ref, type: String, desc: 'branch ref of pipeline'
+ optional :ref, type: String, desc: 'Branch ref of pipeline. Uses project default branch if not specified.',
+ documentation: { example: 'develop' }
end
get ':id/pipelines/latest', urgency: :low, feature_category: :continuous_integration do
authorize! :read_pipeline, latest_pipeline
@@ -104,10 +138,15 @@ module API
desc 'Gets a specific pipeline for the project' do
detail 'This feature was introduced in GitLab 8.11'
- success Entities::Ci::Pipeline
+ success status: 200, model: Entities::Ci::Pipeline
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
+ requires :pipeline_id, type: Integer, desc: 'The pipeline ID', documentation: { example: 18 }
end
get ':id/pipelines/:pipeline_id', urgency: :low, feature_category: :continuous_integration do
authorize! :read_pipeline, pipeline
@@ -116,10 +155,16 @@ module API
end
desc 'Get pipeline jobs' do
- success Entities::Ci::Job
+ success status: 200, model: Entities::Ci::Job
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
end
params do
- requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
+ requires :pipeline_id, type: Integer, desc: 'The pipeline ID', documentation: { example: 18 }
optional :include_retried, type: Boolean, default: false, desc: 'Includes retried jobs'
use :optional_scope
use :pagination
@@ -140,10 +185,16 @@ module API
end
desc 'Get pipeline bridge jobs' do
- success Entities::Ci::Bridge
+ success status: 200, model: Entities::Ci::Bridge
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
end
params do
- requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
+ requires :pipeline_id, type: Integer, desc: 'The pipeline ID', documentation: { example: 18 }
use :optional_scope
use :pagination
end
@@ -163,10 +214,16 @@ module API
desc 'Gets the variables for a given pipeline' do
detail 'This feature was introduced in GitLab 11.11'
- success Entities::Ci::Variable
+ success status: 200, model: Entities::Ci::Variable
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
end
params do
- requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
+ requires :pipeline_id, type: Integer, desc: 'The pipeline ID', documentation: { example: 18 }
end
get ':id/pipelines/:pipeline_id/variables', feature_category: :pipeline_authoring, urgency: :low do
authorize! :read_pipeline_variable, pipeline
@@ -176,10 +233,15 @@ module API
desc 'Gets the test report for a given pipeline' do
detail 'This feature was introduced in GitLab 13.0.'
- success TestReportEntity
+ success status: 200, model: TestReportEntity
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
+ requires :pipeline_id, type: Integer, desc: 'The pipeline ID', documentation: { example: 18 }
end
get ':id/pipelines/:pipeline_id/test_report', feature_category: :code_testing, urgency: :low do
authorize! :read_build, pipeline
@@ -189,10 +251,15 @@ module API
desc 'Gets the test report summary for a given pipeline' do
detail 'This feature was introduced in GitLab 14.2'
- success TestReportSummaryEntity
+ success status: 200, model: TestReportSummaryEntity
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
+ requires :pipeline_id, type: Integer, desc: 'The pipeline ID', documentation: { example: 18 }
end
get ':id/pipelines/:pipeline_id/test_report_summary', feature_category: :code_testing do
authorize! :read_build, pipeline
@@ -205,7 +272,7 @@ module API
http_codes [[204, 'Pipeline was deleted'], [403, 'Forbidden']]
end
params do
- requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
+ requires :pipeline_id, type: Integer, desc: 'The pipeline ID', documentation: { example: 18 }
end
delete ':id/pipelines/:pipeline_id', urgency: :low, feature_category: :continuous_integration do
authorize! :destroy_pipeline, pipeline
@@ -219,10 +286,15 @@ module API
desc 'Retry builds in the pipeline' do
detail 'This feature was introduced in GitLab 8.11.'
- success Entities::Ci::Pipeline
+ success status: 201, model: Entities::Ci::Pipeline
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
+ requires :pipeline_id, type: Integer, desc: 'The pipeline ID', documentation: { example: 18 }
end
post ':id/pipelines/:pipeline_id/retry', urgency: :low, feature_category: :continuous_integration do
authorize! :update_pipeline, pipeline
@@ -238,10 +310,15 @@ module API
desc 'Cancel all builds in the pipeline' do
detail 'This feature was introduced in GitLab 8.11.'
- success Entities::Ci::Pipeline
+ success status: 200, model: Entities::Ci::Pipeline
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
+ requires :pipeline_id, type: Integer, desc: 'The pipeline ID', documentation: { example: 18 }
end
post ':id/pipelines/:pipeline_id/cancel', urgency: :low, feature_category: :continuous_integration do
authorize! :update_pipeline, pipeline
diff --git a/lib/api/ci/resource_groups.rb b/lib/api/ci/resource_groups.rb
index ea6d3cc8fd4..79a9fe58a7d 100644
--- a/lib/api/ci/resource_groups.rb
+++ b/lib/api/ci/resource_groups.rb
@@ -5,17 +5,30 @@ module API
class ResourceGroups < ::API::Base
include PaginationParams
+ ci_resource_groups_tags = %w[ci_resource_groups]
+
+ RESOURCE_GROUP_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
+ .merge(key: API::NO_SLASH_URL_PART_REGEX)
+
before { authenticate! }
feature_category :continuous_delivery
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id,
+ types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
end
resource :projects, requirements: ::API::API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get all resource groups for this project' do
+ desc 'Get all resource groups for a project' do
success Entities::Ci::ResourceGroup
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags ci_resource_groups_tags
end
params do
use :pagination
@@ -26,27 +39,38 @@ module API
present paginate(user_project.resource_groups), with: Entities::Ci::ResourceGroup
end
- desc 'Get a single resource group' do
+ desc 'Get a specific resource group' do
success Entities::Ci::ResourceGroup
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags ci_resource_groups_tags
end
params do
requires :key, type: String, desc: 'The key of the resource group'
end
- get ':id/resource_groups/:key' do
+ get ':id/resource_groups/:key', requirements: RESOURCE_GROUP_ENDPOINT_REQUIREMENTS do
authorize! :read_resource_group, resource_group
present resource_group, with: Entities::Ci::ResourceGroup
end
- desc 'List upcoming jobs of a resource group' do
+ desc 'List upcoming jobs for a specific resource group' do
success Entities::Ci::JobBasic
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags ci_resource_groups_tags
end
params do
requires :key, type: String, desc: 'The key of the resource group'
use :pagination
end
- get ':id/resource_groups/:key/upcoming_jobs' do
+ get ':id/resource_groups/:key/upcoming_jobs', requirements: RESOURCE_GROUP_ENDPOINT_REQUIREMENTS do
authorize! :read_resource_group, resource_group
authorize! :read_build, user_project
@@ -57,15 +81,25 @@ module API
present paginate(upcoming_processables), with: Entities::Ci::JobBasic
end
- desc 'Edit a resource group' do
+ desc 'Edit an existing resource group' do
+ detail "Updates an existing resource group's properties."
success Entities::Ci::ResourceGroup
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags ci_resource_groups_tags
end
params do
requires :key, type: String, desc: 'The key of the resource group'
- optional :process_mode, type: String, desc: 'The process mode',
- values: ::Ci::ResourceGroup.process_modes.keys
+
+ optional :process_mode,
+ type: String,
+ desc: 'The process mode of the resource group',
+ values: ::Ci::ResourceGroup.process_modes.keys
end
- put ':id/resource_groups/:key' do
+ put ':id/resource_groups/:key', requirements: RESOURCE_GROUP_ENDPOINT_REQUIREMENTS do
authorize! :update_resource_group, resource_group
if resource_group.update(declared_params(include_missing: false))
diff --git a/lib/api/ci/runner.rb b/lib/api/ci/runner.rb
index 2d2dcc544f9..c7d1887638a 100644
--- a/lib/api/ci/runner.rb
+++ b/lib/api/ci/runner.rb
@@ -8,25 +8,38 @@ module API
content_type :txt, 'text/plain'
resource :runners do
- desc 'Registers a new Runner' do
+ desc 'Register a new runner' do
+ detail "Register a new runner for the instance"
success Entities::Ci::RunnerRegistrationDetails
- http_codes [[201, 'Runner was created'], [403, 'Forbidden']]
+ failure [[400, 'Bad Request'], [403, 'Forbidden']]
end
params do
requires :token, type: String, desc: 'Registration token'
optional :description, type: String, desc: %q(Runner's description)
- optional :maintainer_note, type: String, desc: %q(Deprecated: Use :maintenance_note instead. Runner's maintenance notes)
- optional :maintenance_note, type: String, desc: %q(Runner's maintenance notes)
- optional :info, type: Hash, desc: %q(Runner's metadata)
- optional :active, type: Boolean, desc: 'Deprecated: Use `:paused` instead. Should runner be active'
- optional :paused, type: Boolean, desc: 'Whether the runner should ignore new jobs'
- optional :locked, type: Boolean, desc: 'Whether the runner should be locked for current project'
+ optional :maintainer_note, type: String, desc: %q(Deprecated: see `maintenance_note`)
+ optional :maintenance_note, type: String,
+ desc: %q(Free-form maintenance notes for the runner (1024 characters))
+ optional :info, type: Hash, desc: %q(Runner's metadata) do
+ optional :name, type: String, desc: %q(Runner's name)
+ optional :version, type: String, desc: %q(Runner's version)
+ optional :revision, type: String, desc: %q(Runner's revision)
+ optional :platform, type: String, desc: %q(Runner's platform)
+ optional :architecture, type: String, desc: %q(Runner's architecture)
+ end
+ optional :active, type: Boolean,
+ desc: 'Deprecated: Use `paused` instead. Specifies whether the runner is allowed ' \
+ 'to receive new jobs'
+ optional :paused, type: Boolean, desc: 'Specifies whether the runner should ignore new jobs'
+ optional :locked, type: Boolean, desc: 'Specifies whether the runner should be locked for the current project'
optional :access_level, type: String, values: ::Ci::Runner.access_levels.keys,
- desc: 'The access_level of the runner; `not_protected` or `ref_protected`'
- optional :run_untagged, type: Boolean, desc: 'Whether the runner should handle untagged jobs'
- optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: %q(List of Runner's tags)
- optional :maximum_timeout, type: Integer, desc: 'Maximum timeout set when this runner handles the job'
- mutually_exclusive :maintainer_note, :maintainer_note
+ desc: 'The access level of the runner'
+ optional :run_untagged, type: Boolean, desc: 'Specifies whether the runner should handle untagged jobs'
+ 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'
+ mutually_exclusive :maintainer_note, :maintenance_note
mutually_exclusive :active, :paused
end
post '/', urgency: :low, feature_category: :runner do
@@ -49,11 +62,12 @@ module API
end
end
- desc 'Deletes a registered Runner' do
- http_codes [[204, 'Runner was deleted'], [403, 'Forbidden']]
+ desc 'Delete a registered runner' do
+ summary "Delete a runner by authentication token"
+ failure [[403, 'Forbidden']]
end
params do
- requires :token, type: String, desc: %q(Runner's authentication token)
+ requires :token, type: String, desc: %q(The runner's authentication token)
end
delete '/', urgency: :low, feature_category: :runner do
authenticate_runner!
@@ -61,11 +75,12 @@ module API
destroy_conditionally!(current_runner) { ::Ci::Runners::UnregisterRunnerService.new(current_runner, params[:token]).execute }
end
- desc 'Validates authentication credentials' do
+ desc 'Validate authentication credentials' do
+ summary "Verify authentication for a registered runner"
http_codes [[200, 'Credentials are valid'], [403, 'Forbidden']]
end
params do
- requires :token, type: String, desc: %q(Runner's authentication token)
+ requires :token, type: String, desc: %q(The runner's authentication token)
end
post '/verify', urgency: :low, feature_category: :runner do
authenticate_runner!
@@ -75,6 +90,7 @@ module API
desc 'Reset runner authentication token with current token' do
success Entities::Ci::ResetTokenResult
+ failure [[403, 'Forbidden']]
end
params do
requires :token, type: String, desc: 'The current authentication token of the runner'
@@ -94,7 +110,8 @@ module API
success Entities::Ci::JobRequest::Response
http_codes [[201, 'Job was scheduled'],
[204, 'No job for Runner'],
- [403, 'Forbidden']]
+ [403, 'Forbidden'],
+ [409, 'Conflict']]
end
params do
requires :token, type: String, desc: %q(Runner's authentication token)
@@ -168,14 +185,14 @@ module API
end
end
- desc 'Updates a job' do
+ desc 'Update a job' do
http_codes [[200, 'Job was updated'],
[202, 'Update accepted'],
[400, 'Unknown parameters'],
[403, 'Forbidden']]
end
params do
- requires :token, type: String, desc: %q(Runners's authentication token)
+ requires :token, type: String, desc: %q(Runner's authentication token)
requires :id, type: Integer, desc: %q(Job's ID)
optional :state, type: String, desc: %q(Job's status: success, failed)
optional :checksum, type: String, desc: %q(Job's trace CRC32 checksum)
@@ -203,7 +220,7 @@ module API
end
end
- desc 'Appends a patch to the job trace' do
+ desc 'Append a patch to the job trace' do
http_codes [[202, 'Trace was patched'],
[400, 'Missing Content-Range header'],
[403, 'Forbidden'],
@@ -285,14 +302,14 @@ module API
end
params do
requires :id, type: Integer, desc: %q(Job's ID)
- requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: %(The artifact file to store (generated by Multipart middleware))
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: %(The artifact file to store (generated by Multipart middleware)), documentation: { type: 'file' }
optional :token, type: String, desc: %q(Job's authentication token)
optional :expire_in, type: String, desc: %q(Specify when artifacts should expire)
optional :artifact_type, type: String, desc: %q(The type of artifact),
default: 'archive', values: ::Ci::JobArtifact.file_types.keys
optional :artifact_format, type: String, desc: %q(The format of artifact),
default: 'zip', values: ::Ci::JobArtifact.file_formats.keys
- optional :metadata, type: ::API::Validations::Types::WorkhorseFile, desc: %(The artifact metadata to store (generated by Multipart middleware))
+ optional :metadata, type: ::API::Validations::Types::WorkhorseFile, desc: %(The artifact metadata to store (generated by Multipart middleware)), documentation: { type: 'file' }
end
post '/:id/artifacts', feature_category: :build_artifacts, urgency: :low do
not_allowed! unless Gitlab.config.artifacts.enabled
@@ -317,6 +334,7 @@ module API
desc 'Download the artifacts file for job' do
http_codes [[200, 'Upload allowed'],
+ [401, 'Unauthorized'],
[403, 'Forbidden'],
[404, 'Artifact not found']]
end
@@ -325,14 +343,11 @@ module API
optional :token, type: String, desc: %q(Job's authentication token)
optional :direct_download, default: false, type: Boolean, desc: %q(Perform direct download from remote storage instead of proxying artifacts)
end
+ route_setting :authentication, job_token_allowed: true
get '/:id/artifacts', feature_category: :build_artifacts do
- if request_using_running_job_token?
- authenticate_job_via_dependent_job!
- else
- authenticate_job!(require_running: false)
- end
+ authenticate_job_via_dependent_job!
- present_artifacts_file!(current_job.artifacts_file, project: current_job.project, supports_direct_download: params[:direct_download])
+ present_artifacts_file!(current_job.artifacts_file, supports_direct_download: params[:direct_download])
end
end
end
diff --git a/lib/api/ci/runners.rb b/lib/api/ci/runners.rb
index 4b578f8b7e5..988c3f4f566 100644
--- a/lib/api/ci/runners.rb
+++ b/lib/api/ci/runners.rb
@@ -10,20 +10,98 @@ module API
feature_category :runner
urgency :low
+ helpers do
+ params :deprecated_filter_params do
+ optional :scope, type: String, values: ::Ci::Runner::AVAILABLE_SCOPES,
+ desc: 'Deprecated: Use `type` or `status` instead. The scope of specific runners to return'
+ end
+
+ params :filter_params do
+ optional :type, type: String, values: ::Ci::Runner::AVAILABLE_TYPES, desc: 'The type of runners to return'
+ optional :paused, type: Boolean,
+ desc: 'Whether to include only runners that are accepting or ignoring new jobs'
+ optional :status, type: String, values: ::Ci::Runner::AVAILABLE_STATUSES,
+ desc: 'The status of runners to return'
+ optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
+ desc: 'A list of runner tags', documentation: { example: "['macos', 'shell']" }
+ use :pagination
+ end
+
+ def filter_runners(runners, scope, allowed_scopes: ::Ci::Runner::AVAILABLE_SCOPES)
+ return runners unless scope.present?
+
+ unless allowed_scopes.include?(scope)
+ render_api_error!('Scope contains invalid value', 400)
+ end
+
+ # Support deprecated scopes
+ if runners.respond_to?("deprecated_#{scope}")
+ scope = "deprecated_#{scope}"
+ end
+
+ runners.public_send(scope) # rubocop:disable GitlabSecurity/PublicSend
+ end
+
+ def apply_filter(runners, params)
+ runners = filter_runners(runners, params[:type], allowed_scopes: ::Ci::Runner::AVAILABLE_TYPES)
+ runners = filter_runners(runners, params[:status], allowed_scopes: ::Ci::Runner::AVAILABLE_STATUSES)
+ runners = filter_runners(runners, params[:paused] ? 'paused' : 'active', allowed_scopes: %w[paused active]) if params.include?(:paused)
+ runners = runners.tagged_with(params[:tag_list]) if params[:tag_list]
+
+ runners
+ end
+
+ def get_runner(id)
+ runner = ::Ci::Runner.find(id)
+ not_found!('Runner') unless runner
+ runner
+ end
+
+ def authenticate_show_runner!(runner)
+ return if runner.instance_type? || current_user.admin?
+
+ forbidden!("No access granted") unless can?(current_user, :read_runner, runner)
+ end
+
+ def authenticate_update_runner!(runner)
+ return if current_user.admin?
+
+ forbidden!("No access granted") unless can?(current_user, :update_runner, runner)
+ end
+
+ def authenticate_delete_runner!(runner)
+ return if current_user.admin?
+
+ forbidden!("Runner associated with more than one project") if runner.runner_projects.count > 1
+ forbidden!("No access granted") unless can?(current_user, :delete_runner, runner)
+ end
+
+ def authenticate_enable_runner!(runner)
+ forbidden!("Runner is a group runner") if runner.group_type?
+
+ return if current_user.admin?
+
+ forbidden!("Runner is locked") if runner.locked?
+ forbidden!("No access granted") unless can?(current_user, :assign_runner, runner)
+ end
+
+ def authenticate_list_runners_jobs!(runner)
+ return if current_user.admin?
+
+ forbidden!("No access granted") unless can?(current_user, :read_builds, runner)
+ end
+ end
+
resource :runners do
desc 'Get runners available for user' do
+ summary 'List owned runners'
success Entities::Ci::Runner
+ failure [[400, 'Scope contains invalid value'], [401, 'Unauthorized']]
+ tags %w[runners]
end
params do
- optional :scope, type: String, values: ::Ci::Runner::AVAILABLE_STATUSES,
- desc: 'The scope of specific runners to show'
- optional :type, type: String, values: ::Ci::Runner::AVAILABLE_TYPES,
- desc: 'The type of the runners to show'
- optional :paused, type: Boolean, desc: 'Whether to include only runners that are accepting or ignoring new jobs'
- optional :status, type: String, values: ::Ci::Runner::AVAILABLE_STATUSES,
- desc: 'The status of the runners to show'
- optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The tags of the runners to show'
- use :pagination
+ use :deprecated_filter_params
+ use :filter_params
end
get do
runners = current_user.ci_owned_runners
@@ -34,18 +112,16 @@ module API
end
desc 'Get all runners - shared and specific' do
+ summary 'List all runners'
+ detail 'Get a list of all runners in the GitLab instance (specific and shared). ' \
+ 'Access is restricted to users with administrator access.'
success Entities::Ci::Runner
+ failure [[400, 'Scope contains invalid value'], [401, 'Unauthorized']]
+ tags %w[runners]
end
params do
- optional :scope, type: String, values: ::Ci::Runner::AVAILABLE_SCOPES,
- desc: 'The scope of specific runners to show'
- optional :type, type: String, values: ::Ci::Runner::AVAILABLE_TYPES,
- desc: 'The type of the runners to show'
- optional :paused, type: Boolean, desc: 'Whether to include only runners that are accepting or ignoring new jobs'
- optional :status, type: String, values: ::Ci::Runner::AVAILABLE_STATUSES,
- desc: 'The status of the runners to show'
- optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The tags of the runners to show'
- use :pagination
+ use :deprecated_filter_params
+ use :filter_params
end
get 'all' do
authenticated_as_admin!
@@ -58,10 +134,13 @@ module API
end
desc "Get runner's details" do
+ detail 'At least the Maintainer role is required to get runner details at the project and group level. ' \
+ 'Instance-level runner details via this endpoint are available to all signed in users.'
success Entities::Ci::RunnerDetails
+ failure [[401, 'Unauthorized'], [403, 'No access granted'], [404, 'Runner not found']]
end
params do
- requires :id, type: Integer, desc: 'The ID of the runner'
+ requires :id, type: Integer, desc: 'The ID of a runner'
end
get ':id' do
runner = get_runner(params[:id])
@@ -71,19 +150,24 @@ module API
end
desc "Update runner's details" do
+ summary "Update details of a runner"
success Entities::Ci::RunnerDetails
+ failure [[400, 'Bad Request'], [401, 'Unauthorized'], [403, 'No access granted'], [404, 'Runner not found']]
end
params do
- requires :id, type: Integer, desc: 'The ID of the runner'
+ requires :id, type: Integer, desc: 'The ID of a runner'
optional :description, type: String, desc: 'The description of the runner'
- optional :active, type: Boolean, desc: 'Deprecated: Use `:paused` instead. Flag indicating whether the runner is allowed to receive jobs'
- optional :paused, type: Boolean, desc: 'Flag indicating whether the runner should ignore new jobs'
- optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The list of tags for a runner'
- optional :run_untagged, type: Boolean, desc: 'Flag indicating whether the runner can execute untagged jobs'
- optional :locked, type: Boolean, desc: 'Flag indicating the runner is locked'
+ optional :active, type: Boolean, desc: 'Deprecated: Use `paused` instead. Flag indicating whether the runner is allowed to receive jobs'
+ optional :paused, type: Boolean, desc: 'Specifies whether the runner should ignore new jobs'
+ optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
+ desc: 'The list of tags for a runner', documentation: { example: "['macos', 'shell']" }
+ optional :run_untagged, type: Boolean, desc: 'Specifies whether the runner can execute untagged jobs'
+ optional :locked, type: Boolean, desc: 'Specifies whether the runner is locked'
optional :access_level, type: String, values: ::Ci::Runner.access_levels.keys,
- desc: 'The access_level of the runner'
- optional :maximum_timeout, type: Integer, desc: 'Maximum timeout set when this Runner will handle the job'
+ desc: 'The access level of the runner'
+ optional :maximum_timeout, type: Integer,
+ desc: 'Maximum timeout that limits the amount of time (in seconds) ' \
+ 'that runners can run jobs'
at_least_one_of :description, :active, :paused, :tag_list, :run_untagged, :locked, :access_level, :maximum_timeout
mutually_exclusive :active, :paused
end
@@ -101,10 +185,15 @@ module API
end
desc 'Remove a runner' do
+ summary 'Delete a runner'
success Entities::Ci::Runner
+ failure [[401, 'Unauthorized'], [403, 'No access granted'],
+ [403, 'Runner associated with more than one project'], [404, 'Runner not found'],
+ [412, 'Precondition Failed']]
+ tags %w[runners]
end
params do
- requires :id, type: Integer, desc: 'The ID of the runner'
+ requires :id, type: Integer, desc: 'The ID of a runner'
end
delete ':id' do
runner = get_runner(params[:id])
@@ -115,13 +204,19 @@ module API
end
desc 'List jobs running on a runner' do
+ summary "List runner's jobs"
+ detail 'List jobs that are being processed or were processed by the specified runner. ' \
+ 'The list of jobs is limited to projects where the user has at least the Reporter role.'
success Entities::Ci::JobBasicWithProject
+ failure [[401, 'Unauthorized'], [403, 'No access granted'], [404, 'Runner not found']]
+ tags %w[runners jobs]
end
params do
- requires :id, type: Integer, desc: 'The ID of the runner'
+ requires :id, type: Integer, desc: 'The ID of a runner'
optional :status, type: String, desc: 'Status of the job', values: ::Ci::Build::AVAILABLE_STATUSES
- optional :order_by, type: String, desc: 'Order by `id` or not', values: ::Ci::RunnerJobsFinder::ALLOWED_INDEXED_COLUMNS
- optional :sort, type: String, values: %w[asc desc], default: 'desc', desc: 'Sort by asc (ascending) or desc (descending)'
+ optional :order_by, type: String, desc: 'Order by `id`', values: ::Ci::RunnerJobsFinder::ALLOWED_INDEXED_COLUMNS
+ optional :sort, type: String, values: %w[asc desc], default: 'desc', desc: 'Sort by `asc` or `desc` order. ' \
+ 'Specify `order_by` as well, including for `id`'
use :pagination
end
get ':id/jobs' do
@@ -143,7 +238,10 @@ module API
end
desc 'Reset runner authentication token' do
+ summary "Reset runner's authentication token"
success Entities::Ci::ResetTokenResult
+ failure [[403, 'No access granted'], [404, 'Runner not found']]
+ tags %w[runners]
end
params do
requires :id, type: Integer, desc: 'The ID of the runner'
@@ -158,24 +256,24 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id,
+ types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authorize_admin_project }
desc 'Get runners available for project' do
+ summary "List project's runners"
+ detail 'List all runners available in the project, including from ancestor groups ' \
+ 'and any allowed shared runners.'
success Entities::Ci::Runner
+ failure [[400, 'Scope contains invalid value'], [403, 'No access granted']]
+ tags %w[runners projects]
end
params do
- optional :scope, type: String, values: ::Ci::Runner::AVAILABLE_SCOPES,
- desc: 'The scope of specific runners to show'
- optional :type, type: String, values: ::Ci::Runner::AVAILABLE_TYPES,
- desc: 'The type of the runners to show'
- optional :paused, type: Boolean, desc: 'Whether to include only runners that are accepting or ignoring new jobs'
- optional :status, type: String, values: ::Ci::Runner::AVAILABLE_STATUSES,
- desc: 'The status of the runners to show'
- optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The tags of the runners to show'
- use :pagination
+ use :deprecated_filter_params
+ use :filter_params
end
get ':id/runners' do
runners = ::Ci::Runner.owned_or_instance_wide(user_project.id)
@@ -187,11 +285,16 @@ module API
present paginate(runners), with: Entities::Ci::Runner
end
- desc 'Enable a runner for a project' do
+ desc 'Enable a runner in project' do
+ detail "Enable an available specific runner in the project."
success Entities::Ci::Runner
+ failure [[400, 'Bad Request'],
+ [403, 'No access granted'], [403, 'Runner is a group runner'], [403, 'Runner is locked'],
+ [404, 'Runner not found']]
+ tags %w[runners projects]
end
params do
- requires :runner_id, type: Integer, desc: 'The ID of the runner'
+ requires :runner_id, type: Integer, desc: 'The ID of a runner'
end
post ':id/runners' do
runner = get_runner(params[:runner_id])
@@ -205,10 +308,17 @@ module API
end
desc "Disable project's runner" do
+ summary "Disable a specific runner from the project"
+ detail "It works only if the project isn't the only project associated with the specified runner. " \
+ "If so, an error is returned. Use the call to delete a runner instead."
success Entities::Ci::Runner
+ failure [[400, 'Bad Request'],
+ [403, 'Only one project associated with the runner. Please remove the runner instead'],
+ [404, 'Runner not found'], [412, 'Precondition Failed']]
+ tags %w[runners projects]
end
params do
- requires :runner_id, type: Integer, desc: 'The ID of the runner'
+ requires :runner_id, type: Integer, desc: 'The ID of a runner'
end
# rubocop: disable CodeReuse/ActiveRecord
delete ':id/runners/:runner_id' do
@@ -230,16 +340,15 @@ module API
before { authorize_admin_group }
desc 'Get runners available for group' do
+ summary "List group's runners"
+ detail 'List all runners available in the group as well as its ancestor groups, ' \
+ 'including any allowed shared runners.'
success Entities::Ci::Runner
+ failure [[400, 'Scope contains invalid value'], [403, 'Forbidden']]
+ tags %w[runners groups]
end
params do
- optional :type, type: String, values: ::Ci::Runner::AVAILABLE_TYPES,
- desc: 'The type of the runners to show'
- optional :paused, type: Boolean, desc: 'Whether to include only runners that are accepting or ignoring new jobs'
- optional :status, type: String, values: ::Ci::Runner::AVAILABLE_STATUSES,
- desc: 'The status of the runners to show'
- optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The tags of the runners to show'
- use :pagination
+ use :filter_params
end
get ':id/runners' do
runners = ::Ci::Runner.group_or_instance_wide(user_group)
@@ -252,8 +361,11 @@ module API
resource :runners do
before { authenticate_non_get! }
- desc 'Resets runner registration token' do
+ desc 'Reset runner registration token' do
+ summary "Reset instance's runner registration token"
success Entities::Ci::ResetTokenResult
+ failure [[403, 'Forbidden']]
+ tags %w[runners groups]
end
post 'reset_registration_token' do
authorize! :update_runners_registration_token, ApplicationSetting.current
@@ -269,8 +381,11 @@ module API
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authenticate_non_get! }
- desc 'Resets runner registration token' do
+ desc 'Reset runner registration token' do
+ summary "Reset the runner registration token for a project"
success Entities::Ci::ResetTokenResult
+ failure [[401, 'Unauthorized'], [403, 'Forbidden'], [404, 'Project Not Found']]
+ tags %w[runners projects]
end
post ':id/runners/reset_registration_token' do
project = find_project! user_project.id
@@ -287,8 +402,11 @@ module API
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authenticate_non_get! }
- desc 'Resets runner registration token' do
+ desc 'Reset runner registration token' do
+ summary "Reset the runner registration token for a group"
success Entities::Ci::ResetTokenResult
+ failure [[401, 'Unauthorized'], [403, 'Forbidden'], [404, 'Group Not Found']]
+ tags %w[runners groups]
end
post ':id/runners/reset_registration_token' do
group = find_group! user_group.id
@@ -298,72 +416,6 @@ module API
present group.runners_token_with_expiration, with: Entities::Ci::ResetTokenResult
end
end
-
- helpers do
- def filter_runners(runners, scope, allowed_scopes: ::Ci::Runner::AVAILABLE_SCOPES)
- return runners unless scope.present?
-
- unless allowed_scopes.include?(scope)
- render_api_error!('Scope contains invalid value', 400)
- end
-
- # Support deprecated scopes
- if runners.respond_to?("deprecated_#{scope}")
- scope = "deprecated_#{scope}"
- end
-
- runners.public_send(scope) # rubocop:disable GitlabSecurity/PublicSend
- end
-
- def apply_filter(runners, params)
- runners = filter_runners(runners, params[:type], allowed_scopes: ::Ci::Runner::AVAILABLE_TYPES)
- runners = filter_runners(runners, params[:status], allowed_scopes: ::Ci::Runner::AVAILABLE_STATUSES)
- runners = filter_runners(runners, params[:paused] ? 'paused' : 'active', allowed_scopes: %w[paused active]) if params.include?(:paused)
- runners = runners.tagged_with(params[:tag_list]) if params[:tag_list]
-
- runners
- end
-
- def get_runner(id)
- runner = ::Ci::Runner.find(id)
- not_found!('Runner') unless runner
- runner
- end
-
- def authenticate_show_runner!(runner)
- return if runner.instance_type? || current_user.admin?
-
- forbidden!("No access granted") unless can?(current_user, :read_runner, runner)
- end
-
- def authenticate_update_runner!(runner)
- return if current_user.admin?
-
- forbidden!("No access granted") unless can?(current_user, :update_runner, runner)
- end
-
- def authenticate_delete_runner!(runner)
- return if current_user.admin?
-
- forbidden!("Runner associated with more than one project") if runner.runner_projects.count > 1
- forbidden!("No access granted") unless can?(current_user, :delete_runner, runner)
- end
-
- def authenticate_enable_runner!(runner)
- forbidden!("Runner is a group runner") if runner.group_type?
-
- return if current_user.admin?
-
- forbidden!("Runner is locked") if runner.locked?
- forbidden!("No access granted") unless can?(current_user, :assign_runner, runner)
- end
-
- def authenticate_list_runners_jobs!(runner)
- return if current_user.admin?
-
- forbidden!("No access granted") unless can?(current_user, :read_builds, runner)
- end
- end
end
end
end
diff --git a/lib/api/ci/secure_files.rb b/lib/api/ci/secure_files.rb
index 511b6e06cd3..dd628a3413f 100644
--- a/lib/api/ci/secure_files.rb
+++ b/lib/api/ci/secure_files.rb
@@ -16,7 +16,7 @@ module API
default_format :json
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
@@ -61,7 +61,7 @@ module API
desc 'Upload a Secure File'
params do
requires :name, type: String, desc: 'The name of the file'
- requires :file, types: [Rack::Multipart::UploadedFile, ::API::Validations::Types::WorkhorseFile], desc: 'The secure file to be uploaded'
+ requires :file, types: [Rack::Multipart::UploadedFile, ::API::Validations::Types::WorkhorseFile], desc: 'The secure file to be uploaded', documentation: { type: 'file' }
end
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: true
post ':id/secure_files' do
diff --git a/lib/api/ci/triggers.rb b/lib/api/ci/triggers.rb
index c49f1c9e9e1..c202d188e43 100644
--- a/lib/api/ci/triggers.rb
+++ b/lib/api/ci/triggers.rb
@@ -11,16 +11,26 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project',
+ documentation: { example: 18 }
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Trigger a GitLab project pipeline' do
- success Entities::Ci::Pipeline
+ success code: 201, model: Entities::Ci::Pipeline
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :ref, type: String, desc: 'The commit sha or name of a branch or tag', allow_blank: false
- requires :token, type: String, desc: 'The unique token of trigger or job token'
- optional :variables, type: Hash, desc: 'The list of variables to be injected into build'
+ requires :ref, type: String, desc: 'The commit sha or name of a branch or tag', allow_blank: false,
+ documentation: { example: 'develop' }
+ requires :token, type: String, desc: 'The unique token of trigger or job token',
+ documentation: { example: '6d056f63e50fe6f8c5f8f4aa10edb7' }
+ optional :variables, type: Hash, desc: 'The list of variables to be injected into build',
+ documentation: { example: { VAR1: "value1", VAR2: "value2" } }
end
post ":id/(ref/:ref/)trigger/pipeline", requirements: { ref: /.+/ } do
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/20758')
@@ -47,7 +57,13 @@ module API
end
desc 'Get triggers list' do
- success Entities::Trigger
+ success code: 200, model: Entities::Trigger
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
end
params do
use :pagination
@@ -64,10 +80,15 @@ module API
# rubocop: enable CodeReuse/ActiveRecord
desc 'Get specific trigger of a project' do
- success Entities::Trigger
+ success code: 200, model: Entities::Trigger
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :trigger_id, type: Integer, desc: 'The trigger ID'
+ requires :trigger_id, type: Integer, desc: 'The trigger ID', documentation: { example: 10 }
end
get ':id/triggers/:trigger_id' do
authenticate!
@@ -80,10 +101,17 @@ module API
end
desc 'Create a trigger' do
- success Entities::Trigger
+ success code: 201, model: Entities::Trigger
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :description, type: String, desc: 'The trigger description'
+ requires :description, type: String, desc: 'The trigger description',
+ documentation: { example: 'my trigger description' }
end
post ':id/triggers' do
authenticate!
@@ -100,7 +128,13 @@ module API
end
desc 'Update a trigger' do
- success Entities::Trigger
+ success code: 200, model: Entities::Trigger
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :trigger_id, type: Integer, desc: 'The trigger ID'
@@ -123,10 +157,16 @@ module API
end
desc 'Delete a trigger' do
- success Entities::Trigger
+ success code: 204
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 412, message: 'Precondition Failed' }
+ ]
end
params do
- requires :trigger_id, type: Integer, desc: 'The trigger ID'
+ requires :trigger_id, type: Integer, desc: 'The trigger ID', documentation: { example: 10 }
end
delete ':id/triggers/:trigger_id' do
authenticate!
diff --git a/lib/api/ci/variables.rb b/lib/api/ci/variables.rb
index c9e1d115d03..5a6b5987228 100644
--- a/lib/api/ci/variables.rb
+++ b/lib/api/ci/variables.rb
@@ -13,12 +13,13 @@ module API
helpers ::API::Helpers::VariablesHelpers
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID of a project or URL-encoded NAMESPACE/PROJECT_NAME of the project owned by the authenticated user'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get project variables' do
success Entities::Ci::Variable
+ tags %w[ci_variables]
end
params do
use :pagination
@@ -28,13 +29,15 @@ module API
present paginate(variables), with: Entities::Ci::Variable
end
- desc 'Get a specific variable from a project' do
+ desc 'Get the details of a single variable from a project' do
success Entities::Ci::Variable
+ failure [{ code: 404, message: 'Variable Not Found' }]
+ tags %w[ci_variables]
end
params do
- requires :key, type: String, desc: 'The key of the variable'
+ requires :key, type: String, desc: 'The key of a variable'
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 the variable'
+ optional :environment_scope, type: String, desc: 'The environment scope of a variable'
end
end
# rubocop: disable CodeReuse/ActiveRecord
@@ -48,13 +51,17 @@ module API
desc 'Create a new variable in a project' do
success Entities::Ci::Variable
+ failure [{ code: 400, message: '400 Bad Request' }]
+ tags %w[ci_variables]
end
+ route_setting :log_safety, { safe: %w[key], unsafe: %w[value] }
params do
- requires :key, type: String, desc: 'The key of the variable'
- requires :value, type: String, desc: 'The value of the variable'
+ requires :key, type: String, desc: 'The key of a variable'
+ requires :value, type: String, desc: 'The value of a variable'
optional :protected, type: Boolean, desc: 'Whether the variable is protected'
optional :masked, type: Boolean, desc: 'Whether the variable is masked'
- optional :variable_type, type: String, values: ::Ci::Variable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file. Defaults to env_var'
+ 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'
end
post ':id/variables' do
@@ -73,16 +80,20 @@ module API
desc 'Update an existing variable from a project' do
success Entities::Ci::Variable
+ failure [{ code: 404, message: 'Variable Not Found' }]
+ tags %w[ci_variables]
end
+ route_setting :log_safety, { safe: %w[key], unsafe: %w[value] }
params do
- optional :key, type: String, desc: 'The key of the variable'
- optional :value, type: String, desc: 'The value of the variable'
+ optional :key, type: String, desc: 'The key of a variable'
+ optional :value, type: String, desc: 'The value of a variable'
optional :protected, type: Boolean, desc: 'Whether the variable is protected'
optional :masked, type: Boolean, desc: 'Whether the variable is masked'
- optional :variable_type, type: String, values: ::Ci::Variable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file'
- optional :environment_scope, type: String, desc: 'The environment_scope of the variable'
+ optional :environment_scope, type: String, desc: 'The environment_scope of a variable'
+ 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 :filter, type: Hash, desc: 'Available filters: [environment_scope]. Example: filter[environment_scope]=production' do
- optional :environment_scope, type: String, desc: 'The environment scope of the variable'
+ optional :environment_scope, type: String, desc: 'The environment scope of a variable'
end
end
# rubocop: disable CodeReuse/ActiveRecord
@@ -106,9 +117,11 @@ module API
desc 'Delete an existing variable from a project' do
success Entities::Ci::Variable
+ failure [{ code: 404, message: 'Variable Not Found' }]
+ tags %w[ci_variables]
end
params do
- requires :key, type: String, desc: 'The key of the variable'
+ requires :key, type: String, desc: 'The key of a variable'
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 the variable'
end
diff --git a/lib/api/clusters/agent_tokens.rb b/lib/api/clusters/agent_tokens.rb
index 1f9c8700d7a..f65ae465b3d 100644
--- a/lib/api/clusters/agent_tokens.rb
+++ b/lib/api/clusters/agent_tokens.rb
@@ -10,7 +10,7 @@ module API
feature_category :kubernetes_management
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
params do
@@ -18,22 +18,24 @@ module API
end
resource ':id/cluster_agents/:agent_id' do
resource :tokens do
- desc 'List agent tokens' do
- detail 'This feature was introduced in GitLab 15.0.'
+ desc 'List tokens for an agent' do
+ detail 'This feature was introduced in GitLab 15.0. Returns a list of tokens for an agent.'
success Entities::Clusters::AgentTokenBasic
+ tags %w[cluster_agents]
end
params do
use :pagination
end
get do
- agent = ::Clusters::AgentsFinder.new(user_project, current_user).find(params[:agent_id])
+ agent_tokens = ::Clusters::AgentTokensFinder.new(user_project, current_user, params[:agent_id]).execute
- present paginate(agent.agent_tokens), with: Entities::Clusters::AgentTokenBasic
+ present paginate(agent_tokens), with: Entities::Clusters::AgentTokenBasic
end
desc 'Get a single agent token' do
- detail 'This feature was introduced in GitLab 15.0.'
+ detail 'This feature was introduced in GitLab 15.0. Gets a single agent token.'
success Entities::Clusters::AgentToken
+ tags %w[cluster_agents]
end
params do
requires :token_id, type: Integer, desc: 'The ID of the agent token'
@@ -47,8 +49,9 @@ module API
end
desc 'Create an agent token' do
- detail 'This feature was introduced in GitLab 15.0.'
+ detail 'This feature was introduced in GitLab 15.0. Creates a new token for an agent.'
success Entities::Clusters::AgentTokenWithToken
+ tags %w[cluster_agents]
end
params do
requires :name, type: String, desc: 'The name for the token'
@@ -71,7 +74,8 @@ module API
end
desc 'Revoke an agent token' do
- detail 'This feature was introduced in GitLab 15.0.'
+ detail 'This feature was introduced in GitLab 15.0. Revokes an agent token.'
+ tags %w[cluster_agents]
end
params do
requires :token_id, type: Integer, desc: 'The ID of the agent token'
diff --git a/lib/api/clusters/agents.rb b/lib/api/clusters/agents.rb
index 2affd9680b6..62d4fb009c6 100644
--- a/lib/api/clusters/agents.rb
+++ b/lib/api/clusters/agents.rb
@@ -11,12 +11,13 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'List agents' do
- detail 'This feature was introduced in GitLab 14.10.'
+ desc 'List the agents for a project' do
+ detail 'This feature was introduced in GitLab 14.10. Returns the list of agents registered for the project.'
success Entities::Clusters::Agent
+ tags %w[cluster_agents]
end
params do
use :pagination
@@ -29,9 +30,10 @@ module API
present paginate(agents), with: Entities::Clusters::Agent
end
- desc 'Get single agent' do
- detail 'This feature was introduced in GitLab 14.10.'
+ desc 'Get details about an agent' do
+ detail 'This feature was introduced in GitLab 14.10. Gets a single agent details.'
success Entities::Clusters::Agent
+ tags %w[cluster_agents]
end
params do
requires :agent_id, type: Integer, desc: 'The ID of an agent'
@@ -42,9 +44,10 @@ module API
present agent, with: Entities::Clusters::Agent
end
- desc 'Add an agent to a project' do
- detail 'This feature was introduced in GitLab 14.10.'
+ desc 'Register an agent with a project' do
+ detail 'This feature was introduced in GitLab 14.10. Registers an agent to the project.'
success Entities::Clusters::Agent
+ tags %w[cluster_agents]
end
params do
requires :name, type: String, desc: 'The name of the agent'
@@ -61,8 +64,9 @@ module API
present result[:cluster_agent], with: Entities::Clusters::Agent
end
- desc 'Delete an agent' do
- detail 'This feature was introduced in GitLab 14.10.'
+ desc 'Delete a registered agent' do
+ detail 'This feature was introduced in GitLab 14.10. Deletes an existing agent registration.'
+ tags %w[cluster_agents]
end
params do
requires :agent_id, type: Integer, desc: 'The ID of an agent'
diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb
index 7d8b58fd7b6..954b572c9b1 100644
--- a/lib/api/commit_statuses.rb
+++ b/lib/api/commit_statuses.rb
@@ -8,7 +8,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
include PaginationParams
@@ -16,14 +16,20 @@ module API
before { authenticate! }
desc "Get a commit's statuses" do
- success Entities::CommitStatus
+ success code: 200, model: Entities::CommitStatus
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
end
params do
- requires :sha, type: String, desc: 'The commit hash'
- optional :ref, type: String, desc: 'The ref'
- optional :stage, type: String, desc: 'The stage'
- optional :name, type: String, desc: 'The name'
- optional :all, type: String, desc: 'Show all statuses, default: false'
+ requires :sha, type: String, desc: 'The commit hash', documentation: { example: '18f3e63d05582537db6d183d9d557be09e1f90c8' }
+ optional :ref, type: String, desc: 'The ref', documentation: { example: 'develop' }
+ optional :stage, type: String, desc: 'The stage', documentation: { example: 'test' }
+ optional :name, type: String, desc: 'The name', documentation: { example: 'bundler:audit' }
+ optional :all, type: Boolean, desc: 'Show all statuses', documentation: { default: false }
use :pagination
end
# rubocop: disable CodeReuse/ActiveRecord
@@ -43,19 +49,32 @@ module API
# rubocop: enable CodeReuse/ActiveRecord
desc 'Post status to a commit' do
- success Entities::CommitStatus
+ success code: 200, model: Entities::CommitStatus
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :sha, type: String, desc: 'The commit hash'
- requires :state, type: String, desc: 'The state of the status',
- values: %w(pending running success failed canceled)
- optional :ref, type: String, desc: 'The ref'
- optional :target_url, type: String, desc: 'The target URL to associate with this status'
- optional :description, type: String, desc: 'A short description of the status'
- optional :name, type: String, desc: 'A string label to differentiate this status from the status of other systems. Default: "default"', documentation: { default: 'default' }
- optional :context, type: String, desc: 'A string label to differentiate this status from the status of other systems. Default: "default"', documentation: { default: 'default' }
- optional :coverage, type: Float, desc: 'The total code coverage'
- optional :pipeline_id, type: Integer, desc: 'An existing pipeline ID, when multiple pipelines on the same commit SHA have been triggered'
+ requires :sha, type: String, desc: 'The commit hash',
+ documentation: { example: '18f3e63d05582537db6d183d9d557be09e1f90c8' }
+ requires :state, type: String, desc: 'The state of the status',
+ values: %w(pending running success failed canceled),
+ documentation: { example: 'pending' }
+ optional :ref, type: String, desc: 'The ref',
+ documentation: { example: 'develop' }
+ optional :target_url, type: String, desc: 'The target URL to associate with this status',
+ documentation: { example: 'https://gitlab.example.com/janedoe/gitlab-foss/builds/91' }
+ optional :description, type: String, desc: 'A short description of the status'
+ optional :name, type: String, desc: 'A string label to differentiate this status from the status of other systems',
+ documentation: { example: 'coverage', default: 'default' }
+ optional :context, type: String, desc: 'A string label to differentiate this status from the status of other systems',
+ documentation: { example: 'coverage', default: 'default' }
+ optional :coverage, type: Float, desc: 'The total code coverage',
+ documentation: { example: 100.0 }
+ optional :pipeline_id, type: Integer, desc: 'An existing pipeline ID, when multiple pipelines on the same commit SHA have been triggered'
end
# rubocop: disable CodeReuse/ActiveRecord
post ':id/statuses/:sha' do
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
index 50d0687ba75..63a13b83a9b 100644
--- a/lib/api/commits.rb
+++ b/lib/api/commits.rb
@@ -9,7 +9,7 @@ module API
before do
require_repository_enabled!
- authorize! :download_code, user_project
+ authorize! :read_code, user_project
verify_pagination_params!
end
@@ -27,17 +27,35 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS, urgency: :low do
desc 'Get a project repository commits' do
- success Entities::Commit
+ success code: 200, model: Entities::Commit
+ tags %w[commits]
+ is_array true
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- optional :ref_name, type: String, desc: 'The name of a repository branch or tag, if not given the default branch is used'
- optional :since, type: DateTime, desc: 'Only commits after or on this date will be returned'
- optional :until, type: DateTime, desc: 'Only commits before or on this date will be returned'
- optional :path, type: String, desc: 'The file path'
+ optional :ref_name,
+ type: String,
+ desc: 'The name of a repository branch or tag, if not given the default branch is used',
+ documentation: { example: 'v1.1.0' }
+ optional :since,
+ type: DateTime,
+ desc: 'Only commits after or on this date will be returned',
+ documentation: { example: '2021-09-20T11:50:22.001' }
+ optional :until,
+ type: DateTime,
+ desc: 'Only commits before or on this date will be returned',
+ documentation: { example: '2021-09-20T11:50:22.001' }
+ optional :path,
+ type: String,
+ desc: 'The file path',
+ documentation: { example: 'README.md' }
optional :all, type: Boolean, desc: 'Every commit will be returned'
optional :with_stats, type: Boolean, desc: 'Stats about each commit will be added to the response'
optional :first_parent, type: Boolean, desc: 'Only include the first parent of merges'
@@ -81,40 +99,87 @@ module API
end
desc 'Commit multiple file changes as one commit' do
- success Entities::CommitDetail
+ success code: 200, model: Entities::CommitDetail
+ tags %w[commits]
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' }
+ ]
detail 'This feature was introduced in GitLab 8.13'
end
params do
- requires :branch, type: String, desc: 'Name of the branch to commit into. To create a new branch, also provide either `start_branch` or `start_sha`, and optionally `start_project`.', allow_blank: false
- requires :commit_message, type: String, desc: 'Commit message'
- requires :actions, type: Array, desc: 'Actions to perform in commit' do
- requires :action, type: String, desc: 'The action to perform, `create`, `delete`, `move`, `update`, `chmod`', values: %w[create update move delete chmod].freeze, allow_blank: false
- requires :file_path, type: String, desc: 'Full path to the file. Ex. `lib/class.rb`'
+ requires :branch,
+ type: String,
+ desc: 'Name of the branch to commit into. To create a new branch, also provide either `start_branch` or `start_sha`, and optionally `start_project`.',
+ allow_blank: false,
+ documentation: { example: 'master' }
+ requires :commit_message,
+ type: String,
+ desc: 'Commit message',
+ documentation: { example: 'initial commit' }
+ requires :actions,
+ type: Array,
+ desc: 'Actions to perform in commit' do
+ requires :action,
+ type: String,
+ desc: 'The action to perform, `create`, `delete`, `move`, `update`, `chmod`', values: %w[create update move delete chmod].freeze,
+ allow_blank: false
+ requires :file_path,
+ type: String,
+ desc: 'Full path to the file.',
+ documentation: { example: 'lib/class.rb' }
given action: ->(action) { action == 'move' } do
- requires :previous_path, type: String, desc: 'Original full path to the file being moved. Ex. `lib/class1.rb`'
+ requires :previous_path,
+ type: String,
+ desc: 'Original full path to the file being moved.',
+ documentation: { example: 'lib/class.rb' }
end
given action: ->(action) { %w[create move].include? action } do
- optional :content, type: String, desc: 'File content'
+ optional :content,
+ type: String,
+ desc: 'File content',
+ documentation: { example: 'Some file content' }
end
given action: ->(action) { action == 'update' } do
- requires :content, type: String, desc: 'File content'
+ requires :content,
+ type: String,
+ desc: 'File content',
+ documentation: { example: 'Some file content' }
end
optional :encoding, type: String, desc: '`text` or `base64`', default: 'text', values: %w[text base64]
given action: ->(action) { %w[update move delete].include? action } do
- optional :last_commit_id, type: String, desc: 'Last known file commit id'
+ optional :last_commit_id,
+ type: String,
+ desc: 'Last known file commit id',
+ documentation: { example: '2695effb5807a22ff3d138d593fd856244e155e7' }
end
given action: ->(action) { action == 'chmod' } do
requires :execute_filemode, type: Boolean, desc: 'When `true/false` enables/disables the execute flag on the file.'
end
end
- optional :start_branch, type: String, desc: 'Name of the branch to start the new branch from'
- optional :start_sha, type: String, desc: 'SHA of the commit to start the new branch from'
+ optional :start_branch,
+ type: String,
+ desc: 'Name of the branch to start the new branch from',
+ documentation: { example: 'staging' }
+ optional :start_sha,
+ type: String,
+ desc: 'SHA of the commit to start the new branch from',
+ documentation: { example: '2695effb5807a22ff3d138d593fd856244e155e7' }
mutually_exclusive :start_branch, :start_sha
- optional :start_project, types: [Integer, String], desc: 'The ID or path of the project to start the new branch from'
- optional :author_email, type: String, desc: 'Author email for commit'
- optional :author_name, type: String, desc: 'Author name for commit'
+ optional :start_project,
+ types: [Integer, String],
+ desc: 'The ID or path of the project to start the new branch from',
+ documentation: { example: 1 }
+ optional :author_email,
+ type: String,
+ desc: 'Author email for commit',
+ documentation: { example: 'janedoe@example.com' }
+ optional :author_name,
+ type: String,
+ desc: 'Author name for commit',
+ documentation: { example: 'Jane Doe' }
optional :stats, type: Boolean, default: true, desc: 'Include commit stats'
optional :force, type: Boolean, default: false, desc: 'When `true` overwrites the target branch with a new commit based on the `start_branch` or `start_sha`'
end
@@ -151,8 +216,11 @@ module API
end
desc 'Get a specific commit of a project' do
- success Entities::CommitDetail
- failure [[404, 'Commit Not Found']]
+ success code: 200, model: Entities::CommitDetail
+ tags %w[commits]
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
@@ -167,7 +235,12 @@ module API
end
desc 'Get the diff for a specific commit of a project' do
- failure [[404, 'Commit Not Found']]
+ success code: 200, model: Entities::Diff
+ tags %w[commits]
+ is_array true
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
@@ -184,8 +257,12 @@ module API
end
desc "Get a commit's comments" do
- success Entities::CommitNote
- failure [[404, 'Commit Not Found']]
+ success code: 200, model: Entities::CommitNote
+ tags %w[commits]
+ is_array true
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
end
params do
use :pagination
@@ -202,13 +279,25 @@ module API
desc 'Cherry pick commit into a branch' do
detail 'This feature was introduced in GitLab 8.15'
- success Entities::Commit
+ success code: 200, model: Entities::Commit
+ tags %w[commits]
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag to be cherry picked'
- requires :branch, type: String, desc: 'The name of the branch', allow_blank: false
+ requires :branch,
+ type: String,
+ desc: 'The name of the branch',
+ allow_blank: false,
+ documentation: { example: 'master' }
optional :dry_run, type: Boolean, default: false, desc: "Does not commit any changes"
- optional :message, type: String, desc: 'A custom commit message to use for the picked commit'
+ optional :message,
+ type: String,
+ desc: 'A custom commit message to use for the picked commit',
+ documentation: { example: 'Initial commit' }
end
post ':id/repository/commits/:sha/cherry_pick', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
authorize_push_to_branch!(params[:branch])
@@ -248,11 +337,20 @@ module API
desc 'Revert a commit in a branch' do
detail 'This feature was introduced in GitLab 11.5'
- success Entities::Commit
+ success code: 200, model: Entities::Commit
+ tags %w[commits]
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :sha, type: String, desc: 'Commit SHA to revert'
- requires :branch, type: String, desc: 'Target branch name', allow_blank: false
+ requires :branch,
+ type: String,
+ desc: 'Target branch name',
+ allow_blank: false,
+ documentation: { example: 'master' }
optional :dry_run, type: Boolean, default: false, desc: "Does not commit any changes"
end
post ':id/repository/commits/:sha/revert', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
@@ -292,7 +390,12 @@ module API
desc 'Get all references a commit is pushed to' do
detail 'This feature was introduced in GitLab 10.6'
- success Entities::BasicRef
+ success code: 200, model: Entities::BasicRef
+ tags %w[commits]
+ is_array true
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :sha, type: String, desc: 'A commit sha'
@@ -312,14 +415,28 @@ module API
end
desc 'Post comment to commit' do
- success Entities::CommitNote
+ success code: 200, model: Entities::CommitNote
+ tags %w[commits]
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag on which to post a comment'
- requires :note, type: String, desc: 'The text of the comment'
- optional :path, type: String, desc: 'The file path'
+ requires :note,
+ type: String,
+ desc: 'The text of the comment',
+ documentation: { example: 'Nice code!' }
+ optional :path,
+ type: String,
+ desc: 'The file path',
+ documentation: { example: 'doc/update/5.4-to-6.0.md' }
given :path do
- requires :line, type: Integer, desc: 'The line number'
+ requires :line,
+ type: Integer,
+ desc: 'The line number',
+ documentation: { example: 11 }
requires :line_type, type: String, values: %w[new old], default: 'new', desc: 'The type of the line'
end
end
@@ -361,7 +478,12 @@ module API
end
desc 'Get Merge Requests associated with a commit' do
- success Entities::MergeRequestBasic
+ success code: 200, model: Entities::MergeRequestBasic
+ tags %w[commits]
+ is_array true
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag on which to find Merge Requests'
@@ -383,7 +505,11 @@ module API
end
desc "Get a commit's signature" do
- success Entities::CommitSignature
+ success code: 200, model: Entities::CommitSignature
+ tags %w[commits]
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
diff --git a/lib/api/concerns/packages/conan_endpoints.rb b/lib/api/concerns/packages/conan_endpoints.rb
index d8c2eb4ff33..fdbffb1689b 100644
--- a/lib/api/concerns/packages/conan_endpoints.rb
+++ b/lib/api/concerns/packages/conan_endpoints.rb
@@ -29,7 +29,7 @@ module API
CONAN_REVISION_REGEX = Gitlab::Regex.conan_revision_regex
CONAN_REVISION_USER_CHANNEL_REGEX = Gitlab::Regex.conan_recipe_user_channel_regex
- CONAN_FILES = (Gitlab::Regex::Packages::CONAN_RECIPE_FILES + Gitlab::Regex::Packages::CONAN_PACKAGE_FILES).freeze
+ CONAN_FILES = (Gitlab::Regex::Packages::CONAN_RECIPE_FILES + Gitlab::Regex::Packages::CONAN_PACKAGE_FILES).uniq.freeze
included do
feature_category :package_registry
@@ -307,7 +307,7 @@ module API
end
params do
- requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)', documentation: { type: 'file' }
end
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true
@@ -358,7 +358,7 @@ module API
end
params do
- requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)', documentation: { type: 'file' }
end
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true
diff --git a/lib/api/container_registry_event.rb b/lib/api/container_registry_event.rb
index 66689f8d7c8..9acf2fca1b3 100644
--- a/lib/api/container_registry_event.rb
+++ b/lib/api/container_registry_event.rb
@@ -23,8 +23,20 @@ module API
content_type :json, DOCKER_DISTRIBUTION_EVENTS_V1_JSON
format :json
+ desc 'Receives notifications from the container registry when an operation occurs' do
+ detail 'This feature was introduced in GitLab 12.10'
+ consumes [:json, DOCKER_DISTRIBUTION_EVENTS_V1_JSON]
+ end
params do
- requires :events, type: Array
+ requires :events, type: Array, desc: 'Event notifications' do
+ requires :action, type: String, desc: 'The action to perform, `push`, `delete`',
+ values: %w[push delete].freeze
+ optional :target, type: Hash, desc: 'The target of the action' do
+ optional :tag, type: String, desc: 'The target tag'
+ optional :repository, type: String, desc: 'The target repository'
+ optional :digest, type: String, desc: 'Unique identifier for target image manifest'
+ end
+ end
end
# This endpoint is used by Docker Registry to push a set of event
diff --git a/lib/api/container_repositories.rb b/lib/api/container_repositories.rb
index d4fa6153a92..f2dd1fa21fd 100644
--- a/lib/api/container_repositories.rb
+++ b/lib/api/container_repositories.rb
@@ -14,7 +14,7 @@ module API
namespace 'registry' do
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :repositories, requirements: { id: /[0-9]*/ } do
desc 'Get a container repository' do
diff --git a/lib/api/debian_project_packages.rb b/lib/api/debian_project_packages.rb
index 03f0f97b805..df3b6e774ae 100644
--- a/lib/api/debian_project_packages.rb
+++ b/lib/api/debian_project_packages.rb
@@ -34,7 +34,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
namespace ':id/packages/debian' do
@@ -64,7 +64,7 @@ module API
# PUT {projects|groups}/:id/packages/debian/:file_name
params do
- requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)', documentation: { type: 'file' }
end
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
diff --git a/lib/api/dependency_proxy.rb b/lib/api/dependency_proxy.rb
index 290a90934d7..fcf18a2792a 100644
--- a/lib/api/dependency_proxy.rb
+++ b/lib/api/dependency_proxy.rb
@@ -12,11 +12,18 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a group'
+ requires :id, types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the group owned by the authenticated user'
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Deletes all dependency_proxy_blobs for a group' do
- detail 'This feature was introduced in GitLab 12.10'
+ desc 'Purge the dependency proxy for a group' do
+ detail 'Schedules for deletion the cached manifests and blobs for a group.'\
+ 'This endpoint requires the Owner role for the group.'
+ success code: 202
+ failure [
+ { code: 401, message: 'Unauthorized' }
+ ]
+ tags %w[dependency_proxy]
end
delete ':id/dependency_proxy/cache' do
not_found! unless user_group.dependency_proxy_feature_available?
diff --git a/lib/api/deploy_keys.rb b/lib/api/deploy_keys.rb
index c53f4bca5a7..ffe0b6589bc 100644
--- a/lib/api/deploy_keys.rb
+++ b/lib/api/deploy_keys.rb
@@ -4,6 +4,8 @@ module API
class DeployKeys < ::API::Base
include PaginationParams
+ deploy_keys_tags = %w[deploy_keys]
+
before { authenticate! }
feature_category :continuous_delivery
@@ -21,7 +23,16 @@ module API
# rubocop: enable CodeReuse/ActiveRecord
end
- desc 'Return all deploy keys'
+ desc 'List all deploy keys' do
+ detail 'Get a list of all deploy keys across all projects of the GitLab instance. This endpoint requires administrator access and is not available on GitLab.com.'
+ success Entities::DeployKey
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' }
+ ]
+ is_array true
+ tags deploy_keys_tags
+ end
params do
use :pagination
optional :public, type: Boolean, default: false, desc: "Only return deploy keys that are public"
@@ -35,13 +46,20 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of the project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authorize_admin_project }
- desc "Get a specific project's deploy keys" do
+ desc 'List deploy keys for project' do
+ detail "Get a list of a project's deploy keys."
success Entities::DeployKeysProject
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags deploy_keys_tags
end
params do
use :pagination
@@ -54,8 +72,14 @@ module API
end
# rubocop: enable CodeReuse/ActiveRecord
- desc 'Get single deploy key' do
+ desc 'Get a single deploy key' do
+ detail 'Get a single key.'
success Entities::DeployKeysProject
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_keys_tags
end
params do
requires :key_id, type: Integer, desc: 'The ID of the deploy key'
@@ -66,12 +90,19 @@ module API
present key, with: Entities::DeployKeysProject
end
- desc 'Add new deploy key to a project' do
+ desc 'Add deploy key' do
+ detail "Creates a new deploy key for a project. If the deploy key already exists in another project, it's joined to the current project only if the original one is accessible by the same user."
success Entities::DeployKeysProject
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_keys_tags
end
params do
- requires :key, type: String, desc: 'The new deploy key'
- requires :title, type: String, desc: 'The name of the deploy key'
+ requires :key, type: String, desc: 'New deploy key'
+ requires :title, type: String, desc: "New deploy key's title"
optional :can_push, type: Boolean, desc: "Can deploy key push to the project's repository"
end
# rubocop: disable CodeReuse/ActiveRecord
@@ -109,12 +140,20 @@ module API
end
# rubocop: enable CodeReuse/ActiveRecord
- desc 'Update an existing deploy key for a project' do
+ desc 'Update deploy key' do
+ detail 'Updates a deploy key for a project.'
success Entities::DeployKey
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_keys_tags
end
params do
requires :key_id, type: Integer, desc: 'The ID of the deploy key'
- optional :title, type: String, desc: 'The name of the deploy key'
+ optional :title, type: String, desc: "New deploy key's title"
optional :can_push, type: Boolean, desc: "Can deploy key push to the project's repository"
at_least_one_of :title, :can_push
end
@@ -143,9 +182,14 @@ module API
end
end
- desc 'Enable a deploy key for a project' do
- detail 'This feature was added in GitLab 8.11'
+ desc 'Enable a deploy key' do
+ detail 'Enables a deploy key for a project so this can be used. Returns the enabled key, with a status code 201 when successful. This feature was added in GitLab 8.11.'
success Entities::DeployKey
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_keys_tags
end
params do
requires :key_id, type: Integer, desc: 'The ID of the deploy key'
@@ -161,7 +205,14 @@ module API
end
end
- desc 'Delete deploy key for a project'
+ desc 'Delete deploy key' do
+ detail "Removes a deploy key from the project. If the deploy key is used only for this project, it's deleted from the system."
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_keys_tags
+ end
params do
requires :key_id, type: Integer, desc: 'The ID of the deploy key'
end
diff --git a/lib/api/deploy_tokens.rb b/lib/api/deploy_tokens.rb
index 3955e29621f..975a65af285 100644
--- a/lib/api/deploy_tokens.rb
+++ b/lib/api/deploy_tokens.rb
@@ -4,6 +4,8 @@ module API
class DeployTokens < ::API::Base
include PaginationParams
+ deploy_tokens_tags = %w[deploy_tokens]
+
feature_category :continuous_delivery
urgency :low
@@ -25,9 +27,15 @@ module API
end
end
- desc 'Return all deploy tokens' do
- detail 'This feature was introduced in GitLab 12.9.'
+ desc 'List all deploy tokens' do
+ detail 'Get a list of all deploy tokens across the GitLab instance. This endpoint requires administrator access. This feature was introduced in GitLab 12.9.'
success Entities::DeployToken
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' }
+ ]
+ is_array true
+ tags deploy_tokens_tags
end
params do
use :pagination
@@ -46,16 +54,23 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
end
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'
+ desc 'List project deploy tokens' do
+ detail "Get a list of a project's deploy tokens. This feature was introduced in GitLab 12.9."
success Entities::DeployToken
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags deploy_tokens_tags
end
get ':id/deploy_tokens' do
authorize!(:read_deploy_token, user_project)
@@ -75,13 +90,19 @@ module API
type: Array[String],
coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
values: ::DeployToken::AVAILABLE_SCOPES.map(&:to_s),
- desc: 'Indicates the deploy token scopes. Must be at least one of "read_repository", "read_registry", "write_registry", "read_package_registry", or "write_package_registry".'
- optional :expires_at, type: DateTime, desc: 'Expiration date for the deploy token. Does not expire if no value is provided.'
+ desc: 'Indicates the deploy token scopes. Must be at least one of `read_repository`, `read_registry`, `write_registry`, `read_package_registry`, or `write_package_registry`.'
+ optional :expires_at, type: DateTime, desc: 'Expiration date for the deploy token. Does not expire if no value is provided. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`).'
optional :username, type: String, desc: 'Username for deploy token. Default is `gitlab+deploy-token-{n}`'
end
desc 'Create a project deploy token' do
- detail 'This feature was introduced in GitLab 12.9'
+ detail 'Creates a new deploy token for a project. This feature was introduced in GitLab 12.9.'
success Entities::DeployTokenWithToken
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_tokens_tags
end
post ':id/deploy_tokens' do
authorize!(:create_deploy_token, user_project)
@@ -98,11 +119,16 @@ module API
end
desc 'Get a project deploy token' do
- detail 'This feature was introduced in GitLab 14.9'
+ detail "Get a single project's deploy token by ID. This feature was introduced in GitLab 14.9."
success Entities::DeployToken
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_tokens_tags
end
params do
- requires :token_id, type: Integer, desc: 'The deploy token ID'
+ requires :token_id, type: Integer, desc: 'The ID of the deploy token'
end
get ':id/deploy_tokens/:token_id' do
authorize!(:read_deploy_token, user_project)
@@ -113,10 +139,15 @@ module API
end
desc 'Delete a project deploy token' do
- detail 'This feature was introduced in GitLab 12.9'
+ detail 'This feature was introduced in GitLab 12.9.'
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_tokens_tags
end
params do
- requires :token_id, type: Integer, desc: 'The deploy token ID'
+ requires :token_id, type: Integer, desc: 'The ID of the deploy token'
end
delete ':id/deploy_tokens/:token_id' do
authorize!(:destroy_deploy_token, user_project)
@@ -130,16 +161,23 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a group'
+ requires :id, types: [Integer, String], desc: 'The ID or URL-encoded path of the group owned by the authenticated user'
end
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'
+ desc 'List group deploy tokens' do
+ detail "Get a list of a group's deploy tokens. This feature was introduced in GitLab 12.9."
success Entities::DeployToken
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags deploy_tokens_tags
end
get ':id/deploy_tokens' do
authorize!(:read_deploy_token, user_group)
@@ -154,18 +192,24 @@ module API
end
params do
- requires :name, type: String, desc: 'The name of the deploy token'
+ requires :name, type: String, desc: "New deploy token's name"
requires :scopes,
type: Array[String],
coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
values: ::DeployToken::AVAILABLE_SCOPES.map(&:to_s),
- desc: 'Indicates the deploy token scopes. Must be at least one of "read_repository", "read_registry", "write_registry", "read_package_registry", or "write_package_registry".'
- optional :expires_at, type: DateTime, desc: 'Expiration date for the deploy token. Does not expire if no value is provided.'
+ desc: 'Indicates the deploy token scopes. Must be at least one of `read_repository`, `read_registry`, `write_registry`, `read_package_registry`, or `write_package_registry`'
+ optional :expires_at, type: DateTime, desc: 'Expiration date for the deploy token. Does not expire if no value is provided. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`)'
optional :username, type: String, desc: 'Username for deploy token. Default is `gitlab+deploy-token-{n}`'
end
desc 'Create a group deploy token' do
- detail 'This feature was introduced in GitLab 12.9'
+ detail 'Creates a new deploy token for a group. This feature was introduced in GitLab 12.9.'
success Entities::DeployTokenWithToken
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_tokens_tags
end
post ':id/deploy_tokens' do
authorize!(:create_deploy_token, user_group)
@@ -182,11 +226,16 @@ module API
end
desc 'Get a group deploy token' do
- detail 'This feature was introduced in GitLab 14.9'
+ detail "Get a single group's deploy token by ID. This feature was introduced in GitLab 14.9. "
success Entities::DeployToken
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_tokens_tags
end
params do
- requires :token_id, type: Integer, desc: 'The deploy token ID'
+ requires :token_id, type: Integer, desc: 'The ID of the deploy token'
end
get ':id/deploy_tokens/:token_id' do
authorize!(:read_deploy_token, user_group)
@@ -197,10 +246,15 @@ module API
end
desc 'Delete a group deploy token' do
- detail 'This feature was introduced in GitLab 12.9'
+ detail 'Removes a deploy token from the group. This feature was introduced in GitLab 12.9.'
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_tokens_tags
end
params do
- requires :token_id, type: Integer, desc: 'The deploy token ID'
+ requires :token_id, type: Integer, desc: 'The ID of the deploy token'
end
delete ':id/deploy_tokens/:token_id' do
authorize!(:destroy_deploy_token, user_group)
diff --git a/lib/api/deployments.rb b/lib/api/deployments.rb
index ee0a026d7ac..141f089b5e1 100644
--- a/lib/api/deployments.rb
+++ b/lib/api/deployments.rb
@@ -5,25 +5,51 @@ module API
class Deployments < ::API::Base
include PaginationParams
+ deployments_tags = %w[deployments]
+
before { authenticate! }
feature_category :continuous_delivery
urgency :low
params do
- requires :id, type: String, desc: 'The project ID'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get all deployments of the project' do
- detail 'This feature was introduced in GitLab 8.11.'
+ desc 'List project deployments' do
+ detail 'Get a list of deployments in a project. This feature was introduced in GitLab 8.11.'
success Entities::Deployment
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags deployments_tags
end
params do
use :pagination
- optional :order_by, type: String, values: DeploymentsFinder::ALLOWED_SORT_VALUES, default: DeploymentsFinder::DEFAULT_SORT_VALUE, desc: 'Return deployments ordered by specified value'
- optional :sort, type: String, values: DeploymentsFinder::ALLOWED_SORT_DIRECTIONS, default: DeploymentsFinder::DEFAULT_SORT_DIRECTION, desc: 'Sort by asc (ascending) or desc (descending)'
- optional :updated_after, type: DateTime, desc: 'Return deployments updated after the specified date'
- optional :updated_before, type: DateTime, desc: 'Return deployments updated before the specified date'
+
+ optional :order_by,
+ type: String,
+ values: DeploymentsFinder::ALLOWED_SORT_VALUES,
+ default: DeploymentsFinder::DEFAULT_SORT_VALUE,
+ desc: 'Return deployments ordered by either one of `id`, `iid`, `created_at`, `updated_at` or `ref` fields. Default is `id`'
+
+ optional :sort,
+ type: String,
+ values: DeploymentsFinder::ALLOWED_SORT_DIRECTIONS,
+ default: DeploymentsFinder::DEFAULT_SORT_DIRECTION,
+ desc: 'Return deployments sorted in `asc` or `desc` order. Default is `asc`'
+
+ optional :updated_after,
+ type: DateTime,
+ desc: 'Return deployments updated after the specified date. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`)'
+
+ optional :updated_before,
+ type: DateTime,
+ desc: 'Return deployments updated before the specified date. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`)'
+
optional :environment,
type: String,
desc: 'The name of the environment to filter deployments by'
@@ -31,7 +57,7 @@ module API
optional :status,
type: String,
values: Deployment.statuses.keys,
- desc: 'The status to filter deployments by'
+ desc: 'The status to filter deployments by. One of `created`, `running`, `success`, `failed`, `canceled`, or `blocked`'
end
get ':id/deployments' do
@@ -46,12 +72,17 @@ module API
bad_request!(e.message)
end
- desc 'Gets a specific deployment' do
+ desc 'Get a specific deployment' do
detail 'This feature was introduced in GitLab 8.11.'
success Entities::DeploymentExtended
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deployments_tags
end
params do
- requires :deployment_id, type: Integer, desc: 'The deployment ID'
+ requires :deployment_id, type: Integer, desc: 'The ID of the deployment'
end
get ':id/deployments/:deployment_id' do
authorize! :read_deployment, user_project
@@ -61,30 +92,36 @@ module API
present deployment, with: Entities::DeploymentExtended
end
- desc 'Creates a new deployment' do
- detail 'This feature was introduced in GitLab 12.4'
+ desc 'Create a deployment' do
+ detail 'This feature was introduced in GitLab 12.4.'
success Entities::DeploymentExtended
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deployments_tags
end
params do
requires :environment,
type: String,
- desc: 'The name of the environment to deploy to'
+ desc: 'The name of the environment to create the deployment for'
requires :sha,
type: String,
- desc: 'The SHA of the commit that was deployed'
+ desc: 'The SHA of the commit that is deployed'
requires :ref,
type: String,
- desc: 'The name of the branch or tag that was deployed'
+ desc: 'The name of the branch or tag that is deployed'
requires :tag,
type: Boolean,
- desc: 'A boolean indicating if the deployment ran for a tag'
+ desc: 'A boolean that indicates if the deployed ref is a tag (`true`) or not (`false`)'
requires :status,
type: String,
- desc: 'The status of the deployment',
+ desc: 'The status to filter deployments by. One of `running`, `success`, `failed`, or `canceled`',
values: %w[running success failed canceled]
end
post ':id/deployments' do
@@ -96,7 +133,7 @@ module API
.find_or_create_by_name(params[:environment])
unless environment.persisted?
- render_validation_error!(deployment)
+ render_validation_error!(environment)
end
authorize!(:create_deployment, environment)
@@ -113,14 +150,21 @@ module API
end
end
- desc 'Updates an existing deployment' do
- detail 'This feature was introduced in GitLab 12.4'
+ desc 'Update a deployment' do
+ detail 'This feature was introduced in GitLab 12.4.'
success Entities::DeploymentExtended
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deployments_tags
end
params do
requires :status,
type: String,
- desc: 'The new status of the deployment',
+ desc: 'The new status of the deployment. One of `running`, `success`, `failed`, or `canceled`',
values: %w[running success failed canceled]
end
put ':id/deployments/:deployment_id' do
@@ -143,12 +187,17 @@ module API
end
end
- desc 'Deletes an existing deployment' do
- detail 'This feature was introduced in GitLab 15.3'
- http_codes [[204, 'Deployment was deleted'], [403, 'Forbidden'], [400, 'Cannot destroy']]
+ desc 'Delete a specific deployment' do
+ detail 'Delete a specific deployment that is not currently the last deployment for an environment or in a running state. This feature was introduced in GitLab 15.3.'
+ http_codes [
+ [204, 'Deployment destroyed'],
+ [403, 'Forbidden'],
+ [400, '"Cannot destroy running deployment" or "Deployment currently deployed to environment"']
+ ]
+ tags deployments_tags
end
params do
- requires :deployment_id, type: Integer, desc: 'The deployment ID'
+ requires :deployment_id, type: Integer, desc: 'The ID of the deployment'
end
delete ':id/deployments/:deployment_id' do
deployment = user_project.deployments.find(params[:deployment_id])
@@ -166,13 +215,21 @@ module API
helpers Helpers::MergeRequestsHelpers
- desc 'Get all merge requests of a deployment' do
- detail 'This feature was introduced in GitLab 12.7.'
+ desc 'List of merge requests associated with a deployment' do
+ detail 'Retrieves the list of merge requests shipped with a given deployment. This feature was introduced in GitLab 12.7.'
success Entities::MergeRequestBasic
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags deployments_tags
end
params do
use :pagination
- requires :deployment_id, type: Integer, desc: 'The deployment ID'
+
+ requires :deployment_id, type: Integer, desc: 'The ID of the deployment'
+
use :merge_requests_base_params
end
diff --git a/lib/api/discussions.rb b/lib/api/discussions.rb
index f73e4b621ab..d3a25a076a0 100644
--- a/lib/api/discussions.rb
+++ b/lib/api/discussions.rb
@@ -18,17 +18,19 @@ module API
Helpers::DiscussionsHelpers.feature_category_per_noteable_type.each do |noteable_type, feature_category|
parent_type = noteable_type.parent_class.to_s.underscore
noteables_str = noteable_type.to_s.underscore.pluralize
+ notable_name = noteable_type.to_s.underscore.humanize.downcase
+ notable_id_type = noteable_type == Commit ? String : Integer
noteables_path = noteable_type == Commit ? "repository/#{noteables_str}" : noteables_str
params do
requires :id, type: String, desc: "The ID of a #{parent_type}"
end
resource parent_type.pluralize.to_sym, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc "Get a list of #{noteable_type.to_s.downcase} discussions" do
+ desc "Get a list of #{notable_name} discussions" do
success Entities::Discussion
end
params do
- requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
+ requires :noteable_id, type: notable_id_type, desc: "The ID of the #{notable_name}"
use :pagination
end
@@ -41,12 +43,12 @@ module API
present Discussion.build_collection(notes, noteable), with: Entities::Discussion
end
- desc "Get a single #{noteable_type.to_s.downcase} discussion" do
+ desc "Get a single #{notable_name} discussion" do
success Entities::Discussion
end
params do
requires :discussion_id, type: String, desc: 'The ID of a discussion'
- requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
+ requires :noteable_id, type: notable_id_type, desc: "The ID of the #{notable_name}"
end
get ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id", feature_category: feature_category do
noteable = find_noteable(noteable_type, params[:noteable_id])
@@ -61,39 +63,44 @@ module API
present discussion, with: Entities::Discussion
end
- desc "Create a new #{noteable_type.to_s.downcase} discussion" do
+ desc "Create a new #{notable_name} discussion" do
success Entities::Discussion
end
params do
- requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
+ requires :noteable_id, type: notable_id_type, desc: "The ID of the #{notable_name}"
requires :body, type: String, desc: 'The content of a note'
optional :created_at, type: String, desc: 'The creation date of the note'
- optional :position, type: Hash do
- requires :base_sha, type: String, desc: 'Base commit SHA in the source branch'
- requires :start_sha, type: String, desc: 'SHA referencing commit in target branch'
- requires :head_sha, type: String, desc: 'SHA referencing HEAD of this merge request'
- requires :position_type, type: String, desc: 'Type of the position reference', values: %w(text image)
- optional :new_path, type: String, desc: 'File path after change'
- optional :new_line, type: Integer, desc: 'Line number after change'
- optional :old_path, type: String, desc: 'File path before change'
- optional :old_line, type: Integer, desc: 'Line number before change'
- optional :width, type: Integer, desc: 'Width of the image'
- optional :height, type: Integer, desc: 'Height of the image'
- optional :x, type: Integer, desc: 'X coordinate in the image'
- optional :y, type: Integer, desc: 'Y coordinate in the image'
-
- optional :line_range, type: Hash, desc: 'Multi-line start and end' do
- optional :start, type: Hash do
- optional :line_code, type: String, desc: 'Start line code for multi-line note'
- optional :type, type: String, desc: 'Start line type for multi-line note'
- optional :old_line, type: String, desc: 'Start old_line line number'
- optional :new_line, type: String, desc: 'Start new_line line number'
- end
- optional :end, type: Hash do
- optional :line_code, type: String, desc: 'End line code for multi-line note'
- optional :type, type: String, desc: 'End line type for multi-line note'
- optional :old_line, type: String, desc: 'End old_line line number'
- optional :new_line, type: String, desc: 'End new_line line number'
+
+ if [Commit, MergeRequest].include?(noteable_type)
+ optional :position, type: Hash do
+ requires :base_sha, type: String, desc: 'Base commit SHA in the source branch'
+ requires :start_sha, type: String, desc: 'SHA referencing commit in target branch'
+ requires :head_sha, type: String, desc: 'SHA referencing HEAD of this merge request'
+ requires :position_type, type: String, desc: 'Type of the position reference', values: %w(text image)
+ optional :new_path, type: String, desc: 'File path after change'
+ optional :new_line, type: Integer, desc: 'Line number after change'
+ optional :old_path, type: String, desc: 'File path before change'
+ optional :old_line, type: Integer, desc: 'Line number before change'
+ optional :width, type: Integer, desc: 'Width of the image'
+ optional :height, type: Integer, desc: 'Height of the image'
+ optional :x, type: Integer, desc: 'X coordinate in the image'
+ optional :y, type: Integer, desc: 'Y coordinate in the image'
+
+ if noteable_type == MergeRequest
+ optional :line_range, type: Hash, desc: 'Multi-line start and end' do
+ optional :start, type: Hash do
+ optional :line_code, type: String, desc: 'Start line code for multi-line note'
+ optional :type, type: String, desc: 'Start line type for multi-line note'
+ optional :old_line, type: String, desc: 'Start old_line line number'
+ optional :new_line, type: String, desc: 'Start new_line line number'
+ end
+ optional :end, type: Hash do
+ optional :line_code, type: String, desc: 'End line code for multi-line note'
+ optional :type, type: String, desc: 'End line type for multi-line note'
+ optional :old_line, type: String, desc: 'End old_line line number'
+ optional :new_line, type: String, desc: 'End new_line line number'
+ end
+ end
end
end
end
@@ -122,12 +129,12 @@ module API
end
end
- desc "Get comments in a single #{noteable_type.to_s.downcase} discussion" do
+ desc "Get comments in a single #{notable_name} discussion" do
success Entities::Discussion
end
params do
requires :discussion_id, type: String, desc: 'The ID of a discussion'
- requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
+ requires :noteable_id, type: notable_id_type, desc: "The ID of the #{notable_name}"
end
get ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id/notes", feature_category: feature_category do
noteable = find_noteable(noteable_type, params[:noteable_id])
@@ -140,11 +147,11 @@ module API
present notes, with: Entities::Note
end
- desc "Add a comment to a #{noteable_type.to_s.downcase} discussion" do
+ desc "Add a comment to a #{notable_name} discussion" do
success Entities::Note
end
params do
- requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
+ requires :noteable_id, type: notable_id_type, desc: "The ID of the #{notable_name}"
requires :discussion_id, type: String, desc: 'The ID of a discussion'
requires :body, type: String, desc: 'The content of a note'
optional :created_at, type: String, desc: 'The creation date of the note'
@@ -175,11 +182,11 @@ module API
end
end
- desc "Get a comment in a #{noteable_type.to_s.downcase} discussion" do
+ desc "Get a comment in a #{notable_name} discussion" do
success Entities::Note
end
params do
- requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
+ requires :noteable_id, type: notable_id_type, desc: "The ID of the #{notable_name}"
requires :discussion_id, type: String, desc: 'The ID of a discussion'
requires :note_id, type: Integer, desc: 'The ID of a note'
end
@@ -189,11 +196,11 @@ module API
get_note(noteable, params[:note_id])
end
- desc "Edit a comment in a #{noteable_type.to_s.downcase} discussion" do
+ desc "Edit a comment in a #{notable_name} discussion" do
success Entities::Note
end
params do
- requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
+ requires :noteable_id, type: notable_id_type, desc: "The ID of the #{notable_name}"
requires :discussion_id, type: String, desc: 'The ID of a discussion'
requires :note_id, type: Integer, desc: 'The ID of a note'
optional :body, type: String, desc: 'The content of a note'
@@ -210,11 +217,11 @@ module API
end
end
- desc "Delete a comment in a #{noteable_type.to_s.downcase} discussion" do
+ desc "Delete a comment in a #{notable_name} discussion" do
success Entities::Note
end
params do
- requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
+ requires :noteable_id, type: notable_id_type, desc: "The ID of the #{notable_name}"
requires :discussion_id, type: String, desc: 'The ID of a discussion'
requires :note_id, type: Integer, desc: 'The ID of a note'
end
@@ -225,11 +232,11 @@ module API
end
if Noteable.resolvable_types.include?(noteable_type.to_s)
- desc "Resolve/unresolve an existing #{noteable_type.to_s.downcase} discussion" do
+ desc "Resolve/unresolve an existing #{notable_name} discussion" do
success Entities::Discussion
end
params do
- requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
+ requires :noteable_id, type: notable_id_type, desc: "The ID of the #{notable_name}"
requires :discussion_id, type: String, desc: 'The ID of a discussion'
requires :resolved, type: Boolean, desc: 'Mark discussion resolved/unresolved'
end
diff --git a/lib/api/entities/application.rb b/lib/api/entities/application.rb
index 33514200424..c3d8f9667c3 100644
--- a/lib/api/entities/application.rb
+++ b/lib/api/entities/application.rb
@@ -4,10 +4,12 @@ module API
module Entities
class Application < Grape::Entity
expose :id
- expose :uid, as: :application_id
- expose :name, as: :application_name
- expose :redirect_uri, as: :callback_url
- expose :confidential
+ expose :uid, as: :application_id,
+ documentation: { type: 'string',
+ example: '5832fc6e14300a0d962240a8144466eef4ee93ef0d218477e55f11cf12fc3737' }
+ expose :name, as: :application_name, documentation: { type: 'string', example: 'MyApplication' }
+ expose :redirect_uri, as: :callback_url, documentation: { type: 'string', example: 'https://redirect.uri' }
+ expose :confidential, documentation: { type: 'boolean', example: true }
end
end
end
diff --git a/lib/api/entities/application_statistics.rb b/lib/api/entities/application_statistics.rb
index 4bcba1da464..7e75ef23675 100644
--- a/lib/api/entities/application_statistics.rb
+++ b/lib/api/entities/application_statistics.rb
@@ -6,47 +6,57 @@ module API
include ActionView::Helpers::NumberHelper
include CountHelper
- expose :forks do |counts|
+ expose :forks,
+ documentation: { type: 'integer', example: 6, desc: 'Approximate number of repo forks' } do |counts|
approximate_fork_count_with_delimiters(counts)
end
- expose :issues do |counts|
+ expose :issues,
+ documentation: { type: 'integer', example: 121, desc: 'Approximate number of issues' } do |counts|
approximate_count_with_delimiters(counts, ::Issue)
end
- expose :merge_requests do |counts|
+ expose :merge_requests,
+ documentation: { type: 'integer', example: 49, desc: 'Approximate number of merge requests' } do |counts|
approximate_count_with_delimiters(counts, ::MergeRequest)
end
- expose :notes do |counts|
+ expose :notes,
+ documentation: { type: 'integer', example: 6, desc: 'Approximate number of notes' } do |counts|
approximate_count_with_delimiters(counts, ::Note)
end
- expose :snippets do |counts|
+ expose :snippets,
+ documentation: { type: 'integer', example: 4, desc: 'Approximate number of snippets' } do |counts|
approximate_count_with_delimiters(counts, ::Snippet)
end
- expose :ssh_keys do |counts|
+ expose :ssh_keys,
+ documentation: { type: 'integer', example: 11, desc: 'Approximate number of SSH keys' } do |counts|
approximate_count_with_delimiters(counts, ::Key)
end
- expose :milestones do |counts|
+ expose :milestones,
+ documentation: { type: 'integer', example: 3, desc: 'Approximate number of milestones' } do |counts|
approximate_count_with_delimiters(counts, ::Milestone)
end
- expose :users do |counts|
+ expose :users, documentation: { type: 'integer', example: 22, desc: 'Approximate number of users' } do |counts|
approximate_count_with_delimiters(counts, ::User)
end
- expose :projects do |counts|
+ expose :projects,
+ documentation: { type: 'integer', example: 4, desc: 'Approximate number of projects' } do |counts|
approximate_count_with_delimiters(counts, ::Project)
end
- expose :groups do |counts|
+ expose :groups,
+ documentation: { type: 'integer', example: 1, desc: 'Approximate number of projects' } do |counts|
approximate_count_with_delimiters(counts, ::Group)
end
- expose :active_users do |_|
+ expose :active_users,
+ documentation: { type: 'integer', example: 21, desc: 'Number of active users' } do |_|
number_with_delimiter(::User.active.count)
end
end
diff --git a/lib/api/entities/application_with_secret.rb b/lib/api/entities/application_with_secret.rb
index 3e540381d89..1d0acee8624 100644
--- a/lib/api/entities/application_with_secret.rb
+++ b/lib/api/entities/application_with_secret.rb
@@ -4,7 +4,8 @@ module API
module Entities
# Use with care, this exposes the secret
class ApplicationWithSecret < Entities::Application
- expose :secret
+ expose :secret, documentation: { type: 'string',
+ example: 'ee1dd64b6adc89cf7e2c23099301ccc2c61b441064e9324d963c46902a85ec34' }
end
end
end
diff --git a/lib/api/entities/basic_project_details.rb b/lib/api/entities/basic_project_details.rb
index e96504db53e..2585b2d0b6d 100644
--- a/lib/api/entities/basic_project_details.rb
+++ b/lib/api/entities/basic_project_details.rb
@@ -6,15 +6,18 @@ module API
include ::API::ProjectsRelationBuilder
include Gitlab::Utils::StrongMemoize
- expose :default_branch_or_main, as: :default_branch, if: -> (project, options) { Ability.allowed?(options[:current_user], :download_code, project) }
+ expose :default_branch_or_main, documentation: { type: 'string', example: 'main' }, as: :default_branch, if: -> (project, options) { Ability.allowed?(options[:current_user], :read_code, project) }
# Avoids an N+1 query: https://github.com/mbleigh/acts-as-taggable-on/issues/91#issuecomment-168273770
- expose :topic_names, as: :tag_list
- expose :topic_names, as: :topics
+ expose :topic_names, as: :tag_list, documentation: { type: 'string', is_array: true, example: 'tag' }
+ expose :topic_names, as: :topics, documentation: { type: 'string', is_array: true, example: 'topic' }
- expose :ssh_url_to_repo, :http_url_to_repo, :web_url, :readme_url
+ expose :ssh_url_to_repo, documentation: { type: 'string', example: 'git@gitlab.example.com:gitlab/gitlab.git' }
+ expose :http_url_to_repo, documentation: { type: 'string', example: 'https://gitlab.example.com/gitlab/gitlab.git' }
+ expose :web_url, documentation: { type: 'string', example: 'https://gitlab.example.com/gitlab/gitlab' }
+ expose :readme_url, documentation: { type: 'string', example: 'https://gitlab.example.com/gitlab/gitlab/blob/master/README.md' }
- expose :license_url, if: :license do |project|
+ expose :license_url, if: :license, documentation: { type: 'string', example: 'https://gitlab.example.com/gitlab/gitlab/blob/master/LICENCE' } do |project|
license = project.repository.license_blob
if license
@@ -26,13 +29,13 @@ module API
project.repository.license
end
- expose :avatar_url do |project, options|
+ expose :avatar_url, documentation: { type: 'string', example: 'http://example.com/uploads/project/avatar/3/uploads/avatar.png' } do |project, options|
project.avatar_url(only_path: false)
end
- expose :forks_count
- expose :star_count
- expose :last_activity_at
+ expose :forks_count, documentation: { type: 'integer', example: 1 }
+ expose :star_count, documentation: { type: 'integer', example: 1 }
+ expose :last_activity_at, documentation: { type: 'dateTime', example: '2013-09-30T13:46:02Z' }
expose :namespace, using: 'API::Entities::NamespaceBasic'
expose :custom_attributes, using: 'API::Entities::CustomAttribute', if: :with_custom_attributes
@@ -57,6 +60,8 @@ module API
super
end
+ def self.postload_relation(projects_relation, options = {}) end
+
private
alias_method :project, :object
diff --git a/lib/api/entities/basic_ref.rb b/lib/api/entities/basic_ref.rb
index 79c15075d99..1b821a5b0ec 100644
--- a/lib/api/entities/basic_ref.rb
+++ b/lib/api/entities/basic_ref.rb
@@ -3,7 +3,8 @@
module API
module Entities
class BasicRef < Grape::Entity
- expose :type, :name
+ expose :type, documentation: { type: 'string', example: 'tag' }
+ expose :name, documentation: { type: 'string', example: 'v1.1.0' }
end
end
end
diff --git a/lib/api/entities/basic_release_details.rb b/lib/api/entities/basic_release_details.rb
index d13080f32f4..dba19b3abd7 100644
--- a/lib/api/entities/basic_release_details.rb
+++ b/lib/api/entities/basic_release_details.rb
@@ -5,12 +5,12 @@ module API
class BasicReleaseDetails < Grape::Entity
include ::API::Helpers::Presentable
- expose :name
- expose :tag, as: :tag_name
- expose :description
- expose :created_at
- expose :released_at
- expose :upcoming_release?, as: :upcoming_release
+ expose :name, documentation: { type: 'string', example: 'Release v1.0' }
+ expose :tag, documentation: { type: 'string', example: 'v1.0' }, as: :tag_name
+ expose :description, documentation: { type: 'string', example: 'Finally released v1.0' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2019-01-03T01:56:19.539Z' }
+ expose :released_at, documentation: { type: 'dateTime', example: '2019-01-03T01:56:19.539Z' }
+ expose :upcoming_release?, documentation: { type: 'boolean' }, as: :upcoming_release
end
end
end
diff --git a/lib/api/entities/basic_repository_storage_move.rb b/lib/api/entities/basic_repository_storage_move.rb
index 3ee112fb9a2..83b4f428a56 100644
--- a/lib/api/entities/basic_repository_storage_move.rb
+++ b/lib/api/entities/basic_repository_storage_move.rb
@@ -3,11 +3,11 @@
module API
module Entities
class BasicRepositoryStorageMove < Grape::Entity
- expose :id
- expose :created_at
- expose :human_state_name, as: :state
- expose :source_storage_name
- expose :destination_storage_name
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :created_at, documentation: { type: 'dateTime', example: '2020-05-07T04:27:17.234Z' }
+ expose :human_state_name, as: :state, documentation: { type: 'string', example: 'scheduled' }
+ expose :source_storage_name, documentation: { type: 'string', example: 'default' }
+ expose :destination_storage_name, documentation: { type: 'string', example: 'storage1' }
end
end
end
diff --git a/lib/api/entities/basic_snippet.rb b/lib/api/entities/basic_snippet.rb
index 26297514798..0e9977fd81b 100644
--- a/lib/api/entities/basic_snippet.rb
+++ b/lib/api/entities/basic_snippet.rb
@@ -3,16 +3,30 @@
module API
module Entities
class BasicSnippet < Grape::Entity
- expose :id, :title, :description, :visibility
- expose :updated_at, :created_at
- expose :project_id
- expose :web_url do |snippet|
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :title, documentation: { type: 'string', example: 'test' }
+ expose :description, documentation: { type: 'string', example: 'Ruby test snippet' }
+ expose :visibility, documentation: { type: 'string', example: 'public' }
+ expose :author, using: Entities::UserBasic, documentation: { type: 'Entities::UserBasic' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2012-06-28T10:52:04Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2012-06-28T10:52:04Z' }
+ expose :project_id, documentation: { type: 'integer', example: 1 }
+ expose :web_url, documentation: {
+ type: 'string', example: 'http://example.com/example/example/snippets/1'
+ } do |snippet|
Gitlab::UrlBuilder.build(snippet)
end
- expose :raw_url do |snippet|
+ expose :raw_url, documentation: {
+ type: 'string', example: 'http://example.com/example/example/snippets/1/raw'
+ } do |snippet|
Gitlab::UrlBuilder.build(snippet, raw: true)
end
- expose :ssh_url_to_repo, :http_url_to_repo, if: ->(snippet) { snippet.repository_exists? }
+ expose :ssh_url_to_repo, documentation: {
+ type: 'string', example: 'ssh://user@gitlab.example.com/snippets/65.git'
+ }, if: ->(snippet) { snippet.repository_exists? }
+ expose :http_url_to_repo, documentation: {
+ type: 'string', example: 'https://gitlab.example.com/snippets/65.git'
+ }, if: ->(snippet) { snippet.repository_exists? }
end
end
end
diff --git a/lib/api/entities/branch.rb b/lib/api/entities/branch.rb
index 6a75dcddeda..01eaf5c8d31 100644
--- a/lib/api/entities/branch.rb
+++ b/lib/api/entities/branch.rb
@@ -5,13 +5,17 @@ module API
class Branch < Grape::Entity
include Gitlab::Routing
- expose :name
+ expose :name, documentation: { type: 'string', example: 'master' }
expose :commit, using: Entities::Commit do |repo_branch, options|
options[:project].repository.commit(repo_branch.dereferenced_target)
end
- expose :merged do |repo_branch, options|
+ expose :merged,
+ documentation: {
+ type: 'boolean',
+ example: true
+ } do |repo_branch, options|
if options[:merged_branch_names]
options[:merged_branch_names].include?(repo_branch.name)
else
@@ -19,27 +23,51 @@ module API
end
end
- expose :protected do |repo_branch, options|
+ expose :protected,
+ documentation: {
+ type: 'boolean',
+ example: true
+ } do |repo_branch, options|
::ProtectedBranch.protected?(options[:project], repo_branch.name)
end
- expose :developers_can_push do |repo_branch, options|
+ expose :developers_can_push,
+ documentation: {
+ type: 'boolean',
+ example: true
+ } do |repo_branch, options|
::ProtectedBranch.developers_can?(:push, repo_branch.name, protected_refs: options[:project].protected_branches)
end
- expose :developers_can_merge do |repo_branch, options|
+ expose :developers_can_merge,
+ documentation: {
+ type: 'boolean',
+ example: true
+ } do |repo_branch, options|
::ProtectedBranch.developers_can?(:merge, repo_branch.name, protected_refs: options[:project].protected_branches)
end
- expose :can_push do |repo_branch, options|
+ expose :can_push,
+ documentation: {
+ type: 'boolean',
+ example: true
+ } do |repo_branch, options|
Gitlab::UserAccess.new(options[:current_user], container: options[:project]).can_push_to_branch?(repo_branch.name)
end
- expose :default do |repo_branch, options|
+ expose :default,
+ documentation: {
+ type: 'boolean',
+ example: true
+ } do |repo_branch, options|
options[:project].default_branch == repo_branch.name
end
- expose :web_url do |repo_branch|
+ expose :web_url,
+ documentation: {
+ type: 'string',
+ example: 'https://gitlab.example.com/Commit921/the-dude/-/tree/master'
+ } do |repo_branch|
project_tree_url(options[:project], repo_branch.name)
end
end
diff --git a/lib/api/entities/bulk_import.rb b/lib/api/entities/bulk_import.rb
index 373ae486dcf..75989cb4180 100644
--- a/lib/api/entities/bulk_import.rb
+++ b/lib/api/entities/bulk_import.rb
@@ -3,11 +3,13 @@
module API
module Entities
class BulkImport < Grape::Entity
- expose :id
- expose :status_name, as: :status
- expose :source_type
- expose :created_at
- expose :updated_at
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :status_name, as: :status, documentation: {
+ type: 'string', example: 'finished', values: %w[created started finished timeout failed]
+ }
+ expose :source_type, documentation: { type: 'string', example: 'gitlab' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
end
end
end
diff --git a/lib/api/entities/bulk_imports/entity.rb b/lib/api/entities/bulk_imports/entity.rb
index 142bfaf2149..8f9fbe57935 100644
--- a/lib/api/entities/bulk_imports/entity.rb
+++ b/lib/api/entities/bulk_imports/entity.rb
@@ -4,19 +4,21 @@ module API
module Entities
module BulkImports
class Entity < Grape::Entity
- expose :id
- expose :bulk_import_id
- expose :status_name, as: :status
- expose :source_full_path
- expose :destination_name # deprecated
- expose :destination_slug
- expose :destination_namespace
- expose :parent_id
- expose :namespace_id
- expose :project_id
- expose :created_at
- expose :updated_at
- expose :failures, using: EntityFailure
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :bulk_import_id, documentation: { type: 'integer', example: 1 }
+ expose :status_name, as: :status, documentation: {
+ type: 'string', example: 'created', values: %w[created started finished timeout failed]
+ }
+ expose :source_full_path, documentation: { type: 'string', example: 'source_group' }
+ expose :destination_name, documentation: { type: 'string', example: 'destination_slug' } # deprecated
+ expose :destination_slug, documentation: { type: 'string', example: 'destination_slug' }
+ expose :destination_namespace, documentation: { type: 'string', example: 'destination_path' }
+ expose :parent_id, documentation: { type: 'integer', example: 1 }
+ expose :namespace_id, documentation: { type: 'integer', example: 1 }
+ expose :project_id, documentation: { type: 'integer', example: 1 }
+ expose :created_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ expose :failures, using: EntityFailure, documentation: { is_array: true }
end
end
end
diff --git a/lib/api/entities/bulk_imports/entity_failure.rb b/lib/api/entities/bulk_imports/entity_failure.rb
index 56312745868..3e69e7fa2aa 100644
--- a/lib/api/entities/bulk_imports/entity_failure.rb
+++ b/lib/api/entities/bulk_imports/entity_failure.rb
@@ -4,16 +4,18 @@ module API
module Entities
module BulkImports
class EntityFailure < Grape::Entity
- expose :relation
- expose :pipeline_step, as: :step
- expose :exception_message do |failure|
+ expose :relation, documentation: { type: 'string', example: 'group' }
+ expose :pipeline_step, as: :step, documentation: { type: 'string', example: 'extractor' }
+ expose :exception_message, documentation: { type: 'string', example: 'error message' } do |failure|
::Projects::ImportErrorFilter.filter_message(failure.exception_message.truncate(72))
end
- expose :exception_class
- expose :correlation_id_value
- expose :created_at
- expose :pipeline_class
- expose :pipeline_step
+ expose :exception_class, documentation: { type: 'string', example: 'Exception' }
+ expose :correlation_id_value, documentation: { type: 'string', example: 'dfcf583058ed4508e4c7c617bd7f0edd' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ expose :pipeline_class, documentation: {
+ type: 'string', example: 'BulkImports::Groups::Pipelines::GroupPipeline'
+ }
+ expose :pipeline_step, documentation: { type: 'string', example: 'extractor' }
end
end
end
diff --git a/lib/api/entities/bulk_imports/export_status.rb b/lib/api/entities/bulk_imports/export_status.rb
index c9c7f34a16a..fee983c6fd8 100644
--- a/lib/api/entities/bulk_imports/export_status.rb
+++ b/lib/api/entities/bulk_imports/export_status.rb
@@ -4,10 +4,10 @@ module API
module Entities
module BulkImports
class ExportStatus < Grape::Entity
- expose :relation
- expose :status
- expose :error
- expose :updated_at
+ expose :relation, documentation: { type: 'string', example: 'issues' }
+ 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' }
end
end
end
diff --git a/lib/api/entities/ci/job.rb b/lib/api/entities/ci/job.rb
index cf87684ce55..d9e6b7eed75 100644
--- a/lib/api/entities/ci/job.rb
+++ b/lib/api/entities/ci/job.rb
@@ -6,10 +6,17 @@ module API
class Job < JobBasic
# artifacts_file is included in job_artifacts, but kept for backward compatibility (remove in api/v5)
expose :artifacts_file, using: ::API::Entities::Ci::JobArtifactFile, if: -> (job, opts) { job.artifacts? }
- expose :job_artifacts, as: :artifacts, using: ::API::Entities::Ci::JobArtifact
+ expose :job_artifacts, as: :artifacts,
+ using: ::API::Entities::Ci::JobArtifact,
+ documentation: { is_array: true }
expose :runner, with: ::API::Entities::Ci::Runner
- expose :artifacts_expire_at
- expose :tag_list do |job|
+ expose :artifacts_expire_at,
+ documentation: { type: 'dateTime', example: '2016-01-19T09:05:50.355Z' }
+
+ expose(
+ :tag_list,
+ documentation: { type: 'string', is_array: true, example: ['ubuntu18', 'docker runner'] }
+ ) do |job|
job.tags.map(&:name).sort
end
end
diff --git a/lib/api/entities/ci/job_artifact.rb b/lib/api/entities/ci/job_artifact.rb
index 9e504aee383..8276c0f4073 100644
--- a/lib/api/entities/ci/job_artifact.rb
+++ b/lib/api/entities/ci/job_artifact.rb
@@ -4,7 +4,12 @@ module API
module Entities
module Ci
class JobArtifact < Grape::Entity
- expose :file_type, :size, :filename, :file_format
+ expose :file_type,
+ documentation: { type: 'string', values: ::Ci::JobArtifact.file_types.keys, example: 'archive' }
+ expose :size, documentation: { type: 'integer', example: 1000 }
+ expose :filename, documentation: { type: 'string', example: 'artifacts.zip' }
+ expose :file_format,
+ documentation: { type: 'string', values: ::Ci::JobArtifact.file_formats.keys, example: 'zip' }
end
end
end
diff --git a/lib/api/entities/ci/job_artifact_file.rb b/lib/api/entities/ci/job_artifact_file.rb
index 418eb408ab6..0266f99cd6d 100644
--- a/lib/api/entities/ci/job_artifact_file.rb
+++ b/lib/api/entities/ci/job_artifact_file.rb
@@ -4,8 +4,8 @@ module API
module Entities
module Ci
class JobArtifactFile < Grape::Entity
- expose :filename
- expose :cached_size, as: :size
+ expose :filename, documentation: { type: 'string', example: 'artifacts.zip' }
+ expose :cached_size, as: :size, documentation: { type: 'integer', example: 1000 }
end
end
end
diff --git a/lib/api/entities/ci/job_basic.rb b/lib/api/entities/ci/job_basic.rb
index fb975475cf5..3cbb8aad313 100644
--- a/lib/api/entities/ci/job_basic.rb
+++ b/lib/api/entities/ci/job_basic.rb
@@ -4,23 +4,36 @@ module API
module Entities
module Ci
class JobBasic < Grape::Entity
- expose :id, :status, :stage, :name, :ref, :tag, :coverage, :allow_failure
- expose :created_at, :started_at, :finished_at
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :status, documentation: { type: 'string', example: 'waiting_for_resource' }
+ expose :stage, documentation: { type: 'string', example: 'deploy' }
+ expose :name, documentation: { type: 'string', example: 'deploy_to_production' }
+ expose :ref, documentation: { type: 'string', example: 'main' }
+ expose :tag, documentation: { type: 'boolean' }
+ expose :coverage, documentation: { type: 'number', format: 'float', example: 98.29 }
+ expose :allow_failure, documentation: { type: 'boolean' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2015-12-24T15:51:21.880Z' }
+ expose :started_at, documentation: { type: 'dateTime', example: '2015-12-24T17:54:30.733Z' }
+ expose :finished_at, documentation: { type: 'dateTime', example: '2015-12-24T17:54:31.198Z' }
expose :duration,
- documentation: { type: 'Floating', desc: 'Time spent running' }
+ documentation: { type: 'number', format: 'float', desc: 'Time spent running', example: 0.465 }
expose :queued_duration,
- documentation: { type: 'Floating', desc: 'Time spent enqueued' }
+ documentation: { type: 'number', format: 'float', desc: 'Time spent enqueued', example: 0.123 }
expose :user, with: ::API::Entities::User
expose :commit, with: ::API::Entities::Commit
expose :pipeline, with: ::API::Entities::Ci::PipelineBasic
- expose :failure_reason, if: -> (job) { job.failed? }
+ expose :failure_reason,
+ documentation: { type: 'string', example: 'script_failure' }, if: -> (job) { job.failed? }
- expose :web_url do |job, _options|
+ expose(
+ :web_url,
+ documentation: { type: 'string', example: 'https://example.com/foo/bar/-/jobs/1' }
+ ) do |job, _options|
Gitlab::Routing.url_helpers.project_job_url(job.project, job)
end
expose :project do
- expose :ci_job_token_scope_enabled do |job|
+ expose :ci_job_token_scope_enabled, documentation: { type: 'string', example: false } do |job|
job.project.ci_outbound_job_token_scope_enabled?
end
end
diff --git a/lib/api/entities/ci/lint/result.rb b/lib/api/entities/ci/lint/result.rb
index b44a6e13463..698b02d3b4a 100644
--- a/lib/api/entities/ci/lint/result.rb
+++ b/lib/api/entities/ci/lint/result.rb
@@ -5,12 +5,17 @@ module API
module Ci
module Lint
class Result < Grape::Entity
- expose :valid?, as: :valid
- expose :errors
- expose :warnings
- expose :merged_yaml
- expose :includes
- expose :jobs, if: -> (result, options) { options[:include_jobs] }
+ expose :valid?, as: :valid, documentation: { type: 'boolean' }
+ expose :errors, documentation: { is_array: true, type: 'string',
+ example: 'variables config should be a hash of key value pairs' }
+ expose :warnings, documentation: { is_array: true, type: 'string',
+ example: 'jobs:job may allow multiple pipelines ...' }
+ expose :merged_yaml, documentation: { type: 'string', example: '---\n:another_test:\n :stage: test\n
+ :script: echo 2\n:test:\n :stage: test\n :script: echo 1\n' }
+ expose :includes, documentation: { is_array: true, type: 'object',
+ example: '{ "blob": "https://gitlab.com/root/example-project/-/blob/...' }
+ expose :jobs, if: -> (result, options) { options[:include_jobs] },
+ documentation: { is_array: true, type: 'object', example: '{ "name": "test: .... }' }
end
end
end
diff --git a/lib/api/entities/ci/pipeline.rb b/lib/api/entities/ci/pipeline.rb
index a8033a21044..7631cf60dbd 100644
--- a/lib/api/entities/ci/pipeline.rb
+++ b/lib/api/entities/ci/pipeline.rb
@@ -4,13 +4,21 @@ module API
module Entities
module Ci
class Pipeline < PipelineBasic
- expose :before_sha, :tag, :yaml_errors
+ expose :before_sha, documentation: { type: 'string', example: 'a91957a858320c0e17f3a0eca7cfacbff50ea29a' }
+ expose :tag, documentation: { type: 'boolean', example: false }
+ expose :yaml_errors, documentation: { type: 'string', example: "widgets:build: needs 'widgets:test'" }
expose :user, with: Entities::UserBasic
- expose :created_at, :updated_at, :started_at, :finished_at, :committed_at
- expose :duration
- expose :queued_duration
- expose :coverage do |pipeline|
+ expose :created_at, documentation: { type: 'dateTime', example: '2015-12-24T15:51:21.880Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2015-12-24T17:54:31.198Z' }
+ expose :started_at, documentation: { type: 'dateTime', example: '2015-12-24T17:54:30.733Z' }
+ expose :finished_at, documentation: { type: 'dateTime', example: '2015-12-24T17:54:31.198Z' }
+ expose :committed_at, documentation: { type: 'dateTime', example: '2015-12-24T15:51:21.880Z' }
+ expose :duration,
+ documentation: { type: 'integer', desc: 'Time spent running in seconds', example: 127 }
+ expose :queued_duration,
+ documentation: { type: 'integer', desc: 'Time spent enqueued in seconds', example: 63 }
+ expose :coverage, documentation: { type: 'number', format: 'float', example: 98.29 } do |pipeline|
pipeline.present.coverage
end
expose :detailed_status, using: DetailedStatusEntity do |pipeline, options|
diff --git a/lib/api/entities/ci/pipeline_basic.rb b/lib/api/entities/ci/pipeline_basic.rb
index a2a5a98920a..6d82cca1bf1 100644
--- a/lib/api/entities/ci/pipeline_basic.rb
+++ b/lib/api/entities/ci/pipeline_basic.rb
@@ -4,10 +4,21 @@ module API
module Entities
module Ci
class PipelineBasic < Grape::Entity
- expose :id, :iid, :project_id, :sha, :ref, :status, :source
- expose :created_at, :updated_at
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :iid, documentation: { type: 'integer', example: 2 }
+ expose :project_id, documentation: { type: 'integer', example: 3 }
+ expose :sha, documentation: { type: 'string', example: '0ec9e58fdfca6cdd6652c083c9edb53abc0bad52' }
+ expose :ref, documentation: { type: 'string', example: 'feature-branch' }
+ expose :status, documentation: { type: 'string', example: 'success' }
+ expose :source, documentation: { type: 'string', example: 'push' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2022-10-21T16:49:48.000+02:00' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2022-10-21T16:49:48.000+02:00' }
- expose :web_url do |pipeline, _options|
+ expose :web_url,
+ documentation: {
+ type: 'string',
+ example: 'https://gitlab.example.com/gitlab-org/gitlab-foss/-/pipelines/61'
+ } do |pipeline, _options|
Gitlab::Routing.url_helpers.project_pipeline_url(pipeline.project, pipeline)
end
end
diff --git a/lib/api/entities/ci/pipeline_schedule.rb b/lib/api/entities/ci/pipeline_schedule.rb
index f1596b7d285..58496bded03 100644
--- a/lib/api/entities/ci/pipeline_schedule.rb
+++ b/lib/api/entities/ci/pipeline_schedule.rb
@@ -4,9 +4,15 @@ module API
module Entities
module Ci
class PipelineSchedule < Grape::Entity
- expose :id
- expose :description, :ref, :cron, :cron_timezone, :next_run_at, :active
- expose :created_at, :updated_at
+ expose :id, documentation: { type: 'integer', example: 13 }
+ expose :description, documentation: { type: 'string', example: 'Test schedule pipeline' }
+ expose :ref, documentation: { type: 'string', example: 'develop' }
+ expose :cron, documentation: { type: 'string', example: '* * * * *' }
+ expose :cron_timezone, documentation: { type: 'string', example: 'Asia/Tokyo' }
+ expose :next_run_at, documentation: { type: 'dateTime', example: '2017-05-19T13:41:00.000Z' }
+ expose :active, documentation: { type: 'boolean', example: true }
+ expose :created_at, documentation: { type: 'dateTime', example: '2017-05-19T13:31:08.849Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2017-05-19T13:40:17.727Z' }
expose :owner, using: ::API::Entities::UserBasic
end
end
diff --git a/lib/api/entities/ci/resource_group.rb b/lib/api/entities/ci/resource_group.rb
index 0afadfa9e2a..c14e32d32b1 100644
--- a/lib/api/entities/ci/resource_group.rb
+++ b/lib/api/entities/ci/resource_group.rb
@@ -4,7 +4,11 @@ module API
module Entities
module Ci
class ResourceGroup < Grape::Entity
- expose :id, :key, :process_mode, :created_at, :updated_at
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :key, documentation: { type: 'string', example: 'production' }
+ expose :process_mode, documentation: { type: 'string', example: 'unordered' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2021-09-01T08:04:59.650Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2021-09-01T08:04:59.650Z' }
end
end
end
diff --git a/lib/api/entities/ci/runner.rb b/lib/api/entities/ci/runner.rb
index f034eb5c94c..9361709b6ed 100644
--- a/lib/api/entities/ci/runner.rb
+++ b/lib/api/entities/ci/runner.rb
@@ -4,20 +4,22 @@ module API
module Entities
module Ci
class Runner < Grape::Entity
- expose :id
- expose :description
- expose :ip_address
- expose :active # TODO Remove in v5 in favor of `paused` for REST calls, see https://gitlab.com/gitlab-org/gitlab/-/issues/375709
- expose :paused do |runner|
+ expose :id, documentation: { type: 'integer', example: 8 }
+ expose :description, documentation: { type: 'string', example: 'test-1-20150125' }
+ 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 }
+ expose :paused, documentation: { type: 'boolean', example: false } do |runner|
!runner.active
end
- expose :instance_type?, as: :is_shared
- expose :runner_type
- expose :name
- expose :online?, as: :online
+ expose :instance_type?, as: :is_shared, documentation: { type: 'boolean', example: true }
+ expose :runner_type,
+ documentation: { type: 'string', values: ::Ci::Runner.runner_types.keys, example: 'instance_type' }
+ expose :name, documentation: { type: 'string', example: 'test' }
+ expose :online?, as: :online, documentation: { type: 'boolean', example: true }
# DEPRECATED
# TODO Remove in v5 in favor of `status` for REST calls, see https://gitlab.com/gitlab-org/gitlab/-/issues/375709
- expose :deprecated_rest_status, as: :status
+ expose :deprecated_rest_status, as: :status, documentation: { type: 'string', example: 'online' }
end
end
end
diff --git a/lib/api/entities/ci/secure_file.rb b/lib/api/entities/ci/secure_file.rb
index 639615e5779..d957e4488fd 100644
--- a/lib/api/entities/ci/secure_file.rb
+++ b/lib/api/entities/ci/secure_file.rb
@@ -9,6 +9,8 @@ module API
expose :checksum
expose :checksum_algorithm
expose :created_at
+ expose :expires_at
+ expose :metadata
end
end
end
diff --git a/lib/api/entities/ci/variable.rb b/lib/api/entities/ci/variable.rb
index f4d5248245a..47597cb77be 100644
--- a/lib/api/entities/ci/variable.rb
+++ b/lib/api/entities/ci/variable.rb
@@ -4,10 +4,16 @@ module API
module Entities
module Ci
class Variable < Grape::Entity
- expose :variable_type, :key, :value
- expose :protected?, as: :protected, if: -> (entity, _) { entity.respond_to?(:protected?) }
- expose :masked?, as: :masked, if: -> (entity, _) { entity.respond_to?(:masked?) }
- expose :environment_scope, if: -> (entity, _) { entity.respond_to?(:environment_scope) }
+ expose :variable_type, documentation: { type: 'string', example: 'env_var' }
+ expose :key, documentation: { type: 'string', example: 'TEST_VARIABLE_1' }
+ expose :value, documentation: { type: 'string', example: 'TEST_1' }
+ expose :protected?, as: :protected, if: -> (entity, _) { entity.respond_to?(:protected?) },
+ documentation: { type: 'boolean' }
+ expose :masked?, as: :masked, if: -> (entity, _) { entity.respond_to?(:masked?) },
+ documentation: { type: 'boolean' }
+ 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: '*' }
end
end
end
diff --git a/lib/api/entities/commit.rb b/lib/api/entities/commit.rb
index 6cd180cd584..ab1f51289d7 100644
--- a/lib/api/entities/commit.rb
+++ b/lib/api/entities/commit.rb
@@ -3,15 +3,26 @@
module API
module Entities
class Commit < Grape::Entity
- expose :id, :short_id, :created_at
- expose :parent_ids
- expose :full_title, as: :title
- expose :safe_message, as: :message
- expose :author_name, :author_email, :authored_date
- expose :committer_name, :committer_email, :committed_date
- expose :trailers
+ expose :id, documentation: { type: 'string', example: '2695effb5807a22ff3d138d593fd856244e155e7' }
+ expose :short_id, documentation: { type: 'string', example: '2695effb' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2017-07-26T11:08:53.000+02:00' }
+ expose :parent_ids,
+ documentation: { type: 'string', is_array: true, example: '2a4b78934375d7f53875269ffd4f45fd83a84ebe' }
+ expose :full_title, as: :title, documentation: { type: 'string', example: 'Initial commit' }
+ expose :safe_message, as: :message, documentation: { type: 'string', example: 'Initial commit' }
+ expose :author_name, documentation: { type: 'string', example: 'John Smith' }
+ expose :author_email, documentation: { type: 'string', example: 'john@example.com' }
+ expose :authored_date, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ expose :committer_name, documentation: { type: 'string', example: 'Jack Smith' }
+ expose :committer_email, documentation: { type: 'string', example: 'jack@example.com' }
+ expose :committed_date, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ expose :trailers, documentation: { type: 'object', example: '{ "Merged-By": "Jane Doe janedoe@gitlab.com" }' }
- expose :web_url do |commit, _options|
+ expose :web_url,
+ documentation: {
+ type: 'string',
+ example: 'https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746'
+ } do |commit, _options|
c = commit
c = c.__subject__ if c.is_a?(Gitlab::View::Presenter::Base)
Gitlab::UrlBuilder.build(c)
diff --git a/lib/api/entities/commit_detail.rb b/lib/api/entities/commit_detail.rb
index cc529639359..428c53f7fe3 100644
--- a/lib/api/entities/commit_detail.rb
+++ b/lib/api/entities/commit_detail.rb
@@ -6,10 +6,10 @@ module API
include ::API::Helpers::Presentable
expose :stats, using: Entities::CommitStats, if: :include_stats
- expose :status_for, as: :status
- expose :project_id
+ expose :status_for, as: :status, documentation: { type: 'string', example: 'success' }
+ expose :project_id, documentation: { type: 'integer', example: 1 }
- expose :last_pipeline do |commit, options|
+ expose :last_pipeline, documentation: { type: ::API::Entities::Ci::PipelineBasic.to_s } do |commit, options|
pipeline = commit.last_pipeline if can_read_pipeline?
::API::Entities::Ci::PipelineBasic.represent(pipeline, options)
end
diff --git a/lib/api/entities/commit_note.rb b/lib/api/entities/commit_note.rb
index fe91712b48d..0632dc467b8 100644
--- a/lib/api/entities/commit_note.rb
+++ b/lib/api/entities/commit_note.rb
@@ -3,12 +3,22 @@
module API
module Entities
class CommitNote < Grape::Entity
- expose :note
- expose(:path) { |note| note.diff_file.try(:file_path) if note.diff_note? }
- expose(:line) { |note| note.diff_line.try(:line) if note.diff_note? }
- expose(:line_type) { |note| note.diff_line.try(:type) if note.diff_note? }
+ expose :note, documentation: { type: 'string', example: 'this doc is really nice' }
+
+ expose :path, documentation: { type: 'string', example: 'README.md' } do |note|
+ note.diff_file.try(:file_path) if note.diff_note?
+ end
+
+ expose :line, documentation: { type: 'integer', example: 11 } do |note|
+ note.diff_line.try(:line) if note.diff_note?
+ end
+
+ expose :line_type, documentation: { type: 'string', example: 'new' } do |note|
+ note.diff_line.try(:type) if note.diff_note?
+ end
+
expose :author, using: Entities::UserBasic
- expose :created_at
+ expose :created_at, documentation: { type: 'dateTime', example: '2016-01-19T09:44:55.600Z' }
end
end
end
diff --git a/lib/api/entities/commit_signature.rb b/lib/api/entities/commit_signature.rb
index 0d8e977a9f5..9430dd5e2a2 100644
--- a/lib/api/entities/commit_signature.rb
+++ b/lib/api/entities/commit_signature.rb
@@ -3,7 +3,7 @@
module API
module Entities
class CommitSignature < Grape::Entity
- expose :signature_type
+ expose :signature_type, documentation: { type: 'string', example: 'PGP' }
expose :signature, merge: true do |commit, options|
if commit.signature.is_a?(::CommitSignatures::GpgSignature) || commit.raw_commit_from_rugged?
@@ -13,7 +13,7 @@ module API
end
end
- expose :commit_source do |commit, _|
+ expose :commit_source, documentation: { type: 'string', example: 'gitaly' } do |commit, _|
commit.raw_commit_from_rugged? ? "rugged" : "gitaly"
end
diff --git a/lib/api/entities/commit_stats.rb b/lib/api/entities/commit_stats.rb
index d9ba99c8eb0..e07483e5d97 100644
--- a/lib/api/entities/commit_stats.rb
+++ b/lib/api/entities/commit_stats.rb
@@ -3,7 +3,9 @@
module API
module Entities
class CommitStats < Grape::Entity
- expose :additions, :deletions, :total
+ expose :additions, documentation: { type: 'integer', example: 1 }
+ expose :deletions, documentation: { type: 'integer', example: 0 }
+ expose :total, documentation: { type: 'integer', example: 1 }
end
end
end
diff --git a/lib/api/entities/commit_status.rb b/lib/api/entities/commit_status.rb
index 61b8bf89cfe..df6a41895ff 100644
--- a/lib/api/entities/commit_status.rb
+++ b/lib/api/entities/commit_status.rb
@@ -3,8 +3,22 @@
module API
module Entities
class CommitStatus < Grape::Entity
- expose :id, :sha, :ref, :status, :name, :target_url, :description,
- :created_at, :started_at, :finished_at, :allow_failure, :coverage
+ expose :id, documentation: { type: 'integer', example: 93 }
+ expose :sha, documentation: { type: 'string', example: '18f3e63d05582537db6d183d9d557be09e1f90c8' }
+ expose :ref, documentation: { type: 'string', example: 'develop' }
+ expose :status, documentation: { type: 'string', example: 'success' }
+ expose :name, documentation: { type: 'string', example: 'default' }
+ expose :target_url, documentation: {
+ type: 'string',
+ example: 'https://gitlab.example.com/janedoe/gitlab-foss/builds/91'
+ }
+ expose :description, documentation: { type: 'string' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2016-01-19T09:05:50.355Z' }
+ expose :started_at, documentation: { type: 'dateTime', example: '2016-01-20T08:40:25.832Z' }
+ expose :finished_at, documentation: { type: 'dateTime', example: '2016-01-21T08:40:25.832Z' }
+ expose :allow_failure, documentation: { type: 'boolean', example: false }
+ expose :coverage, documentation: { type: 'number', format: 'float', example: 98.29 }
+
expose :author, using: Entities::UserBasic
end
end
diff --git a/lib/api/entities/compare.rb b/lib/api/entities/compare.rb
index 75a36d9bb01..92066868d3c 100644
--- a/lib/api/entities/compare.rb
+++ b/lib/api/entities/compare.rb
@@ -7,21 +7,24 @@ module API
compare.commits.last
end
- expose :commits, using: Entities::Commit do |compare, _|
+ expose :commits, documentation: { is_array: true }, using: Entities::Commit do |compare, _|
compare.commits
end
- expose :diffs, using: Entities::Diff do |compare, _|
+ expose :diffs, documentation: { is_array: true }, using: Entities::Diff do |compare, _|
compare.diffs.diffs.to_a
end
- expose :compare_timeout do |compare, _|
+ expose :compare_timeout, documentation: { type: 'boolean' } do |compare, _|
compare.diffs.diffs.overflow?
end
- expose :same, as: :compare_same_ref
+ expose :same, as: :compare_same_ref, documentation: { type: 'boolean' }
- expose :web_url do |compare, _|
+ expose :web_url,
+ documentation: {
+ example: "https://gitlab.example.com/gitlab/gitlab-foss/-/compare/main...feature"
+ } do |compare, _|
Gitlab::UrlBuilder.build(compare)
end
end
diff --git a/lib/api/entities/container_registry.rb b/lib/api/entities/container_registry.rb
index 2fdfac40c32..d12c8142e69 100644
--- a/lib/api/entities/container_registry.rb
+++ b/lib/api/entities/container_registry.rb
@@ -12,13 +12,13 @@ module API
class Repository < Grape::Entity
include ::API::Helpers::RelatedResourcesHelpers
- expose :id
- expose :name
- expose :path
- expose :project_id
- expose :location
- expose :created_at
- expose :expiration_policy_started_at, as: :cleanup_policy_started_at
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :name, documentation: { type: 'string', example: 'releases' }
+ expose :path, documentation: { type: 'string', example: 'group/project/releases' }
+ expose :project_id, documentation: { type: 'integer', example: 9 }
+ expose :location, documentation: { type: 'string', example: 'gitlab.example.com/group/project/releases' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2019-01-10T13:39:08.229Z' }
+ expose :expiration_policy_started_at, as: :cleanup_policy_started_at, documentation: { type: 'dateTime', example: '2020-08-17T03:12:35.489Z' }
expose :tags_count, if: -> (_, options) { options[:tags_count] }
expose :tags, using: Tag, if: -> (_, options) { options[:tags] }
expose :delete_api_path, if: ->(object, options) { Ability.allowed?(options[:user], :admin_container_image, object) }
diff --git a/lib/api/entities/contributor.rb b/lib/api/entities/contributor.rb
index 8763822b674..4fab953f0f6 100644
--- a/lib/api/entities/contributor.rb
+++ b/lib/api/entities/contributor.rb
@@ -3,7 +3,11 @@
module API
module Entities
class Contributor < Grape::Entity
- expose :name, :email, :commits, :additions, :deletions
+ expose :name, documentation: { example: 'John Doe' }
+ expose :email, documentation: { example: 'johndoe@example.com' }
+ expose :commits, documentation: { type: 'integer', example: 117 }
+ expose :additions, documentation: { type: 'integer', example: 3 }
+ expose :deletions, documentation: { type: 'integer', example: 5 }
end
end
end
diff --git a/lib/api/entities/custom_attribute.rb b/lib/api/entities/custom_attribute.rb
index f949b709517..883b572ac75 100644
--- a/lib/api/entities/custom_attribute.rb
+++ b/lib/api/entities/custom_attribute.rb
@@ -3,8 +3,8 @@
module API
module Entities
class CustomAttribute < Grape::Entity
- expose :key
- expose :value
+ expose :key, documentation: { type: 'string', example: 'foo' }
+ expose :value, documentation: { type: 'string', example: 'bar' }
end
end
end
diff --git a/lib/api/entities/deploy_key.rb b/lib/api/entities/deploy_key.rb
index 2c9c33549a1..1bcd06f2c88 100644
--- a/lib/api/entities/deploy_key.rb
+++ b/lib/api/entities/deploy_key.rb
@@ -3,9 +3,15 @@
module API
module Entities
class DeployKey < Entities::SSHKey
- expose :key
- expose :fingerprint, if: ->(key, _) { key.fingerprint.present? }
- expose :fingerprint_sha256
+ expose :key,
+ documentation: { type: 'string', example: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDNJAkI3Wdf0r13c8a5pEExB2YowPWCSVzfZV22pNBc1CuEbyYLHpUyaD0GwpGvFdx2aP7lMEk35k6Rz3ccBF6jRaVJyhsn5VNnW92PMpBJ/P1UebhXwsFHdQf5rTt082cSxWuk61kGWRQtk4ozt/J2DF/dIUVaLvc+z4HomT41fQ==' }
+
+ expose :fingerprint,
+ documentation: { type: 'string', example: '4a:9d:64:15:ed:3a:e6:07:6e:89:36:b3:3b:03:05:d9' },
+ if: ->(key, _) { key.fingerprint.present? }
+
+ expose :fingerprint_sha256,
+ documentation: { type: 'string', example: 'SHA256:Jrs3LD1Ji30xNLtTVf9NDCj7kkBgPBb2pjvTZ3HfIgU' }
expose :projects_with_write_access, using: Entities::ProjectIdentity, if: -> (_, options) { options[:include_projects_with_write_access] }
end
diff --git a/lib/api/entities/deploy_keys_project.rb b/lib/api/entities/deploy_keys_project.rb
index 12a86fbdf8e..4501af88067 100644
--- a/lib/api/entities/deploy_keys_project.rb
+++ b/lib/api/entities/deploy_keys_project.rb
@@ -4,7 +4,7 @@ module API
module Entities
class DeployKeysProject < Grape::Entity
expose :deploy_key, merge: true, using: Entities::DeployKey
- expose :can_push
+ expose :can_push, documentation: { type: 'boolean' }
end
end
end
diff --git a/lib/api/entities/deploy_token.rb b/lib/api/entities/deploy_token.rb
index daee104ba6b..9861467e35d 100644
--- a/lib/api/entities/deploy_token.rb
+++ b/lib/api/entities/deploy_token.rb
@@ -4,8 +4,13 @@ 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, :revoked
- expose :expired?, as: :expired
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :name, documentation: { type: 'string', example: 'MyToken' }
+ expose :username, documentation: { type: 'string', example: 'gitlab+deploy-token-1' }
+ expose :expires_at, documentation: { type: 'dateTime', example: '2020-02-14T00:00:00.000Z' }
+ expose :scopes, documentation: { type: 'array', example: ['read_repository'] }
+ expose :revoked, documentation: { type: 'boolean' }
+ expose :expired?, documentation: { type: 'boolean' }, as: :expired
end
end
end
diff --git a/lib/api/entities/deploy_token_with_token.rb b/lib/api/entities/deploy_token_with_token.rb
index 11efe3720fa..a96051e1403 100644
--- a/lib/api/entities/deploy_token_with_token.rb
+++ b/lib/api/entities/deploy_token_with_token.rb
@@ -3,7 +3,7 @@
module API
module Entities
class DeployTokenWithToken < Entities::DeployToken
- expose :token
+ expose :token, documentation: { type: 'string', example: 'jMRvtPNxrn3crTAGukpZ' }
end
end
end
diff --git a/lib/api/entities/deployment.rb b/lib/api/entities/deployment.rb
index 4e3a4c289d9..426e92e7723 100644
--- a/lib/api/entities/deployment.rb
+++ b/lib/api/entities/deployment.rb
@@ -3,11 +3,16 @@
module API
module Entities
class Deployment < Grape::Entity
- expose :id, :iid, :ref, :sha, :created_at, :updated_at
+ expose :id, documentation: { type: 'integer', example: 41 }
+ expose :iid, documentation: { type: 'integer', example: 1 }
+ expose :ref, documentation: { type: 'string', example: 'main' }
+ expose :sha, documentation: { type: 'string', example: '99d03678b90d914dbb1b109132516d71a4a03ea8' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2016-08-11T11:32:35.444Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2016-08-11T11:32:35.444Z' }
expose :user, using: Entities::UserBasic
expose :environment, using: Entities::EnvironmentBasic
expose :deployable, using: Entities::Ci::Job
- expose :status
+ expose :status, documentation: { type: 'string', example: 'created' }
end
end
end
diff --git a/lib/api/entities/diff.rb b/lib/api/entities/diff.rb
index e92bc5d6b68..e9650f07f00 100644
--- a/lib/api/entities/diff.rb
+++ b/lib/api/entities/diff.rb
@@ -3,11 +3,17 @@
module API
module Entities
class Diff < Grape::Entity
- expose :old_path, :new_path, :a_mode, :b_mode
- expose :new_file?, as: :new_file
- expose :renamed_file?, as: :renamed_file
- expose :deleted_file?, as: :deleted_file
- expose :json_safe_diff, as: :diff
+ expose :json_safe_diff, as: :diff, documentation: {
+ type: 'string',
+ example: '--- a/doc/update/5.4-to-6.0.md\n+++ b/doc/update/5.4-to-6.0.md\n@@ -71,6 +71,8 @@\n...'
+ }
+ expose :new_path, documentation: { type: 'string', example: 'doc/update/5.4-to-6.0.md' }
+ expose :old_path, documentation: { type: 'string', example: 'doc/update/5.4-to-6.0.md' }
+ expose :a_mode, documentation: { type: 'string', example: '100755' }
+ expose :b_mode, documentation: { type: 'string', example: '100644' }
+ expose :new_file?, as: :new_file, documentation: { type: 'boolean' }
+ expose :renamed_file?, as: :renamed_file, documentation: { type: 'boolean' }
+ expose :deleted_file?, as: :deleted_file, documentation: { type: 'boolean' }
end
end
end
diff --git a/lib/api/entities/entity_helpers.rb b/lib/api/entities/entity_helpers.rb
index 3a68044ad35..6fb04bb8ad6 100644
--- a/lib/api/entities/entity_helpers.rb
+++ b/lib/api/entities/entity_helpers.rb
@@ -11,8 +11,8 @@ module API
->(obj, opts) { Ability.allowed?(opts[:user], "destroy_#{attr}".to_sym, yield(obj)) }
end
- def expose_restricted(attr, &block)
- expose attr, if: can_read(attr, &block)
+ def expose_restricted(attr, documentation: {}, &block)
+ expose attr, documentation: documentation, if: can_read(attr, &block)
end
end
end
diff --git a/lib/api/entities/environment.rb b/lib/api/entities/environment.rb
index 3b6ed94c3f1..dc9911d5acb 100644
--- a/lib/api/entities/environment.rb
+++ b/lib/api/entities/environment.rb
@@ -5,10 +5,10 @@ module API
class Environment < Entities::EnvironmentBasic
include RequestAwareEntity
- expose :tier
+ expose :tier, documentation: { type: 'string', example: 'development' }
expose :project, using: Entities::BasicProjectDetails
expose :last_deployment, using: Entities::Deployment, if: { last_deployment: true }
- expose :state
+ expose :state, documentation: { type: 'string', example: 'available' }
end
end
end
diff --git a/lib/api/entities/environment_basic.rb b/lib/api/entities/environment_basic.rb
index d9894eac147..1b4a9371820 100644
--- a/lib/api/entities/environment_basic.rb
+++ b/lib/api/entities/environment_basic.rb
@@ -3,7 +3,12 @@
module API
module Entities
class EnvironmentBasic < Grape::Entity
- expose :id, :name, :slug, :external_url, :created_at, :updated_at
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :name, documentation: { type: 'string', example: 'deploy' }
+ expose :slug, documentation: { type: 'string', example: 'deploy' }
+ expose :external_url, documentation: { type: 'string', example: 'https://deploy.gitlab.example.com' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2019-05-25T18:55:13.252Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2019-05-25T18:55:13.252Z' }
end
end
end
diff --git a/lib/api/entities/error_tracking.rb b/lib/api/entities/error_tracking.rb
index 163bda92680..5e3b983c58c 100644
--- a/lib/api/entities/error_tracking.rb
+++ b/lib/api/entities/error_tracking.rb
@@ -4,11 +4,11 @@ module API
module Entities
module ErrorTracking
class ProjectSetting < Grape::Entity
- expose :enabled, as: :active
- expose :project_name
- expose :sentry_external_url
- expose :api_url
- expose :integrated
+ expose :enabled, as: :active, documentation: { type: 'boolean' }
+ expose :project_name, documentation: { type: 'string', example: 'sample sentry project' }
+ expose :sentry_external_url, documentation: { type: 'string', example: 'https://sentry.io/myawesomeproject/project' }
+ expose :api_url, documentation: { type: 'string', example: 'https://sentry.io/api/0/projects/myawesomeproject/project' }
+ expose :integrated, documentation: { type: 'boolean' }
def integrated
return false unless ::Feature.enabled?(:integrated_error_tracking, object.project)
@@ -18,10 +18,10 @@ module API
end
class ClientKey < Grape::Entity
- expose :id
- expose :active
- expose :public_key
- expose :sentry_dsn
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :active, documentation: { type: 'boolean' }
+ expose :public_key, documentation: { type: 'string', example: 'glet_aa77551d849c083f76d0bc545ed053a3' }
+ expose :sentry_dsn, documentation: { type: 'string', example: 'https://glet_aa77551d849c083f76d0bc545ed053a3@gitlab.example.com/api/v4/error_tracking/collector/5' }
end
end
end
diff --git a/lib/api/entities/feature.rb b/lib/api/entities/feature.rb
index d1151849cd7..48dd5a22a7e 100644
--- a/lib/api/entities/feature.rb
+++ b/lib/api/entities/feature.rb
@@ -3,8 +3,8 @@
module API
module Entities
class Feature < Grape::Entity
- expose :name
- expose :state
+ expose :name, documentation: { type: 'string', example: 'experimental_feature' }
+ expose :state, documentation: { type: 'string', example: 'off' }
expose :gates, using: Entities::FeatureGate do |model|
model.gates.map do |gate|
value = model.gate_values[gate.key]
diff --git a/lib/api/entities/feature_flag.rb b/lib/api/entities/feature_flag.rb
index 9dec3873504..273307357a2 100644
--- a/lib/api/entities/feature_flag.rb
+++ b/lib/api/entities/feature_flag.rb
@@ -3,12 +3,12 @@
module API
module Entities
class FeatureFlag < Grape::Entity
- expose :name
- expose :description
- expose :active
- expose :version
- expose :created_at
- expose :updated_at
+ expose :name, documentation: { type: 'string', example: 'merge_train' }
+ expose :description, documentation: { type: 'string', example: 'merge train feature flag' }
+ expose :active, documentation: { type: 'boolean' }
+ expose :version, documentation: { type: 'string', example: 'new_version_flag' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2019-11-04T08:13:51.423Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2019-11-04T08:13:51.423Z' }
expose :scopes do |_ff|
[]
end
diff --git a/lib/api/entities/feature_flag/scope.rb b/lib/api/entities/feature_flag/scope.rb
index 906fe718257..e29793c250a 100644
--- a/lib/api/entities/feature_flag/scope.rb
+++ b/lib/api/entities/feature_flag/scope.rb
@@ -4,8 +4,8 @@ module API
module Entities
class FeatureFlag < Grape::Entity
class Scope < Grape::Entity
- expose :id
- expose :environment_scope
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :environment_scope, documentation: { type: 'string', example: 'production' }
end
end
end
diff --git a/lib/api/entities/feature_flag/strategy.rb b/lib/api/entities/feature_flag/strategy.rb
index 32699be0ee3..62178420370 100644
--- a/lib/api/entities/feature_flag/strategy.rb
+++ b/lib/api/entities/feature_flag/strategy.rb
@@ -4,9 +4,9 @@ module API
module Entities
class FeatureFlag < Grape::Entity
class Strategy < Grape::Entity
- expose :id
- expose :name
- expose :parameters
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :name, documentation: { type: 'string', example: 'userWithId' }
+ expose :parameters, documentation: { type: 'string', example: '{"userIds": "user1"}' }
expose :scopes, using: FeatureFlag::Scope
end
end
diff --git a/lib/api/entities/feature_flag/user_list.rb b/lib/api/entities/feature_flag/user_list.rb
index bc8b12ea22e..efb3261658a 100644
--- a/lib/api/entities/feature_flag/user_list.rb
+++ b/lib/api/entities/feature_flag/user_list.rb
@@ -6,13 +6,13 @@ module API
class UserList < Grape::Entity
include RequestAwareEntity
- expose :id
- expose :iid
- expose :project_id
- expose :created_at
- expose :updated_at
- expose :name
- expose :user_xids
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :iid, documentation: { type: 'integer', example: 1 }
+ expose :project_id, documentation: { type: 'integer', example: 2 }
+ expose :created_at, documentation: { type: 'dateTime', example: '2020-02-04T08:13:10.507Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2020-02-04T08:13:10.507Z' }
+ expose :name, documentation: { type: 'string', example: 'user_list' }
+ expose :user_xids, documentation: { type: 'string', example: 'user1,user2' }
expose :path do |list|
project_feature_flags_user_list_path(list.project, list)
diff --git a/lib/api/entities/feature_gate.rb b/lib/api/entities/feature_gate.rb
index bea9c9474b3..ad4702bf210 100644
--- a/lib/api/entities/feature_gate.rb
+++ b/lib/api/entities/feature_gate.rb
@@ -3,8 +3,8 @@
module API
module Entities
class FeatureGate < Grape::Entity
- expose :key
- expose :value
+ expose :key, documentation: { type: 'string', example: 'percentage_of_actors' }
+ expose :value, documentation: { type: 'integer', example: 34 }
end
end
end
diff --git a/lib/api/entities/freeze_period.rb b/lib/api/entities/freeze_period.rb
index 9b5f08925db..d6853c544a5 100644
--- a/lib/api/entities/freeze_period.rb
+++ b/lib/api/entities/freeze_period.rb
@@ -3,9 +3,11 @@
module API
module Entities
class FreezePeriod < Grape::Entity
- expose :id
- expose :freeze_start, :freeze_end, :cron_timezone
- expose :created_at, :updated_at
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :freeze_start, documentation: { type: 'string', example: '0 23 * * 5' }
+ expose :freeze_end, documentation: { type: 'string', example: '0 8 * * 1' }
+ expose :cron_timezone, documentation: { type: 'string', example: 'UTC' }
+ expose :created_at, :updated_at, documentation: { type: 'dateTime', example: '2020-05-15T17:03:35.702Z' }
end
end
end
diff --git a/lib/api/entities/go_module_version.rb b/lib/api/entities/go_module_version.rb
index 643e25df9e0..b9dd88982dd 100644
--- a/lib/api/entities/go_module_version.rb
+++ b/lib/api/entities/go_module_version.rb
@@ -3,8 +3,8 @@
module API
module Entities
class GoModuleVersion < Grape::Entity
- expose :name, as: 'Version'
- expose :time, as: 'Time'
+ expose :name, as: 'Version', documentation: { type: 'string', example: 'v1.0.0' }
+ expose :time, as: 'Time', documentation: { type: 'string', example: '1617822312 -0600' }
end
end
end
diff --git a/lib/api/entities/hook.rb b/lib/api/entities/hook.rb
index 95924321221..e24e201ac57 100644
--- a/lib/api/entities/hook.rb
+++ b/lib/api/entities/hook.rb
@@ -3,12 +3,18 @@
module API
module Entities
class Hook < Grape::Entity
- expose :id, :url, :created_at, :push_events, :tag_push_events, :merge_requests_events, :repository_update_events
- expose :enable_ssl_verification
+ expose :id, documentation: { type: 'string', example: 1 }
+ expose :url, documentation: { type: 'string', example: 'https://webhook.site' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ expose :push_events, documentation: { type: 'boolean' }
+ expose :tag_push_events, documentation: { type: 'boolean' }
+ expose :merge_requests_events, documentation: { type: 'boolean' }
+ expose :repository_update_events, documentation: { type: 'boolean' }
+ expose :enable_ssl_verification, documentation: { type: 'boolean' }
- expose :alert_status
- expose :disabled_until
- expose :url_variables
+ expose :alert_status, documentation: { type: 'symbol', example: :executable }
+ expose :disabled_until, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ expose :url_variables, documentation: { type: 'Hash', example: { "token" => "secr3t" }, is_array: true }
def url_variables
object.url_variables.keys.map { { key: _1 } }
diff --git a/lib/api/entities/issuable_entity.rb b/lib/api/entities/issuable_entity.rb
index e2c674c0b8b..4e70f945a48 100644
--- a/lib/api/entities/issuable_entity.rb
+++ b/lib/api/entities/issuable_entity.rb
@@ -3,10 +3,16 @@
module API
module Entities
class IssuableEntity < Grape::Entity
- expose :id, :iid
- expose(:project_id) { |entity| entity&.project.try(:id) }
- expose :title, :description
- expose :state, :created_at, :updated_at
+ expose :id, documentation: { type: 'integer', example: 84 }
+ expose :iid, documentation: { type: 'integer', example: 14 }
+ expose :project_id, documentation: { type: 'integer', example: 4 } do |entity|
+ entity&.project.try(:id)
+ end
+ expose :title, documentation: { type: 'string', example: 'Impedit et ut et dolores vero provident ullam est' }
+ expose :description, documentation: { type: 'string', example: 'Repellendus impedit et vel velit dignissimos.' }
+ expose :state, documentation: { type: 'string', example: 'closed' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2022-08-17T12:46:35.053Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2022-11-14T17:22:01.470Z' }
def presented
lazy_issuable_metadata
diff --git a/lib/api/entities/issue_basic.rb b/lib/api/entities/issue_basic.rb
index 20f66c026e6..89fb8bbe1c0 100644
--- a/lib/api/entities/issue_basic.rb
+++ b/lib/api/entities/issue_basic.rb
@@ -7,10 +7,10 @@ module API
item.upcase if item.respond_to?(:upcase)
end
- expose :closed_at
+ expose :closed_at, documentation: { type: 'dateTime', example: '2022-11-15T08:30:55.232Z' }
expose :closed_by, using: Entities::UserBasic
- expose :labels do |issue, options|
+ expose :labels, documentation: { type: 'string', is_array: true, example: 'bug' } do |issue, options|
if options[:with_labels_details]
::API::Entities::LabelBasic.represent(issue.labels.sort_by(&:title))
else
@@ -23,7 +23,7 @@ module API
expose :issue_type,
as: :type,
format_with: :upcase,
- documentation: { type: "String", desc: "One of #{::WorkItems::Type.allowed_types_for_issues.map(&:upcase)}" }
+ documentation: { type: 'String', example: 'ISSUE', desc: "One of #{::WorkItems::Type.allowed_types_for_issues.map(&:upcase)}" }
expose :assignee, using: ::API::Entities::UserBasic do |issue|
issue.assignees.first
@@ -33,12 +33,12 @@ module API
expose(:merge_requests_count) { |issue, options| issuable_metadata.merge_requests_count }
expose(:upvotes) { |issue, options| issuable_metadata.upvotes }
expose(:downvotes) { |issue, options| issuable_metadata.downvotes }
- expose :due_date
- expose :confidential
- expose :discussion_locked
- expose :issue_type
+ expose :due_date, documentation: { type: 'date', example: '2022-11-20' }
+ expose :confidential, documentation: { type: 'boolean' }
+ expose :discussion_locked, documentation: { type: 'boolean' }
+ expose :issue_type, documentation: { type: 'string', example: 'issue' }
- expose :web_url do |issue|
+ expose :web_url, documentation: { type: 'string', example: 'http://example.com/example/example/issues/14' } do |issue|
Gitlab::UrlBuilder.build(issue)
end
diff --git a/lib/api/entities/license.rb b/lib/api/entities/license.rb
index 8ecf8a430fe..6318fec6774 100644
--- a/lib/api/entities/license.rb
+++ b/lib/api/entities/license.rb
@@ -4,12 +4,25 @@ module API
module Entities
# Serializes a Licensee::License
class License < Entities::LicenseBasic
- expose :popular?, as: :popular
- expose(:description) { |license| license.meta['description'] }
- expose(:conditions) { |license| license.meta['conditions'] }
- expose(:permissions) { |license| license.meta['permissions'] }
- expose(:limitations) { |license| license.meta['limitations'] }
- expose :content
+ expose :popular?, as: :popular, documentation: { type: 'boolean' }
+
+ expose :description, documentation: { type: 'string', example: 'A simple license' } do |license|
+ license.meta['description']
+ end
+
+ expose :conditions, documentation: { type: 'string', is_array: true, example: 'include-copyright' } do |license|
+ license.meta['conditions']
+ end
+
+ expose :permissions, documentation: { type: 'string', is_array: true, example: 'commercial-use' } do |license|
+ license.meta['permissions']
+ end
+
+ expose :limitations, documentation: { type: 'string', is_array: true, example: 'liability' } do |license|
+ license.meta['limitations']
+ end
+
+ expose :content, documentation: { type: 'string', example: 'GNU GENERAL PUBLIC LICENSE' }
end
end
end
diff --git a/lib/api/entities/license_basic.rb b/lib/api/entities/license_basic.rb
index 0916738d21d..e3bb55d4104 100644
--- a/lib/api/entities/license_basic.rb
+++ b/lib/api/entities/license_basic.rb
@@ -4,8 +4,10 @@ module API
module Entities
# Serializes a Gitlab::Git::DeclaredLicense
class LicenseBasic < Grape::Entity
- expose :key, :name, :nickname
- expose :url, as: :html_url
+ expose :key, documentation: { type: 'string', example: 'gpl-3.0' }
+ expose :name, documentation: { type: 'string', example: 'GNU General Public License v3.0' }
+ expose :nickname, documentation: { type: 'string', example: 'GNU GPLv3' }
+ expose :url, as: :html_url, documentation: { example: 'http://choosealicense.com/licenses/gpl-3.0' }
# This was dropped:
# https://github.com/github/choosealicense.com/commit/325806b42aa3d5b78e84120327ec877bc936dbdd#diff-66df8f1997786f7052d29010f2cbb4c66391d60d24ca624c356acc0ab986f139
diff --git a/lib/api/entities/markdown.rb b/lib/api/entities/markdown.rb
new file mode 100644
index 00000000000..0fbaec4375e
--- /dev/null
+++ b/lib/api/entities/markdown.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class Markdown < Grape::Entity
+ expose :html, documentation: { type: 'string', example: '<p dir=\"auto\">Hello world!</p>"' }
+ end
+ end
+end
diff --git a/lib/api/entities/merge_request_approvals.rb b/lib/api/entities/merge_request_approvals.rb
index 6810952b2fc..54f196e0d74 100644
--- a/lib/api/entities/merge_request_approvals.rb
+++ b/lib/api/entities/merge_request_approvals.rb
@@ -3,15 +3,15 @@
module API
module Entities
class MergeRequestApprovals < Grape::Entity
- expose :user_has_approved do |merge_request, options|
+ expose :user_has_approved, documentation: { type: 'boolean' } do |merge_request, options|
merge_request.approved_by?(options[:current_user])
end
- expose :user_can_approve do |merge_request, options|
+ expose :user_can_approve, documentation: { type: 'boolean' } do |merge_request, options|
merge_request.eligible_for_approval_by?(options[:current_user])
end
- expose :approved do |merge_request|
+ expose :approved, documentation: { type: 'boolean' } do |merge_request|
merge_request.approvals.present?
end
diff --git a/lib/api/entities/merge_request_basic.rb b/lib/api/entities/merge_request_basic.rb
index 55d58166590..27f6e6ade06 100644
--- a/lib/api/entities/merge_request_basic.rb
+++ b/lib/api/entities/merge_request_basic.rb
@@ -58,6 +58,7 @@ module API
merge_request.check_mergeability(async: true) unless options[:skip_merge_status_recheck]
merge_request.public_merge_status
end
+ expose :detailed_merge_status
expose :diff_head_sha, as: :sha
expose :merge_commit_sha
expose :squash_commit_sha
@@ -93,6 +94,12 @@ module API
expose :task_completion_status
expose :cannot_be_merged?, as: :has_conflicts
expose :mergeable_discussions_state?, as: :blocking_discussions_resolved
+
+ private
+
+ def detailed_merge_status
+ ::MergeRequests::Mergeability::DetailedMergeStatusService.new(merge_request: object).execute
+ end
end
end
end
diff --git a/lib/api/entities/merge_request_simple.rb b/lib/api/entities/merge_request_simple.rb
index f3ff4cc18a8..d5c511ad9a4 100644
--- a/lib/api/entities/merge_request_simple.rb
+++ b/lib/api/entities/merge_request_simple.rb
@@ -3,8 +3,11 @@
module API
module Entities
class MergeRequestSimple < IssuableEntity
- expose :title
- expose :web_url do |merge_request, options|
+ expose :title, documentation: { type: 'string', example: 'Test MR 1580978354' }
+ expose :web_url,
+ documentation: {
+ type: 'string', example: 'http://local.gitlab.test:8181/root/merge-train-race-condition/-/merge_requests/59'
+ } do |merge_request, options|
Gitlab::UrlBuilder.build(merge_request)
end
end
diff --git a/lib/api/entities/metadata.rb b/lib/api/entities/metadata.rb
index daa491ec42a..7dfcad2ccab 100644
--- a/lib/api/entities/metadata.rb
+++ b/lib/api/entities/metadata.rb
@@ -3,13 +3,14 @@
module API
module Entities
class Metadata < Grape::Entity
- expose :version
- expose :revision
+ expose :version, documentation: { type: 'string', example: '15.2-pre' }
+ expose :revision, documentation: { type: 'string', example: 'c401a659d0c' }
expose :kas do
expose :enabled, documentation: { type: 'boolean' }
- expose :externalUrl
- expose :version
+ expose :externalUrl, documentation: { type: 'string', example: 'grpc://gitlab.example.com:8150' }
+ expose :version, documentation: { type: 'string', example: '15.0.0' }
end
+ expose :enterprise, documentation: { type: 'boolean' }
end
end
end
diff --git a/lib/api/entities/metrics/dashboard/annotation.rb b/lib/api/entities/metrics/dashboard/annotation.rb
index 66bd09d84f9..08d1a333259 100644
--- a/lib/api/entities/metrics/dashboard/annotation.rb
+++ b/lib/api/entities/metrics/dashboard/annotation.rb
@@ -5,13 +5,13 @@ module API
module Metrics
module Dashboard
class Annotation < Grape::Entity
- expose :id
- expose :starting_at
- expose :ending_at
- expose :dashboard_path
- expose :description
- expose :environment_id
- expose :cluster_id
+ expose :id, documentation: { type: 'integer', example: 4 }
+ expose :starting_at, documentation: { type: 'dateTime', example: '2016-04-08T03:45:40.000Z' }
+ expose :ending_at, documentation: { type: 'dateTime', example: '2016-08-08T09:00:00.000Z' }
+ expose :dashboard_path, documentation: { type: 'string', example: '.gitlab/dashboards/custom_metrics.yml' }
+ expose :description, documentation: { type: 'string', example: 'annotation description' }
+ expose :environment_id, documentation: { type: 'integer', example: 1 }
+ expose :cluster_id, documentation: { type: 'integer', example: 2 }
end
end
end
diff --git a/lib/api/entities/metrics/user_starred_dashboard.rb b/lib/api/entities/metrics/user_starred_dashboard.rb
index d774160e3ea..1d2a8a39547 100644
--- a/lib/api/entities/metrics/user_starred_dashboard.rb
+++ b/lib/api/entities/metrics/user_starred_dashboard.rb
@@ -4,7 +4,10 @@ module API
module Entities
module Metrics
class UserStarredDashboard < Grape::Entity
- expose :id, :dashboard_path, :user_id, :project_id
+ expose :id, documentation: { type: 'integer', example: 5 }
+ expose :dashboard_path, documentation: { type: 'string', example: 'config/prometheus/common_metrics.yml' }
+ expose :user_id, documentation: { type: 'integer', example: 1 }
+ expose :project_id, documentation: { type: 'integer', example: 20 }
end
end
end
diff --git a/lib/api/entities/ml/mlflow/run.rb b/lib/api/entities/ml/mlflow/run.rb
index a8e1cfe08dd..8b16c67611f 100644
--- a/lib/api/entities/ml/mlflow/run.rb
+++ b/lib/api/entities/ml/mlflow/run.rb
@@ -6,7 +6,7 @@ module API
module Mlflow
class Run < Grape::Entity
expose :run do
- expose(:info) { |candidate| RunInfo.represent(candidate) }
+ expose :itself, using: RunInfo, as: :info
expose :data do
expose :metrics, using: Metric
expose :params, using: RunParam
diff --git a/lib/api/entities/ml/mlflow/run_info.rb b/lib/api/entities/ml/mlflow/run_info.rb
index 096950e349d..d3934545ba4 100644
--- a/lib/api/entities/ml/mlflow/run_info.rb
+++ b/lib/api/entities/ml/mlflow/run_info.rb
@@ -11,7 +11,7 @@ module API
expose(:start_time) { |candidate| candidate.start_time || 0 }
expose :end_time, expose_nil: false
expose(:status) { |candidate| candidate.status.to_s.upcase }
- expose(:artifact_uri) { |candidate| 'not_implemented' }
+ expose(:artifact_uri) { |candidate, options| "#{options[:packages_url]}#{candidate.artifact_root}" }
expose(:lifecycle_stage) { |candidate| 'active' }
expose(:user_id) { |candidate| candidate.user_id.to_s }
diff --git a/lib/api/entities/ml/mlflow/update_run.rb b/lib/api/entities/ml/mlflow/update_run.rb
index 090d69b8895..55def810ef5 100644
--- a/lib/api/entities/ml/mlflow/update_run.rb
+++ b/lib/api/entities/ml/mlflow/update_run.rb
@@ -5,13 +5,7 @@ module API
module Ml
module Mlflow
class UpdateRun < Grape::Entity
- expose :run_info
-
- private
-
- def run_info
- RunInfo.represent object
- end
+ expose :itself, using: RunInfo, as: :run_info
end
end
end
diff --git a/lib/api/entities/package.rb b/lib/api/entities/package.rb
index 18fc0576dd4..c92a4677220 100644
--- a/lib/api/entities/package.rb
+++ b/lib/api/entities/package.rb
@@ -4,11 +4,12 @@ module API
module Entities
class Package < Grape::Entity
include ::API::Helpers::RelatedResourcesHelpers
+ include ::Routing::PackagesHelper
extend ::API::Entities::EntityHelpers
- expose :id
+ expose :id, documentation: { type: 'integer', example: 1 }
- expose :name do |package|
+ expose :name, documentation: { type: 'string', example: '@foo/bar' } do |package|
if package.conan?
package.conan_recipe
else
@@ -20,17 +21,13 @@ module API
package.name
end
- expose :version
- expose :package_type
- expose :status
+ expose :version, documentation: { type: 'string', example: '1.0.3' }
+ expose :package_type, documentation: { type: 'string', example: 'npm' }
+ expose :status, documentation: { type: 'string', example: 'default' }
expose :_links do
- expose :web_path do |package, opts|
- if package.infrastructure_package?
- ::Gitlab::Routing.url_helpers.namespace_project_infrastructure_registry_path(opts[:namespace], package.project, package)
- else
- ::Gitlab::Routing.url_helpers.project_package_path(package.project, package)
- end
+ expose :web_path do |package|
+ package_path(package)
end
expose :delete_api_path, if: can_destroy(:package, &:project) do |package|
@@ -38,10 +35,12 @@ module API
end
end
- expose :created_at
- expose :last_downloaded_at
- expose :project_id, if: ->(_, opts) { opts[:group] }
- expose :project_path, if: ->(obj, opts) { opts[:group] && Ability.allowed?(opts[:user], :read_project, obj.project) }
+ expose :created_at, documentation: { type: 'dateTime', example: '2022-09-16T12:47:31.949Z' }
+ expose :last_downloaded_at, documentation: { type: 'dateTime', example: '2022-09-19T11:32:35.169Z' }
+ expose :project_id, documentation: { type: 'integer', example: 2 }, if: ->(_, opts) { opts[:group] }
+ expose :project_path, documentation: { type: 'string', example: 'gitlab/foo/bar' }, if: ->(obj, opts) do
+ opts[:group] && Ability.allowed?(opts[:user], :read_project, obj.project)
+ end
expose :tags
expose :pipeline, if: ->(package) { package.original_build_info }, using: Package::Pipeline
diff --git a/lib/api/entities/package_file.rb b/lib/api/entities/package_file.rb
index e34a6a7aa1d..19372b75012 100644
--- a/lib/api/entities/package_file.rb
+++ b/lib/api/entities/package_file.rb
@@ -3,9 +3,14 @@
module API
module Entities
class PackageFile < Grape::Entity
- expose :id, :package_id, :created_at
- expose :file_name, :size
- expose :file_md5, :file_sha1, :file_sha256
+ expose :id, documentation: { type: 'integer', example: 225 }
+ expose :package_id, documentation: { type: 'integer', example: 4 }
+ expose :created_at, documentation: { type: 'dateTime', example: '2018-11-07T15:25:52.199Z' }
+ expose :file_name, documentation: { type: 'string', example: 'my-app-1.5-20181107.152550-1.jar' }
+ expose :size, documentation: { type: 'integer', example: '2421' }
+ expose :file_md5, documentation: { type: 'string', example: '58e6a45a629910c6ff99145a688971ac' }
+ expose :file_sha1, documentation: { type: 'string', example: 'ebd193463d3915d7e22219f52740056dfd26cbfe' }
+ expose :file_sha256, documentation: { type: 'string', example: 'a903393463d3915d7e22219f52740056dfd26cbfeff321b' }
expose :pipelines, if: ->(package_file) { package_file.pipelines.present? }, using: Package::Pipeline
end
end
diff --git a/lib/api/entities/personal_access_token.rb b/lib/api/entities/personal_access_token.rb
index 55764daef9d..3ec91ca5fc9 100644
--- a/lib/api/entities/personal_access_token.rb
+++ b/lib/api/entities/personal_access_token.rb
@@ -3,9 +3,16 @@
module API
module Entities
class PersonalAccessToken < Grape::Entity
- expose :id, :name, :revoked, :created_at, :scopes, :user_id, :last_used_at
- expose :active?, as: :active
- expose :expires_at do |personal_access_token|
+ expose :id, documentation: { type: 'integer', example: 2 }
+ expose :name, documentation: { type: 'string', example: 'John Doe' }
+ expose :revoked, documentation: { type: 'boolean' }
+ expose :created_at, documentation: { type: 'dateTime' }
+ expose :scopes, documentation: { type: 'array', example: ['api'] }
+ expose :user_id, documentation: { type: 'integer', example: 3 }
+ expose :last_used_at, documentation: { type: 'dateTime', example: '2020-08-31T15:53:00.073Z' }
+ expose :active?, as: :active, documentation: { type: 'boolean' }
+ expose :expires_at, documentation:
+ { type: 'dateTime', example: '2020-08-31T15:53:00.073Z' } do |personal_access_token|
personal_access_token.expires_at ? personal_access_token.expires_at.strftime("%Y-%m-%d") : nil
end
end
diff --git a/lib/api/entities/plan_limit.rb b/lib/api/entities/plan_limit.rb
index 94e50f19b35..34018f03eb1 100644
--- a/lib/api/entities/plan_limit.rb
+++ b/lib/api/entities/plan_limit.rb
@@ -3,23 +3,23 @@
module API
module Entities
class PlanLimit < Grape::Entity
- expose :ci_pipeline_size
- expose :ci_active_jobs
- expose :ci_active_pipelines
- expose :ci_project_subscriptions
- expose :ci_pipeline_schedules
- expose :ci_needs_size_limit
- expose :ci_registered_group_runners
- expose :ci_registered_project_runners
- expose :conan_max_file_size
- expose :generic_packages_max_file_size
- expose :helm_max_file_size
- expose :maven_max_file_size
- expose :npm_max_file_size
- expose :nuget_max_file_size
- expose :pypi_max_file_size
- expose :terraform_module_max_file_size
- expose :storage_size_limit
+ expose :ci_pipeline_size, documentation: { type: 'integer', example: 0 }
+ expose :ci_active_jobs, documentation: { type: 'integer', example: 0 }
+ expose :ci_active_pipelines, documentation: { type: 'integer', example: 0 }
+ expose :ci_project_subscriptions, documentation: { type: 'integer', example: 2 }
+ expose :ci_pipeline_schedules, documentation: { type: 'integer', example: 10 }
+ expose :ci_needs_size_limit, documentation: { type: 'integer', example: 50 }
+ expose :ci_registered_group_runners, documentation: { type: 'integer', example: 1000 }
+ expose :ci_registered_project_runners, documentation: { type: 'integer', example: 1000 }
+ expose :conan_max_file_size, documentation: { type: 'integer', example: 3221225472 }
+ expose :generic_packages_max_file_size, documentation: { type: 'integer', example: 5368709120 }
+ expose :helm_max_file_size, documentation: { type: 'integer', example: 5242880 }
+ expose :maven_max_file_size, documentation: { type: 'integer', example: 3221225472 }
+ expose :npm_max_file_size, documentation: { type: 'integer', example: 524288000 }
+ expose :nuget_max_file_size, documentation: { type: 'integer', example: 524288000 }
+ expose :pypi_max_file_size, documentation: { type: 'integer', example: 3221225472 }
+ expose :terraform_module_max_file_size, documentation: { type: 'integer', example: 1073741824 }
+ expose :storage_size_limit, documentation: { type: 'integer', example: 15000 }
end
end
end
diff --git a/lib/api/entities/project.rb b/lib/api/entities/project.rb
index f158695f605..1c1bafbf161 100644
--- a/lib/api/entities/project.rb
+++ b/lib/api/entities/project.rb
@@ -5,147 +5,148 @@ module API
class Project < BasicProjectDetails
include ::API::Helpers::RelatedResourcesHelpers
- expose :container_registry_url, as: :container_registry_image_prefix, if: -> (_, _) { Gitlab.config.registry.enabled }
+ expose :container_registry_url, as: :container_registry_image_prefix, documentation: { type: 'string', example: 'registry.gitlab.example.com/gitlab/gitlab-client' }, if: -> (_, _) { Gitlab.config.registry.enabled }
expose :_links do
- expose :self do |project|
+ expose :self, documentation: { type: 'string', example: 'https://gitlab.example.com/api/v4/projects/4' } do |project|
expose_url(api_v4_projects_path(id: project.id))
end
- expose :issues, if: -> (project, options) { issues_available?(project, options) } do |project|
+ expose :issues, documentation: { type: 'string', example: 'https://gitlab.example.com/api/v4/projects/4/issues' }, if: -> (project, options) { issues_available?(project, options) } do |project|
expose_url(api_v4_projects_issues_path(id: project.id))
end
- expose :merge_requests, if: -> (project, options) { mrs_available?(project, options) } do |project|
+ expose :merge_requests, documentation: { type: 'string', example: 'https://gitlab.example.com/api/v4/projects/4/merge_requests' }, if: -> (project, options) { mrs_available?(project, options) } do |project|
expose_url(api_v4_projects_merge_requests_path(id: project.id))
end
- expose :repo_branches do |project|
+ expose :repo_branches, documentation: { type: 'string', example: 'https://gitlab.example.com/api/v4/projects/4/repository/branches' } do |project|
expose_url(api_v4_projects_repository_branches_path(id: project.id))
end
- expose :labels do |project|
+ expose :labels, documentation: { type: 'string', example: 'https://gitlab.example.com/api/v4/projects/4/labels' } do |project|
expose_url(api_v4_projects_labels_path(id: project.id))
end
- expose :events do |project|
+ expose :events, documentation: { type: 'string', example: 'https://gitlab.example.com/api/v4/projects/4/events' } do |project|
expose_url(api_v4_projects_events_path(id: project.id))
end
- expose :members do |project|
+ expose :members, documentation: { type: 'string', example: 'https://gitlab.example.com/api/v4/projects/4/members' } do |project|
expose_url(api_v4_projects_members_path(id: project.id))
end
- expose :cluster_agents do |project|
+ expose :cluster_agents, documentation: { type: 'string', example: 'https://gitlab.example.com/api/v4/projects/4/cluster_agents' } do |project|
expose_url(api_v4_projects_cluster_agents_path(id: project.id))
end
end
- expose :packages_enabled
- expose :empty_repo?, as: :empty_repo
- expose :archived?, as: :archived
- expose :visibility
+ expose :packages_enabled, documentation: { type: 'boolean' }
+ expose :empty_repo?, as: :empty_repo, documentation: { type: 'boolean' }
+ expose :archived?, as: :archived, documentation: { type: 'boolean' }
+ expose :visibility, documentation: { type: 'string', example: 'public' }
expose :owner, using: Entities::UserBasic, unless: ->(project, options) { project.group }
- expose :resolve_outdated_diff_discussions
+ expose :resolve_outdated_diff_discussions, documentation: { type: 'boolean' }
expose :container_expiration_policy,
using: Entities::ContainerExpirationPolicy,
if: -> (project, _) { project.container_expiration_policy }
# Expose old field names with the new permissions methods to keep API compatible
# TODO: remove in API v5, replaced by *_access_level
- expose(:issues_enabled) { |project, options| project.feature_available?(:issues, options[:current_user]) }
- expose(:merge_requests_enabled) { |project, options| project.feature_available?(:merge_requests, options[:current_user]) }
- expose(:wiki_enabled) { |project, options| project.feature_available?(:wiki, options[:current_user]) }
- expose(:jobs_enabled) { |project, options| project.feature_available?(:builds, options[:current_user]) }
- expose(:snippets_enabled) { |project, options| project.feature_available?(:snippets, options[:current_user]) }
- expose(:container_registry_enabled) { |project, options| project.feature_available?(:container_registry, options[:current_user]) }
- expose :service_desk_enabled
- expose :service_desk_address, if: -> (project, options) do
+ expose(:issues_enabled, documentation: { type: 'boolean' }) { |project, options| project.feature_available?(:issues, options[:current_user]) }
+ expose(:merge_requests_enabled, documentation: { type: 'boolean' }) { |project, options| project.feature_available?(:merge_requests, options[:current_user]) }
+ expose(:wiki_enabled, documentation: { type: 'boolean' }) { |project, options| project.feature_available?(:wiki, options[:current_user]) }
+ expose(:jobs_enabled, documentation: { type: 'boolean' }) { |project, options| project.feature_available?(:builds, options[:current_user]) }
+ expose(:snippets_enabled, documentation: { type: 'boolean' }) { |project, options| project.feature_available?(:snippets, options[:current_user]) }
+ expose(:container_registry_enabled, documentation: { type: 'boolean' }) { |project, options| project.feature_available?(:container_registry, options[:current_user]) }
+ expose :service_desk_enabled, documentation: { type: 'boolean' }
+ expose :service_desk_address, documentation: { type: 'string', example: 'address@example.com' }, if: -> (project, options) do
Ability.allowed?(options[:current_user], :admin_issue, project)
end
- expose(:can_create_merge_request_in) do |project, options|
+ expose(:can_create_merge_request_in, documentation: { type: 'boolean' }) do |project, options|
Ability.allowed?(options[:current_user], :create_merge_request_in, project)
end
- expose(:issues_access_level) { |project, options| project_feature_string_access_level(project, :issues) }
- expose(:repository_access_level) { |project, options| project_feature_string_access_level(project, :repository) }
- expose(:merge_requests_access_level) { |project, options| project_feature_string_access_level(project, :merge_requests) }
- expose(:forking_access_level) { |project, options| project_feature_string_access_level(project, :forking) }
- expose(:wiki_access_level) { |project, options| project_feature_string_access_level(project, :wiki) }
- expose(:builds_access_level) { |project, options| project_feature_string_access_level(project, :builds) }
- expose(:snippets_access_level) { |project, options| project_feature_string_access_level(project, :snippets) }
- expose(:pages_access_level) { |project, options| project_feature_string_access_level(project, :pages) }
- expose(:operations_access_level) { |project, options| project_feature_string_access_level(project, :operations) }
- expose(:analytics_access_level) { |project, options| project_feature_string_access_level(project, :analytics) }
- expose(:container_registry_access_level) { |project, options| project_feature_string_access_level(project, :container_registry) }
- expose(:security_and_compliance_access_level) { |project, options| project_feature_string_access_level(project, :security_and_compliance) }
- expose(:releases_access_level) { |project, options| project_feature_string_access_level(project, :releases) }
-
- expose :emails_disabled
- expose :shared_runners_enabled
- expose :lfs_enabled?, as: :lfs_enabled
- expose :creator_id
+ expose(:issues_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :issues) }
+ expose(:repository_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :repository) }
+ expose(:merge_requests_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :merge_requests) }
+ expose(:forking_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :forking) }
+ expose(:wiki_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :wiki) }
+ expose(:builds_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :builds) }
+ expose(:snippets_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :snippets) }
+ expose(:pages_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :pages) }
+ expose(:operations_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :operations) }
+ expose(:analytics_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :analytics) }
+ expose(:container_registry_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :container_registry) }
+ expose(:security_and_compliance_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :security_and_compliance) }
+ expose(:releases_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :releases) }
+
+ expose :emails_disabled, documentation: { type: 'boolean' }
+ expose :shared_runners_enabled, documentation: { type: 'boolean' }
+ expose :lfs_enabled?, as: :lfs_enabled, documentation: { type: 'boolean' }
+ expose :creator_id, documentation: { type: 'integer', example: 1 }
expose :forked_from_project, using: Entities::BasicProjectDetails, if: ->(project, options) do
project.forked? && Ability.allowed?(options[:current_user], :read_project, project.forked_from_project)
end
- expose :mr_default_target_self, if: -> (project) { project.forked? }
+ expose :mr_default_target_self, if: -> (project) { project.forked? }, documentation: { type: 'boolean' }
- expose :import_url, if: -> (project, options) { Ability.allowed?(options[:current_user], :admin_project, project) } do |project|
+ expose :import_url, documentation: { type: 'string', example: 'https://gitlab.com/gitlab/gitlab.git' }, if: -> (project, options) { Ability.allowed?(options[:current_user], :admin_project, project) } do |project|
project[:import_url]
end
- expose :import_type, if: -> (project, options) { Ability.allowed?(options[:current_user], :admin_project, project) }
- expose :import_status
- expose :import_error, if: lambda { |_project, options| options[:user_can_admin_project] } do |project|
+ expose :import_type, documentation: { type: 'string', example: 'git' }, if: -> (project, options) { Ability.allowed?(options[:current_user], :admin_project, project) }
+ expose :import_status, documentation: { type: 'string', example: 'none' }
+ expose :import_error, documentation: { type: 'string', example: 'Import error' }, if: lambda { |_project, options| options[:user_can_admin_project] } do |project|
project.import_state&.last_error
end
- expose :open_issues_count, if: lambda { |project, options| project.feature_available?(:issues, options[:current_user]) }
- expose :runners_token, if: lambda { |_project, options| options[:user_can_admin_project] }
- expose :ci_default_git_depth
- expose :ci_forward_deployment_enabled
- expose(:ci_job_token_scope_enabled) { |p, _| p.ci_outbound_job_token_scope_enabled? }
- expose :ci_separated_caches
- expose :ci_opt_in_jwt
- expose :ci_allow_fork_pipelines_to_run_in_parent_project
- expose :public_builds, as: :public_jobs
- expose :build_git_strategy, if: lambda { |project, options| options[:user_can_admin_project] } do |project, options|
+ expose :open_issues_count, documentation: { type: 'integer', example: 1 }, if: lambda { |project, options| project.feature_available?(:issues, options[:current_user]) }
+ expose :runners_token, documentation: { type: 'string', example: 'b8547b1dc37721d05889db52fa2f02' }, if: lambda { |_project, options| options[:user_can_admin_project] }
+ expose :ci_default_git_depth, documentation: { type: 'integer', example: 20 }
+ expose :ci_forward_deployment_enabled, documentation: { type: 'boolean' }
+ expose(:ci_job_token_scope_enabled, documentation: { type: 'boolean' }) { |p, _| p.ci_outbound_job_token_scope_enabled? }
+ expose :ci_separated_caches, documentation: { type: 'boolean' }
+ expose :ci_opt_in_jwt, documentation: { type: 'boolean' }
+ expose :ci_allow_fork_pipelines_to_run_in_parent_project, documentation: { type: 'boolean' }
+ expose :public_builds, as: :public_jobs, documentation: { type: 'boolean' }
+ expose :build_git_strategy, documentation: { type: 'string', example: 'fetch' }, if: lambda { |project, options| options[:user_can_admin_project] } do |project, options|
project.build_allow_git_fetch ? 'fetch' : 'clone'
end
- expose :build_timeout
- expose :auto_cancel_pending_pipelines
- expose :ci_config_path, if: -> (project, options) { Ability.allowed?(options[:current_user], :download_code, project) }
- expose :shared_with_groups do |project, options|
+ expose :build_timeout, documentation: { type: 'integer', example: 3600 }
+ expose :auto_cancel_pending_pipelines, documentation: { type: 'string', example: 'enabled' }
+ expose :ci_config_path, documentation: { type: 'string', example: '' }, if: -> (project, options) { Ability.allowed?(options[:current_user], :read_code, project) }
+ expose :shared_with_groups, documentation: { is_array: true } do |project, options|
user = options[:current_user]
SharedGroupWithProject.represent(project.visible_group_links(for_user: user), options)
end
- expose :only_allow_merge_if_pipeline_succeeds
- expose :allow_merge_on_skipped_pipeline
- expose :restrict_user_defined_variables
- expose :request_access_enabled
- expose :only_allow_merge_if_all_discussions_are_resolved
- expose :remove_source_branch_after_merge
- expose :printing_merge_request_link_enabled
- expose :merge_method
- expose :squash_option
- expose :enforce_auth_checks_on_uploads
- expose :suggestion_commit_message
- expose :merge_commit_template
- expose :squash_commit_template
+ expose :only_allow_merge_if_pipeline_succeeds, documentation: { type: 'boolean' }
+ expose :allow_merge_on_skipped_pipeline, documentation: { type: 'boolean' }
+ expose :restrict_user_defined_variables, documentation: { type: 'boolean' }
+ expose :request_access_enabled, documentation: { type: 'boolean' }
+ expose :only_allow_merge_if_all_discussions_are_resolved, documentation: { type: 'boolean' }
+ expose :remove_source_branch_after_merge, documentation: { type: 'boolean' }
+ expose :printing_merge_request_link_enabled, documentation: { type: 'boolean' }
+ expose :merge_method, documentation: { type: 'string', example: 'merge' }
+ expose :squash_option, documentation: { type: 'string', example: 'default_off' }
+ expose :enforce_auth_checks_on_uploads, documentation: { type: 'boolean' }
+ expose :suggestion_commit_message, documentation: { type: 'string', example: 'Suggestion message' }
+ expose :merge_commit_template, documentation: { type: 'string', example: '%(title)' }
+ expose :squash_commit_template, documentation: { type: 'string', example: '%(source_branch)' }
+ expose :issue_branch_template, documentation: { type: 'string', example: '%(title)' }
expose :statistics, using: 'API::Entities::ProjectStatistics', if: -> (project, options) {
options[:statistics] && Ability.allowed?(options[:current_user], :read_statistics, project)
}
- expose :auto_devops_enabled?, as: :auto_devops_enabled
- expose :auto_devops_deploy_strategy do |project, options|
+ expose :auto_devops_enabled?, as: :auto_devops_enabled, documentation: { type: 'boolean' }
+ expose :auto_devops_deploy_strategy, documentation: { type: 'string', example: 'continuous' } do |project, options|
project.auto_devops.nil? ? 'continuous' : project.auto_devops.deploy_strategy
end
- expose :autoclose_referenced_issues
- expose :repository_storage, if: ->(project, options) {
+ expose :autoclose_referenced_issues, documentation: { type: 'boolean' }
+ expose :repository_storage, documentation: { type: 'string', example: 'default' }, if: ->(project, options) {
Ability.allowed?(options[:current_user], :change_repository_storage, project)
}
- expose :keep_latest_artifacts_available?, as: :keep_latest_artifact
- expose :runner_token_expiration_interval
+ expose :keep_latest_artifacts_available?, as: :keep_latest_artifact, documentation: { type: 'boolean' }
+ expose :runner_token_expiration_interval, documentation: { type: 'integer', example: 3600 }
# rubocop: disable CodeReuse/ActiveRecord
def self.preload_resource(project)
diff --git a/lib/api/entities/project_daily_fetches.rb b/lib/api/entities/project_daily_fetches.rb
index 036b5dc99b8..8797aeb9521 100644
--- a/lib/api/entities/project_daily_fetches.rb
+++ b/lib/api/entities/project_daily_fetches.rb
@@ -3,8 +3,8 @@
module API
module Entities
class ProjectDailyFetches < Grape::Entity
- expose :fetch_count, as: :count
- expose :date
+ expose :fetch_count, as: :count, documentation: { type: 'integer', example: 3 }
+ expose :date, documentation: { type: 'date', example: '2022-01-01' }
end
end
end
diff --git a/lib/api/entities/project_daily_statistics.rb b/lib/api/entities/project_daily_statistics.rb
index 803ee445851..555ecc6be39 100644
--- a/lib/api/entities/project_daily_statistics.rb
+++ b/lib/api/entities/project_daily_statistics.rb
@@ -4,8 +4,8 @@ module API
module Entities
class ProjectDailyStatistics < Grape::Entity
expose :fetches do
- expose :total_fetch_count, as: :total
- expose :fetches, as: :days, using: ProjectDailyFetches
+ expose :total_fetch_count, as: :total, documentation: { type: 'integer', example: 3 }
+ expose :fetches, as: :days, using: ProjectDailyFetches, documentation: { is_array: true }
end
end
end
diff --git a/lib/api/entities/project_export_status.rb b/lib/api/entities/project_export_status.rb
index ad84a45996a..9a2aeb7a6bb 100644
--- a/lib/api/entities/project_export_status.rb
+++ b/lib/api/entities/project_export_status.rb
@@ -5,13 +5,21 @@ module API
class ProjectExportStatus < ProjectIdentity
include ::API::Helpers::RelatedResourcesHelpers
- expose :export_status
+ expose :export_status, documentation: {
+ type: 'string', example: 'finished', values: %w[queued started finished failed]
+ }
expose :_links, if: lambda { |project, _options| project.export_status == :finished } do
- expose :api_url do |project|
+ expose :api_url, documentation: {
+ type: 'string',
+ example: 'https://gitlab.example.com/api/v4/projects/1/export/download'
+ } do |project|
expose_url(api_v4_projects_export_download_path(id: project.id))
end
- expose :web_url do |project|
+ expose :web_url, documentation: {
+ type: 'string',
+ example: 'https://gitlab.example.com/gitlab-org/gitlab-test/download_export'
+ } do |project|
Gitlab::Routing.url_helpers.download_export_project_url(project)
end
end
diff --git a/lib/api/entities/project_group_link.rb b/lib/api/entities/project_group_link.rb
index 89138854e67..b5d5991ec7f 100644
--- a/lib/api/entities/project_group_link.rb
+++ b/lib/api/entities/project_group_link.rb
@@ -3,7 +3,11 @@
module API
module Entities
class ProjectGroupLink < Grape::Entity
- expose :id, :project_id, :group_id, :group_access, :expires_at
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :project_id, documentation: { type: 'integer', example: 1 }
+ expose :group_id, documentation: { type: 'integer', example: 1 }
+ expose :group_access, documentation: { type: 'integer', example: 10 }
+ expose :expires_at, documentation: { type: 'date', example: '2016-09-26' }
end
end
end
diff --git a/lib/api/entities/project_hook.rb b/lib/api/entities/project_hook.rb
index 6c71e5d317c..bffb057abed 100644
--- a/lib/api/entities/project_hook.rb
+++ b/lib/api/entities/project_hook.rb
@@ -3,10 +3,17 @@
module API
module Entities
class ProjectHook < Hook
- expose :project_id, :issues_events, :confidential_issues_events
- expose :note_events, :confidential_note_events, :pipeline_events, :wiki_page_events, :deployment_events
- expose :job_events, :releases_events
- expose :push_events_branch_filter
+ expose :project_id, documentation: { type: 'string', example: 1 }
+ expose :issues_events, documentation: { type: 'boolean' }
+ expose :confidential_issues_events, documentation: { type: 'boolean' }
+ expose :note_events, documentation: { type: 'boolean' }
+ expose :confidential_note_events, documentation: { type: 'boolean' }
+ expose :pipeline_events, documentation: { type: 'boolean' }
+ expose :wiki_page_events, documentation: { type: 'boolean' }
+ expose :deployment_events, documentation: { type: 'boolean' }
+ expose :job_events, documentation: { type: 'boolean' }
+ expose :releases_events, documentation: { type: 'boolean' }
+ expose :push_events_branch_filter, documentation: { type: 'string', example: 'my-branch-*' }
end
end
end
diff --git a/lib/api/entities/project_identity.rb b/lib/api/entities/project_identity.rb
index 2055195eea0..14aef05b95e 100644
--- a/lib/api/entities/project_identity.rb
+++ b/lib/api/entities/project_identity.rb
@@ -3,10 +3,13 @@
module API
module Entities
class ProjectIdentity < Grape::Entity
- expose :id, :description
- expose :name, :name_with_namespace
- expose :path, :path_with_namespace
- expose :created_at
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :description, documentation: { type: 'string', example: 'desc' }
+ expose :name, documentation: { type: 'string', example: 'project1' }
+ expose :name_with_namespace, documentation: { type: 'string', example: 'John Doe / project1' }
+ expose :path, documentation: { type: 'string', example: 'project1' }
+ expose :path_with_namespace, documentation: { type: 'string', example: 'namespace1/project1' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2020-05-07T04:27:17.016Z' }
end
end
end
diff --git a/lib/api/entities/project_import_failed_relation.rb b/lib/api/entities/project_import_failed_relation.rb
index 26cfae7260c..543cc62f364 100644
--- a/lib/api/entities/project_import_failed_relation.rb
+++ b/lib/api/entities/project_import_failed_relation.rb
@@ -3,14 +3,17 @@
module API
module Entities
class ProjectImportFailedRelation < Grape::Entity
- expose :id, :created_at, :exception_class, :source
+ expose :id, documentation: { type: 'string', example: 1 }
+ expose :created_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ expose :exception_class, documentation: { type: 'string', example: 'StandardError' }
+ expose :source, documentation: { type: 'string', example: 'ImportRepositoryWorker' }
- expose :exception_message do |_|
+ expose :exception_message, documentation: { type: 'string' } do |_|
nil
end
- expose :relation_key, as: :relation_name
- expose :relation_index, as: :line_number
+ expose :relation_key, as: :relation_name, documentation: { type: 'string', example: 'issues' }
+ expose :relation_index, as: :line_number, documentation: { type: 'integer', example: 1 }
end
end
end
diff --git a/lib/api/entities/project_import_status.rb b/lib/api/entities/project_import_status.rb
index 5daae4a70f2..59388aacafd 100644
--- a/lib/api/entities/project_import_status.rb
+++ b/lib/api/entities/project_import_status.rb
@@ -3,21 +3,25 @@
module API
module Entities
class ProjectImportStatus < ProjectIdentity
- expose :import_status
- expose :import_type
- expose :correlation_id do |project, _options|
+ expose :import_status, documentation: { type: 'string', example: 'scheduled' }
+ expose :import_type, documentation: { type: 'string', example: 'gitlab_project' }
+ expose :correlation_id, documentation: {
+ type: 'string', example: 'dfcf583058ed4508e4c7c617bd7f0edd'
+ } do |project, _options|
project.import_state&.correlation_id
end
- expose :failed_relations, using: Entities::ProjectImportFailedRelation do |project, _options|
+ expose :failed_relations, using: Entities::ProjectImportFailedRelation, documentation: {
+ is_array: true
+ } do |project, _options|
project.import_state&.relation_hard_failures(limit: 100) || []
end
- expose :import_error do |project, _options|
+ expose :import_error, documentation: { type: 'string', example: 'Error message' } do |project, _options|
project.import_state&.last_error
end
- expose :stats do |project, _options|
+ expose :stats, documentation: { type: 'object' } do |project, _options|
if project.github_import?
::Gitlab::GithubImport::ObjectCounter.summary(project)
end
diff --git a/lib/api/entities/project_integration.rb b/lib/api/entities/project_integration.rb
index 155136d2f80..29bb60a19e5 100644
--- a/lib/api/entities/project_integration.rb
+++ b/lib/api/entities/project_integration.rb
@@ -4,7 +4,7 @@ module API
module Entities
class ProjectIntegration < Entities::ProjectIntegrationBasic
# Expose serialized properties
- expose :properties do |integration, options|
+ expose :properties, documentation: { type: 'Hash', example: { "token" => "secr3t" } } do |integration, options|
integration.api_field_names.to_h do |name|
[name, integration.public_send(name)] # rubocop:disable GitlabSecurity/PublicSend
end
diff --git a/lib/api/entities/project_integration_basic.rb b/lib/api/entities/project_integration_basic.rb
index 2870123b83d..aa0ad158b83 100644
--- a/lib/api/entities/project_integration_basic.rb
+++ b/lib/api/entities/project_integration_basic.rb
@@ -3,15 +3,26 @@
module API
module Entities
class ProjectIntegrationBasic < Grape::Entity
- expose :id, :title
- expose :slug do |integration|
+ expose :id, documentation: { type: 'integer', example: 75 }
+ expose :title, documentation: { type: 'string', example: 'Jenkins CI' }
+ expose :slug, documentation: { type: 'integer', example: 'jenkins' } do |integration|
integration.to_param.dasherize
end
- expose :created_at, :updated_at, :active
- expose :commit_events, :push_events, :issues_events, :confidential_issues_events
- expose :merge_requests_events, :tag_push_events, :note_events
- expose :confidential_note_events, :pipeline_events, :wiki_page_events
- expose :job_events, :comment_on_event_enabled
+ expose :created_at, documentation: { type: 'dateTime', example: '2019-11-20T11:20:25.297Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2019-11-20T12:24:37.498Z' }
+ expose :active, documentation: { type: 'boolean' }
+ expose :commit_events, documentation: { type: 'boolean' }
+ expose :push_events, documentation: { type: 'boolean' }
+ expose :issues_events, documentation: { type: 'boolean' }
+ expose :confidential_issues_events, documentation: { type: 'boolean' }
+ expose :merge_requests_events, documentation: { type: 'boolean' }
+ expose :tag_push_events, documentation: { type: 'boolean' }
+ expose :note_events, documentation: { type: 'boolean' }
+ expose :confidential_note_events, documentation: { type: 'boolean' }
+ expose :pipeline_events, documentation: { type: 'boolean' }
+ expose :wiki_page_events, documentation: { type: 'boolean' }
+ expose :job_events, documentation: { type: 'boolean' }
+ expose :comment_on_event_enabled, documentation: { type: 'boolean' }
end
end
end
diff --git a/lib/api/entities/project_repository_storage.rb b/lib/api/entities/project_repository_storage.rb
index 0816bebde2c..ae5039601d7 100644
--- a/lib/api/entities/project_repository_storage.rb
+++ b/lib/api/entities/project_repository_storage.rb
@@ -5,12 +5,16 @@ module API
class ProjectRepositoryStorage < Grape::Entity
include Gitlab::Routing
- expose :disk_path do |project|
+ expose :disk_path, documentation: {
+ type: 'string',
+ example: '@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b'
+ } do |project|
project.repository.disk_path
end
- expose :id, as: :project_id
- expose :repository_storage, :created_at
+ expose :id, as: :project_id, documentation: { type: 'integer', example: 1 }
+ expose :repository_storage, documentation: { type: 'string', example: 'default' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2012-10-12T17:04:47Z' }
end
end
end
diff --git a/lib/api/entities/project_with_access.rb b/lib/api/entities/project_with_access.rb
index b541ccbadcf..9722b8806d4 100644
--- a/lib/api/entities/project_with_access.rb
+++ b/lib/api/entities/project_with_access.rb
@@ -25,23 +25,41 @@ module API
# rubocop: disable CodeReuse/ActiveRecord
def self.preload_relation(projects_relation, options = {})
- relation = super(projects_relation, options)
- # use reselect to override the existing select and
- # prevent an error `subquery has too many columns`
- project_ids = relation.reselect('projects.id')
- namespace_ids = relation.reselect(:namespace_id)
+ if ::Feature.enabled?(:projects_preloader_fix)
+ super(projects_relation, options)
+ else
+ relation = super(projects_relation, options)
+ # use reselect to override the existing select and
+ # prevent an error `subquery has too many columns`
+ project_ids = relation.reselect('projects.id')
+ namespace_ids = relation.reselect(:namespace_id)
+
+ options[:project_members] = options[:current_user]
+ .project_members
+ .where(source_id: project_ids)
+ .preload(:source, user: [notification_settings: :source])
+
+ options[:group_members] = options[:current_user]
+ .group_members
+ .where(source_id: namespace_ids)
+ .preload(:source, user: [notification_settings: :source])
+
+ relation
+ end
+ end
+
+ def self.postload_relation(projects_relation, options = {})
+ return unless ::Feature.enabled?(:projects_preloader_fix)
options[:project_members] = options[:current_user]
.project_members
- .where(source_id: project_ids)
+ .where(source_id: projects_relation.subquery(:id))
.preload(:source, user: [notification_settings: :source])
options[:group_members] = options[:current_user]
.group_members
- .where(source_id: namespace_ids)
+ .where(source_id: projects_relation.subquery(:namespace_id))
.preload(:source, user: [notification_settings: :source])
-
- relation
end
# rubocop: enable CodeReuse/ActiveRecord
end
diff --git a/lib/api/entities/protected_branch.rb b/lib/api/entities/protected_branch.rb
index ac44d06e69c..42f721b40a6 100644
--- a/lib/api/entities/protected_branch.rb
+++ b/lib/api/entities/protected_branch.rb
@@ -3,11 +3,11 @@
module API
module Entities
class ProtectedBranch < Grape::Entity
- expose :id
- expose :name
- expose :push_access_levels, using: Entities::ProtectedRefAccess
- expose :merge_access_levels, using: Entities::ProtectedRefAccess
- expose :allow_force_push
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :name, documentation: { type: 'string', example: 'main' }
+ expose :push_access_levels, using: Entities::ProtectedRefAccess, documentation: { is_array: true }
+ expose :merge_access_levels, using: Entities::ProtectedRefAccess, documentation: { is_array: true }
+ expose :allow_force_push, 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 443277e23cf..ba28c724448 100644
--- a/lib/api/entities/protected_ref_access.rb
+++ b/lib/api/entities/protected_ref_access.rb
@@ -3,10 +3,12 @@
module API
module Entities
class ProtectedRefAccess < Grape::Entity
- expose :access_level
- expose :access_level_description do |protected_ref_access|
- protected_ref_access.humanize
- end
+ 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
end
end
end
diff --git a/lib/api/entities/protected_tag.rb b/lib/api/entities/protected_tag.rb
index dc397f01af6..ba984ae79b8 100644
--- a/lib/api/entities/protected_tag.rb
+++ b/lib/api/entities/protected_tag.rb
@@ -3,7 +3,7 @@
module API
module Entities
class ProtectedTag < Grape::Entity
- expose :name
+ expose :name, documentation: { type: 'string', example: 'release-1-0' }
expose :create_access_levels, using: Entities::ProtectedRefAccess
end
end
diff --git a/lib/api/entities/pull_mirror.rb b/lib/api/entities/pull_mirror.rb
new file mode 100644
index 00000000000..72a5220987e
--- /dev/null
+++ b/lib/api/entities/pull_mirror.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class PullMirror < Grape::Entity
+ expose :id, documentation: { type: 'integer', example: 101486 }
+ expose :status, as: :update_status, documentation: { type: 'string', example: 'finished' }
+ expose :url,
+documentation: { type: 'string',
+ example: 'https://*****:*****@gitlab.com/gitlab-org/security/gitlab.git' } do |import_state|
+ import_state.project.safe_import_url
+ end
+ expose :last_error, documentation: { type: 'string', example: nil }
+ expose :last_update_at, documentation: { type: 'dateTime', example: '2020-01-06T17:32:02.823Z' }
+ expose :last_update_started_at, documentation: { type: 'dateTime', example: '2020-01-06T17:32:02.823Z' }
+ expose :last_successful_update_at, documentation: { type: 'dateTime', example: '2020-01-06T17:32:02.823Z' }
+ end
+ end
+end
diff --git a/lib/api/entities/release.rb b/lib/api/entities/release.rb
index 2403c907f7f..c1a48a46d64 100644
--- a/lib/api/entities/release.rb
+++ b/lib/api/entities/release.rb
@@ -9,22 +9,24 @@ module API
MarkupHelper.markdown_field(entity, :description, current_user: options[:current_user])
end
expose :author, using: Entities::UserBasic, if: -> (release, _) { release.author.present? }
- expose :commit, using: Entities::Commit, if: ->(_, _) { can_download_code? }
+ expose :commit, using: Entities::Commit, if: ->(_, _) { can_read_code? }
expose :milestones,
using: Entities::MilestoneWithStats,
if: -> (release, _) { release.milestones.present? && can_read_milestone? } do |release, _|
release.milestones.order_by_dates_and_title
end
- expose :commit_path, expose_nil: false
- expose :tag_path, expose_nil: false
+ expose :commit_path,
+ documentation: { type: 'string', example: '/root/app/commit/588440f66559714280628a4f9799f0c4eb880a4a' },
+ expose_nil: false
+ expose :tag_path, documentation: { type: 'string', example: '/root/app/-/tags/v1.0' }, expose_nil: false
expose :assets do
- expose :assets_count, as: :count
- expose :sources, using: Entities::Releases::Source, if: ->(_, _) { can_download_code? }
+ expose :assets_count, documentation: { type: 'integer', example: 2 }, as: :count
+ expose :sources, using: Entities::Releases::Source, if: ->(_, _) { can_read_code? }
expose :sorted_links, as: :links, using: Entities::Releases::Link
end
- expose :evidences, using: Entities::Releases::Evidence, expose_nil: false, if: ->(_, _) { can_download_code? }
+ expose :evidences, using: Entities::Releases::Evidence, expose_nil: false, if: ->(_, _) { can_read_code? }
expose :_links do
expose :self_url, as: :self, expose_nil: false
expose :edit_url, expose_nil: false
@@ -32,8 +34,8 @@ module API
private
- def can_download_code?
- Ability.allowed?(options[:current_user], :download_code, object.project)
+ def can_read_code?
+ Ability.allowed?(options[:current_user], :read_code, object.project)
end
def can_read_milestone?
diff --git a/lib/api/entities/releases/evidence.rb b/lib/api/entities/releases/evidence.rb
index 01603a71dbf..9d324309213 100644
--- a/lib/api/entities/releases/evidence.rb
+++ b/lib/api/entities/releases/evidence.rb
@@ -6,9 +6,9 @@ module API
class Evidence < Grape::Entity
include ::API::Helpers::Presentable
- expose :sha
- expose :filepath
- expose :collected_at
+ expose :sha, documentation: { type: 'string', example: '760d6cdfb0879c3ffedec13af470e0f71cf52c6cde4d' }
+ expose :filepath, documentation: { type: 'string', example: 'https://gitlab.example.com/root/app/-/releases/v1.0/evidence.json' }
+ expose :collected_at, documentation: { type: 'dateTime', example: '2019-01-03T01:56:19.539Z' }
end
end
end
diff --git a/lib/api/entities/releases/link.rb b/lib/api/entities/releases/link.rb
index 5157645af69..abf380e11d5 100644
--- a/lib/api/entities/releases/link.rb
+++ b/lib/api/entities/releases/link.rb
@@ -4,14 +4,22 @@ module API
module Entities
module Releases
class Link < Grape::Entity
- expose :id
- expose :name
- expose :url
- expose :direct_asset_url do |link|
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :name, documentation: { type: 'string', example: 'app-v1.0.dmg' }
+ expose :url, documentation:
+ {
+ type: 'string',
+ example: 'https://gitlab.example.com/root/app/-/jobs/688/artifacts/raw/bin/app-v1.0.dmg'
+ }
+ expose :direct_asset_url, documentation:
+ {
+ type: 'string',
+ example: 'https://gitlab.example.com/root/app/-/releases/v1.0/downloads/app-v1.0.dmg'
+ } do |link|
::Releases::LinkPresenter.new(link).direct_asset_url
end
- expose :external?, as: :external
- expose :link_type
+ expose :external?, documentation: { type: 'boolean' }, as: :external
+ expose :link_type, documentation: { type: 'string', example: 'other' }
end
end
end
diff --git a/lib/api/entities/releases/source.rb b/lib/api/entities/releases/source.rb
index 2b0c8038ddf..8c6750d6142 100644
--- a/lib/api/entities/releases/source.rb
+++ b/lib/api/entities/releases/source.rb
@@ -4,8 +4,8 @@ module API
module Entities
module Releases
class Source < Grape::Entity
- expose :format
- expose :url
+ expose :format, documentation: { type: 'string', example: 'zip' }
+ expose :url, documentation: { type: 'string', example: 'https://gitlab.example.com/root/app/-/archive/v1.0/app-v1.0.zip' }
end
end
end
diff --git a/lib/api/entities/remote_mirror.rb b/lib/api/entities/remote_mirror.rb
index 87daef9a05c..9fb5b2697bc 100644
--- a/lib/api/entities/remote_mirror.rb
+++ b/lib/api/entities/remote_mirror.rb
@@ -3,16 +3,16 @@
module API
module Entities
class RemoteMirror < Grape::Entity
- expose :id
- expose :enabled
- expose :safe_url, as: :url
- expose :update_status
- expose :last_update_at
- expose :last_update_started_at
- expose :last_successful_update_at
- expose :last_error
- expose :only_protected_branches
- expose :keep_divergent_refs
+ expose :id, documentation: { type: 'integer', example: 101486 }
+ expose :enabled, documentation: { type: 'boolean', example: true }
+ expose :safe_url, as: :url, documentation: { type: 'string', example: 'https://*****:*****@example.com/gitlab/example.git' }
+ expose :update_status, documentation: { type: 'string', example: 'finished' }
+ expose :last_update_at, documentation: { type: 'dateTime', example: '2020-01-06T17:32:02.823Z' }
+ expose :last_update_started_at, documentation: { type: 'dateTime', example: '2020-01-06T17:32:02.823Z' }
+ expose :last_successful_update_at, documentation: { type: 'dateTime', example: '2020-01-06T17:31:55.864Z' }
+ expose :last_error, documentation: { type: 'integer', example: 'The remote mirror URL is invalid.' }
+ expose :only_protected_branches, documentation: { type: 'boolean' }
+ expose :keep_divergent_refs, documentation: { type: 'boolean' }
end
end
end
diff --git a/lib/api/entities/resource_access_token.rb b/lib/api/entities/resource_access_token.rb
index 569fd16f488..e4f140d3fc0 100644
--- a/lib/api/entities/resource_access_token.rb
+++ b/lib/api/entities/resource_access_token.rb
@@ -3,7 +3,12 @@
module API
module Entities
class ResourceAccessToken < Entities::PersonalAccessToken
- expose :access_level do |token, options|
+ expose :access_level,
+ documentation: { type: 'integer',
+ example: 40,
+ description: 'Access level. Valid values are 10 (Guest), 20 (Reporter), 30 (Developer) \
+ , 40 (Maintainer), and 50 (Owner). Defaults to 40.',
+ values: [10, 20, 30, 40, 50] } do |token, options|
options[:resource].member(token.user).access_level
end
end
diff --git a/lib/api/entities/resource_milestone_event.rb b/lib/api/entities/resource_milestone_event.rb
index 26dc6620cbe..b301f5b7d0a 100644
--- a/lib/api/entities/resource_milestone_event.rb
+++ b/lib/api/entities/resource_milestone_event.rb
@@ -3,18 +3,18 @@
module API
module Entities
class ResourceMilestoneEvent < Grape::Entity
- expose :id
+ expose :id, documentation: { type: 'integer', example: 142 }
expose :user, using: Entities::UserBasic
- expose :created_at
- expose :resource_type do |event, _options|
+ expose :created_at, documentation: { type: 'dateTime', example: '2018-08-20T13:38:20.077Z' }
+ expose :resource_type, documentation: { type: 'string', example: 'Issue' } do |event, _options|
event.issuable.class.name
end
- expose :resource_id do |event, _options|
+ expose :resource_id, documentation: { type: 'integer', example: 253 } do |event, _options|
event.issuable.id
end
expose :milestone, using: Entities::Milestone
- expose :action
- expose :state
+ expose :action, documentation: { type: 'string', example: 'add' }
+ expose :state, documentation: { type: 'string', example: 'active' }
end
end
end
diff --git a/lib/api/entities/snippet.rb b/lib/api/entities/snippet.rb
index af885aaf0eb..709566944ed 100644
--- a/lib/api/entities/snippet.rb
+++ b/lib/api/entities/snippet.rb
@@ -3,11 +3,13 @@
module API
module Entities
class Snippet < BasicSnippet
- expose :author, using: Entities::UserBasic
- expose :file_name do |snippet|
+ expose :author, using: Entities::UserBasic, documentation: { type: 'Entities::UserBasic' }
+ expose :file_name, documentation: { type: 'string', example: 'add.rb' } do |snippet|
snippet_files.first || snippet.file_name
end
- expose :files do |snippet, options|
+ expose :files, documentation: {
+ is_array: true, example: 'e0d123e5f316bef78bfdf5a008837577'
+ } do |snippet, options|
snippet_files.map do |file|
{
path: file,
diff --git a/lib/api/entities/snippets/repository_storage_move.rb b/lib/api/entities/snippets/repository_storage_move.rb
index 4e14d1dfba2..711d07545fb 100644
--- a/lib/api/entities/snippets/repository_storage_move.rb
+++ b/lib/api/entities/snippets/repository_storage_move.rb
@@ -4,7 +4,7 @@ module API
module Entities
module Snippets
class RepositoryStorageMove < BasicRepositoryStorageMove
- expose :snippet, using: Entities::BasicSnippet
+ expose :snippet, using: Entities::BasicSnippet, documentation: { type: 'Entities::BasicSnippet' }
end
end
end
diff --git a/lib/api/entities/ssh_key.rb b/lib/api/entities/ssh_key.rb
index e1554730cb6..3db10bb8ec2 100644
--- a/lib/api/entities/ssh_key.rb
+++ b/lib/api/entities/ssh_key.rb
@@ -3,8 +3,15 @@
module API
module Entities
class SSHKey < Grape::Entity
- expose :id, :title, :created_at, :expires_at
- expose :publishable_key, as: :key
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :title, documentation: { type: 'string', example: 'Sample key 25' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2015-09-03T07:24:44.627Z' }
+ expose :expires_at, documentation: { type: 'dateTime', example: '2020-09-03T07:24:44.627Z' }
+ expose :publishable_key, as: :key, documentation:
+ { type: 'string',
+ example: 'ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt1256k6Yjz\
+ GGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCdd\
+ NaP0L+hM7zhFNzjFvpaMgJw0=' }
end
end
end
diff --git a/lib/api/entities/tag.rb b/lib/api/entities/tag.rb
index 2d3569bb9bb..713bae64d5c 100644
--- a/lib/api/entities/tag.rb
+++ b/lib/api/entities/tag.rb
@@ -3,7 +3,9 @@
module API
module Entities
class Tag < Grape::Entity
- expose :name, :message, :target
+ expose :name, documentation: { type: 'string', example: 'v1.0.0' }
+ expose :message, documentation: { type: 'string', example: 'Release v1.0.0' }
+ expose :target, documentation: { type: 'string', example: '2695effb5807a22ff3d138d593fd856244e155e7' }
expose :commit, using: Entities::Commit do |repo_tag, options|
options[:project].repository.commit(repo_tag.dereferenced_target)
@@ -15,7 +17,7 @@ module API
end
# rubocop: enable CodeReuse/ActiveRecord
- expose :protected do |repo_tag, options|
+ expose :protected, documentation: { type: 'boolean', example: true } do |repo_tag, options|
::ProtectedTag.protected?(options[:project], repo_tag.name)
end
end
diff --git a/lib/api/entities/tag_release.rb b/lib/api/entities/tag_release.rb
index d5f73d60332..66d1eeeab4a 100644
--- a/lib/api/entities/tag_release.rb
+++ b/lib/api/entities/tag_release.rb
@@ -4,8 +4,8 @@ module API
module Entities
# deprecated old Release representation
class TagRelease < Grape::Entity
- expose :tag, as: :tag_name
- expose :description
+ expose :tag, as: :tag_name, documentation: { type: 'string', example: '1.0.0' }
+ expose :description, documentation: { type: 'string', example: 'Amazing release. Wow' }
end
end
end
diff --git a/lib/api/entities/templates_list.rb b/lib/api/entities/templates_list.rb
index 8e8aa1bd285..eba80bd04d3 100644
--- a/lib/api/entities/templates_list.rb
+++ b/lib/api/entities/templates_list.rb
@@ -3,8 +3,8 @@
module API
module Entities
class TemplatesList < Grape::Entity
- expose :key
- expose :name
+ expose :key, documentation: { type: 'string', example: 'mit' }
+ expose :name, documentation: { type: 'string', example: 'MIT License' }
end
end
end
diff --git a/lib/api/entities/tree_object.rb b/lib/api/entities/tree_object.rb
index e4e840ebe43..1f542885169 100644
--- a/lib/api/entities/tree_object.rb
+++ b/lib/api/entities/tree_object.rb
@@ -3,9 +3,12 @@
module API
module Entities
class TreeObject < Grape::Entity
- expose :id, :name, :type, :path
+ expose :id, documentation: { example: 'a1e8f8d745cc87e3a9248358d9352bb7f9a0aeba' }
+ expose :name, documentation: { example: 'html' }
+ expose :type, documentation: { example: 'tree' }
+ expose :path, documentation: { example: 'files/html' }
- expose :mode do |obj, options|
+ expose :mode, documentation: { example: '040000' } do |obj, options|
filemode = obj.mode
filemode = "0" + filemode if filemode.length < 6
filemode
diff --git a/lib/api/entities/trigger.rb b/lib/api/entities/trigger.rb
index 6a9f772fc6b..ccdaeb6a07a 100644
--- a/lib/api/entities/trigger.rb
+++ b/lib/api/entities/trigger.rb
@@ -5,10 +5,12 @@ module API
class Trigger < Grape::Entity
include ::API::Helpers::Presentable
- expose :id
- expose :token
- expose :description
- expose :created_at, :updated_at, :last_used
+ expose :id, documentation: { type: 'integer', example: 10 }
+ expose :token, documentation: { type: 'string', example: '6d056f63e50fe6f8c5f8f4aa10edb7' }
+ expose :description, documentation: { type: 'string', example: 'test' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2015-12-24T15:51:21.880Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2015-12-24T17:54:31.198Z' }
+ expose :last_used, documentation: { type: 'dateTime', example: '2015-12-24T17:54:31.198Z' }
expose :owner, using: Entities::UserBasic
end
end
diff --git a/lib/api/entities/user_agent_detail.rb b/lib/api/entities/user_agent_detail.rb
index a2d02c16589..eb6d909794e 100644
--- a/lib/api/entities/user_agent_detail.rb
+++ b/lib/api/entities/user_agent_detail.rb
@@ -3,9 +3,9 @@
module API
module Entities
class UserAgentDetail < Grape::Entity
- expose :user_agent
- expose :ip_address
- expose :submitted, as: :akismet_submitted
+ expose :user_agent, documentation: { type: 'string', example: 'AppleWebKit/537.36' }
+ expose :ip_address, documentation: { type: 'string', example: '127.0.0.1' }
+ expose :submitted, as: :akismet_submitted, documentation: { type: 'boolean', example: false }
end
end
end
diff --git a/lib/api/entities/user_associations_count.rb b/lib/api/entities/user_associations_count.rb
new file mode 100644
index 00000000000..af744d2d49a
--- /dev/null
+++ b/lib/api/entities/user_associations_count.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class UserAssociationsCount < Grape::Entity
+ expose :groups_count do |user|
+ user.groups.size
+ end
+
+ expose :projects_count do |user|
+ user.projects.size
+ end
+
+ expose :issues_count do |user|
+ user.issues.size
+ end
+
+ expose :merge_requests_count do |user|
+ user.merge_requests.size
+ end
+ end
+ end
+end
diff --git a/lib/api/entities/user_basic.rb b/lib/api/entities/user_basic.rb
index b8ee4e5a6e0..32e066b9f7e 100644
--- a/lib/api/entities/user_basic.rb
+++ b/lib/api/entities/user_basic.rb
@@ -3,16 +3,25 @@
module API
module Entities
class UserBasic < UserSafe
- expose :state
+ expose :state, documentation: { type: 'string', example: 'active' }
- expose :avatar_url do |user, options|
+ expose :avatar_url, documentation: { type: 'string', example: 'https://gravatar.com/avatar/1' } do |user, options|
user.avatar_url(only_path: false)
end
- expose :avatar_path, if: ->(user, options) { options.fetch(:only_path, false) && user.avatar_path }
- expose :custom_attributes, using: 'API::Entities::CustomAttribute', if: :with_custom_attributes
+ expose(
+ :avatar_path,
+ documentation: {
+ type: 'string',
+ example: '/user/avatar/28/The-Big-Lebowski-400-400.png'
+ },
+ if: ->(user, options) { options.fetch(:only_path, false) && user.avatar_path }
+ )
- expose :web_url do |user, options|
+ expose :custom_attributes, using: 'API::Entities::CustomAttribute', if: :with_custom_attributes,
+ documentation: { is_array: true }
+
+ expose :web_url, documentation: { type: 'string', example: 'https://gitlab.example.com/root' } do |user, options|
Gitlab::Routing.url_helpers.user_url(user)
end
end
diff --git a/lib/api/entities/user_counts.rb b/lib/api/entities/user_counts.rb
new file mode 100644
index 00000000000..e86454c249b
--- /dev/null
+++ b/lib/api/entities/user_counts.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class UserCounts < Grape::Entity
+ expose(
+ :assigned_open_merge_requests_count, # @deprecated
+ as: :merge_requests,
+ documentation: { type: 'integer', example: 10 }
+ )
+ expose :assigned_open_issues_count, as: :assigned_issues, documentation: { type: 'integer', example: 10 }
+ expose(
+ :assigned_open_merge_requests_count,
+ as: :assigned_merge_requests,
+ documentation: { type: 'integer', example: 10 }
+ )
+ expose(
+ :review_requested_open_merge_requests_count,
+ as: :review_requested_merge_requests,
+ documentation: { type: 'integer', example: 10 }
+ )
+ expose :todos_pending_count, as: :todos, documentation: { type: 'integer', example: 10 }
+ end
+ end
+end
diff --git a/lib/api/entities/user_public.rb b/lib/api/entities/user_public.rb
index 5d0e464abe1..eda72d2cfc6 100644
--- a/lib/api/entities/user_public.rb
+++ b/lib/api/entities/user_public.rb
@@ -3,17 +3,23 @@
module API
module Entities
class UserPublic < Entities::User
- expose :last_sign_in_at
- expose :confirmed_at
- expose :last_activity_on
- expose :email
- expose :theme_id, :color_scheme_id, :projects_limit, :current_sign_in_at
+ expose :last_sign_in_at, documentation: { type: 'dateTime', example: '2015-09-03T07:24:01.670Z' }
+ expose :confirmed_at, documentation: { type: 'dateTime', example: '2015-09-03T07:24:01.670Z' }
+ expose :last_activity_on, documentation: { type: 'dateTime', example: '2015-09-03T07:24:01.670Z' }
+ expose :email, documentation: { type: 'string', example: 'john@example.com' }
+ expose :theme_id, documentation: { type: 'integer', example: 2 }
+ expose :color_scheme_id, documentation: { type: 'integer', example: 1 }
+ expose :projects_limit, documentation: { type: 'integer', example: 10 }
+ expose :current_sign_in_at, documentation: { type: 'dateTime', example: '2015-09-03T07:24:01.670Z' }
expose :identities, using: Entities::Identity
- expose :can_create_group?, as: :can_create_group
- expose :can_create_project?, as: :can_create_project
- expose :two_factor_enabled?, as: :two_factor_enabled
+ expose :can_create_group?, as: :can_create_group, documentation: { type: 'boolean', example: true }
+ expose :can_create_project?, as: :can_create_project, documentation: { type: 'boolean', example: true }
+
+ expose :two_factor_enabled?, as: :two_factor_enabled, documentation: { type: 'boolean', example: true }
+
expose :external
- expose :private_profile
+
+ expose :private_profile, documentation: { type: 'boolean', example: :null }
expose :commit_email_or_default, as: :commit_email
end
end
diff --git a/lib/api/entities/user_safe.rb b/lib/api/entities/user_safe.rb
index 127a8ef2160..0fbb10307cf 100644
--- a/lib/api/entities/user_safe.rb
+++ b/lib/api/entities/user_safe.rb
@@ -5,8 +5,9 @@ module API
class UserSafe < Grape::Entity
include RequestAwareEntity
- expose :id, :username
- expose :name do |user|
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :username, documentation: { type: 'string', example: 'admin' }
+ expose :name, documentation: { type: 'string', example: 'Administrator' } do |user|
current_user = request.respond_to?(:current_user) ? request.current_user : options.fetch(:current_user, nil)
user.redacted_name(current_user)
diff --git a/lib/api/entities/wiki_attachment.rb b/lib/api/entities/wiki_attachment.rb
index 03a6cc8d644..8629261cfc6 100644
--- a/lib/api/entities/wiki_attachment.rb
+++ b/lib/api/entities/wiki_attachment.rb
@@ -5,12 +5,16 @@ module API
class WikiAttachment < Grape::Entity
include Gitlab::FileMarkdownLinkBuilder
- expose :file_name
- expose :file_path
- expose :branch
+ expose :file_name, documentation: { type: 'string', example: 'dk.png' }
+ expose :file_path, documentation: { type: 'string', example: 'uploads/6a061c4cf9f1c28cb22c384b4b8d4e3c/dk.png' }
+ expose :branch, documentation: { type: 'string', example: 'main' }
expose :link do
- expose :file_path, as: :url
- expose :markdown do |_entity|
+ expose :file_path, as: :url, documentation: {
+ type: 'string', example: 'uploads/6a061c4cf9f1c28cb22c384b4b8d4e3c/dk.png'
+ }
+ expose :markdown, documentation: {
+ type: 'string', example: '![dk](uploads/6a061c4cf9f1c28cb22c384b4b8d4e3c/dk.png)'
+ } do |_entity|
self.markdown_link
end
end
diff --git a/lib/api/entities/wiki_page.rb b/lib/api/entities/wiki_page.rb
index 5bba4271396..07ef4a4a156 100644
--- a/lib/api/entities/wiki_page.rb
+++ b/lib/api/entities/wiki_page.rb
@@ -5,7 +5,9 @@ module API
class WikiPage < WikiPageBasic
include ::MarkupHelper
- expose :content do |wiki_page, options|
+ expose :content, documentation: {
+ type: 'string', example: 'Here is an instruction how to deploy this project.'
+ } do |wiki_page, options|
if options[:render_html]
render_wiki_content(
wiki_page,
@@ -17,7 +19,7 @@ module API
end
end
- expose :encoding do |wiki_page|
+ expose :encoding, documentation: { type: 'string', example: 'UTF-8' } do |wiki_page|
wiki_page.content.encoding.name
end
end
diff --git a/lib/api/entities/wiki_page_basic.rb b/lib/api/entities/wiki_page_basic.rb
index e10c0e6d553..088a0d1bf55 100644
--- a/lib/api/entities/wiki_page_basic.rb
+++ b/lib/api/entities/wiki_page_basic.rb
@@ -3,9 +3,9 @@
module API
module Entities
class WikiPageBasic < Grape::Entity
- expose :format
- expose :slug
- expose :title
+ expose :format, documentation: { type: 'string', example: 'markdown' }
+ expose :slug, documentation: { type: 'string', example: 'deploy' }
+ expose :title, documentation: { type: 'string', example: 'deploy' }
end
end
end
diff --git a/lib/api/entities/x509_certificate.rb b/lib/api/entities/x509_certificate.rb
index aad11339148..95d4948906e 100644
--- a/lib/api/entities/x509_certificate.rb
+++ b/lib/api/entities/x509_certificate.rb
@@ -3,13 +3,16 @@
module API
module Entities
class X509Certificate < Grape::Entity
- expose :id
- expose :subject
- expose :subject_key_identifier
- expose :email
- expose :serial_number
- expose :certificate_status
- expose :x509_issuer, using: 'API::Entities::X509Issuer'
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :subject, documentation: { type: 'string', example: 'CN=gitlab@example.org,OU=Example,O=World' }
+ expose :subject_key_identifier, documentation: {
+ type: 'string',
+ example: 'BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC'
+ }
+ expose :email, documentation: { type: 'string', example: 'gitlab@example.org' }
+ expose :serial_number, documentation: { type: 'integer', example: 278969561018901340486471282831158785578 }
+ expose :certificate_status, documentation: { type: 'string', example: 'good' }
+ expose :x509_issuer, using: 'API::Entities::X509Issuer', documentation: { type: 'string', example: '100755' }
end
end
end
diff --git a/lib/api/entities/x509_issuer.rb b/lib/api/entities/x509_issuer.rb
index b480bc107bc..22429560c72 100644
--- a/lib/api/entities/x509_issuer.rb
+++ b/lib/api/entities/x509_issuer.rb
@@ -3,10 +3,13 @@
module API
module Entities
class X509Issuer < Grape::Entity
- expose :id
- expose :subject
- expose :subject_key_identifier
- expose :crl_url
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :subject, documentation: { type: 'string', example: 'CN=PKI,OU=Example,O=World' }
+ expose :subject_key_identifier, documentation: {
+ type: 'string',
+ example: 'AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB'
+ }
+ expose :crl_url, documentation: { type: 'string', example: 'http://example.com/pki.crl' }
end
end
end
diff --git a/lib/api/entities/x509_signature.rb b/lib/api/entities/x509_signature.rb
index 909b630288c..c3f0cb3659d 100644
--- a/lib/api/entities/x509_signature.rb
+++ b/lib/api/entities/x509_signature.rb
@@ -3,7 +3,7 @@
module API
module Entities
class X509Signature < Grape::Entity
- expose :verification_status
+ expose :verification_status, documentation: { type: 'string', example: 'unverified' }
expose :x509_certificate, using: 'API::Entities::X509Certificate'
end
end
diff --git a/lib/api/environments.rb b/lib/api/environments.rb
index 42d5e6a73b3..01d46ee7bfb 100644
--- a/lib/api/environments.rb
+++ b/lib/api/environments.rb
@@ -5,24 +5,35 @@ module API
class Environments < ::API::Base
include PaginationParams
+ environments_tags = %w[environments]
+
before { authenticate! }
feature_category :continuous_delivery
urgency :low
params do
- requires :id, type: String, desc: 'The project ID'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get all environments of the project' do
- detail 'This feature was introduced in GitLab 8.11.'
+ desc 'List environments' do
+ detail 'Get all environments for a given project. This feature was introduced in GitLab 8.11.'
success Entities::Environment
+ is_array true
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags environments_tags
end
params do
use :pagination
- optional :name, type: String, desc: 'Returns the environment with this name'
- optional :search, type: String, desc: 'Returns list of environments matching the search criteria'
- optional :states, type: String, values: Environment.valid_states.map(&:to_s), desc: 'List all environments that match a specific state'
+ optional :name, type: String, desc: 'Return the environment with this name. Mutually exclusive with search'
+ optional :search, type: String, desc: 'Return list of environments matching the search criteria. Mutually exclusive with name'
+ optional :states,
+ type: String,
+ values: Environment.valid_states.map(&:to_s),
+ 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
get ':id/environments' do
@@ -33,15 +44,21 @@ module API
present paginate(environments), with: Entities::Environment, current_user: current_user
end
- desc 'Creates a new environment' do
- detail 'This feature was introduced in GitLab 8.11.'
+ desc 'Create a new environment' do
+ detail 'Creates a new environment with the given name and `external_url`. It returns `201` if the environment was successfully created, `400` for wrong parameters. This feature was introduced in GitLab 8.11.'
success Entities::Environment
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags environments_tags
end
params do
- requires :name, type: String, desc: 'The name of the environment to be created'
- optional :external_url, type: String, desc: 'URL on which this deployment is viewable'
+ requires :name, type: String, desc: 'The name of the environment'
+ optional :external_url, type: String, desc: 'Place to link to for this environment'
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 environment to be created'
+ 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
post ':id/environments' do
authorize! :create_environment, user_project
@@ -55,17 +72,23 @@ module API
end
end
- desc 'Updates an existing environment' do
- detail 'This feature was introduced in GitLab 8.11.'
+ desc 'Update an existing environment' do
+ detail 'Updates an existing environment name and/or `external_url`. It returns `200` if the environment was successfully updated. In case of an error, a status code `400` is returned. This feature was introduced in GitLab 8.11.'
success Entities::Environment
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags environments_tags
end
params do
- requires :environment_id, type: Integer, desc: 'The environment ID'
+ requires :environment_id, type: Integer, desc: 'The ID of the environment'
# TODO: disallow renaming via the API https://gitlab.com/gitlab-org/gitlab/-/issues/338897
optional :name, type: String, desc: 'DEPRECATED: Renaming environment can lead to errors, this will be removed in 15.0'
optional :external_url, type: String, desc: 'The new URL on which this deployment is viewable'
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 environment to be created'
+ 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
put ':id/environments/:environment_id' do
authorize! :update_environment, user_project
@@ -80,14 +103,21 @@ module API
end
end
- desc "Delete multiple stopped review apps" do
- detail "Remove multiple stopped review environments older than a specific age"
+ desc 'Delete multiple stopped review apps' do
+ detail 'It schedules for deletion multiple environments that have already been stopped and are in the review app folder. The actual deletion is performed after 1 week from the time of execution. By default, it only deletes environments 30 days or older. You can change this default using the `before` parameter.'
success Entities::EnvironmentBasic
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' },
+ { code: 409, message: 'Conflict' }
+ ]
+ tags environments_tags
end
params do
- optional :before, type: Time, desc: "The timestamp before which environments can be deleted. Defaults to 30 days ago.", default: -> { 30.days.ago }
- 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: "If set, perform a dry run where no actual deletions will be performed. Defaults to true.", default: true
+ optional :before, type: Time, desc: "The date before which environments can be deleted. Defaults to 30 days ago. Expected in ISO 8601 format (`YYYY-MM-DDTHH:MM:SSZ`)", default: -> { 30.days.ago }
+ 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
delete ":id/environments/review_apps" do
authorize! :read_environment, user_project
@@ -107,12 +137,17 @@ module API
end
end
- desc 'Deletes an existing environment' do
- detail 'This feature was introduced in GitLab 8.11.'
+ desc 'Delete an environment' do
+ detail 'It returns 204 if the environment was successfully deleted, and 404 if the environment does not exist. This feature was introduced in GitLab 8.11.'
success Entities::Environment
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[environments]
end
params do
- requires :environment_id, type: Integer, desc: 'The environment ID'
+ requires :environment_id, type: Integer, desc: 'The ID of the environment'
end
delete ':id/environments/:environment_id' do
authorize! :read_environment, user_project
@@ -123,12 +158,18 @@ module API
destroy_conditionally!(environment)
end
- desc 'Stops an existing environment' do
+ desc 'Stop an environment' do
+ detail 'It returns 200 if the environment was successfully stopped, and 404 if the environment does not exist.'
success Entities::Environment
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[environments]
end
params do
- requires :environment_id, type: Integer, desc: 'The environment ID'
- optional :force, type: Boolean, default: false
+ 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
post ':id/environments/:environment_id/stop' do
authorize! :read_environment, user_project
@@ -141,11 +182,16 @@ module API
present environment, with: Entities::Environment, current_user: current_user
end
- desc 'Get a single environment' do
+ desc 'Get a specific environment' do
success Entities::Environment
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[environments]
end
params do
- requires :environment_id, type: Integer, desc: 'The environment ID'
+ requires :environment_id, type: Integer, desc: 'The ID of the environment'
end
get ':id/environments/:environment_id' do
authorize! :read_environment, user_project
diff --git a/lib/api/error_tracking/client_keys.rb b/lib/api/error_tracking/client_keys.rb
index c1c378111a7..8a0a5e2a9b7 100644
--- a/lib/api/error_tracking/client_keys.rb
+++ b/lib/api/error_tracking/client_keys.rb
@@ -4,11 +4,14 @@ module API
class ErrorTracking::ClientKeys < ::API::Base
before { authenticate! }
+ ERROR_TRACKING_CLIENT_KEYS_TAGS = %w[error_tracking_client_keys].freeze
+
feature_category :error_tracking
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
@@ -17,9 +20,11 @@ module API
authorize! :admin_operations, user_project
end
- desc 'List all client keys' do
- detail 'This feature was introduced in GitLab 14.3.'
+ desc 'List project client keys' do
+ detail 'List all client keys. This feature was introduced in GitLab 14.3.'
success Entities::ErrorTracking::ClientKey
+ is_array true
+ tags ERROR_TRACKING_CLIENT_KEYS_TAGS
end
get '/client_keys' do
collection = user_project.error_tracking_client_keys
@@ -28,8 +33,10 @@ module API
end
desc 'Create a client key' do
- detail 'This feature was introduced in GitLab 14.3.'
+ detail 'Creates a new client key for a project. The public key attribute is generated automatically.'\
+ 'This feature was introduced in GitLab 14.3.'
success Entities::ErrorTracking::ClientKey
+ tags ERROR_TRACKING_CLIENT_KEYS_TAGS
end
post '/client_keys' do
key = user_project.error_tracking_client_keys.create!
@@ -38,8 +45,14 @@ module API
end
desc 'Delete a client key' do
- detail 'This feature was introduced in GitLab 14.3.'
+ detail 'Removes a client key from the project. This feature was introduced in GitLab 14.3.'
success Entities::ErrorTracking::ClientKey
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags ERROR_TRACKING_CLIENT_KEYS_TAGS
end
delete '/client_keys/:key_id' do
key = user_project.error_tracking_client_keys.find(params[:key_id])
diff --git a/lib/api/error_tracking/collector.rb b/lib/api/error_tracking/collector.rb
index eea0fd2bce9..e10125e02c6 100644
--- a/lib/api/error_tracking/collector.rb
+++ b/lib/api/error_tracking/collector.rb
@@ -67,7 +67,7 @@ module API
detail 'This feature was introduced in GitLab 14.1.'
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
post 'error_tracking/collector/api/:id/envelope' do
# There is a reason why we have such uncommon path.
@@ -119,7 +119,7 @@ module API
detail 'This feature was introduced in GitLab 14.1.'
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
post 'error_tracking/collector/api/:id/store' do
# There is a reason why we have such uncommon path.
diff --git a/lib/api/error_tracking/project_settings.rb b/lib/api/error_tracking/project_settings.rb
index fefc2098137..ec1d6a8b87f 100644
--- a/lib/api/error_tracking/project_settings.rb
+++ b/lib/api/error_tracking/project_settings.rb
@@ -4,6 +4,8 @@ module API
class ErrorTracking::ProjectSettings < ::API::Base
before { authenticate! }
+ ERROR_TRACKING_PROJECT_SETTINGS_TAGS = %w[error_tracking_project_settings].freeze
+
feature_category :error_tracking
urgency :low
@@ -14,7 +16,8 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
@@ -24,22 +27,35 @@ module API
not_found!('Error Tracking Setting') unless project_setting
end
- desc 'Get error tracking settings for the project' do
- detail 'This feature was introduced in GitLab 12.7.'
+ desc 'Get Error Tracking settings' do
+ detail 'Get error tracking settings for the project. This feature was introduced in GitLab 12.7.'
success Entities::ErrorTracking::ProjectSetting
+ tags ERROR_TRACKING_PROJECT_SETTINGS_TAGS
end
get ':id/error_tracking/settings' do
present project_setting, with: Entities::ErrorTracking::ProjectSetting
end
- desc 'Enable or disable error tracking settings for the project' do
- detail 'This feature was introduced in GitLab 12.8.'
+ desc 'Enable or disable the Error Tracking project settings' do
+ detail 'The API allows you to enable or disable the Error Tracking settings for a project.'\
+ 'Only for users with the Maintainer role for the project.'
success Entities::ErrorTracking::ProjectSetting
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags ERROR_TRACKING_PROJECT_SETTINGS_TAGS
end
params do
- requires :active, type: Boolean, desc: 'Specifying whether to enable or disable error tracking settings', allow_blank: false
- optional :integrated, type: Boolean, desc: 'Specifying whether to enable or disable integrated error tracking'
+ requires :active,
+ type: Boolean,
+ desc: 'Pass true to enable the already configured Error Tracking settings or false to disable it.',
+ allow_blank: false
+ optional :integrated,
+ type: Boolean,
+ desc: 'Pass true to enable the integrated Error Tracking backend. Available in GitLab 14.2 and later.'
end
patch ':id/error_tracking/settings/' do
diff --git a/lib/api/feature_flags.rb b/lib/api/feature_flags.rb
index 67e96284449..1846ddf6833 100644
--- a/lib/api/feature_flags.rb
+++ b/lib/api/feature_flags.rb
@@ -4,6 +4,8 @@ module API
class FeatureFlags < ::API::Base
include PaginationParams
+ feature_flags_tags = %w[feature_flags]
+
FEATURE_FLAG_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
.merge(name: API::NO_SLASH_URL_PART_REGEX)
@@ -15,18 +17,24 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource 'projects/:id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
resource :feature_flags do
- desc 'Get all feature flags of a project' do
- detail 'This feature was introduced in GitLab 12.5'
+ desc 'List feature flags for a project' do
+ detail 'Gets all feature flags of the requested project. This feature was introduced in GitLab 12.5.'
success ::API::Entities::FeatureFlag
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags feature_flags_tags
end
params do
optional :scope,
type: String,
- desc: 'The scope of feature flags',
+ desc: 'The scope of feature flags, one of: `enabled`, `disabled`',
values: %w[enabled disabled]
use :pagination
end
@@ -39,22 +47,23 @@ module API
end
desc 'Create a new feature flag' do
- detail 'This feature was introduced in GitLab 12.5'
+ detail 'Creates a new feature flag. This feature was introduced in GitLab 12.5.'
success ::API::Entities::FeatureFlag
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' }
+ ]
+ tags feature_flags_tags
end
params do
- requires :name, type: String, desc: 'The name of feature flag'
+ requires :name, type: String, desc: 'The name of the feature flag'
optional :description, type: String, desc: 'The description of the feature flag'
- optional :active, type: Boolean, desc: 'Active/inactive value of the flag'
- optional :version, type: String, desc: 'The version of the feature flag'
- optional :scopes, type: Array do
- requires :environment_scope, type: String, desc: 'The environment scope of the scope'
- requires :active, type: Boolean, desc: 'Active/inactive of the scope'
- requires :strategies, type: JSON, desc: 'The strategies of the scope'
- end
+ optional :active, type: Boolean, desc: 'The active state of the flag. Defaults to `true`. Supported in GitLab 13.3 and later'
+ optional :version, type: String, desc: 'The version of the feature flag. Must be `new_version_flag`. Omit to create a Legacy feature flag.'
optional :strategies, type: Array do
- requires :name, type: String, desc: 'The strategy name'
- requires :parameters, type: JSON, desc: 'The strategy parameters'
+ requires :name, type: String, desc: 'The strategy name. Can be `default`, `gradualRolloutUserId`, `userWithId`, or `gitlabUserList`. In GitLab 13.5 and later, can be `flexibleRollout`'
+ requires :parameters, type: JSON, desc: 'The strategy parameters as a JSON-formatted string e.g. `{"userIds":"user1"}`', documentation: { type: 'String' }
optional :scopes, type: Array do
requires :environment_scope, type: String, desc: 'The environment scope of the scope'
end
@@ -87,9 +96,14 @@ module API
requires :feature_flag_name, type: String, desc: 'The name of the feature flag'
end
resource 'feature_flags/:feature_flag_name', requirements: FEATURE_FLAG_ENDPOINT_REQUIREMENTS do
- desc 'Get a feature flag of a project' do
- detail 'This feature was introduced in GitLab 12.5'
+ desc 'Get a single feature flag' do
+ detail 'Gets a single feature flag. This feature was introduced in GitLab 12.5.'
success ::API::Entities::FeatureFlag
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags feature_flags_tags
end
get do
authorize_read_feature_flag!
@@ -99,20 +113,27 @@ module API
end
desc 'Update a feature flag' do
- detail 'This feature was introduced in GitLab 13.2'
+ detail 'Updates a feature flag. This feature was introduced in GitLab 13.2.'
success ::API::Entities::FeatureFlag
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags feature_flags_tags
end
params do
- optional :name, type: String, desc: 'The name of the feature flag'
+ optional :name, type: String, desc: 'The new name of the feature flag. Supported in GitLab 13.3 and later'
optional :description, type: String, desc: 'The description of the feature flag'
- optional :active, type: Boolean, desc: 'Active/inactive value of the flag'
+ optional :active, type: Boolean, desc: 'The active state of the flag. Supported in GitLab 13.3 and later'
optional :strategies, type: Array do
- optional :id, type: Integer, desc: 'The strategy id'
- optional :name, type: String, desc: 'The strategy type'
- optional :parameters, type: JSON, desc: 'The strategy parameters'
+ optional :id, type: Integer, desc: 'The feature flag strategy ID'
+ optional :name, type: String, desc: 'The strategy name'
+ optional :parameters, type: JSON, desc: 'The strategy parameters as a JSON-formatted string e.g. `{"userIds":"user1"}`', documentation: { type: 'String' }
optional :_destroy, type: Boolean, desc: 'Delete the strategy when true'
optional :scopes, type: Array do
- optional :id, type: Integer, desc: 'The environment scope id'
+ optional :id, type: Integer, desc: 'The scope id'
optional :environment_scope, type: String, desc: 'The environment scope of the scope'
optional :_destroy, type: Boolean, desc: 'Delete the scope when true'
end
@@ -142,8 +163,14 @@ module API
end
desc 'Delete a feature flag' do
- detail 'This feature was introduced in GitLab 12.5'
+ detail 'Deletes a feature flag. This feature was introduced in GitLab 12.5.'
success ::API::Entities::FeatureFlag
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags feature_flags_tags
end
delete do
authorize_destroy_feature_flag!
diff --git a/lib/api/feature_flags_user_lists.rb b/lib/api/feature_flags_user_lists.rb
index f4771c07260..aed277d28a2 100644
--- a/lib/api/feature_flags_user_lists.rb
+++ b/lib/api/feature_flags_user_lists.rb
@@ -4,6 +4,8 @@ module API
class FeatureFlagsUserLists < ::API::Base
include PaginationParams
+ feature_flags_user_lists_tags = %w[feature_flags_user_lists]
+
error_formatter :json, -> (message, _backtrace, _options, _env, _original_exception) {
message.is_a?(String) ? { message: message }.to_json : message.to_json
}
@@ -16,16 +18,23 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource 'projects/:id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
resource :feature_flags_user_lists do
- desc 'Get all feature flags user lists of a project' do
- detail 'This feature was introduced in GitLab 12.10'
+ desc 'List all feature flag user lists for a project' do
+ detail 'Gets all feature flag user lists for the requested project. ' \
+ 'This feature was introduced in GitLab 12.10.'
success ::API::Entities::FeatureFlag::UserList
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags feature_flags_user_lists_tags
end
params do
- optional :search, type: String, desc: 'Returns the list of user lists matching the search critiera'
+ optional :search, type: String, desc: 'Return user lists matching the search criteria'
use :pagination
end
@@ -35,9 +44,15 @@ module API
with: ::API::Entities::FeatureFlag::UserList
end
- desc 'Create a feature flags user list for a project' do
- detail 'This feature was introduced in GitLab 12.10'
+ desc 'Create a feature flag user list' do
+ detail 'Creates a feature flag user list. This feature was introduced in GitLab 12.10.'
success ::API::Entities::FeatureFlag::UserList
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags feature_flags_user_lists_tags
end
params do
requires :name, type: String, desc: 'The name of the list'
@@ -59,12 +74,17 @@ module API
end
params do
- requires :iid, type: String, desc: 'The internal ID of the user list'
+ requires :iid, types: [String, Integer], desc: "The internal ID of the project's feature flag user list"
end
resource 'feature_flags_user_lists/:iid' do
- desc 'Get a single feature flag user list belonging to a project' do
- detail 'This feature was introduced in GitLab 12.10'
+ desc 'Get a feature flag user list' do
+ detail 'Gets a feature flag user list. This feature was introduced in GitLab 12.10.'
success ::API::Entities::FeatureFlag::UserList
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags feature_flags_user_lists_tags
end
get do
present user_project.operations_feature_flags_user_lists.find_by_iid!(params[:iid]),
@@ -72,8 +92,14 @@ module API
end
desc 'Update a feature flag user list' do
- detail 'This feature was introduced in GitLab 12.10'
+ detail 'Updates a feature flag user list. This feature was introduced in GitLab 12.10.'
success ::API::Entities::FeatureFlag::UserList
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags feature_flags_user_lists_tags
end
params do
optional :name, type: String, desc: 'The name of the list'
@@ -93,8 +119,14 @@ module API
end
end
- desc 'Delete a feature flag user list' do
- detail 'This feature was introduced in GitLab 12.10'
+ desc 'Delete feature flag user list' do
+ detail 'Deletes a feature flag user list. This feature was introduced in GitLab 12.10.'
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' },
+ { code: 409, message: 'Conflict' }
+ ]
+ tags feature_flags_user_lists_tags
end
delete do
# TODO: Move the business logic to a service class in app/services/feature_flags.
diff --git a/lib/api/features.rb b/lib/api/features.rb
index 9d4e6eee82c..6b6f5cbfb3f 100644
--- a/lib/api/features.rb
+++ b/lib/api/features.rb
@@ -4,6 +4,8 @@ module API
class Features < ::API::Base
before { authenticated_as_admin! }
+ features_tags = %w[features]
+
feature_category :feature_flags
urgency :low
@@ -44,8 +46,11 @@ module API
end
resource :features do
- desc 'Get a list of all features' do
+ desc 'List all features' do
+ detail 'Get a list of all persisted features, with its gate values.'
success Entities::Feature
+ is_array true
+ tags features_tags
end
get do
features = Feature.all
@@ -53,8 +58,11 @@ module API
present features, with: Entities::Feature, current_user: current_user
end
- desc 'Get a list of all feature definitions' do
+ desc 'List all feature definitions' do
+ detail 'Get a list of all feature definitions.'
success Entities::Feature::Definition
+ is_array true
+ tags features_tags
end
get :definitions do
definitions = ::Feature::Definition.definitions.values.map(&:to_h)
@@ -62,30 +70,44 @@ module API
present definitions, with: Entities::Feature::Definition, current_user: current_user
end
- desc 'Set the gate value for the given feature' do
+ desc 'Set or create a feature' do
+ detail "Set a feature's gate value. If a feature with the given name doesn't exist yet, it's created. " \
+ "The value can be a boolean, or an integer to indicate percentage of time."
success Entities::Feature
+ failure [
+ { code: 400, message: 'Bad request' }
+ ]
+ tags features_tags
end
params do
- requires :value, type: String, desc: '`true` or `false` to enable/disable, a float for percentage of time'
- optional :key, type: String, desc: '`percentage_of_actors` or the default `percentage_of_time`'
+ requires :value,
+ types: [String, Integer],
+ desc: '`true` or `false` to enable/disable, or an integer for percentage of time'
+ optional :key, type: String, desc: '`percentage_of_actors` or `percentage_of_time` (default)'
optional :feature_group, type: String, desc: 'A Feature group name'
optional :user, type: String, desc: 'A GitLab username or comma-separated multiple usernames'
optional :group,
type: String,
- desc: "A GitLab group's path, such as 'gitlab-org', or comma-separated multiple group paths"
+ desc: "A GitLab group's path, for example `gitlab-org`, or comma-separated multiple group paths"
optional :namespace,
type: String,
- desc: "A GitLab group or user namespace path, such as 'john-doe', or comma-separated multiple namespace paths"
+ desc: "A GitLab group or user namespace's path, for example `john-doe`, or comma-separated " \
+ "multiple namespace paths. Introduced in GitLab 15.0."
optional :project,
type: String,
- desc: "A projects path, such as `gitlab-org/gitlab-ce`, or comma-separated multiple project paths"
- optional :force, type: Boolean, desc: 'Skip feature flag validation checks, ie. YAML definition'
+ desc: "A projects path, for example `gitlab-org/gitlab-foss`, or comma-separated multiple project paths"
+ optional :repository,
+ type: String,
+ desc: "A repository path, for example `gitlab-org/gitlab-test.git`, `gitlab-org/gitlab-test.wiki.git`, " \
+ "`snippets/21.git`, to name a few. Use comma to separate multiple repository paths"
+ optional :force, type: Boolean, desc: 'Skip feature flag validation checks, such as a YAML definition'
mutually_exclusive :key, :feature_group
mutually_exclusive :key, :user
mutually_exclusive :key, :group
mutually_exclusive :key, :namespace
mutually_exclusive :key, :project
+ mutually_exclusive :key, :repository
end
post ':name' do
if Feature.enabled?(:set_feature_flag_service)
@@ -135,7 +157,10 @@ module API
bad_request!(e.message)
end
- desc 'Remove the gate value for the given feature'
+ desc 'Delete a feature' do
+ detail "Removes a feature gate. Response is equal when the gate exists, or doesn't."
+ tags features_tags
+ end
delete ':name' do
Feature.remove(params[:name])
diff --git a/lib/api/files.rb b/lib/api/files.rb
index fd574ca865b..fa749299b9a 100644
--- a/lib/api/files.rb
+++ b/lib/api/files.rb
@@ -30,7 +30,7 @@ module API
end
def assign_file_vars!
- authorize! :download_code, user_project
+ authorize! :read_code, user_project
@commit = user_project.commit(params[:ref])
not_found!('Commit') unless @commit
@@ -82,33 +82,44 @@ module API
end
params :simple_file_params do
- requires :file_path, type: String, file_path: true, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
- requires :branch, type: String, desc: 'Name of the branch to commit into. To create a new branch, also provide `start_branch`.', allow_blank: false
- requires :commit_message, type: String, allow_blank: false, desc: 'Commit message'
- optional :start_branch, type: String, desc: 'Name of the branch to start the new commit from'
- optional :author_email, type: String, desc: 'The email of the author'
- optional :author_name, type: String, desc: 'The name of the author'
+ requires :file_path, type: String, file_path: true,
+ desc: 'The url encoded path to the file.', documentation: { example: 'lib%2Fclass%2Erb' }
+ requires :branch, type: String,
+ desc: 'Name of the branch to commit into. To create a new branch, also provide `start_branch`.', allow_blank: false,
+ documentation: { example: 'main' }
+ requires :commit_message, type: String,
+ allow_blank: false, desc: 'Commit message', documentation: { example: 'Initial commit' }
+ optional :start_branch, type: String,
+ desc: 'Name of the branch to start the new commit from', documentation: { example: 'main' }
+ optional :author_email, type: String,
+ desc: 'The email of the author', documentation: { example: 'johndoe@example.com' }
+ optional :author_name, type: String,
+ desc: 'The name of the author', documentation: { example: 'John Doe' }
end
params :extended_file_params do
use :simple_file_params
- requires :content, type: String, desc: 'File content'
- optional :encoding, type: String, values: %w[base64], desc: 'File encoding'
- optional :last_commit_id, type: String, desc: 'Last known commit id for this file'
+ requires :content, type: String, desc: 'File content', documentation: { example: 'file content' }
+ optional :encoding, type: String, values: %w[base64 text], default: 'text', desc: 'File encoding'
+ optional :last_commit_id, type: String,
+ desc: 'Last known commit id for this file',
+ documentation: { example: '2695effb5807a22ff3d138d593fd856244e155e7' }
optional :execute_filemode, type: Boolean, desc: 'Enable / Disable the executable flag on the file path'
end
end
params do
- requires :id, type: String, desc: 'The project ID'
+ requires :id, type: String, desc: 'The project ID', documentation: { example: 'gitlab-org/gitlab' }
end
resource :projects, requirements: FILE_ENDPOINT_REQUIREMENTS do
allow_access_with_scope :read_repository, if: -> (request) { request.get? || request.head? }
desc 'Get blame file metadata from repository'
params do
- requires :file_path, type: String, file_path: true, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
- requires :ref, type: String, desc: 'The name of branch, tag or commit', allow_blank: false
+ requires :file_path, type: String, file_path: true,
+ desc: 'The url encoded path to the file.', documentation: { example: 'lib%2Fclass%2Erb' }
+ requires :ref, type: String,
+ desc: 'The name of branch, tag or commit', allow_blank: false, documentation: { example: 'main' }
end
head ":id/repository/files/:file_path/blame", requirements: FILE_ENDPOINT_REQUIREMENTS do
assign_file_vars!
@@ -118,11 +129,15 @@ module API
desc 'Get blame file from the repository'
params do
- requires :file_path, type: String, file_path: true, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
- requires :ref, type: String, desc: 'The name of branch, tag or commit', allow_blank: false
+ requires :file_path, type: String, file_path: true,
+ desc: 'The url encoded path to the file.', documentation: { example: 'lib%2Fclass%2Erb' }
+ requires :ref, type: String,
+ desc: 'The name of branch, tag or commit', allow_blank: false, documentation: { example: 'main' }
optional :range, type: Hash do
- requires :start, type: Integer, desc: 'The first line of the range to blame', allow_blank: false, values: ->(v) { v > 0 }
- requires :end, type: Integer, desc: 'The last line of the range to blame', allow_blank: false, values: ->(v) { v > 0 }
+ requires :start, type: Integer,
+ desc: 'The first line of the range to blame', allow_blank: false, values: ->(v) { v > 0 }
+ requires :end, type: Integer,
+ desc: 'The last line of the range to blame', allow_blank: false, values: ->(v) { v > 0 }
end
end
get ":id/repository/files/:file_path/blame", requirements: FILE_ENDPOINT_REQUIREMENTS do
@@ -138,8 +153,10 @@ module API
desc 'Get raw file metadata from repository'
params do
- requires :file_path, type: String, file_path: true, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
- optional :ref, type: String, desc: 'The name of branch, tag or commit', allow_blank: false
+ requires :file_path, type: String, file_path: true,
+ desc: 'The url encoded path to the file.', documentation: { example: 'lib%2Fclass%2Erb' }
+ optional :ref, type: String,
+ desc: 'The name of branch, tag or commit', allow_blank: false, documentation: { example: 'main' }
end
head ":id/repository/files/:file_path/raw", requirements: FILE_ENDPOINT_REQUIREMENTS, urgency: :low do
assign_file_vars!
@@ -147,10 +164,14 @@ module API
set_http_headers(blob_data)
end
- desc 'Get raw file contents from the repository'
+ desc 'Get raw file contents from the repository' do
+ success File
+ end
params do
- requires :file_path, type: String, file_path: true, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
- optional :ref, type: String, desc: 'The name of branch, tag or commit', allow_blank: false
+ requires :file_path, type: String, file_path: true,
+ desc: 'The url encoded path to the file.', documentation: { example: 'lib%2Fclass%2Erb' }
+ optional :ref, type: String,
+ desc: 'The name of branch, tag or commit', allow_blank: false, documentation: { example: 'main' }
end
get ":id/repository/files/:file_path/raw", requirements: FILE_ENDPOINT_REQUIREMENTS, urgency: :low do
assign_file_vars!
@@ -163,8 +184,10 @@ module API
desc 'Get file metadata from repository'
params do
- requires :file_path, type: String, file_path: true, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
- requires :ref, type: String, desc: 'The name of branch, tag or commit', allow_blank: false
+ requires :file_path, type: String, file_path: true,
+ desc: 'The url encoded path to the file.', documentation: { example: 'lib%2Fclass%2Erb' }
+ requires :ref, type: String,
+ desc: 'The name of branch, tag or commit', allow_blank: false, documentation: { example: 'main' }
end
head ":id/repository/files/:file_path", requirements: FILE_ENDPOINT_REQUIREMENTS, urgency: :low do
assign_file_vars!
@@ -174,8 +197,10 @@ module API
desc 'Get a file from the repository'
params do
- requires :file_path, type: String, file_path: true, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
- requires :ref, type: String, desc: 'The name of branch, tag or commit', allow_blank: false
+ requires :file_path, type: String, file_path: true,
+ desc: 'The url encoded path to the file.', documentation: { example: 'lib%2Fclass%2Erb' }
+ requires :ref, type: String,
+ desc: 'The name of branch, tag or commit', allow_blank: false, documentation: { example: 'main' }
end
get ":id/repository/files/:file_path", requirements: FILE_ENDPOINT_REQUIREMENTS do
assign_file_vars!
diff --git a/lib/api/freeze_periods.rb b/lib/api/freeze_periods.rb
index e69baeee97f..40f1be83028 100644
--- a/lib/api/freeze_periods.rb
+++ b/lib/api/freeze_periods.rb
@@ -4,19 +4,28 @@ module API
class FreezePeriods < ::API::Base
include PaginationParams
+ freeze_periods_tags = %w[freeze_periods]
+
before { authenticate! }
feature_category :continuous_delivery
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get project freeze periods' do
- detail 'This feature was introduced in GitLab 13.0.'
+ desc 'List freeze periods' do
+ detail 'Paginated list of Freeze Periods, sorted by created_at in ascending order. ' \
+ 'This feature was introduced in GitLab 13.0.'
success Entities::FreezePeriod
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags freeze_periods_tags
end
params do
use :pagination
@@ -30,12 +39,17 @@ module API
present paginate(freeze_periods), with: Entities::FreezePeriod, current_user: current_user
end
- desc 'Get a single freeze period' do
- detail 'This feature was introduced in GitLab 13.0.'
+ desc 'Get a freeze period' do
+ detail 'Get a freeze period for the given `freeze_period_id`. This feature was introduced in GitLab 13.0.'
success Entities::FreezePeriod
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags freeze_periods_tags
end
params do
- requires :freeze_period_id, type: Integer, desc: 'The ID of a project freeze period'
+ requires :freeze_period_id, type: Integer, desc: 'The ID of the freeze period'
end
get ":id/freeze_periods/:freeze_period_id" do
authorize! :read_freeze_period, user_project
@@ -43,14 +57,21 @@ module API
present freeze_period, with: Entities::FreezePeriod, current_user: current_user
end
- desc 'Create a new freeze period' do
- detail 'This feature was introduced in GitLab 13.0.'
+ desc 'Create a freeze period' do
+ detail 'Creates a freeze period. This feature was introduced in GitLab 13.0.'
success Entities::FreezePeriod
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' }
+ ]
+ tags freeze_periods_tags
end
params do
- requires :freeze_start, type: String, desc: 'Freeze Period start'
- requires :freeze_end, type: String, desc: 'Freeze Period end'
- optional :cron_timezone, type: String, desc: 'Timezone'
+ requires :freeze_start, type: String, desc: 'Start of the freeze period in cron format.'
+ requires :freeze_end, type: String, desc: 'End of the freeze period in cron format'
+ optional :cron_timezone,
+ type: String,
+ desc: 'The time zone for the cron fields, defaults to UTC if not provided'
end
post ':id/freeze_periods' do
authorize! :create_freeze_period, user_project
@@ -67,13 +88,18 @@ module API
end
desc 'Update a freeze period' do
- detail 'This feature was introduced in GitLab 13.0.'
+ detail 'Updates a freeze period for the given `freeze_period_id`. This feature was introduced in GitLab 13.0.'
success Entities::FreezePeriod
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' }
+ ]
+ tags freeze_periods_tags
end
params do
- optional :freeze_start, type: String, desc: 'Freeze Period start'
- optional :freeze_end, type: String, desc: 'Freeze Period end'
- optional :cron_timezone, type: String, desc: 'Freeze Period Timezone'
+ optional :freeze_start, type: String, desc: 'Start of the freeze period in cron format'
+ optional :freeze_end, type: String, desc: 'End of the freeze period in cron format'
+ optional :cron_timezone, type: String, desc: 'The time zone for the cron fields'
end
put ':id/freeze_periods/:freeze_period_id' do
authorize! :update_freeze_period, user_project
@@ -88,11 +114,15 @@ module API
end
desc 'Delete a freeze period' do
- detail 'This feature was introduced in GitLab 13.0.'
+ detail 'Deletes a freeze period for the given `freeze_period_id`. This feature was introduced in GitLab 13.0.'
success Entities::FreezePeriod
+ failure [
+ { code: 401, message: 'Unauthorized' }
+ ]
+ tags freeze_periods_tags
end
params do
- requires :freeze_period_id, type: Integer, desc: 'Freeze Period ID'
+ requires :freeze_period_id, type: Integer, desc: 'The ID of the freeze period'
end
delete ':id/freeze_periods/:freeze_period_id' do
authorize! :destroy_freeze_period, user_project
diff --git a/lib/api/generic_packages.rb b/lib/api/generic_packages.rb
index 0098b074f05..3584f8d025a 100644
--- a/lib/api/generic_packages.rb
+++ b/lib/api/generic_packages.rb
@@ -18,7 +18,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
@@ -54,7 +54,7 @@ module API
requires :package_version, type: String, desc: 'Package version', regexp: Gitlab::Regex.generic_package_version_regex
requires :file_name, type: String, desc: 'Package file name', regexp: Gitlab::Regex.generic_package_file_name_regex, file_path: true
optional :status, type: String, values: ALLOWED_STATUSES, desc: 'Package status'
- requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)', documentation: { type: 'file' }
optional :select, type: String, values: %w[package_file]
end
diff --git a/lib/api/geo.rb b/lib/api/geo.rb
index cb04d2a4e1e..8798b76b52b 100644
--- a/lib/api/geo.rb
+++ b/lib/api/geo.rb
@@ -13,6 +13,13 @@ module API
end
resource :geo do
+ desc 'Returns a Geo proxy response' do
+ summary "Determine if a Geo site should proxy requests"
+ success code: 200
+ failure [{ code: 403, message: 'Forbidden' }]
+ tags %w[geo]
+ end
+
# Workhorse calls this to determine if it is a Geo site that should proxy
# requests. Workhorse doesn't know if it's in a FOSS/EE context.
get '/proxy' do
diff --git a/lib/api/go_proxy.rb b/lib/api/go_proxy.rb
index 2d9c0cd6ce1..8fde40a4713 100755
--- a/lib/api/go_proxy.rb
+++ b/lib/api/go_proxy.rb
@@ -4,6 +4,8 @@ module API
helpers Gitlab::Golang
helpers ::API::Helpers::PackagesHelpers
+ GO_PROXY_TAGS = %w[go_proxy].freeze
+
feature_category :package_registry
urgency :low
@@ -17,6 +19,10 @@ module API
before { require_packages_enabled! }
helpers do
+ def project
+ user_project(action: :read_package)
+ end
+
def case_decode(str)
# Converts "github.com/!azure" to "github.com/Azure"
#
@@ -32,12 +38,12 @@ module API
end
def find_module
- not_found! unless Feature.enabled?(:go_proxy, user_project)
+ not_found! unless Feature.enabled?(:go_proxy, project)
module_name = case_decode params[:module_name]
bad_request_missing_attribute!('Module Name') if module_name.blank?
- mod = ::Packages::Go::ModuleFinder.new(user_project, module_name).execute
+ mod = ::Packages::Go::ModuleFinder.new(project, module_name).execute
not_found! unless mod
@@ -58,18 +64,21 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
- requires :module_name, type: String, desc: 'Module name', coerce_with: ->(val) { CGI.unescape(val) }
+ requires :id, types: [String, Integer], desc: 'The project ID or full path of a project'
+ requires :module_name, type: String, desc: 'The name of the Go module', coerce_with: ->(val) { CGI.unescape(val) }
end
- route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true, authenticate_non_public: true
+ route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true,
+ authenticate_non_public: true
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before do
- authorize_read_package!
+ authorize_read_package!(project)
end
namespace ':id/packages/go/*module_name/@v' do
- desc 'Get all tagged versions for a given Go module' do
- detail 'See `go help goproxy`, GET $GOPROXY/<module>/@v/list. This feature was introduced in GitLab 13.1.'
+ desc 'List' do
+ detail 'Get all tagged versions for a given Go module.'\
+ 'See `go help goproxy`, GET $GOPROXY/<module>/@v/list. This feature was introduced in GitLab 13.1.'
+ tags GO_PROXY_TAGS
end
get 'list' do
mod = find_module
@@ -78,12 +87,14 @@ module API
mod.versions.map { |t| t.name }.join("\n")
end
- desc 'Get information about the given module version' do
- detail 'See `go help goproxy`, GET $GOPROXY/<module>/@v/<version>.info. This feature was introduced in GitLab 13.1.'
+ desc 'Version metadata' do
+ detail 'Get all tagged versions for a given Go module.'\
+ 'See `go help goproxy`, GET $GOPROXY/<module>/@v/<version>.info. This feature was introduced in GitLab 13.1'
success ::API::Entities::GoModuleVersion
+ tags GO_PROXY_TAGS
end
params do
- requires :module_version, type: String, desc: 'Module version'
+ requires :module_version, type: String, desc: 'The version of the Go module'
end
get ':module_version.info', requirements: MODULE_VERSION_REQUIREMENTS do
ver = find_version
@@ -91,11 +102,13 @@ module API
present ::Packages::Go::ModuleVersionPresenter.new(ver), with: ::API::Entities::GoModuleVersion
end
- desc 'Get the module file of the given module version' do
- detail 'See `go help goproxy`, GET $GOPROXY/<module>/@v/<version>.mod. This feature was introduced in GitLab 13.1.'
+ desc 'Download module file' do
+ detail 'Get the module file of a given module version.'\
+ 'See `go help goproxy`, GET $GOPROXY/<module>/@v/<version>.mod. This feature was introduced in GitLab 13.1.'
+ tags GO_PROXY_TAGS
end
params do
- requires :module_version, type: String, desc: 'Module version'
+ requires :module_version, type: String, desc: 'The version of the Go module'
end
get ':module_version.mod', requirements: MODULE_VERSION_REQUIREMENTS do
ver = find_version
@@ -104,18 +117,21 @@ module API
ver.gomod
end
- desc 'Get a zip of the source of the given module version' do
- detail 'See `go help goproxy`, GET $GOPROXY/<module>/@v/<version>.zip. This feature was introduced in GitLab 13.1.'
+ desc 'Download module source' do
+ detail 'Get a zip of the source of the given module version.'\
+ 'See `go help goproxy`, GET $GOPROXY/<module>/@v/<version>.zip. This feature was introduced in GitLab 13.1.'
+ tags GO_PROXY_TAGS
end
params do
- requires :module_version, type: String, desc: 'Module version'
+ requires :module_version, type: String, desc: 'The version of the Go module'
end
get ':module_version.zip', requirements: MODULE_VERSION_REQUIREMENTS do
ver = find_version
content_type 'application/zip'
env['api.format'] = :binary
- header['Content-Disposition'] = ActionDispatch::Http::ContentDisposition.format(disposition: 'attachment', filename: ver.name + '.zip')
+ header['Content-Disposition'] =
+ ActionDispatch::Http::ContentDisposition.format(disposition: 'attachment', filename: "#{ver.name}.zip")
header['Content-Transfer-Encoding'] = 'binary'
status :ok
body ver.archive.string
diff --git a/lib/api/group_avatar.rb b/lib/api/group_avatar.rb
index 9063040c763..0820011fd89 100644
--- a/lib/api/group_avatar.rb
+++ b/lib/api/group_avatar.rb
@@ -7,11 +7,13 @@ module API
feature_category :subgroups
params do
- requires :id, type: String, desc: 'The ID of a group'
+ requires :id, type: String, desc: 'The ID of the group'
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Download the group avatar' do
detail 'This feature was introduced in GitLab 14.0'
+ tags %w[group_avatar]
+ success code: 200
end
get ':id/avatar' do
avatar = user_group.avatar
diff --git a/lib/api/group_clusters.rb b/lib/api/group_clusters.rb
index edaa32c26c4..de5ca0f86ae 100644
--- a/lib/api/group_clusters.rb
+++ b/lib/api/group_clusters.rb
@@ -16,8 +16,14 @@ module API
requires :id, type: String, desc: 'The ID of the group'
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get all clusters from the group' do
+ desc 'List group clusters' do
+ detail 'This feature was introduced in GitLab 12.1. Returns a list of group clusters.'
success Entities::Cluster
+ failure [
+ { code: 403, message: 'Forbidden' }
+ ]
+ is_array true
+ tags %w[clusters]
end
params do
use :pagination
@@ -28,8 +34,14 @@ module API
present paginate(clusters_for_current_user), with: Entities::Cluster
end
- desc 'Get specific cluster for the group' do
+ desc 'Get a single group cluster' do
+ detail 'This feature was introduced in GitLab 12.1. Gets a single group cluster.'
success Entities::ClusterGroup
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The cluster ID'
@@ -40,8 +52,15 @@ module API
present cluster, with: Entities::ClusterGroup
end
- desc 'Adds an existing cluster' do
+ desc 'Add existing cluster to group' do
+ detail 'This feature was introduced in GitLab 12.1. Adds an existing Kubernetes cluster to the group.'
success Entities::ClusterGroup
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :name, type: String, desc: 'Cluster name'
@@ -73,8 +92,15 @@ module API
end
end
- desc 'Update an existing cluster' do
+ desc 'Edit group cluster' do
+ detail 'This feature was introduced in GitLab 12.1. Updates an existing group cluster.'
success Entities::ClusterGroup
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The cluster ID'
@@ -104,8 +130,14 @@ module API
end
end
- desc 'Remove a cluster' do
+ desc 'Delete group cluster' do
+ detail 'This feature was introduced in GitLab 12.1. Deletes an existing group cluster. Does not remove existing resources within the connected Kubernetes cluster.'
success Entities::ClusterGroup
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The Cluster ID'
diff --git a/lib/api/group_container_repositories.rb b/lib/api/group_container_repositories.rb
index b834d177a12..753f0db10c1 100644
--- a/lib/api/group_container_repositories.rb
+++ b/lib/api/group_container_repositories.rb
@@ -16,12 +16,19 @@ module API
tag_name: API::NO_SLASH_URL_PART_REGEX)
params do
- requires :id, type: String, desc: "Group's ID or path"
+ requires :id, types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the group accessible by the authenticated user'
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get a list of all repositories within a group' do
- detail 'This feature was introduced in GitLab 12.2.'
+ desc 'List registry repositories within a group' do
+ detail 'Get a list of registry repositories in a group. This feature was introduced in GitLab 12.2.'
success Entities::ContainerRegistry::Repository
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Group Not Found' }
+ ]
+ is_array true
+ tags %w[container_registry]
end
params do
use :pagination
diff --git a/lib/api/group_export.rb b/lib/api/group_export.rb
index 2948960a9b4..eb0a01e0d3d 100644
--- a/lib/api/group_export.rb
+++ b/lib/api/group_export.rb
@@ -15,6 +15,16 @@ module API
resource :groups, requirements: { id: %r{[^/]+} } do
desc 'Download export' do
detail 'This feature was introduced in GitLab 12.5.'
+ tags %w[group_export]
+ produces %w[application/octet-stream application/json]
+ success code: 200
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
get ':id/export/download' do
check_rate_limit! :group_download_export, scope: [current_user, user_group]
@@ -32,6 +42,15 @@ module API
desc 'Start export' do
detail 'This feature was introduced in GitLab 12.5.'
+ tags %w[group_export]
+ success code: 202
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 429, message: 'Too many requests' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
post ':id/export' do
check_rate_limit! :group_export, scope: current_user
@@ -47,6 +66,14 @@ module API
desc 'Start relations export' do
detail 'This feature was introduced in GitLab 13.12'
+ tags %w[group_export]
+ success code: 202
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
post ':id/export_relations' do
response = ::BulkImports::ExportService.new(portable: user_group, user: current_user).execute
@@ -60,6 +87,15 @@ module API
desc 'Download relations export' do
detail 'This feature was introduced in GitLab 13.12'
+ produces %w[application/octet-stream application/json]
+ tags %w[group_export]
+ success code: 200
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
params do
requires :relation, type: String, desc: 'Group relation name'
@@ -77,6 +113,15 @@ module API
desc 'Relations export status' do
detail 'This feature was introduced in GitLab 13.12'
+ is_array true
+ tags %w[group_export]
+ success code: 200, model: Entities::BulkImports::ExportStatus
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
get ':id/export_relations/status' do
present user_group.bulk_import_exports, with: Entities::BulkImports::ExportStatus
diff --git a/lib/api/group_import.rb b/lib/api/group_import.rb
index cef9b542c9e..609a7ed0ef0 100644
--- a/lib/api/group_import.rb
+++ b/lib/api/group_import.rb
@@ -32,6 +32,7 @@ module API
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Workhorse authorize the group import upload' do
detail 'This feature was introduced in GitLab 12.8'
+ tags ['group_import']
end
post 'import/authorize' do
require_gitlab_workhorse!
@@ -49,7 +50,15 @@ module API
desc 'Create a new group import' do
detail 'This feature was introduced in GitLab 12.8'
- success Entities::Group
+ success code: 202
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 400, message: 'Bad request' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ consumes ['multipart/form-data']
+ tags ['group_import']
end
params do
requires :path, type: String, desc: 'Group path'
diff --git a/lib/api/group_packages.rb b/lib/api/group_packages.rb
index 72d67b41c31..c2b4cbf732f 100644
--- a/lib/api/group_packages.rb
+++ b/lib/api/group_packages.rb
@@ -14,13 +14,19 @@ module API
helpers ::API::Helpers::PackagesHelpers
params do
- requires :id, type: String, desc: "Group's ID or path"
+ requires :id, types: [String, Integer], desc: 'ID or URL-encoded path of the group'
optional :exclude_subgroups, type: Boolean, default: false, desc: 'Determines if subgroups should be excluded'
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get all project packages within a group' do
- detail 'This feature was introduced in GitLab 12.5'
+ desc 'List packages within a group' do
+ detail 'Get a list of project packages at the group level. This feature was introduced in GitLab 12.5'
success ::API::Entities::Package
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Group Not Found' }
+ ]
+ is_array true
+ tags %w[group_packages]
end
params do
use :pagination
@@ -53,10 +59,13 @@ module API
packages = Packages::GroupPackagesFinder.new(
current_user,
user_group,
- declared(params).slice(:exclude_subgroups, :order_by, :sort, :package_type, :package_name, :include_versionless, :status)
+ declared(params).slice(
+ :exclude_subgroups, :order_by, :sort, :package_type, :package_name, :include_versionless, :status
+ )
).execute
- present paginate(packages), with: ::API::Entities::Package, user: current_user, group: true, namespace: user_group
+ present paginate(packages), with: ::API::Entities::Package, user: current_user, group: true,
+ namespace: user_group
end
end
end
diff --git a/lib/api/group_variables.rb b/lib/api/group_variables.rb
index 2235746b254..a42f9045b9d 100644
--- a/lib/api/group_variables.rb
+++ b/lib/api/group_variables.rb
@@ -11,12 +11,14 @@ module API
helpers ::API::Helpers::VariablesHelpers
params do
- requires :id, type: String, desc: 'The ID of a group'
+ requires :id, type: String, desc: 'The ID of a group or URL-encoded path of the group owned by the authenticated
+ user'
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get group-level variables' do
+ desc 'Get a list of group-level variables' do
success Entities::Ci::Variable
+ tags %w[ci_variables]
end
params do
use :pagination
@@ -26,8 +28,10 @@ module API
present paginate(variables), with: Entities::Ci::Variable
end
- desc 'Get a specific variable from a group' do
+ desc 'Get the details of a group’s specific variable' do
success Entities::Ci::Variable
+ failure [{ code: 404, message: 'Group Variable Not Found' }]
+ tags %w[ci_variables]
end
params do
requires :key, type: String, desc: 'The key of the variable'
@@ -42,14 +46,19 @@ module API
desc 'Create a new variable in a group' do
success Entities::Ci::Variable
+ failure [{ code: 400, message: '400 Bad Request' }]
+ tags %w[ci_variables]
end
+ route_setting :log_safety, { safe: %w[key], unsafe: %w[value] }
params do
- requires :key, type: String, desc: 'The key of the variable'
- requires :value, type: String, desc: 'The value of the variable'
+ requires :key, type: String, desc: 'The ID of a group or URL-encoded path of the group owned by the
+ authenticated user'
+ requires :value, type: String, desc: 'The value of a variable'
optional :protected, type: String, desc: 'Whether the variable is protected'
optional :masked, type: String, desc: 'Whether the variable is masked'
- optional :variable_type, type: String, values: ::Ci::GroupVariable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file. Defaults to env_var'
-
+ 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'
use :optional_group_variable_params_ee
end
post ':id/variables' do
@@ -73,13 +82,18 @@ module API
desc 'Update an existing variable from a group' do
success Entities::Ci::Variable
+ failure [{ code: 400, message: '400 Bad Request' }, { code: 404, message: 'Group Variable Not Found' }]
+ tags %w[ci_variables]
end
+ route_setting :log_safety, { safe: %w[key], unsafe: %w[value] }
params do
- optional :key, type: String, desc: 'The key of the variable'
- optional :value, type: String, desc: 'The value of the variable'
+ optional :key, type: String, desc: 'The key of a variable'
+ optional :value, type: String, desc: 'The value of a variable'
optional :protected, type: String, desc: 'Whether the variable is protected'
optional :masked, type: String, desc: 'Whether the variable is masked'
- optional :variable_type, type: String, values: ::Ci::GroupVariable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file'
+ 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'
use :optional_group_variable_params_ee
end
@@ -106,9 +120,11 @@ module API
desc 'Delete an existing variable from a group' do
success Entities::Ci::Variable
+ failure [{ code: 404, message: 'Group Variable Not Found' }]
+ tags %w[ci_variables]
end
params do
- requires :key, type: String, desc: 'The key of the variable'
+ requires :key, type: String, desc: 'The key of a variable'
end
delete ':id/variables/:key' do
variable = find_variable(user_group, params)
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 0eb4fbb196c..75e7612bd5b 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -592,19 +592,19 @@ module API
end
end
- def present_artifacts_file!(file, project:, **args)
+ def present_artifacts_file!(file, **args)
log_artifacts_filesize(file&.model)
- present_carrierwave_file!(file, project: project, **args)
+ present_carrierwave_file!(file, **args)
end
- def present_carrierwave_file!(file, project: nil, supports_direct_download: true)
+ def present_carrierwave_file!(file, supports_direct_download: true)
return not_found! unless file&.exists?
if file.file_storage?
present_disk_file!(file.path, file.filename)
elsif supports_direct_download && file.class.direct_download_enabled?
- redirect(cdn_fronted_url(file, project))
+ redirect(cdn_fronted_url(file))
else
header(*Gitlab::Workhorse.send_url(file.url))
status :ok
@@ -612,9 +612,9 @@ module API
end
end
- def cdn_fronted_url(file, project)
+ def cdn_fronted_url(file)
if file.respond_to?(:cdn_enabled_url)
- result = file.cdn_enabled_url(project, ip_address)
+ result = file.cdn_enabled_url(ip_address)
Gitlab::ApplicationContext.push(artifact_used_cdn: result.used_cdn)
result.url
else
@@ -673,7 +673,6 @@ module API
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_namespaces] = true if params[:search_namespaces].present?
finder_params[:user] = params.delete(:user) if params[:user]
finder_params[:id_after] = sanitize_id_param(params[:id_after]) if params[:id_after]
diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb
index e03f029a6ef..56db6ee4c5c 100644
--- a/lib/api/helpers/internal_helpers.rb
+++ b/lib/api/helpers/internal_helpers.rb
@@ -124,7 +124,12 @@ module API
repository: repository.gitaly_repository.to_h,
address: Gitlab::GitalyClient.address(repository.shard),
token: Gitlab::GitalyClient.token(repository.shard),
- features: Feature::Gitaly.server_feature_flags(repository.project)
+ features: Feature::Gitaly.server_feature_flags(
+ user: ::Feature::Gitaly.user_actor(actor.user),
+ repository: repository,
+ project: ::Feature::Gitaly.project_actor(repository.container),
+ group: ::Feature::Gitaly.group_actor(repository.container)
+ )
}
end
end
diff --git a/lib/api/helpers/label_helpers.rb b/lib/api/helpers/label_helpers.rb
index 8572cc89e71..b3ba962666f 100644
--- a/lib/api/helpers/label_helpers.rb
+++ b/lib/api/helpers/label_helpers.rb
@@ -137,9 +137,10 @@ module API
end
def create_service_params(parent)
- if parent.is_a?(Project)
+ case parent
+ when Project
{ project: parent }
- elsif parent.is_a?(Group)
+ when Group
{ group: parent }
else
raise TypeError, 'Parent type is not supported'
diff --git a/lib/api/helpers/merge_requests_helpers.rb b/lib/api/helpers/merge_requests_helpers.rb
index 85648cd166d..eed9fa30d3c 100644
--- a/lib/api/helpers/merge_requests_helpers.rb
+++ b/lib/api/helpers/merge_requests_helpers.rb
@@ -8,6 +8,9 @@ module API
UNPROCESSABLE_ERROR_KEYS = [:project_access, :branch_conflict, :validate_fork, :base].freeze
+ params :ee_approval_params do
+ end
+
params :merge_requests_negatable_params do
optional :author_id, type: Integer, desc: 'Return merge requests which are authored by the user with the given ID'
optional :author_username, type: String, desc: 'Return merge requests which are authored by the user with the given username'
@@ -136,3 +139,5 @@ module API
end
end
end
+
+API::Helpers::MergeRequestsHelpers.prepend_mod_with('API::Helpers::MergeRequestsHelpers')
diff --git a/lib/api/helpers/packages/dependency_proxy_helpers.rb b/lib/api/helpers/packages/dependency_proxy_helpers.rb
index dc81e5e1b51..1ae863a5a25 100644
--- a/lib/api/helpers/packages/dependency_proxy_helpers.rb
+++ b/lib/api/helpers/packages/dependency_proxy_helpers.rb
@@ -45,7 +45,7 @@ module API
raise ArgumentError, "Can't find application setting for package_type #{package_type}" unless application_setting_name
- if target.present? && Feature.enabled?(:cascade_package_forwarding_settings, target)
+ if target.present?
target.public_send(application_setting_name) # rubocop:disable GitlabSecurity/PublicSend
else
::Gitlab::CurrentSettings
diff --git a/lib/api/helpers/packages/npm.rb b/lib/api/helpers/packages/npm.rb
index 34e126c73fc..352d77f472c 100644
--- a/lib/api/helpers/packages/npm.rb
+++ b/lib/api/helpers/packages/npm.rb
@@ -19,7 +19,7 @@ module API
strong_memoize(:project) do
case endpoint_scope
when :project
- user_project
+ user_project(action: :read_package)
when :instance
# Simulate the same behavior as #user_project by re-using #find_project!
# but take care if the project_id is nil as #find_project! is not designed
diff --git a/lib/api/helpers/packages_helpers.rb b/lib/api/helpers/packages_helpers.rb
index 687c8330cc8..96a10d43401 100644
--- a/lib/api/helpers/packages_helpers.rb
+++ b/lib/api/helpers/packages_helpers.rb
@@ -3,6 +3,8 @@
module API
module Helpers
module PackagesHelpers
+ extend ::Gitlab::Utils::Override
+
MAX_PACKAGE_FILE_SIZE = 50.megabytes.freeze
def require_packages_enabled!
@@ -48,6 +50,34 @@ module API
require_gitlab_workhorse!
end
+ override :user_project
+ def user_project(action: :read_project)
+ case action
+ when :read_project
+ super()
+ when :read_package
+ user_project_with_read_package
+ else
+ raise ArgumentError, "unexpected action: #{action}"
+ end
+ end
+
+ # This function is similar to the `find_project!` function, but it considers the `read_package` ability.
+ def user_project_with_read_package
+ strong_memoize(:user_project_with_read_package) do
+ project = find_project(params[:id])
+
+ next forbidden! unless authorized_project_scope?(project)
+
+ next project if can?(current_user, :read_package, project&.packages_policy_subject)
+ # guest users can have :read_project but not :read_package
+ next forbidden! if can?(current_user, :read_project, project)
+ next unauthorized! if authenticate_non_public?
+
+ not_found!('Project')
+ end
+ end
+
def track_package_event(event_name, scope, **args)
::Packages::CreateEventService.new(nil, current_user, event_name: event_name, scope: scope).execute
category = args.delete(:category) || self.options[:for].name
diff --git a/lib/api/helpers/projects_helpers.rb b/lib/api/helpers/projects_helpers.rb
index 9839828a5b4..c95bf0f0c21 100644
--- a/lib/api/helpers/projects_helpers.rb
+++ b/lib/api/helpers/projects_helpers.rb
@@ -65,6 +65,7 @@ module API
optional :suggestion_commit_message, type: String, desc: 'The commit message used to apply merge request suggestions'
optional :merge_commit_template, type: String, desc: 'Template used to create merge commit message'
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'
@@ -96,7 +97,7 @@ module API
end
params :optional_update_params_ce do
- optional :ci_forward_deployment_enabled, type: Boolean, desc: 'Skip older deployment jobs that are still pending'
+ 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.'
optional :restrict_user_defined_variables, type: Boolean, desc: 'Restrict use of user-defined variables when triggering a pipeline'
@@ -174,6 +175,7 @@ module API
:suggestion_commit_message,
:merge_commit_template,
:squash_commit_template,
+ :issue_branch_template,
:repository_storage,
:packages_enabled,
:service_desk_enabled,
diff --git a/lib/api/helpers/users_helpers.rb b/lib/api/helpers/users_helpers.rb
index 1a019283bc6..e80b89488a2 100644
--- a/lib/api/helpers/users_helpers.rb
+++ b/lib/api/helpers/users_helpers.rb
@@ -18,6 +18,13 @@ module API
error_messages[:bio] = error_messages.delete(:"user_detail.bio") if error_messages.has_key?(:"user_detail.bio")
end
end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def find_user_by_id(params)
+ id = params[:user_id] || params[:id]
+ User.find_by(id: id) || not_found!('User')
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
end
end
end
diff --git a/lib/api/helpers/web_hooks_helpers.rb b/lib/api/helpers/web_hooks_helpers.rb
index a71e56af4c3..5d5067bc70e 100644
--- a/lib/api/helpers/web_hooks_helpers.rb
+++ b/lib/api/helpers/web_hooks_helpers.rb
@@ -6,7 +6,7 @@ module API
extend Grape::API::Helpers
params :requires_url do
- requires :url, type: String, desc: "The URL to send the request to"
+ requires :url, type: String, desc: "The URL to send the request to", documentation: { example: 'http://example.com/hook' }
end
params :optional_url do
@@ -15,8 +15,8 @@ module API
params :url_variables do
optional :url_variables, type: Array, desc: 'URL variables for interpolation' do
- requires :key, type: String, desc: 'Name of the variable'
- requires :value, type: String, desc: 'Value of the variable'
+ requires :key, type: String, desc: 'Name of the variable', documentation: { example: 'token' }
+ requires :value, type: String, desc: 'Value of the variable', documentation: { example: '123' }
end
end
diff --git a/lib/api/import_bitbucket_server.rb b/lib/api/import_bitbucket_server.rb
index 0f2d6239d0d..f315ae5afff 100644
--- a/lib/api/import_bitbucket_server.rb
+++ b/lib/api/import_bitbucket_server.rb
@@ -22,6 +22,14 @@ module API
desc 'Import a BitBucket Server repository' do
detail 'This feature was introduced in GitLab 13.2.'
success ::ProjectEntity
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 422, message: 'Unprocessable entity' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_import_bitbucket']
end
params do
diff --git a/lib/api/import_github.rb b/lib/api/import_github.rb
index 493cc038f46..d742e3732a8 100644
--- a/lib/api/import_github.rb
+++ b/lib/api/import_github.rb
@@ -2,6 +2,8 @@
module API
class ImportGithub < ::API::Base
+ before { authenticate! }
+
feature_category :importers
urgency :low
@@ -35,7 +37,15 @@ module API
desc 'Import a GitHub project' do
detail 'This feature was introduced in GitLab 11.3.4.'
- success ::ProjectEntity
+ success code: 201, model: ::ProjectEntity
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 422, message: 'Unprocessable entity' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_import_github']
end
params do
requires :personal_access_token, type: String, desc: 'GitHub personal access token'
@@ -56,6 +66,18 @@ module API
end
end
+ desc 'Cancel GitHub project import' do
+ detail 'This feature was introduced in GitLab 15.5'
+ success code: 200, model: ProjectImportEntity
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_import_github']
+ end
params do
requires :project_id, type: Integer, desc: 'ID of importing project to be canceled'
end
diff --git a/lib/api/integrations.rb b/lib/api/integrations.rb
index 71c55704ddf..408fa038b0d 100644
--- a/lib/api/integrations.rb
+++ b/lib/api/integrations.rb
@@ -3,6 +3,8 @@ module API
class Integrations < ::API::Base
feature_category :integrations
+ INTEGRATIONS_TAGS = %w[integrations].freeze
+
integrations = Helpers::IntegrationsHelpers.integrations
integration_classes = Helpers::IntegrationsHelpers.integration_classes
@@ -65,14 +67,21 @@ module API
# The support for `:id/services` can be dropped if we create an API V5.
[':id/services', ':id/integrations'].each do |path|
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authenticate! }
before { authorize_admin_project }
- desc 'Get all active project integrations' do
+ desc 'List all active integrations' do
+ detail 'Get a list of all active project integrations.'
success Entities::ProjectIntegrationBasic
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags INTEGRATIONS_TAGS
end
get path do
integrations = user_project.integrations.active
@@ -81,7 +90,16 @@ module API
end
INTEGRATIONS.each do |slug, settings|
- desc "Set #{slug} integration for project"
+ desc "Create/Edit #{slug.titleize} integration" do
+ detail "Set #{slug.titleize} integration for a project."
+ success Entities::ProjectIntegrationBasic
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags INTEGRATIONS_TAGS
+ end
params do
settings.each do |setting|
if setting[:required]
@@ -103,7 +121,16 @@ module API
end
end
- desc "Delete an integration from a project"
+ desc "Disable an integration" do
+ detail "Disable the integration for a project. Integration settings are preserved."
+ success code: 204
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags INTEGRATIONS_TAGS
+ end
params do
requires :slug, type: String, values: INTEGRATIONS.keys, desc: 'The name of the integration'
end
@@ -124,8 +151,15 @@ module API
end
end
- desc 'Get the integration settings for a project' do
+ desc "Get an integration settings" do
+ detail "Get the integration settings for a project."
success Entities::ProjectIntegration
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags INTEGRATIONS_TAGS
end
params do
requires :slug, type: String, values: INTEGRATIONS.keys, desc: 'The name of the integration'
@@ -149,11 +183,16 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc "Trigger a slash command for #{integration_slug}" do
detail 'Added in GitLab 8.13'
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags INTEGRATIONS_TAGS
end
params do
settings.each do |setting|
diff --git a/lib/api/internal/kubernetes.rb b/lib/api/internal/kubernetes.rb
index 6f964d5636b..d06d1e9862a 100644
--- a/lib/api/internal/kubernetes.rb
+++ b/lib/api/internal/kubernetes.rb
@@ -61,15 +61,6 @@ module API
Guest.can?(:download_code, project) || agent.has_access_to?(project)
end
- def count_events
- strong_memoize(:count_events) do
- events = params.slice(:gitops_sync_count, :k8s_api_proxy_request_count)
- events.transform_keys! { |event| event.to_s.chomp('_count') }
- events = params[:counters]&.slice(:gitops_sync, :k8s_api_proxy_request) unless events.present?
- events
- end
- end
-
def increment_unique_events
events = params[:unique_counters]&.slice(:agent_users_using_ci_tunnel)
@@ -77,6 +68,12 @@ module API
increment_unique_values(event, entity_ids)
end
end
+
+ def increment_count_events
+ events = params[:counters]&.slice(:gitops_sync, :k8s_api_proxy_request)
+
+ Gitlab::UsageDataCounters::KubernetesAgentCounter.increment_event_counts(events)
+ end
end
namespace 'internal' do
@@ -144,26 +141,17 @@ module API
detail 'Updates usage metrics for agent'
end
params do
- # Todo: Remove gitops_sync_count and k8s_api_proxy_request_count in the next milestone
- # https://gitlab.com/gitlab-org/gitlab/-/issues/369489
- # We're only keeping it for backwards compatibility until KAS is released
- # using `counts:` instead
- 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'
optional :counters, type: Hash do
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_count metric by'
+ optional :k8s_api_proxy_request, type: Integer, desc: 'The count to increment the k8s_api_proxy_request metric by'
end
- mutually_exclusive :counters, :gitops_sync_count
- mutually_exclusive :counters, :k8s_api_proxy_request_count
optional :unique_counters, type: Hash do
optional :agent_users_using_ci_tunnel, type: Set[Integer], desc: 'A set of user ids that have interacted a CI Tunnel to'
end
end
post '/' do
- Gitlab::UsageDataCounters::KubernetesAgentCounter.increment_event_counts(count_events) if count_events
-
+ increment_count_events
increment_unique_events
no_content!
diff --git a/lib/api/internal/pages.rb b/lib/api/internal/pages.rb
index 6be2679af14..771059053ac 100644
--- a/lib/api/internal/pages.rb
+++ b/lib/api/internal/pages.rb
@@ -5,6 +5,7 @@ module API
module Internal
class Pages < ::API::Base
feature_category :pages
+ urgency :low
before do
authenticate_gitlab_pages_request!
diff --git a/lib/api/invitations.rb b/lib/api/invitations.rb
index 6fb3eca0ba8..6aefdf146cf 100644
--- a/lib/api/invitations.rb
+++ b/lib/api/invitations.rb
@@ -18,11 +18,12 @@ module API
desc 'Invite non-members by email address to a group or project.' do
detail 'This feature was introduced in GitLab 13.6'
success Entities::Invitation
+ tags %w[invitations]
end
params do
requires :access_level, type: Integer, values: Gitlab::Access.all_values, desc: 'A valid access level (defaults: `30`, developer access level)'
- optional :email, types: [String, Array[String]], email_or_email_list: true, desc: 'The email address to invite, or multiple emails separated by comma'
- optional :user_id, types: [Integer, String], desc: 'The user ID of the new member or multiple IDs separated by commas.'
+ optional :email, type: Array[String], email_or_email_list: true, coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The email address to invite, or multiple emails separated by comma'
+ optional :user_id, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The user ID of the new member or multiple IDs separated by commas.'
optional :expires_at, type: DateTime, desc: 'Date string in the format YEAR-MONTH-DAY'
optional :invite_source, type: String, desc: 'Source that triggered the member creation process', default: 'invitations-api'
optional :tasks_to_be_done, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Tasks the inviter wants the member to do'
@@ -44,8 +45,12 @@ module API
desc 'Get a list of group or project invitations viewable by the authenticated user' do
detail 'This feature was introduced in GitLab 13.6'
success Entities::Invitation
+ is_array true
+ tags %w[invitations]
end
params do
+ optional :page, type: Integer, desc: 'Page to retrieve'
+ optional :per_page, type: Integer, desc: 'Number of member invitations to return per page'
optional :query, type: String, desc: 'A query string to search for members'
use :pagination
end
@@ -62,6 +67,7 @@ module API
desc 'Updates a group or project invitation.' do
success Entities::Member
+ tags %w[invitations]
end
params do
requires :email, type: String, desc: 'The email address of the invitation'
@@ -93,7 +99,15 @@ module API
end
end
- desc 'Removes an invitation from a group or project.'
+ desc 'Removes an invitation from a group or project.' do
+ success code: 204
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 409, message: 'Could not delete invitation' }
+ ]
+ tags %w[invitations]
+ end
params do
requires :email, type: String, desc: 'The email address of the invitation'
end
diff --git a/lib/api/issue_links.rb b/lib/api/issue_links.rb
index 563fb3358ed..020b02248a0 100644
--- a/lib/api/issue_links.rb
+++ b/lib/api/issue_links.rb
@@ -6,16 +6,27 @@ module API
before { authenticate! }
+ ISSUE_LINKS_TAGS = %w[issue_links].freeze
+
feature_category :team_planning
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
- requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue'
+ requires :id, types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
+ requires :issue_iid, type: Integer, desc: 'The internal ID of a project’s issue'
end
resource :projects, requirements: { id: %r{[^/]+} } do
- desc 'Get related issues' do
+ desc 'List issue relations' do
+ detail 'Get a list of a given issue’s linked issues, sorted by the relationship creation datetime (ascending).'\
+ 'Issues are filtered according to the user authorizations.'
success Entities::RelatedIssue
+ is_array true
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags ISSUE_LINKS_TAGS
end
get ':id/issues/:issue_iid/links' do
source_issue = find_project_issue(params[:issue_iid])
@@ -30,14 +41,23 @@ module API
include_subscribed: false
end
- desc 'Relate issues' do
+ desc 'Create an issue link' do
+ detail 'Creates a two-way relation between two issues.'\
+ 'The user must be allowed to update both issues to succeed.'
success Entities::IssueLink
+ failure [
+ { code: 400, message: 'Bad Request' },
+ { code: 401, message: 'Unauthorized' }
+ ]
+ tags ISSUE_LINKS_TAGS
end
params do
- requires :target_project_id, type: String, desc: 'The ID of the target project'
- requires :target_issue_iid, type: Integer, desc: 'The IID of the target issue'
+ requires :target_project_id, types: [String, Integer],
+ desc: 'The ID or URL-encoded path of a target project'
+ requires :target_issue_iid, types: [String, Integer], desc: 'The internal ID of a target project’s issue'
optional :link_type, type: String, values: IssueLink.link_types.keys,
- desc: 'The type of the relation'
+ desc: 'The type of the relation (“relates_to”, “blocks”, “is_blocked_by”),'\
+ 'defaults to “relates_to”)'
end
# rubocop: disable CodeReuse/ActiveRecord
post ':id/issues/:issue_iid/links' do
@@ -61,12 +81,17 @@ module API
end
# rubocop: enable CodeReuse/ActiveRecord
- desc 'Get issues relation' do
- detail 'This feature was introduced in GitLab 15.1.'
+ desc 'Get an issue link' do
+ detail 'Gets details about an issue link. This feature was introduced in GitLab 15.1.'
success Entities::IssueLink
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags ISSUE_LINKS_TAGS
end
params do
- requires :issue_link_id, type: Integer, desc: 'The ID of an issue link'
+ requires :issue_link_id, types: [String, Integer], desc: 'ID of an issue relationship'
end
get ':id/issues/:issue_iid/links/:issue_link_id' do
issue = find_project_issue(params[:issue_iid])
@@ -77,11 +102,17 @@ module API
present issue_link, with: Entities::IssueLink
end
- desc 'Remove issues relation' do
+ desc 'Delete an issue link' do
+ detail 'Deletes an issue link, thus removes the two-way relationship.'
success Entities::IssueLink
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags ISSUE_LINKS_TAGS
end
params do
- requires :issue_link_id, type: Integer, desc: 'The ID of an issue link'
+ requires :issue_link_id, types: [String, Integer], desc: 'The ID of an issue relationship'
end
delete ':id/issues/:issue_iid/links/:issue_link_id' do
issue = find_project_issue(params[:issue_iid])
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index b8b4019765d..b08819e34e3 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -198,7 +198,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
include TimeTrackingEndpoints
diff --git a/lib/api/keys.rb b/lib/api/keys.rb
index fb1bedd5e92..77952bac01a 100644
--- a/lib/api/keys.rb
+++ b/lib/api/keys.rb
@@ -9,8 +9,13 @@ module API
resource :keys do
desc 'Get single ssh key by id. Only available to admin users' do
+ detail 'Get SSH key with user by ID of an SSH key. Note only administrators can lookup SSH key with user by ID\
+ of an SSH key'
success Entities::SSHKeyWithUser
end
+ params do
+ requires :id, types: [String, Integer], desc: 'The ID of an SSH key', documentation: { example: '2' }
+ end
get ":id" do
authenticated_as_admin!
@@ -19,11 +24,14 @@ module API
present key, with: Entities::SSHKeyWithUser, current_user: current_user
end
- desc 'Get SSH Key information' do
+ desc 'Get user by fingerprint of SSH key' do
success Entities::UserWithAdmin
+ detail 'You can search for a user that owns a specific SSH key. Note only administrators can lookup SSH key\
+ with the fingerprint of an SSH key'
end
params do
- requires :fingerprint, type: String, desc: 'Search for a SSH fingerprint'
+ requires :fingerprint, type: String, desc: 'The fingerprint of an SSH key',
+ documentation: { example: 'ba:81:59:68:d7:6c:cd:02:02:bf:6a:9b:55:4e:af:d1' }
end
get do
authenticated_with_can_read_all_resources!
diff --git a/lib/api/labels.rb b/lib/api/labels.rb
index 0a107a96d61..2e00affbbdf 100644
--- a/lib/api/labels.rb
+++ b/lib/api/labels.rb
@@ -15,7 +15,7 @@ module API
label_id: API::NO_SLASH_URL_PART_REGEX)
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: LABEL_ENDPOINT_REQUIREMENTS do
desc 'Get all labels of the project' do
diff --git a/lib/api/lint.rb b/lib/api/lint.rb
index f65ecf3b4a6..89787ba00c2 100644
--- a/lib/api/lint.rb
+++ b/lib/api/lint.rb
@@ -15,12 +15,18 @@ module API
end
namespace :ci do
- desc 'Validation of .gitlab-ci.yml content'
+ desc '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: 'Content of .gitlab-ci.yml'
- optional :include_merged_yaml, type: Boolean, desc: 'Whether or not to include merged CI config yaml in the response'
- optional :include_jobs, type: Boolean, desc: 'Whether or not to include CI jobs in the response'
+ 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
unauthorized! unless can_lint_ci?
@@ -36,16 +42,21 @@ module API
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Validation of .gitlab-ci.yml content' do
- detail 'This feature was introduced in GitLab 13.5.'
+ 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
+ valid'
+ success Entities::Ci::Lint::Result
+ tags %w[ci_lint]
end
params do
- optional :dry_run, type: Boolean, default: false, desc: 'Run pipeline creation simulation, or only do static check.'
- optional :include_jobs, type: Boolean, desc: 'Whether or not to include CI jobs in the response'
+ optional :dry_run, type: Boolean, default: false, desc: 'Run pipeline creation simulation, or only do static check. This is false by default'
+ optional :include_jobs, type: Boolean, desc: 'If the list of jobs that would exist in a static check or pipeline
+ simulation should be included in the response. This is false by default'
optional :ref, type: String, desc: 'Branch or tag used to execute a dry run. Defaults to the default branch of the project. Only used when dry_run is true'
end
+
get ':id/ci/lint', urgency: :low do
- authorize! :download_code, user_project
+ authorize! :read_code, user_project
if user_project.commit.present?
content = user_project.repository.gitlab_ci_yml_for(user_project.commit.id, user_project.ci_config_path_or_default)
@@ -60,15 +71,19 @@ module API
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Validation of .gitlab-ci.yml content' do
- detail 'This feature was introduced in GitLab 13.6.'
+ desc 'Validate a CI YAML configuration with a namespace' do
+ detail 'Checks if CI/CD YAML configuration is valid. This endpoint has namespace specific context'
+ success code: 200, model: Entities::Ci::Lint::Result
+ tags %w[ci_lint]
end
params do
requires :content, type: String, desc: 'Content of .gitlab-ci.yml'
- optional :dry_run, type: Boolean, default: false, desc: 'Run pipeline creation simulation, or only do static check.'
- optional :include_jobs, type: Boolean, desc: 'Whether or not to include CI jobs in the response'
- optional :ref, type: String, desc: 'Branch or tag used to execute a dry run. Defaults to the default branch of the project. Only used when dry_run is true'
+ optional :dry_run, type: Boolean, default: false, desc: 'Run pipeline creation simulation, or only do static check. This is false by default'
+ optional :include_jobs, type: Boolean, desc: 'If the list of jobs that would exist in a static check or pipeline
+ simulation should be included in the response. This is false by default'
+ optional :ref, type: String, desc: 'When dry_run is true, sets the branch or tag to use. Defaults to the project’s default branch when not set'
end
+
post ':id/ci/lint', urgency: :low do
authorize! :create_pipeline, user_project
diff --git a/lib/api/markdown.rb b/lib/api/markdown.rb
index 1f8255fd6a4..276560f3433 100644
--- a/lib/api/markdown.rb
+++ b/lib/api/markdown.rb
@@ -7,13 +7,19 @@ module API
feature_category :team_planning
params do
- requires :text, type: String, desc: "The markdown text to render"
- optional :gfm, type: Boolean, desc: "Render text using GitLab Flavored Markdown"
- optional :project, type: String, desc: "The full path of a project to use as the context when creating references using GitLab Flavored Markdown"
+ requires :text, type: String, desc: "The Markdown text to render"
+ optional :gfm, type: Boolean, desc: "Render text using GitLab Flavored Markdown. Default is false"
+ optional :project, type: String, desc: "Use project as a context when creating references using GitLab Flavored Markdown"
end
resource :markdown do
- desc "Render markdown text" do
+ desc "Render an arbitrary Markdown document" do
detail "This feature was introduced in GitLab 11.0."
+ success ::API::Entities::Markdown
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' }
+ ]
+ tags %w[markdown]
end
post do
context = { only_path: false, current_user: current_user }
@@ -29,7 +35,7 @@ module API
context[:skip_project_check] = true
end
- { html: Banzai.render_and_post_process(params[:text], context) }
+ present({ html: Banzai.render_and_post_process(params[:text], context) }, with: Entities::Markdown)
end
end
end
diff --git a/lib/api/maven_packages.rb b/lib/api/maven_packages.rb
index 72313d6a588..30cdaba76ba 100644
--- a/lib/api/maven_packages.rb
+++ b/lib/api/maven_packages.rb
@@ -220,7 +220,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Download the maven package file' do
@@ -232,18 +232,20 @@ module API
end
route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true
get ':id/packages/maven/*path/:file_name', requirements: MAVEN_ENDPOINT_REQUIREMENTS do
+ project = user_project(action: :read_package)
+
# return a similar failure to user_project
- unless Feature.enabled?(:maven_central_request_forwarding, user_project&.root_ancestor)
+ unless Feature.enabled?(:maven_central_request_forwarding, project&.root_ancestor)
not_found!('Project') unless path_exists?(params[:path])
end
- authorize_read_package!(user_project)
+ authorize_read_package!(project)
file_name, format = extract_format(params[:file_name])
- package = fetch_package(file_name: file_name, project: user_project)
+ package = fetch_package(file_name: file_name, project: project)
- find_and_present_package_file(package, file_name, format, params.merge(target: user_project))
+ find_and_present_package_file(package, file_name, format, params.merge(target: project))
end
desc 'Workhorse authorize the maven package file upload' do
@@ -268,7 +270,7 @@ module API
params do
requires :path, type: String, desc: 'Package path'
requires :file_name, type: String, desc: 'Package file name', regexp: Gitlab::Regex.maven_file_name_regex
- requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)', documentation: { type: 'file' }
end
route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true
put ':id/packages/maven/*path/:file_name', requirements: MAVEN_ENDPOINT_REQUIREMENTS do
diff --git a/lib/api/merge_request_approvals.rb b/lib/api/merge_request_approvals.rb
index 71ca8331ed6..7622ec717cc 100644
--- a/lib/api/merge_request_approvals.rb
+++ b/lib/api/merge_request_approvals.rb
@@ -6,10 +6,9 @@ module API
feature_category :source_code_management
- helpers do
- params :ee_approval_params do
- end
+ helpers ::API::Helpers::MergeRequestsHelpers
+ helpers do
def present_approval(merge_request)
present merge_request, with: ::API::Entities::MergeRequestApprovals, current_user: current_user
end
@@ -24,7 +23,12 @@ module API
# merge_request_iid (required) - IID of MR
# Examples:
# GET /projects/:id/merge_requests/:merge_request_iid/approvals
- desc 'List approvals for merge request'
+ desc 'List approvals for merge request' do
+ success ::API::Entities::MergeRequestApprovals
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ end
get 'approvals', urgency: :low do
merge_request = find_merge_request_with_access(params[:merge_request_iid])
@@ -39,7 +43,13 @@ module API
# Examples:
# POST /projects/:id/merge_requests/:merge_request_iid/approve
#
- desc 'Approve a merge request'
+ desc 'Approve a merge request' do
+ success code: 201, model: ::API::Entities::MergeRequestApprovals
+ failure [
+ { code: 404, message: 'Not found' },
+ { code: 401, message: 'Unauthorized' }
+ ]
+ end
params do
optional :sha, type: String, desc: 'When present, must have the HEAD SHA of the source branch'
@@ -60,7 +70,13 @@ module API
present_approval(merge_request)
end
- desc 'Remove an approval from a merge request'
+ desc 'Remove an approval from a merge request' do
+ success code: 201, model: ::API::Entities::MergeRequestApprovals
+ failure [
+ { code: 404, message: 'Not found' },
+ { code: 401, message: 'Unauthorized' }
+ ]
+ end
post 'unapprove', urgency: :low do
merge_request = find_merge_request_with_access(params[:merge_request_iid], :approve_merge_request)
diff --git a/lib/api/merge_request_diffs.rb b/lib/api/merge_request_diffs.rb
index 87623568a04..c7f0f88eacc 100644
--- a/lib/api/merge_request_diffs.rb
+++ b/lib/api/merge_request_diffs.rb
@@ -10,16 +10,18 @@ module API
feature_category :code_review
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a list of merge request diff versions' do
detail 'This feature was introduced in GitLab 8.12.'
success Entities::MergeRequestDiff
+ tags %w[merge_requests]
+ is_array true
end
params do
- requires :merge_request_iid, type: Integer, desc: 'The IID of a merge request'
+ requires :merge_request_iid, type: Integer, desc: 'The internal ID of the merge request'
use :pagination
end
get ":id/merge_requests/:merge_request_iid/versions" do
@@ -31,11 +33,12 @@ module API
desc 'Get a single merge request diff version' do
detail 'This feature was introduced in GitLab 8.12.'
success Entities::MergeRequestDiffFull
+ tags %w[merge_requests]
end
params do
- requires :merge_request_iid, type: Integer, desc: 'The IID of a merge request'
- requires :version_id, type: Integer, desc: 'The ID of a merge request diff version'
+ requires :merge_request_iid, type: Integer, desc: 'The internal ID of the merge request'
+ requires :version_id, type: Integer, desc: 'The ID of the merge request diff version'
end
get ":id/merge_requests/:merge_request_iid/versions/:version_id", urgency: :low do
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index a0e7d0b10cd..bb2861aa221 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -170,7 +170,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
include TimeTrackingEndpoints
diff --git a/lib/api/metadata.rb b/lib/api/metadata.rb
index 3e42ffe336a..788d9843c63 100644
--- a/lib/api/metadata.rb
+++ b/lib/api/metadata.rb
@@ -9,6 +9,8 @@ module API
before { authenticate! }
+ METADATA_TAGS = %w[metadata].freeze
+
feature_category :not_owned # rubocop:todo Gitlab/AvoidFeatureCategoryNotOwned
METADATA_QUERY = <<~EOF
@@ -21,6 +23,7 @@ module API
externalUrl
version
}
+ enterprise
}
}
EOF
@@ -35,30 +38,13 @@ module API
end
end
- desc 'Retrieve metadata information for this GitLab instance.' do
+ desc 'Retrieve metadata information for this GitLab instance' do
detail 'This feature was introduced in GitLab 15.2.'
- success [
- {
- code: 200,
- model: Entities::Metadata,
- message: 'successful operation',
- examples: {
- successful_response: {
- 'value' => {
- version: "15.0-pre",
- revision: "c401a659d0c",
- kas: {
- enabled: true,
- externalUrl: "grpc://gitlab.example.com:8150",
- version: "15.0.0"
- }
- }
- }
- }
- }
+ success Entities::Metadata
+ failure [
+ { code: 401, message: 'Unauthorized' }
]
- failure [{ code: 401, message: 'unauthorized operation' }]
- tags %w[metadata]
+ tags METADATA_TAGS
end
get '/metadata' do
run_metadata_query
@@ -66,31 +52,14 @@ module API
# Support the deprecated `/version` route.
# See https://gitlab.com/gitlab-org/gitlab/-/issues/366287
- desc 'Get the version information of the GitLab instance.' do
+ desc 'Retrieves version information for the GitLab instance' do
detail 'This feature was introduced in GitLab 8.13 and deprecated in 15.5. ' \
'We recommend you instead use the Metadata API.'
- success [
- {
- code: 200,
- model: Entities::Metadata,
- message: 'successful operation',
- examples: {
- 'Example' => {
- 'value' => {
- version: "15.0-pre",
- revision: "c401a659d0c",
- kas: {
- enabled: true,
- externalUrl: "grpc://gitlab.example.com:8150",
- version: "15.0.0"
- }
- }
- }
- }
- }
+ success Entities::Metadata
+ failure [
+ { code: 401, message: 'Unauthorized' }
]
- failure [{ code: 401, message: 'unauthorized operation' }]
- tags %w[metadata]
+ tags METADATA_TAGS
end
get '/version' do
diff --git a/lib/api/metrics/dashboard/annotations.rb b/lib/api/metrics/dashboard/annotations.rb
index 478adcdce70..6ba154191be 100644
--- a/lib/api/metrics/dashboard/annotations.rb
+++ b/lib/api/metrics/dashboard/annotations.rb
@@ -7,8 +7,15 @@ module API
feature_category :metrics
urgency :low
- desc 'Create a new monitoring dashboard annotation' do
+ desc 'Create a new annotation' do
+ detail 'Creates a new monitoring dashboard annotation'
success Entities::Metrics::Dashboard::Annotation
+ failure [
+ { code: 400, message: 'Bad Request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not Found' }
+ ]
+ tags %w[dashboard_annotations]
end
ANNOTATIONS_SOURCES = [
@@ -20,12 +27,16 @@ module API
resource annotations_source[:resource] do
params do
requires :starting_at, type: DateTime,
- desc: 'Date time indicating starting moment to which the annotation relates.'
+ desc: 'Date time string, ISO 8601 formatted, such as 2016-03-11T03:45:40Z.'\
+ 'Timestamp marking start point of annotation.'
optional :ending_at, type: DateTime,
- desc: 'Date time indicating ending moment to which the annotation relates.'
+ desc: 'Date time string, ISO 8601 formatted, such as 2016-03-11T03:45:40Z.'\
+ 'Timestamp marking end point of annotation.'\
+ 'When not supplied, an annotation displays as a single event at the start point.'
requires :dashboard_path, type: String, coerce_with: -> (val) { CGI.unescape(val) },
- desc: 'The path to a file defining the dashboard on which the annotation should be added'
- requires :description, type: String, desc: 'The description of the annotation'
+ desc: 'ID of the dashboard which needs to be annotated.'\
+ 'Treated as a CGI-escaped path, and automatically un-escaped.'
+ requires :description, type: String, desc: 'Description of the annotation.'
end
post ':id/metrics_dashboard/annotations' do
@@ -33,7 +44,9 @@ module API
forbidden! unless can?(current_user, :create_metrics_dashboard_annotation, annotations_source_object)
- create_service_params = declared(params).merge(annotations_source[:create_service_param_key] => annotations_source_object)
+ create_service_params = declared(params).merge(
+ annotations_source[:create_service_param_key] => annotations_source_object
+ )
result = ::Metrics::Dashboard::Annotations::CreateService.new(current_user, create_service_params).execute
diff --git a/lib/api/metrics/user_starred_dashboards.rb b/lib/api/metrics/user_starred_dashboards.rb
index 4d5396acccb..0a91e914d52 100644
--- a/lib/api/metrics/user_starred_dashboards.rb
+++ b/lib/api/metrics/user_starred_dashboards.rb
@@ -6,14 +6,22 @@ module API
feature_category :metrics
urgency :low
+ USER_STARRED_DASHBOARDS_TAGS = %w[user_starred_dashboards].freeze
+
resource :projects do
- desc 'Marks selected metrics dashboard as starred' do
+ desc 'Add a star to a dashboard' do
+ detail 'Marks selected metrics dashboard as starred. Introduced in GitLab 13.0.'
success Entities::Metrics::UserStarredDashboard
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags USER_STARRED_DASHBOARDS_TAGS
end
params do
requires :dashboard_path, type: String, allow_blank: false, coerce_with: ->(val) { CGI.unescape(val) },
- desc: 'Url encoded path to a file defining the dashboard to which the star should be added'
+ desc: 'URL-encoded path to file defining the dashboard which should be marked as favorite'
end
post ':id/metrics/user_starred_dashboards' do
@@ -26,7 +34,15 @@ module API
end
end
- desc 'Remove star from selected metrics dashboard'
+ desc 'Remove a star from a dashboard' do
+ detail 'Remove star from selected metrics dashboard. Introduced in GitLab 13.0.'
+ success code: 200
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags USER_STARRED_DASHBOARDS_TAGS
+ end
params do
optional :dashboard_path, type: String, allow_blank: false, coerce_with: ->(val) { CGI.unescape(val) },
diff --git a/lib/api/ml/mlflow.rb b/lib/api/ml/mlflow.rb
index 2ffb04ebcbd..56bfac1530e 100644
--- a/lib/api/ml/mlflow.rb
+++ b/lib/api/ml/mlflow.rb
@@ -68,10 +68,19 @@ module API
def find_candidate!(iid)
candidate_repository.by_iid(iid) || resource_not_found!
end
+
+ def packages_url
+ path = api_v4_projects_packages_generic_package_version_path(
+ id: user_project.id, package_name: '', file_name: ''
+ )
+ path = path.delete_suffix('/package_version')
+
+ "#{request.base_url}#{path}"
+ end
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'API to interface with MLFlow Client, REST API version 1.28.0' do
@@ -130,8 +139,7 @@ module API
resource :runs do
desc 'Creates a Run.' do
success Entities::Ml::Mlflow::Run
- detail ['https://www.mlflow.org/docs/1.28.0/rest-api.html#create-run',
- 'MLFlow Runs map to GitLab Candidates']
+ detail 'MLFlow Runs map to GitLab Candidates. https://www.mlflow.org/docs/1.28.0/rest-api.html#create-run'
end
params do
requires :experiment_id, type: Integer,
@@ -143,7 +151,8 @@ module API
optional :tags, type: Array, desc: 'This will be ignored'
end
post 'create', urgency: :low do
- present candidate_repository.create!(experiment, params[:start_time]), with: Entities::Ml::Mlflow::Run
+ present candidate_repository.create!(experiment, params[:start_time]),
+ with: Entities::Ml::Mlflow::Run, packages_url: packages_url
end
desc 'Gets an MLFlow Run, which maps to GitLab Candidates' do
@@ -155,13 +164,12 @@ module API
optional :run_uuid, type: String, desc: 'This parameter is ignored'
end
get 'get', urgency: :low do
- present candidate, with: Entities::Ml::Mlflow::Run
+ present candidate, with: Entities::Ml::Mlflow::Run, packages_url: packages_url
end
desc 'Updates a Run.' do
success Entities::Ml::Mlflow::UpdateRun
- detail ['https://www.mlflow.org/docs/1.28.0/rest-api.html#update-run',
- 'MLFlow Runs map to GitLab Candidates']
+ detail 'MLFlow Runs map to GitLab Candidates. https://www.mlflow.org/docs/1.28.0/rest-api.html#update-run'
end
params do
requires :run_id, type: String, desc: 'UUID of the candidate.'
@@ -174,7 +182,7 @@ module API
post 'update', urgency: :low do
candidate_repository.update(candidate, params[:status], params[:end_time])
- present candidate, with: Entities::Ml::Mlflow::UpdateRun
+ present candidate, with: Entities::Ml::Mlflow::UpdateRun, packages_url: packages_url
end
desc 'Logs a metric to a run.' do
diff --git a/lib/api/npm_project_packages.rb b/lib/api/npm_project_packages.rb
index 166c0b755fe..494b493f5e0 100644
--- a/lib/api/npm_project_packages.rb
+++ b/lib/api/npm_project_packages.rb
@@ -11,7 +11,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
namespace 'projects/:id/packages/npm' do
desc 'Download the NPM tarball' do
diff --git a/lib/api/nuget_project_packages.rb b/lib/api/nuget_project_packages.rb
index 3e05ea13311..d549a8be035 100644
--- a/lib/api/nuget_project_packages.rb
+++ b/lib/api/nuget_project_packages.rb
@@ -35,7 +35,7 @@ module API
helpers do
params :file_params do
- requires :package, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ requires :package, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)', documentation: { type: 'file' }
end
def project_or_group
@@ -91,7 +91,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project', regexp: ::API::Concerns::Packages::NugetEndpoints::POSITIVE_INTEGER_REGEX
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project', regexp: ::API::Concerns::Packages::NugetEndpoints::POSITIVE_INTEGER_REGEX
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
namespace ':id/packages/nuget' do
diff --git a/lib/api/package_files.rb b/lib/api/package_files.rb
index 278dc4c2044..bb9f96cdbb1 100644
--- a/lib/api/package_files.rb
+++ b/lib/api/package_files.rb
@@ -8,19 +8,23 @@ module API
authorize_packages_access!(user_project)
end
+ PACKAGE_FILES_TAGS = %w[package_files].freeze
+
feature_category :package_registry
urgency :low
helpers ::API::Helpers::PackagesHelpers
params do
- requires :id, type: String, desc: 'The ID of a project'
- requires :package_id, type: Integer, desc: 'The ID of a package'
+ requires :id, types: [String, Integer], desc: 'ID or URL-encoded path of the project'
+ requires :package_id, type: Integer, desc: 'ID of a package'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get all package files' do
- detail 'This feature was introduced in GitLab 11.8'
+ desc 'List package files' do
+ detail 'Get a list of package files of a single package'
success ::API::Entities::PackageFile
+ is_array true
+ tags PACKAGE_FILES_TAGS
end
params do
use :pagination
@@ -35,11 +39,17 @@ module API
present paginate(package_files), with: ::API::Entities::PackageFile
end
- desc 'Remove a package file' do
+ desc 'Delete a package file' do
detail 'This feature was introduced in GitLab 13.12'
+ success code: 204
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags PACKAGE_FILES_TAGS
end
params do
- requires :package_file_id, type: Integer, desc: 'The ID of a package file'
+ requires :package_file_id, type: Integer, desc: 'ID of a package file'
end
delete ':id/packages/:package_id/package_files/:package_file_id' do
authorize_destroy_package!(user_project)
diff --git a/lib/api/pages.rb b/lib/api/pages.rb
index 5f695f3853d..7e230bd3c67 100644
--- a/lib/api/pages.rb
+++ b/lib/api/pages.rb
@@ -10,7 +10,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Unpublish pages' do
diff --git a/lib/api/pages_domains.rb b/lib/api/pages_domains.rb
index 9cf61967ba4..967847a8e62 100644
--- a/lib/api/pages_domains.rb
+++ b/lib/api/pages_domains.rb
@@ -54,7 +54,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before do
diff --git a/lib/api/pagination_params.rb b/lib/api/pagination_params.rb
index bdb69d0ba44..c3505780396 100644
--- a/lib/api/pagination_params.rb
+++ b/lib/api/pagination_params.rb
@@ -17,8 +17,9 @@ module API
included do
helpers do
params :pagination do
- optional :page, type: Integer, default: 1, desc: 'Current page number'
- optional :per_page, type: Integer, default: 20, desc: 'Number of items per page', except_values: [0]
+ optional :page, type: Integer, default: 1, desc: 'Current page number', documentation: { example: 1 }
+ optional :per_page, type: Integer, default: 20,
+ desc: 'Number of items per page', except_values: [0], documentation: { example: 20 }
end
def verify_pagination_params!
diff --git a/lib/api/personal_access_tokens.rb b/lib/api/personal_access_tokens.rb
index a2903faa4ad..66930ecd797 100644
--- a/lib/api/personal_access_tokens.rb
+++ b/lib/api/personal_access_tokens.rb
@@ -6,24 +6,6 @@ module API
feature_category :authentication_and_authorization
- desc 'Get all Personal Access Tokens' do
- detail 'This feature was added in GitLab 13.3'
- success Entities::PersonalAccessToken
- end
- params do
- optional :user_id, type: Integer, desc: 'Filter PATs by User ID'
- optional :revoked, type: Boolean, desc: 'Filter PATs where revoked state matches parameter'
- optional :state, type: String, desc: 'Filter PATs which are either active or not',
- values: %w[active inactive]
- optional :created_before, type: DateTime, desc: 'Filter PATs which were created before given datetime'
- optional :created_after, type: DateTime, desc: 'Filter PATs which were created after given datetime'
- optional :last_used_before, type: DateTime, desc: 'Filter PATs which were used before given datetime'
- optional :last_used_after, type: DateTime, desc: 'Filter PATs which were used after given datetime'
- optional :search, type: String, desc: 'Filters PATs by its name'
-
- use :pagination
- end
-
before do
authenticate!
restrict_non_admins! unless current_user.can_admin_all_resources?
@@ -32,12 +14,47 @@ module API
helpers ::API::Helpers::PersonalAccessTokensHelpers
resources :personal_access_tokens do
+ desc 'List personal access tokens' do
+ detail 'Get all personal access tokens the authenticated user has access to.'
+ is_array true
+ success Entities::PersonalAccessToken
+ tags %w[personal_access_tokens]
+ failure [
+ { code: 401, message: 'Unauthorized' }
+ ]
+ end
+ params do
+ optional :user_id, type: Integer, desc: 'Filter PATs by User ID', documentation: { example: 2 }
+ optional :revoked, type: Boolean, desc: 'Filter PATs where revoked state matches parameter',
+ documentation: { example: false }
+ optional :state, type: String, desc: 'Filter PATs which are either active or not',
+ values: %w[active inactive], documentation: { example: 'active' }
+ optional :created_before, type: DateTime, desc: 'Filter PATs which were created before given datetime',
+ documentation: { example: '2022-01-01' }
+ optional :created_after, type: DateTime, desc: 'Filter PATs which were created after given datetime',
+ documentation: { example: '2021-01-01' }
+ optional :last_used_before, type: DateTime, desc: 'Filter PATs which were used before given datetime',
+ documentation: { example: '2021-01-01' }
+ optional :last_used_after, type: DateTime, desc: 'Filter PATs which were used after given datetime',
+ documentation: { example: '2022-01-01' }
+ optional :search, type: String, desc: 'Filters PATs by its name', documentation: { example: 'token' }
+
+ use :pagination
+ end
get do
tokens = PersonalAccessTokensFinder.new(finder_params(current_user), current_user).execute
present paginate(tokens), with: Entities::PersonalAccessToken
end
+ desc 'Get single personal access token' do
+ detail 'Get a personal access token by using the ID of the personal access token.'
+ success Entities::PersonalAccessToken
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ end
get ':id' do
token = PersonalAccessToken.find_by_id(params[:id])
@@ -51,6 +68,13 @@ module API
end
end
+ desc 'Revoke a personal access token' do
+ detail 'Revoke a personal access token by using the ID of the personal access token.'
+ success code: 204
+ failure [
+ { code: 400, message: 'Bad Request' }
+ ]
+ end
delete ':id' do
token = find_token(params[:id])
diff --git a/lib/api/personal_access_tokens/self_information.rb b/lib/api/personal_access_tokens/self_information.rb
index 89850614f94..5735fe49f33 100644
--- a/lib/api/personal_access_tokens/self_information.rb
+++ b/lib/api/personal_access_tokens/self_information.rb
@@ -17,10 +17,28 @@ module API
before { authenticate! }
resource :personal_access_tokens do
+ desc "Get single personal access token" do
+ detail 'Get the details of a personal access token by passing it to the API in a header'
+ success code: 200, model: Entities::PersonalAccessToken
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[personal_access_tokens]
+ end
get 'self' do
present access_token, with: Entities::PersonalAccessToken
end
+ desc "Revoke a personal access token" do
+ detail 'Revoke a personal access token by passing it to the API in a header'
+ success code: 204
+ failure [
+ { code: 400, message: 'Bad Request' }
+ ]
+ tags %w[personal_access_tokens]
+ end
+
delete 'self' do
revoke_token(access_token)
end
diff --git a/lib/api/project_clusters.rb b/lib/api/project_clusters.rb
index 4644d38ea80..21f1ee69613 100644
--- a/lib/api/project_clusters.rb
+++ b/lib/api/project_clusters.rb
@@ -13,12 +13,17 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of the project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get all clusters from the project' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'List project clusters' do
+ detail 'This feature was introduced in GitLab 11.7. Returns a list of project clusters.'
success Entities::Cluster
+ failure [
+ { code: 403, message: 'Forbidden' }
+ ]
+ is_array true
+ tags %w[clusters]
end
params do
use :pagination
@@ -29,9 +34,14 @@ module API
present paginate(clusters_for_current_user), with: Entities::Cluster
end
- desc 'Get specific cluster for the project' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Get a single project cluster' do
+ detail 'This feature was introduced in GitLab 11.7. Gets a single project cluster.'
success Entities::ClusterProject
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The cluster ID'
@@ -42,9 +52,15 @@ module API
present cluster, with: Entities::ClusterProject
end
- desc 'Adds an existing cluster' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Add existing cluster to project' do
+ detail 'This feature was introduced in GitLab 11.7. Adds an existing Kubernetes cluster to the project.'
success Entities::ClusterProject
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :name, type: String, desc: 'Cluster name'
@@ -76,9 +92,15 @@ module API
end
end
- desc 'Update an existing cluster' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Edit project cluster' do
+ detail 'This feature was introduced in GitLab 11.7. Updates an existing project cluster.'
success Entities::ClusterProject
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The cluster ID'
@@ -108,9 +130,14 @@ module API
end
end
- desc 'Remove a cluster' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Delete project cluster' do
+ detail 'This feature was introduced in GitLab 11.7. Deletes an existing project cluster. Does not remove existing resources within the connected Kubernetes cluster.'
success Entities::ClusterProject
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The Cluster ID'
diff --git a/lib/api/project_container_repositories.rb b/lib/api/project_container_repositories.rb
index 6a6275ed02a..c5add42decc 100644
--- a/lib/api/project_container_repositories.rb
+++ b/lib/api/project_container_repositories.rb
@@ -16,7 +16,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
route_setting :authentication, job_token_allowed: true, job_token_scope: :project
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
@@ -47,8 +47,12 @@ module API
end
delete ':id/registry/repositories/:repository_id', requirements: REPOSITORY_ENDPOINT_REQUIREMENTS do
authorize_admin_container_image!
+ repository.delete_scheduled!
+
+ unless Feature.enabled?(:container_registry_delete_repository_with_cron_worker)
+ DeleteContainerRepositoryWorker.perform_async(current_user.id, repository.id) # rubocop:disable CodeReuse/Worker
+ end
- DeleteContainerRepositoryWorker.perform_async(current_user.id, repository.id) # rubocop:disable CodeReuse/Worker
track_package_event('delete_repository', :container, user: current_user, project: user_project, namespace: user_project.namespace)
status :accepted
diff --git a/lib/api/project_debian_distributions.rb b/lib/api/project_debian_distributions.rb
index b8ca9428fa3..1e27f5c8856 100644
--- a/lib/api/project_debian_distributions.rb
+++ b/lib/api/project_debian_distributions.rb
@@ -3,7 +3,7 @@
module API
class ProjectDebianDistributions < ::API::Base
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
before do
diff --git a/lib/api/project_events.rb b/lib/api/project_events.rb
index e8829216336..d90ce32c354 100644
--- a/lib/api/project_events.rb
+++ b/lib/api/project_events.rb
@@ -12,10 +12,15 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
+ optional :action, type: String, desc: 'Include only events of a particular action type'
+ optional :target_type, type: String, desc: 'Include only events of a particular target type'
+ optional :before, type: DateTime, desc: 'Include only events created before a particular date'
+ optional :after, type: DateTime, desc: 'Include only events created after a particular date'
+ optional :sort, type: String, desc: 'Sort events in asc or desc order by created_at. Default is desc'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc "List a Project's visible events" do
+ desc "List a project's visible events" do
success Entities::Event
end
params do
diff --git a/lib/api/project_export.rb b/lib/api/project_export.rb
index 29fdfe45566..e4e950fb603 100644
--- a/lib/api/project_export.rb
+++ b/lib/api/project_export.rb
@@ -11,12 +11,19 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: { id: %r{[^/]+} } do
desc 'Get export status' do
detail 'This feature was introduced in GitLab 10.6.'
- success Entities::ProjectExportStatus
+ success code: 200, model: Entities::ProjectExportStatus
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_export']
end
get ':id/export' do
present user_project, with: Entities::ProjectExportStatus
@@ -24,6 +31,15 @@ module API
desc 'Download export' do
detail 'This feature was introduced in GitLab 10.6.'
+ success code: 200
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_export']
+ produces %w[application/octet-stream application/json]
end
get ':id/export/download' do
check_rate_limit! :project_download_export, scope: [current_user, user_project.namespace]
@@ -41,6 +57,16 @@ module API
desc 'Start export' do
detail 'This feature was introduced in GitLab 10.6.'
+ success code: 202
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 429, message: 'Too many requests' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_export']
end
params do
optional :description, type: String, desc: 'Override the project description'
@@ -86,6 +112,15 @@ module API
desc 'Start relations export' do
detail 'This feature was introduced in GitLab 14.4'
+ success code: 202
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_export']
end
post ':id/export_relations' do
response = ::BulkImports::ExportService.new(portable: user_project, user: current_user).execute
@@ -93,12 +128,23 @@ module API
if response.success?
accepted!
else
- render_api_error!(message: 'Project relations export could not be started.')
+ render_api_error!('Project relations export could not be started.', 500)
end
end
desc 'Download relations export' do
detail 'This feature was introduced in GitLab 14.4'
+ success code: 200
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 500, message: 'Internal Server Error' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_export']
+ produces %w[application/octet-stream application/json]
end
params do
requires :relation,
@@ -119,6 +165,15 @@ module API
desc 'Relations export status' do
detail 'This feature was introduced in GitLab 14.4'
+ is_array true
+ success code: 200, model: Entities::BulkImports::ExportStatus
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_export']
end
get ':id/export_relations/status' do
present user_project.bulk_import_exports, with: Entities::BulkImports::ExportStatus
diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb
index 466e80d68c8..ced8ecec883 100644
--- a/lib/api/project_hooks.rb
+++ b/lib/api/project_hooks.rb
@@ -4,6 +4,8 @@ module API
class ProjectHooks < ::API::Base
include PaginationParams
+ project_hooks_tags = %w[project_hooks]
+
before { authenticate! }
before { authorize_admin_project }
@@ -37,15 +39,18 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
namespace ':id/hooks' do
mount ::API::Hooks::UrlVariables
end
- desc 'Get project hooks' do
+ desc 'List project hooks' do
+ detail 'Get a list of project hooks'
success Entities::ProjectHook
+ is_array true
+ tags project_hooks_tags
end
params do
use :pagination
@@ -54,8 +59,13 @@ module API
present paginate(user_project.hooks), with: Entities::ProjectHook
end
- desc 'Get a project hook' do
+ desc 'Get project hook' do
+ detail 'Get a specific hook for a project'
success Entities::ProjectHook
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags project_hooks_tags
end
params do
requires :hook_id, type: Integer, desc: 'The ID of a project hook'
@@ -65,8 +75,15 @@ module API
present hook, with: Entities::ProjectHook
end
- desc 'Add hook to project' do
+ desc 'Add project hook' do
+ detail 'Adds a hook to a specified project'
success Entities::ProjectHook
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags project_hooks_tags
end
params do
use :requires_url
@@ -79,11 +96,18 @@ module API
save_hook(hook, Entities::ProjectHook)
end
- desc 'Update an existing hook' do
+ desc 'Edit project hook' do
+ detail 'Edits a hook for a specified project.'
success Entities::ProjectHook
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags project_hooks_tags
end
params do
- requires :hook_id, type: Integer, desc: "The ID of the hook to update"
+ requires :hook_id, type: Integer, desc: 'The ID of the project hook'
use :optional_url
use :common_hook_parameters
end
@@ -91,11 +115,16 @@ module API
update_hook(entity: Entities::ProjectHook)
end
- desc 'Deletes project hook' do
+ desc 'Delete a project hook' do
+ detail 'Removes a hook from a project. This is an idempotent method and can be called multiple times. Either the hook is available or not.'
success Entities::ProjectHook
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags project_hooks_tags
end
params do
- requires :hook_id, type: Integer, desc: 'The ID of the hook to delete'
+ requires :hook_id, type: Integer, desc: 'The ID of the project hook'
end
delete ":id/hooks/:hook_id" do
hook = find_hook
diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb
index 0da8c1ecedd..02f0d9a2a70 100644
--- a/lib/api/project_import.rb
+++ b/lib/api/project_import.rb
@@ -40,6 +40,7 @@ module API
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Workhorse authorize the project import upload' do
detail 'This feature was introduced in GitLab 12.9'
+ tags ['project_import']
end
post 'import/authorize' do
require_gitlab_workhorse!
@@ -77,7 +78,16 @@ module API
end
desc 'Create a new project import' do
detail 'This feature was introduced in GitLab 10.6.'
- success Entities::ProjectImportStatus
+ success code: 201, model: Entities::ProjectImportStatus
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_import']
+ consumes ['multipart/form-data']
end
post 'import' do
require_gitlab_workhorse!
@@ -108,11 +118,19 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
desc 'Get a project import status' do
detail 'This feature was introduced in GitLab 10.6.'
- success Entities::ProjectImportStatus
+ success code: 200, model: Entities::ProjectImportStatus
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_import']
end
route_setting :skip_authentication, true
get ':id/import' do
@@ -133,7 +151,17 @@ module API
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
+ consumes ['multipart/form-data']
+ tags ['project_import']
+ success code: 201, model: Entities::ProjectImportStatus
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' },
+ { code: 429, message: 'Too many requests' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
post 'remote-import' do
check_rate_limit! :project_import, scope: [current_user, :project_import]
@@ -176,7 +204,17 @@ module API
end
desc 'Create a new project import using a file from AWS S3' do
detail 'This feature was introduced in GitLab 14.9.'
- success Entities::ProjectImportStatus
+ consumes ['multipart/form-data']
+ tags ['project_import']
+ success code: 201, model: Entities::ProjectImportStatus
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' },
+ { code: 429, message: 'Too many requests' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
post 'remote-import-s3' do
not_found! unless ::Feature.enabled?(:import_project_from_remote_file_s3)
diff --git a/lib/api/project_milestones.rb b/lib/api/project_milestones.rb
index 9f82dbf9813..a7a583aaa23 100644
--- a/lib/api/project_milestones.rb
+++ b/lib/api/project_milestones.rb
@@ -11,7 +11,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a list of project milestones' do
diff --git a/lib/api/project_packages.rb b/lib/api/project_packages.rb
index 800966408fc..d09c481403f 100644
--- a/lib/api/project_packages.rb
+++ b/lib/api/project_packages.rb
@@ -14,7 +14,7 @@ module API
helpers ::API::Helpers::PackagesHelpers
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get all project packages' do
diff --git a/lib/api/project_repository_storage_moves.rb b/lib/api/project_repository_storage_moves.rb
index ab5d8b3a888..5777b8754e7 100644
--- a/lib/api/project_repository_storage_moves.rb
+++ b/lib/api/project_repository_storage_moves.rb
@@ -11,7 +11,8 @@ module API
resource :project_repository_storage_moves do
desc 'Get a list of all project repository storage moves' do
detail 'This feature was introduced in GitLab 13.0.'
- success Entities::Projects::RepositoryStorageMove
+ is_array true
+ success code: 200, model: Entities::Projects::RepositoryStorageMove
end
params do
use :pagination
@@ -24,7 +25,7 @@ module API
desc 'Get a project repository storage move' do
detail 'This feature was introduced in GitLab 13.0.'
- success Entities::Projects::RepositoryStorageMove
+ success code: 200, model: Entities::Projects::RepositoryStorageMove
end
params do
requires :repository_storage_move_id, type: Integer, desc: 'The ID of a project repository storage move'
@@ -37,6 +38,7 @@ module API
desc 'Schedule bulk project repository storage moves' do
detail 'This feature was introduced in GitLab 13.7.'
+ success code: 202
end
params do
requires :source_storage_name, type: String, desc: 'The source storage shard', values: -> { Gitlab.config.repositories.storages.keys }
@@ -53,12 +55,13 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a list of all project repository storage moves' do
detail 'This feature was introduced in GitLab 13.1.'
- success Entities::Projects::RepositoryStorageMove
+ is_array true
+ success code: 200, model: Entities::Projects::RepositoryStorageMove
end
params do
use :pagination
@@ -71,7 +74,7 @@ module API
desc 'Get a project repository storage move' do
detail 'This feature was introduced in GitLab 13.1.'
- success Entities::Projects::RepositoryStorageMove
+ success code: 200, model: Entities::Projects::RepositoryStorageMove
end
params do
requires :repository_storage_move_id, type: Integer, desc: 'The ID of a project repository storage move'
@@ -84,14 +87,14 @@ module API
desc 'Schedule a project repository storage move' do
detail 'This feature was introduced in GitLab 13.1.'
- success Entities::Projects::RepositoryStorageMove
+ success code: 201, model: Entities::Projects::RepositoryStorageMove
end
params do
optional :destination_storage_name, type: String, desc: 'The destination storage shard'
end
post ':id/repository_storage_moves' do
storage_move = user_project.repository_storage_moves.build(
- declared_params.merge(source_storage_name: user_project.repository_storage)
+ declared_params.compact.merge(source_storage_name: user_project.repository_storage)
)
if storage_move.schedule
diff --git a/lib/api/project_snapshots.rb b/lib/api/project_snapshots.rb
index d33d2976b1c..d2ed7f75fb7 100644
--- a/lib/api/project_snapshots.rb
+++ b/lib/api/project_snapshots.rb
@@ -11,6 +11,11 @@ module API
resource :projects do
desc 'Download a (possibly inconsistent) snapshot of a repository' do
detail 'This feature was introduced in GitLab 10.7'
+ success File
+ produces 'application/x-tar'
+ failure [
+ { code: 401, message: 'Unauthorized' }
+ ]
end
params do
optional :wiki, type: Boolean, desc: 'Set to true to receive the wiki repository'
diff --git a/lib/api/project_snippets.rb b/lib/api/project_snippets.rb
index 14792730eae..93ffb23fea8 100644
--- a/lib/api/project_snippets.rb
+++ b/lib/api/project_snippets.rb
@@ -9,7 +9,7 @@ module API
feature_category :snippets
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
helpers Helpers::SnippetsHelpers
@@ -34,6 +34,11 @@ module API
desc 'Get all project snippets' do
success Entities::ProjectSnippet
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[project_snippets]
+ is_array true
end
params do
use :pagination
@@ -46,6 +51,10 @@ module API
desc 'Get a single project snippet' do
success Entities::ProjectSnippet
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[project_snippets]
end
params do
requires :snippet_id, type: Integer, desc: 'The ID of a project snippet'
@@ -60,6 +69,12 @@ module API
desc 'Create a new project snippet' do
success Entities::ProjectSnippet
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags %w[project_snippets]
end
params do
requires :title, type: String, allow_blank: false, desc: 'The title of the snippet'
@@ -91,6 +106,12 @@ module API
desc 'Update an existing project snippet' do
success Entities::ProjectSnippet
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags %w[project_snippets]
end
params do
requires :snippet_id, type: Integer, desc: 'The ID of a project snippet'
@@ -132,7 +153,14 @@ module API
end
# rubocop: enable CodeReuse/ActiveRecord
- desc 'Delete a project snippet'
+ desc 'Delete a project snippet' do
+ success code: 204
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[project_snippets]
+ end
params do
requires :snippet_id, type: Integer, desc: 'The ID of a project snippet'
end
@@ -156,7 +184,13 @@ module API
end
# rubocop: enable CodeReuse/ActiveRecord
- desc 'Get a raw project snippet'
+ desc 'Get a raw project snippet' do
+ success Entities::ProjectSnippet
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[project_snippets]
+ end
params do
requires :snippet_id, type: Integer, desc: 'The ID of a project snippet'
end
@@ -168,7 +202,13 @@ module API
present content_for(snippet)
end
- desc 'Get raw project snippet file contents from the repository'
+ desc 'Get raw project snippet file contents from the repository' do
+ success Entities::ProjectSnippet
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[project_snippets]
+ end
params do
use :raw_file_params
end
@@ -182,6 +222,10 @@ module API
desc 'Get the user agent details for a project snippet' do
success Entities::UserAgentDetail
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[project_snippets]
end
params do
requires :snippet_id, type: Integer, desc: 'The ID of a project snippet'
diff --git a/lib/api/project_statistics.rb b/lib/api/project_statistics.rb
index 3db8d20ebac..859e53b6981 100644
--- a/lib/api/project_statistics.rb
+++ b/lib/api/project_statistics.rb
@@ -10,10 +10,18 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get the list of project fetch statistics for the last 30 days'
+ desc 'Get the list of project fetch statistics for the last 30 days' do
+ success Entities::ProjectDailyStatistics
+ failure [
+ { code: 404, message: '404 Project Not Found' },
+ { code: 401, message: '401 Unauthorized' }
+ ]
+ tags %w[projects]
+ end
+
get ":id/statistics" do
statistic_finder = ::Projects::DailyStatisticsFinder.new(user_project)
diff --git a/lib/api/project_templates.rb b/lib/api/project_templates.rb
index f6e1286d616..8ec67988e39 100644
--- a/lib/api/project_templates.rb
+++ b/lib/api/project_templates.rb
@@ -15,12 +15,18 @@ module API
feature_category :source_code_management
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
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
detail 'This endpoint was introduced in GitLab 11.4'
+ is_array true
+ success Entities::TemplatesList
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
use :pagination
@@ -33,13 +39,24 @@ module API
desc 'Download a template available to this project' do
detail 'This endpoint was introduced in GitLab 11.4'
+ success Entities::License
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :name, type: String, desc: 'The name of the template'
+ requires :name, type: String,
+ desc: 'The key of the template, as obtained from the collection endpoint.', documentation: { example: 'MIT' }
optional :source_template_project_id, type: Integer,
- desc: 'The project id where a given template is being stored. This is useful when multiple templates from different projects have the same name'
- optional :project, type: String, desc: 'The project name to use when expanding placeholders in the template. Only affects licenses'
- optional :fullname, type: String, desc: 'The full name of the copyright holder to use when expanding placeholders in the template. Only affects licenses'
+ desc: 'The project id where a given template is being stored. This is useful when multiple templates from different projects have the same name',
+ documentation: { example: 1 }
+ optional :project, type: String,
+ desc: 'The project name to use when expanding placeholders in the template. Only affects licenses',
+ documentation: { example: 'GitLab' }
+ optional :fullname, type: String,
+ desc: 'The full name of the copyright holder to use when expanding placeholders in the template. Only affects licenses',
+ documentation: { example: 'GitLab B.V.' }
end
get ':id/templates/:type/:name', requirements: TEMPLATE_NAMES_ENDPOINT_REQUIREMENTS do
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index bb97f4fa7ce..fc898c30a71 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -151,7 +151,6 @@ module API
project_params = project_finder_params
support_order_by_similarity!(project_params)
verify_project_filters!(project_params)
-
ProjectsFinder.new(current_user: current_user, params: project_params).execute
end
@@ -336,7 +335,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a single project' do
@@ -424,7 +423,7 @@ module API
end
desc 'Check pages access of this project'
- get ':id/pages_access', feature_category: :pages do
+ get ':id/pages_access', urgency: :low, feature_category: :pages do
authorize! :read_pages_content, user_project unless user_project.public_pages?
status 200
end
@@ -654,7 +653,7 @@ module API
desc 'Upload a file'
params do
- requires :file, types: [Rack::Multipart::UploadedFile, ::API::Validations::Types::WorkhorseFile], desc: 'The attachment file to be uploaded'
+ requires :file, types: [Rack::Multipart::UploadedFile, ::API::Validations::Types::WorkhorseFile], desc: 'The attachment file to be uploaded', documentation: { type: 'file' }
end
post ":id/uploads", feature_category: :not_owned do # rubocop:todo Gitlab/AvoidFeatureCategoryNotOwned
log_if_upload_exceed_max_size(user_project, params[:file])
diff --git a/lib/api/projects_relation_builder.rb b/lib/api/projects_relation_builder.rb
index fb782b49f02..bb1420534f1 100644
--- a/lib/api/projects_relation_builder.rb
+++ b/lib/api/projects_relation_builder.rb
@@ -10,9 +10,13 @@ module API
execute_batch_counting(projects_relation)
+ postload_relation(projects_relation, options)
+
preload_repository_cache(projects_relation)
Preloaders::UserMaxAccessLevelInProjectsPreloader.new(projects_relation, options[:current_user]).execute if options[:current_user]
+
+ options[:current_user].preloaded_member_roles_for_projects(projects_relation) if options[:current_user]
Preloaders::SingleHierarchyProjectGroupPlansPreloader.new(projects_relation).execute if options[:single_hierarchy]
preload_groups(projects_relation) if options[:with] == Entities::Project
diff --git a/lib/api/protected_branches.rb b/lib/api/protected_branches.rb
index 38bafac25b2..786045684b8 100644
--- a/lib/api/protected_branches.rb
+++ b/lib/api/protected_branches.rb
@@ -13,15 +13,23 @@ module API
helpers Helpers::ProtectedBranchesHelpers
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id,
+ types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the project',
+ documentation: { example: 'gitlab-org/gitlab' }
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc "Get a project's protected branches" do
- success Entities::ProtectedBranch
+ success code: 200, model: Entities::ProtectedBranch
+ is_array true
+ failure [
+ { code: 404, message: '404 Project Not Found' },
+ { code: 401, message: '401 Unauthorized' }
+ ]
end
params do
use :pagination
- optional :search, type: String, desc: 'Search for a protected branch by name'
+ optional :search, type: String, desc: 'Search for a protected branch by name', documentation: { example: 'mai' }
end
# rubocop: disable CodeReuse/ActiveRecord
get ':id/protected_branches' do
@@ -36,10 +44,14 @@ module API
# rubocop: enable CodeReuse/ActiveRecord
desc 'Get a single protected branch' do
- success Entities::ProtectedBranch
+ success code: 200, model: Entities::ProtectedBranch
+ failure [
+ { code: 404, message: '404 Project Not Found' },
+ { code: 401, message: '401 Unauthorized' }
+ ]
end
params do
- requires :name, type: String, desc: 'The name of the branch or wildcard'
+ requires :name, type: String, desc: 'The name of the branch or wildcard', documentation: { example: 'main' }
end
# rubocop: disable CodeReuse/ActiveRecord
get ':id/protected_branches/:name', requirements: BRANCH_ENDPOINT_REQUIREMENTS do
@@ -50,10 +62,16 @@ module API
# rubocop: enable CodeReuse/ActiveRecord
desc 'Protect a single branch' do
- success Entities::ProtectedBranch
+ success code: 201, model: Entities::ProtectedBranch
+ failure [
+ { code: 422, message: 'name is missing' },
+ { code: 409, message: "Protected branch 'main' already exists" },
+ { code: 404, message: '404 Project Not Found' },
+ { code: 401, message: '401 Unauthorized' }
+ ]
end
params do
- requires :name, type: String, desc: 'The name of the protected branch'
+ requires :name, type: String, desc: 'The name of the protected branch', documentation: { example: 'main' }
optional :push_access_level, type: Integer,
values: ProtectedBranch::PushAccessLevel.allowed_access_levels,
desc: 'Access levels allowed to push (defaults: `40`, maintainer access level)'
@@ -86,9 +104,47 @@ module API
end
# rubocop: enable CodeReuse/ActiveRecord
+ desc 'Update a protected branch' do
+ success code: 200, model: Entities::ProtectedBranch
+ failure [
+ { code: 422, message: 'Push access levels access level has already been taken' },
+ { code: 404, message: '404 Project Not Found' },
+ { code: 401, message: '401 Unauthorized' }
+ ]
+ end
+ params do
+ requires :name, type: String, desc: 'The name of the branch', documentation: { example: 'main' }
+ optional :allow_force_push, type: Boolean,
+ desc: 'Allow force push for all users with push access.'
+
+ use :optional_params_ee
+ end
+ # rubocop: disable CodeReuse/ActiveRecord
+ patch ':id/protected_branches/:name', requirements: BRANCH_ENDPOINT_REQUIREMENTS do
+ protected_branch = user_project.protected_branches.find_by!(name: params[:name])
+
+ declared_params = declared_params(include_missing: false)
+ api_service = ::ProtectedBranches::ApiService.new(user_project, current_user, declared_params)
+ protected_branch = api_service.update(protected_branch)
+
+ if protected_branch.valid?
+ present protected_branch, with: Entities::ProtectedBranch, project: user_project
+ else
+ render_api_error!(protected_branch.errors.full_messages, 422)
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
desc 'Unprotect a single branch'
params do
- requires :name, type: String, desc: 'The name of the protected branch'
+ requires :name, type: String, desc: 'The name of the protected branch', documentation: { example: 'main' }
+ end
+ desc 'Unprotect a single branch' do
+ success code: 204
+ failure [
+ { code: 404, message: '404 Project Not Found' },
+ { code: 401, message: '401 Unauthorized' }
+ ]
end
# rubocop: disable CodeReuse/ActiveRecord
delete ':id/protected_branches/:name', requirements: BRANCH_ENDPOINT_REQUIREMENTS, urgency: :low do
diff --git a/lib/api/protected_tags.rb b/lib/api/protected_tags.rb
index 4611ee58479..7b55b1fd61d 100644
--- a/lib/api/protected_tags.rb
+++ b/lib/api/protected_tags.rb
@@ -13,12 +13,18 @@ module API
helpers Helpers::ProtectedTagsHelpers
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc "Get a project's protected tags" do
detail 'This feature was introduced in GitLab 11.3.'
- success Entities::ProtectedTag
+ is_array true
+ success code: 200, model: Entities::ProtectedTag
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[protected_tags]
end
params do
use :pagination
@@ -33,10 +39,15 @@ module API
desc 'Get a single protected tag' do
detail 'This feature was introduced in GitLab 11.3.'
- success Entities::ProtectedTag
+ success code: 200, model: Entities::ProtectedTag
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[protected_tags]
end
params do
- requires :name, type: String, desc: 'The name of the tag or wildcard'
+ requires :name, type: String, desc: 'The name of the tag or wildcard', documentation: { example: 'release*' }
end
# rubocop: disable CodeReuse/ActiveRecord
get ':id/protected_tags/:name', requirements: TAG_ENDPOINT_REQUIREMENTS do
@@ -48,13 +59,21 @@ module API
desc 'Protect a single tag or wildcard' do
detail 'This feature was introduced in GitLab 11.3.'
- success Entities::ProtectedTag
+ success code: 201, model: Entities::ProtectedTag
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags %w[protected_tags]
end
params do
- requires :name, type: String, desc: 'The name of the protected tag'
- optional :create_access_level, type: Integer,
- values: ProtectedTag::CreateAccessLevel.allowed_access_levels,
- desc: 'Access levels allowed to create (defaults: `40`, maintainer access level)'
+ requires :name, type: String, desc: 'The name of the protected tag', documentation: { example: 'release-1-0' }
+ optional :create_access_level,
+ type: Integer,
+ values: ProtectedTag::CreateAccessLevel.allowed_access_levels,
+ desc: 'Access levels allowed to create (defaults: `40`, maintainer access level)',
+ documentation: { example: 30 }
use :optional_params_ee
end
post ':id/protected_tags' do
@@ -76,9 +95,16 @@ module API
desc 'Unprotect a single tag' do
detail 'This feature was introduced in GitLab 11.3.'
+ success code: 204
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' },
+ { code: 412, message: 'Precondition Failed' }
+ ]
+ tags %w[protected_tags]
end
params do
- requires :name, type: String, desc: 'The name of the protected tag'
+ requires :name, type: String, desc: 'The name of the protected tag', documentation: { example: 'release-1-0' }
end
# rubocop: disable CodeReuse/ActiveRecord
delete ':id/protected_tags/:name', requirements: TAG_ENDPOINT_REQUIREMENTS do
diff --git a/lib/api/pypi_packages.rb b/lib/api/pypi_packages.rb
index 1f27fcce879..6c649483da1 100644
--- a/lib/api/pypi_packages.rb
+++ b/lib/api/pypi_packages.rb
@@ -95,9 +95,9 @@ module API
find_authorized_group!
end
- def ensure_project!
+ def project!(action: :read_package)
find_project(params[:id]) || not_found!
- authorized_user_project
+ authorized_user_project(action: action)
end
end
@@ -157,14 +157,10 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- before do
- ensure_project!
- end
-
namespace ':id/packages/pypi' do
desc 'The PyPi package download endpoint' do
detail 'This feature was introduced in GitLab 12.10'
@@ -176,8 +172,7 @@ module API
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
get 'files/:sha256/*file_identifier' do
- project = authorized_user_project
- authorize_read_package!(project)
+ project = project!
filename = "#{params[:file_identifier]}.#{params[:format]}"
package = Packages::Pypi::PackageFinder.new(current_user, project, { filename: filename, sha256: params[:sha256] }).execute
@@ -196,7 +191,7 @@ module API
# PyPi simple API returns a list of packages as a simple HTML file.
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
get 'simple', format: :txt do
- present_simple_index(authorized_user_project)
+ present_simple_index(project!)
end
desc 'The PyPi Simple Project Package Endpoint' do
@@ -211,7 +206,7 @@ module API
# PyPi simple API returns the package descriptor as a simple HTML file.
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
get 'simple/*package_name', format: :txt do
- present_simple_package(authorized_user_project)
+ present_simple_package(project!)
end
desc 'The PyPi Package upload endpoint' do
@@ -219,7 +214,7 @@ module API
end
params do
- requires :content, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ requires :content, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)', documentation: { type: 'file' }
requires :name, type: String
requires :version, type: String
optional :requires_python, type: String
@@ -229,15 +224,16 @@ module API
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
post do
- authorize_upload!(authorized_user_project)
- bad_request!('File is too large') if authorized_user_project.actual_limits.exceeded?(:pypi_max_file_size, params[:content].size)
+ project = project!(action: :read_project)
+ authorize_upload!(project)
+ bad_request!('File is too large') if project.actual_limits.exceeded?(:pypi_max_file_size, params[:content].size)
- track_package_event('push_package', :pypi, project: authorized_user_project, user: current_user, namespace: authorized_user_project.namespace)
+ track_package_event('push_package', :pypi, project: project, user: current_user, namespace: project.namespace)
unprocessable_entity! if Gitlab::FIPS.enabled? && declared_params[:md5_digest].present?
::Packages::Pypi::CreatePackageService
- .new(authorized_user_project, current_user, declared_params.merge(build: current_authenticated_job))
+ .new(project, current_user, declared_params.merge(build: current_authenticated_job))
.execute
created!
@@ -249,10 +245,11 @@ module API
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
post 'authorize' do
+ project = project!(action: :read_project)
authorize_workhorse!(
- subject: authorized_user_project,
+ subject: project,
has_length: false,
- maximum_size: authorized_user_project.actual_limits.pypi_max_file_size
+ maximum_size: project.actual_limits.pypi_max_file_size
)
end
end
diff --git a/lib/api/release/links.rb b/lib/api/release/links.rb
index 8b9380b332e..c72f90dfdf3 100644
--- a/lib/api/release/links.rb
+++ b/lib/api/release/links.rb
@@ -5,6 +5,8 @@ module API
class Links < ::API::Base
include PaginationParams
+ release_links_tags = %w[release_links]
+
RELEASE_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
.merge(tag_name: API::NO_SLASH_URL_PART_REGEX)
@@ -14,17 +16,23 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, type: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource 'projects/:id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
params do
- requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
+ requires :tag_name, type: String, desc: 'The tag associated with the release', as: :tag
end
resource 'releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do
resource :assets do
- desc 'Get a list of links of a release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'List links of a release' do
+ detail 'Get assets as links from a release. This feature was introduced in GitLab 11.7.'
success Entities::Releases::Link
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags release_links_tags
end
params do
use :pagination
@@ -36,15 +44,24 @@ module API
present paginate(release.links.sorted), with: Entities::Releases::Link
end
- desc 'Create a link of a release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Create a release link' do
+ detail 'Create an asset as a link from a release. This feature was introduced in GitLab 11.7.'
success Entities::Releases::Link
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' }
+ ]
+ tags release_links_tags
end
params do
- requires :name, type: String, desc: 'The name of the link'
- requires :url, type: String, desc: 'The URL of the link'
- optional :filepath, type: String, desc: 'The filepath of the link'
- optional :link_type, type: String, desc: 'The link type, one of: "runbook", "image", "package" or "other"'
+ requires :name, type: String, desc: 'The name of the link. Link names must be unique in the release'
+ requires :url, type: String, desc: 'The URL of the link. Link URLs must be unique in the release.'
+ optional :filepath, type: String, desc: 'Optional path for a direct asset link'
+ optional :link_type,
+ type: String,
+ values: %w[other runbook image package],
+ default: 'other',
+ desc: 'The type of the link: `other`, `runbook`, `image`, or `package`. Defaults to `other`'
end
route_setting :authentication, job_token_allowed: true
post 'links' do
@@ -60,12 +77,17 @@ module API
end
params do
- requires :link_id, type: String, desc: 'The ID of the link'
+ requires :link_id, type: Integer, desc: 'The ID of the link'
end
resource 'links/:link_id' do
- desc 'Get a link detail of a release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Get a release link' do
+ detail 'Get an asset as a link from a release. This feature was introduced in GitLab 11.7.'
success Entities::Releases::Link
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags release_links_tags
end
route_setting :authentication, job_token_allowed: true
get do
@@ -74,15 +96,25 @@ module API
present link, with: Entities::Releases::Link
end
- desc 'Update a link of a release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Update a release link' do
+ detail 'Update an asset as a link from a release. This feature was introduced in GitLab 11.7.'
success Entities::Releases::Link
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' }
+ ]
+ tags release_links_tags
end
params do
optional :name, type: String, desc: 'The name of the link'
optional :url, type: String, desc: 'The URL of the link'
- optional :filepath, type: String, desc: 'The filepath of the link'
- optional :link_type, type: String, desc: 'The link type'
+ optional :filepath, type: String, desc: 'Optional path for a direct asset link'
+ optional :link_type,
+ type: String,
+ values: %w[other runbook image package],
+ default: 'other',
+ desc: 'The type of the link: `other`, `runbook`, `image`, or `package`. Defaults to `other`'
+
at_least_one_of :name, :url
end
route_setting :authentication, job_token_allowed: true
@@ -96,9 +128,14 @@ module API
end
end
- desc 'Delete a link of a release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Delete a release link' do
+ detail 'Deletes an asset as a link from a release. This feature was introduced in GitLab 11.7.'
success Entities::Releases::Link
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' }
+ ]
+ tags release_links_tags
end
route_setting :authentication, job_token_allowed: true
delete do
diff --git a/lib/api/releases.rb b/lib/api/releases.rb
index cdfcce9dddb..e6884e66200 100644
--- a/lib/api/releases.rb
+++ b/lib/api/releases.rb
@@ -4,6 +4,8 @@ module API
class Releases < ::API::Base
include PaginationParams
+ releases_tags = %w[releases]
+
RELEASE_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
.merge(tag_name: API::NO_SLASH_URL_PART_REGEX)
RELEASE_CLI_USER_AGENT = 'GitLab-release-cli'
@@ -12,20 +14,37 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a group'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the group'
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authorize_read_group_releases! }
- desc 'Get a list of releases for projects in this group.' do
+ desc 'List group releases' do
+ detail 'Returns a list of group releases.'
success Entities::Release
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags releases_tags
end
params do
- requires :id, type: Integer, desc: 'The ID of the group to get releases for'
- optional :sort, type: String, values: %w[asc desc], default: 'desc',
- desc: 'Return projects sorted in ascending and descending order by released_at'
- optional :simple, type: Boolean, default: false,
- desc: 'Return only the ID, URL, name, and path of each project'
+ requires :id,
+ types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the group owned by the authenticated user'
+
+ optional :sort,
+ type: String,
+ values: %w[asc desc],
+ default: 'desc',
+ desc: 'The direction of the order. Either `desc` (default) for descending order or `asc` for ascending order'
+
+ optional :simple,
+ type: Boolean,
+ default: false,
+ desc: 'Return only limited fields for each release'
use :pagination
end
@@ -42,26 +61,38 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authorize_read_releases! }
after { track_release_event }
- desc 'Get a project releases' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'List Releases' do
+ detail 'Returns a paginated list of releases. This feature was introduced in GitLab 11.7.'
named 'get_releases'
+ is_array true
success Entities::Release
+ tags releases_tags
end
params do
use :pagination
- optional :order_by, type: String, values: %w[released_at created_at], default: 'released_at',
- desc: 'Return releases ordered by `released_at` or `created_at`.'
- optional :sort, type: String, values: %w[asc desc], default: 'desc',
- desc: 'Return releases sorted in `asc` or `desc` order.'
- optional :include_html_description, type: Boolean,
- desc: 'If `true`, a response includes HTML rendered markdown of the release description.'
+
+ optional :order_by,
+ type: String,
+ values: %w[released_at created_at],
+ default: 'released_at',
+ desc: 'The field to use as order. Either `released_at` (default) or `created_at`'
+
+ optional :sort,
+ type: String,
+ values: %w[asc desc],
+ default: 'desc',
+ desc: 'The direction of the order. Either `desc` (default) for descending order or `asc` for ascending order'
+
+ optional :include_html_description,
+ type: Boolean,
+ desc: 'If `true`, a response includes HTML rendered markdown of the release description'
end
route_setting :authentication, job_token_allowed: true
get ':id/releases' do
@@ -81,19 +112,26 @@ module API
include_html_description: params[:include_html_description]
end
- desc 'Get a single project release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Get a release by a tag name' do
+ detail 'Gets a release for the given tag. This feature was introduced in GitLab 11.7.'
named 'get_release'
success Entities::Release
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags releases_tags
end
params do
- requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
- optional :include_html_description, type: Boolean,
- desc: 'If `true`, a response includes HTML rendered markdown of the release description.'
+ requires :tag_name, type: String, desc: 'The Git tag the release is associated with', as: :tag
+
+ optional :include_html_description,
+ type: Boolean,
+ desc: 'If `true`, a response includes HTML rendered markdown of the release description'
end
route_setting :authentication, job_token_allowed: true
get ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do
- authorize_download_code!
+ authorize_read_code!
not_found! unless release
@@ -103,17 +141,23 @@ module API
desc 'Download a project release asset file' do
detail 'This feature was introduced in GitLab 15.4.'
named 'download_release_asset_file'
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags releases_tags
end
params do
- requires :tag_name, type: String,
- desc: 'The name of the tag.', as: :tag
- requires :file_path, type: String,
- file_path: true,
- desc: 'The path to the file to download, as specified when creating the release asset.'
+ requires :tag_name, type: String, desc: 'The Git tag the release is associated with', as: :tag
+
+ requires :file_path,
+ type: String,
+ file_path: true,
+ desc: 'The path to the file to download, as specified when creating the release asset'
end
route_setting :authentication, job_token_allowed: true
get ':id/releases/:tag_name/downloads/*file_path', format: false, requirements: RELEASE_ENDPOINT_REQUIREMENTS do
- authorize_download_code!
+ authorize_read_code!
not_found! unless release
@@ -127,13 +171,21 @@ module API
desc 'Get the latest project release' do
detail 'This feature was introduced in GitLab 15.4.'
named 'get_latest_release'
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags releases_tags
end
params do
- requires :suffix_path, type: String, file_path: true, desc: 'The path to be suffixed to the latest release'
+ requires :suffix_path,
+ type: String,
+ file_path: true,
+ desc: 'The path to be suffixed to the latest release'
end
route_setting :authentication, job_token_allowed: true
get ':id/releases/permalink/latest(/)(*suffix_path)', format: false, requirements: RELEASE_ENDPOINT_REQUIREMENTS do
- authorize_download_code!
+ authorize_read_code!
# Try to find the latest release
latest_release = find_latest_release
@@ -156,27 +208,50 @@ module API
redirect redirect_url
end
- desc 'Create a new release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Create a release' do
+ detail 'Creates a release. Developer level access to the project is required to create a release. This feature was introduced in GitLab 11.7.'
named 'create_release'
success Entities::Release
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 409, message: 'Conflict' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags releases_tags
end
params do
- requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
+ requires :tag_name, type: String, desc: 'The tag where the release is created from', as: :tag
optional :tag_message, type: String, desc: 'Message to use if creating a new annotated tag'
- optional :name, type: String, desc: 'The name of the release'
- optional :description, type: String, desc: 'The release notes'
- optional :ref, type: String, desc: 'Commit SHA or branch name to use if creating a new tag'
+ optional :name, type: String, desc: 'The release name'
+ optional :description, type: String, desc: 'The description of the release. You can use Markdown'
+
+ optional :ref,
+ type: String,
+ desc: "If a tag specified in `tag_name` doesn't exist, the release is created from `ref` and tagged " \
+ "with `tag_name`. It can be a commit SHA, another tag name, or a branch name."
+
optional :assets, type: Hash do
optional :links, type: Array do
- requires :name, type: String, desc: 'The name of the link'
- requires :url, type: String, desc: 'The URL of the link'
- optional :filepath, type: String, desc: 'The filepath of the link'
- optional :link_type, type: String, desc: 'The link type, one of: "runbook", "image", "package" or "other"'
+ requires :name, type: String, desc: 'The name of the link. Link names must be unique within the release'
+ requires :url, type: String, desc: 'The URL of the link. Link URLs must be unique within the release'
+ optional :filepath, type: String, desc: 'Optional path for a direct asset link'
+ optional :link_type, type: String, desc: 'The type of the link: `other`, `runbook`, `image`, `package`. Defaults to `other`'
end
end
- optional :milestones, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The titles of the related milestones', default: []
- optional :released_at, type: DateTime, desc: 'The date when the release will be/was ready. Defaults to the current time.'
+
+ optional :milestones,
+ type: Array[String],
+ coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
+ desc: 'The title of each milestone the release is associated with. GitLab Premium customers can specify group milestones',
+ default: []
+
+ optional :released_at,
+ type: DateTime,
+ desc: 'Date and time for the release. Defaults to the current time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). ' \
+ 'Only provide this field if creating an upcoming or historical release.'
end
route_setting :authentication, job_token_allowed: true
post ':id/releases' do
@@ -196,16 +271,27 @@ module API
end
desc 'Update a release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ detail 'Updates a release. Developer level access to the project is required to update a release. This feature was introduced in GitLab 11.7.'
named 'update_release'
success Entities::Release
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags releases_tags
end
params do
- requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
- optional :name, type: String, desc: 'The name of the release'
- optional :description, type: String, desc: 'Release notes with markdown support'
- optional :released_at, type: DateTime, desc: 'The date when the release will be/was ready.'
- optional :milestones, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The titles of the related milestones'
+ requires :tag_name, type: String, desc: 'The Git tag the release is associated with', as: :tag
+ optional :name, type: String, desc: 'The release name'
+ optional :description, type: String, desc: 'The description of the release. You can use Markdown'
+ optional :released_at, type: DateTime, desc: 'The date when the release is/was ready. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`)'
+
+ optional :milestones,
+ type: Array[String],
+ coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
+ desc: 'The title of each milestone to associate with the release. GitLab Premium customers can specify group milestones. To remove all milestones from the release, specify `[]`'
end
route_setting :authentication, job_token_allowed: true
put ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do
@@ -226,12 +312,19 @@ module API
end
desc 'Delete a release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ detail "Delete a release. Deleting a release doesn't delete the associated tag. Maintainer level access to the project is required to delete a release. This feature was introduced in GitLab 11.7."
named 'delete_release'
success Entities::Release
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags releases_tags
end
params do
- requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
+ requires :tag_name, type: String, desc: 'The Git tag the release is associated with', as: :tag
end
route_setting :authentication, job_token_allowed: true
delete ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do
@@ -280,6 +373,10 @@ module API
authorize! :download_code, user_project
end
+ def authorize_read_code!
+ authorize! :read_code, user_project
+ end
+
def authorize_create_evidence!
# extended in EE
end
diff --git a/lib/api/remote_mirrors.rb b/lib/api/remote_mirrors.rb
index 8de155312fb..f7ea5a6ad2b 100644
--- a/lib/api/remote_mirrors.rb
+++ b/lib/api/remote_mirrors.rb
@@ -11,11 +11,17 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc "List the project's remote mirrors" do
- success Entities::RemoteMirror
+ success code: 200, model: Entities::RemoteMirror
+ is_array true
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[remote_mirrors]
end
params do
use :pagination
@@ -26,7 +32,12 @@ module API
end
desc 'Get a single remote mirror' do
- success Entities::RemoteMirror
+ success code: 200, model: Entities::RemoteMirror
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[remote_mirrors]
end
params do
requires :mirror_id, type: String, desc: 'The ID of a remote mirror'
@@ -38,13 +49,21 @@ module API
end
desc 'Create remote mirror for a project' do
- success Entities::RemoteMirror
+ success code: 201, model: Entities::RemoteMirror
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[remote_mirrors]
end
params do
- requires :url, type: String, desc: 'The URL for a remote mirror'
- optional :enabled, type: Boolean, desc: 'Determines if the mirror is enabled'
- optional :only_protected_branches, type: Boolean, desc: 'Determines if only protected branches are mirrored'
- optional :keep_divergent_refs, type: Boolean, desc: 'Determines if divergent refs are kept on the target'
+ requires :url, type: String, desc: 'The URL for a remote mirror', documentation: { example: 'https://*****:*****@example.com/gitlab/example.git' }
+ optional :enabled, type: Boolean, desc: 'Determines if the mirror is enabled', documentation: { example: false }
+ optional :only_protected_branches, type: Boolean, desc: 'Determines if only protected branches are mirrored',
+ documentation: { example: false }
+ optional :keep_divergent_refs, type: Boolean, desc: 'Determines if divergent refs are kept on the target',
+ documentation: { example: false }
end
post ':id/remote_mirrors' do
create_params = declared_params(include_missing: false)
@@ -59,13 +78,21 @@ module API
end
desc 'Update the attributes of a single remote mirror' do
- success Entities::RemoteMirror
+ success code: 200, model: Entities::RemoteMirror
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[remote_mirrors]
end
params do
requires :mirror_id, type: String, desc: 'The ID of a remote mirror'
- optional :enabled, type: Boolean, desc: 'Determines if the mirror is enabled'
- optional :only_protected_branches, type: Boolean, desc: 'Determines if only protected branches are mirrored'
- optional :keep_divergent_refs, type: Boolean, desc: 'Determines if divergent refs are kept on the target'
+ optional :enabled, type: Boolean, desc: 'Determines if the mirror is enabled', documentation: { example: true }
+ optional :only_protected_branches, type: Boolean, desc: 'Determines if only protected branches are mirrored',
+ documentation: { example: false }
+ optional :keep_divergent_refs, type: Boolean, desc: 'Determines if divergent refs are kept on the target',
+ documentation: { example: false }
end
put ':id/remote_mirrors/:mirror_id' do
mirror = user_project.remote_mirrors.find(params[:mirror_id])
@@ -88,6 +115,13 @@ module API
desc 'Delete a single remote mirror' do
detail 'This feature was introduced in GitLab 14.10'
+ success code: 204
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[remote_mirrors]
end
params do
requires :mirror_id, type: String, desc: 'The ID of a remote mirror'
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index c6a2d582d8a..70535496b12 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -15,33 +15,40 @@ module API
requires :version,
type: String,
regexp: Gitlab::Regex.unbounded_semver_regex,
- desc: 'The version of the release, using the semantic versioning format'
+ desc: 'The version of the release, using the semantic versioning format',
+ documentation: { example: '1.0.0' }
optional :from,
type: String,
- desc: 'The first commit in the range of commits to use for the changelog'
+ desc: 'The first commit in the range of commits to use for the changelog',
+ documentation: { example: 'ed899a2f4b50b4370feeea94676502b42383c746' }
optional :to,
type: String,
- desc: 'The last commit in the range of commits to use for the changelog'
+ desc: 'The last commit in the range of commits to use for the changelog',
+ documentation: { example: '6104942438c14ec7bd21c6cd5bd995272b3faff6' }
optional :date,
type: DateTime,
- desc: 'The date and time of the release'
+ desc: 'The date and time of the release',
+ documentation: { type: 'dateTime', example: '2021-09-20T11:50:22.001+00:00' }
optional :trailer,
type: String,
desc: 'The Git trailer to use for determining if commits are to be included in the changelog',
- default: ::Repositories::ChangelogService::DEFAULT_TRAILER
+ default: ::Repositories::ChangelogService::DEFAULT_TRAILER,
+ documentation: { example: 'Changelog' }
end
end
- before { authorize! :download_code, user_project }
+ before { authorize! :read_code, user_project }
feature_category :source_code_management
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the project',
+ documentation: { example: 1 }
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
helpers do
@@ -56,7 +63,7 @@ module API
end
def assign_blob_vars!(limit:)
- authorize! :download_code, user_project
+ authorize! :read_code, user_project
@repo = user_project.repository
@@ -94,15 +101,19 @@ module API
success Entities::TreeObject
end
params do
- optional :ref, type: String, desc: 'The name of a repository branch or tag, if not given the default branch is used'
- optional :path, type: String, desc: 'The path of the tree'
+ optional :ref, type: String,
+ desc: 'The name of a repository branch or tag, if not given the default branch is used',
+ documentation: { example: 'main' }
+ optional :path, type: String, desc: 'The path of the tree', documentation: { example: 'files/html' }
optional :recursive, type: Boolean, default: false, desc: 'Used to get a recursive tree'
use :pagination
optional :pagination, type: String, values: %w(legacy keyset none), default: 'legacy', desc: 'Specify the pagination method ("none" is only valid if "recursive" is true)'
given pagination: ->(value) { value == 'keyset' } do
- optional :page_token, type: String, desc: 'Record from which to start the keyset pagination'
+ optional :page_token, type: String,
+ desc: 'Record from which to start the keyset pagination',
+ documentation: { example: 'a1e8f8d745cc87e3a9248358d9352bb7f9a0aeba' }
end
given pagination: ->(value) { value == 'none' } do
@@ -123,7 +134,8 @@ module API
desc 'Get raw blob contents from the repository'
params do
- requires :sha, type: String, desc: 'The commit hash'
+ requires :sha, type: String,
+ desc: 'The commit hash', documentation: { example: '7d70e02340bac451f281cecf0a980907974bd8be' }
end
get ':id/repository/blobs/:sha/raw' do
# Load metadata enough to ask Workhorse to load the whole blob
@@ -136,7 +148,8 @@ module API
desc 'Get a blob from the repository'
params do
- requires :sha, type: String, desc: 'The commit hash'
+ requires :sha, type: String,
+ desc: 'The commit hash', documentation: { example: '7d70e02340bac451f281cecf0a980907974bd8be' }
end
get ':id/repository/blobs/:sha' do
assign_blob_vars!(limit: -1)
@@ -151,9 +164,12 @@ module API
desc 'Get an archive of the repository'
params do
- optional :sha, type: String, desc: 'The commit sha of the archive to be downloaded'
- optional :format, type: String, desc: 'The archive format'
- optional :path, type: String, desc: 'Subfolder of the repository to be downloaded'
+ optional :sha, type: String,
+ desc: 'The commit sha of the archive to be downloaded',
+ documentation: { example: '7d70e02340bac451f281cecf0a980907974bd8be' }
+ optional :format, type: String, desc: 'The archive format', documentation: { example: 'tar.gz' }
+ optional :path, type: String,
+ desc: 'Subfolder of the repository to be downloaded', documentation: { example: 'files/archives' }
end
get ':id/repository/archive', requirements: { format: Gitlab::PathRegex.archive_formats_regex } do
check_archive_rate_limit!(current_user, user_project) do
@@ -171,9 +187,13 @@ module API
success Entities::Compare
end
params do
- requires :from, type: String, desc: 'The commit, branch name, or tag name to start comparison'
- requires :to, type: String, desc: 'The commit, branch name, or tag name to stop comparison'
- optional :from_project_id, type: String, desc: 'The project to compare from'
+ requires :from, type: String,
+ desc: 'The commit, branch name, or tag name to start comparison',
+ documentation: { example: 'main' }
+ requires :to, type: String,
+ desc: 'The commit, branch name, or tag name to stop comparison',
+ documentation: { example: 'feature' }
+ optional :from_project_id, type: Integer, desc: 'The project to compare from', documentation: { example: 1 }
optional :straight, type: Boolean, desc: 'Comparison method, `true` for direct comparison between `from` and `to` (`from`..`to`), `false` to compare using merge base (`from`...`to`)', default: false
end
get ':id/repository/compare', urgency: :low do
@@ -215,7 +235,10 @@ module API
success Entities::Commit
end
params do
- requires :refs, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce
+ requires :refs, type: Array[String],
+ coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
+ desc: 'The refs to find the common ancestor of, multiple refs can be passed',
+ documentation: { example: 'main' }
end
get ':id/repository/merge_base' do
refs = params[:refs]
@@ -241,12 +264,14 @@ module API
desc 'Generates a changelog section for a release and returns it' do
detail 'This feature was introduced in GitLab 14.6'
+ success Entities::Changelog
end
params do
use :release_params
optional :config_file,
type: String,
+ documentation: { example: '.gitlab/changelog_config.yml' },
desc: "The file path to the configuration file as stored in the project's Git repository. Defaults to '.gitlab/changelog_config.yml'"
end
get ':id/repository/changelog' do
@@ -264,26 +289,31 @@ module API
desc 'Generates a changelog section for a release and commits it in a changelog file' do
detail 'This feature was introduced in GitLab 13.9'
+ success code: 200
end
params do
use :release_params
optional :branch,
type: String,
- desc: 'The branch to commit the changelog changes to'
+ desc: 'The branch to commit the changelog changes to',
+ documentation: { example: 'main' }
optional :config_file,
type: String,
+ documentation: { example: '.gitlab/changelog_config.yml' },
desc: "The file path to the configuration file as stored in the project's Git repository. Defaults to '.gitlab/changelog_config.yml'"
optional :file,
type: String,
desc: 'The file to commit the changelog changes to',
- default: ::Repositories::ChangelogService::DEFAULT_FILE
+ default: ::Repositories::ChangelogService::DEFAULT_FILE,
+ documentation: { example: 'CHANGELOG.md' }
optional :message,
type: String,
- desc: 'The commit message to use when committing the changelog'
+ desc: 'The commit message to use when committing the changelog',
+ documentation: { example: 'Initial commit' }
end
post ':id/repository/changelog' do
branch = params[:branch] || user_project.default_branch_or_main
diff --git a/lib/api/resource_access_tokens.rb b/lib/api/resource_access_tokens.rb
index 2ba109b7092..754dfadb5fc 100644
--- a/lib/api/resource_access_tokens.rb
+++ b/lib/api/resource_access_tokens.rb
@@ -4,6 +4,8 @@ module API
class ResourceAccessTokens < ::API::Base
include PaginationParams
+ ALLOWED_RESOURCE_ACCESS_LEVELS = Gitlab::Access.options_with_owner.freeze
+
before { authenticate! }
feature_category :authentication_and_authorization
@@ -12,9 +14,12 @@ module API
resource source_type.pluralize, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get list of all access tokens for the specified resource' do
detail 'This feature was introduced in GitLab 13.9.'
+ is_array true
+ tags ["#{source_type}_access_tokens"]
+ success Entities::ResourceAccessToken
end
params do
- requires :id, type: String, desc: "The #{source_type} ID"
+ requires :id, types: [String, Integer], desc: "ID or URL-encoded path of the #{source_type}"
end
get ":id/access_tokens" do
resource = find_source(source_type, params[:id])
@@ -29,9 +34,11 @@ module API
desc 'Get an access token for the specified resource by ID' do
detail 'This feature was introduced in GitLab 14.10.'
+ tags ["#{source_type}_access_tokens"]
+ success Entities::ResourceAccessToken
end
params do
- requires :id, type: String, desc: "The #{source_type} ID"
+ requires :id, types: [String, Integer], desc: "ID or URL-encoded path of the #{source_type}"
requires :token_id, type: String, desc: "The ID of the token"
end
get ":id/access_tokens/:token_id" do
@@ -51,6 +58,12 @@ module API
desc 'Revoke a resource access token' do
detail 'This feature was introduced in GitLab 13.9.'
+ tags ["#{source_type}_access_tokens"]
+ success code: 204
+ failure [
+ { code: 400, message: 'Bad Request' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :id, type: String, desc: "The #{source_type} ID"
@@ -75,13 +88,21 @@ module API
desc 'Create a resource access token' do
detail 'This feature was introduced in GitLab 13.9.'
+ tags ["#{source_type}_access_tokens"]
+ success Entities::ResourceAccessTokenWithToken
end
params do
- requires :id, type: String, desc: "The #{source_type} ID"
- requires :name, type: String, desc: "Resource access token name"
- requires :scopes, type: Array[String], desc: "The permissions of the token"
- optional :access_level, type: Integer, desc: "The access level of the token in the #{source_type}"
- optional :expires_at, type: Date, desc: "The expiration date of the token"
+ requires :id, type: String, desc: "The #{source_type} ID", documentation: { example: 2 }
+ requires :name, type: String, desc: "Resource access token name", documentation: { example: 'test' }
+ requires :scopes, type: Array[String], values: ::Gitlab::Auth.resource_bot_scopes.map(&:to_s),
+ desc: "The permissions of the token",
+ documentation: { example: %w[api read_repository] }
+ optional :access_level, type: Integer,
+ values: ALLOWED_RESOURCE_ACCESS_LEVELS.values,
+ default: Gitlab::Access::MAINTAINER,
+ desc: "The access level of the token in the #{source_type}",
+ documentation: { example: 40 }
+ optional :expires_at, type: Date, desc: "The expiration date of the token", documentation: { example: '"2021-01-31' }
end
post ':id/access_tokens' do
resource = find_source(source_type, params[:id])
diff --git a/lib/api/resource_milestone_events.rb b/lib/api/resource_milestone_events.rb
index 04d71faa56a..5640e88ae6e 100644
--- a/lib/api/resource_milestone_events.rb
+++ b/lib/api/resource_milestone_events.rb
@@ -5,6 +5,8 @@ module API
include PaginationParams
helpers ::API::Helpers::NotesHelpers
+ resource_milestone_events_tags = %w[resource_milestone_events]
+
before { authenticate! }
{
@@ -15,17 +17,19 @@ module API
eventables_str = eventable_type.to_s.underscore.pluralize
params do
- requires :id, type: String, desc: "The ID of a #{parent_type}"
+ requires :id, types: [String, Integer], desc: "The ID or URL-encoded path of the #{parent_type}"
end
resource parent_type.pluralize.to_sym, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc "Get a list of #{eventable_type.to_s.downcase} resource milestone events" do
+ desc "List project #{eventable_type.underscore.humanize} milestone events" do
+ detail "Gets a list of all milestone events for a single #{eventable_type.underscore.humanize}"
success Entities::ResourceMilestoneEvent
+ is_array true
+ tags resource_milestone_events_tags
end
params do
requires :eventable_id, types: [Integer, String], desc: 'The ID of the eventable'
use :pagination
end
-
get ":id/#{eventables_str}/:eventable_id/resource_milestone_events", feature_category: feature_category, urgency: :low do
eventable = find_noteable(eventable_type, params[:eventable_id])
@@ -34,8 +38,13 @@ module API
present paginate(events), with: Entities::ResourceMilestoneEvent
end
- desc "Get a single #{eventable_type.to_s.downcase} resource milestone event" do
+ desc "Get single #{eventable_type.underscore.humanize} milestone event" do
+ detail "Returns a single milestone event for a specific project #{eventable_type.underscore.humanize}"
success Entities::ResourceMilestoneEvent
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags resource_milestone_events_tags
end
params do
requires :event_id, type: String, desc: 'The ID of a resource milestone event'
diff --git a/lib/api/rpm_project_packages.rb b/lib/api/rpm_project_packages.rb
index d17470ae92d..40b8d022c6c 100644
--- a/lib/api/rpm_project_packages.rb
+++ b/lib/api/rpm_project_packages.rb
@@ -21,7 +21,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
namespace ':id/packages/rpm' do
@@ -30,7 +30,14 @@ module API
requires :file_name, type: String, desc: 'Repository metadata file name'
end
get 'repodata/*file_name', requirements: { file_name: API::NO_SLASH_URL_PART_REGEX } do
- not_found!
+ authorize_read_package!(authorized_user_project)
+
+ repository_file = Packages::Rpm::RepositoryFile.find_by_project_id_and_file_name!(
+ authorized_user_project.id,
+ "#{params['file_name']}.#{params['format']}"
+ )
+
+ present_carrierwave_file!(repository_file.file)
end
desc 'Download RPM package files'
@@ -39,6 +46,13 @@ module API
requires :file_name, type: String, desc: 'RPM package file name'
end
get '*package_file_id/*file_name', requirements: { file_name: API::NO_SLASH_URL_PART_REGEX } do
+ track_package_event(
+ 'pull_package',
+ :rpm,
+ category: self.class.name,
+ project: authorized_user_project,
+ namespace: authorized_user_project.namespace
+ )
not_found!
end
@@ -50,6 +64,15 @@ module API
bad_request!('File is too large')
end
+ track_package_event(
+ 'push_package',
+ :rpm,
+ user: current_user,
+ category: self.class.name,
+ project: authorized_user_project,
+ namespace: authorized_user_project.namespace
+ )
+
not_found!
end
diff --git a/lib/api/rubygem_packages.rb b/lib/api/rubygem_packages.rb
index b4d02613e4c..87cf1f66223 100644
--- a/lib/api/rubygem_packages.rb
+++ b/lib/api/rubygem_packages.rb
@@ -93,7 +93,7 @@ module API
detail 'This feature was introduced in GitLab 13.9'
end
params do
- requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)', documentation: { type: 'file' }
end
post 'gems' do
authorize_upload!(user_project)
diff --git a/lib/api/search.rb b/lib/api/search.rb
index ff17696ed3e..cf6a1385783 100644
--- a/lib/api/search.rb
+++ b/lib/api/search.rb
@@ -67,8 +67,8 @@ module API
Gitlab::Metrics::GlobalSearchSlis.record_apdex(
elapsed: @search_duration_s,
- search_type: search_type,
- search_level: search_service.level,
+ search_type: search_type(additional_params),
+ search_level: search_service(additional_params).level,
search_scope: search_scope
)
@@ -81,7 +81,7 @@ module API
# with a 200 status code, but an empty @search_duration_s.
Gitlab::Metrics::GlobalSearchSlis.record_error_rate(
error: @search_duration_s.nil? || (status < 200 || status >= 400),
- search_type: search_type,
+ search_type: search_type(additional_params),
search_level: search_service(additional_params).level,
search_scope: search_scope
)
@@ -171,7 +171,7 @@ module API
detail 'This feature was introduced in GitLab 10.5.'
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
requires :search, type: String, desc: 'The expression it should be searched for'
requires :scope,
type: String,
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index 8c8b6c0a1ba..26b7e58bc7a 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -53,6 +53,7 @@ module API
optional :default_project_visibility, type: String, values: Gitlab::VisibilityLevel.string_values, desc: 'The default project visibility'
optional :default_projects_limit, type: Integer, desc: 'The maximum number of personal projects'
optional :default_snippet_visibility, type: String, values: Gitlab::VisibilityLevel.string_values, desc: 'The default snippet visibility'
+ optional :disable_admin_oauth_scopes, type: Boolean, desc: 'Stop administrators from connecting to non-trusted OAuth applications.'
optional :disable_feed_token, type: Boolean, desc: 'Disable display of RSS/Atom and Calendar `feed_tokens`'
optional :disabled_oauth_sign_in_sources, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Disable certain OAuth sign-in sources'
optional :domain_denylist_enabled, type: Boolean, desc: 'Enable domain denylist for sign ups'
diff --git a/lib/api/snippet_repository_storage_moves.rb b/lib/api/snippet_repository_storage_moves.rb
index e3034191641..92eb10b3bb8 100644
--- a/lib/api/snippet_repository_storage_moves.rb
+++ b/lib/api/snippet_repository_storage_moves.rb
@@ -11,7 +11,8 @@ module API
resource :snippet_repository_storage_moves do
desc 'Get a list of all snippet repository storage moves' do
detail 'This feature was introduced in GitLab 13.8.'
- success Entities::Snippets::RepositoryStorageMove
+ is_array true
+ success code: 200, model: Entities::Snippets::RepositoryStorageMove
end
params do
use :pagination
@@ -24,7 +25,7 @@ module API
desc 'Get a snippet repository storage move' do
detail 'This feature was introduced in GitLab 13.8.'
- success Entities::Snippets::RepositoryStorageMove
+ success code: 200, model: Entities::Snippets::RepositoryStorageMove
end
params do
requires :repository_storage_move_id, type: Integer, desc: 'The ID of a snippet repository storage move'
@@ -37,6 +38,7 @@ module API
desc 'Schedule bulk snippet repository storage moves' do
detail 'This feature was introduced in GitLab 13.8.'
+ success code: 202
end
params do
requires :source_storage_name, type: String, desc: 'The source storage shard', values: -> { Gitlab.config.repositories.storages.keys }
@@ -68,7 +70,8 @@ module API
desc 'Get a list of all snippets repository storage moves' do
detail 'This feature was introduced in GitLab 13.8.'
- success Entities::Snippets::RepositoryStorageMove
+ is_array true
+ success code: 200, model: Entities::Snippets::RepositoryStorageMove
end
params do
use :pagination
@@ -81,7 +84,7 @@ module API
desc 'Get a snippet repository storage move' do
detail 'This feature was introduced in GitLab 13.8.'
- success Entities::Snippets::RepositoryStorageMove
+ success code: 200, model: Entities::Snippets::RepositoryStorageMove
end
params do
requires :repository_storage_move_id, type: Integer, desc: 'The ID of a snippet repository storage move'
@@ -94,14 +97,14 @@ module API
desc 'Schedule a snippet repository storage move' do
detail 'This feature was introduced in GitLab 13.8.'
- success Entities::Snippets::RepositoryStorageMove
+ success code: 201, model: Entities::Snippets::RepositoryStorageMove
end
params do
optional :destination_storage_name, type: String, desc: 'The destination storage shard'
end
post ':id/repository_storage_moves' do
storage_move = user_snippet.repository_storage_moves.build(
- declared_params.merge(source_storage_name: user_snippet.repository_storage)
+ declared_params.compact.merge(source_storage_name: user_snippet.repository_storage)
)
if storage_move.schedule
diff --git a/lib/api/snippets.rb b/lib/api/snippets.rb
index 5f8e6c806cb..36698a220bd 100644
--- a/lib/api/snippets.rb
+++ b/lib/api/snippets.rb
@@ -28,6 +28,11 @@ module API
desc 'Get a snippets list for an authenticated user' do
detail 'This feature was introduced in GitLab 8.15.'
success Entities::Snippet
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[snippets]
+ is_array true
end
params do
optional :created_after, type: DateTime, desc: 'Return snippets created after the specified time'
@@ -45,6 +50,11 @@ module API
desc 'List all public personal snippets current_user has access to' do
detail 'This feature was introduced in GitLab 8.15.'
success Entities::PersonalSnippet
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[snippets]
+ is_array true
end
params do
optional :created_after, type: DateTime, desc: 'Return snippets created after the specified time'
@@ -62,6 +72,10 @@ module API
desc 'Get a single snippet' do
detail 'This feature was introduced in GitLab 8.15.'
success Entities::PersonalSnippet
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[snippets]
end
params do
requires :id, type: Integer, desc: 'The ID of a snippet'
@@ -77,6 +91,12 @@ module API
desc 'Create new snippet' do
detail 'This feature was introduced in GitLab 8.15.'
success Entities::PersonalSnippet
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags %w[snippets]
end
params do
requires :title, type: String, allow_blank: false, desc: 'The title of a snippet'
@@ -110,6 +130,12 @@ module API
desc 'Update an existing snippet' do
detail 'This feature was introduced in GitLab 8.15.'
success Entities::PersonalSnippet
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags %w[snippets]
end
params do
@@ -154,6 +180,11 @@ module API
desc 'Remove snippet' do
detail 'This feature was introduced in GitLab 8.15.'
success Entities::PersonalSnippet
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[snippets]
end
params do
requires :id, type: Integer, desc: 'The ID of a snippet'
@@ -178,6 +209,10 @@ module API
desc 'Get a raw snippet' do
detail 'This feature was introduced in GitLab 8.15.'
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[snippets]
end
params do
requires :id, type: Integer, desc: 'The ID of a snippet'
@@ -189,7 +224,12 @@ module API
present content_for(snippet)
end
- desc 'Get raw snippet file contents from the repository'
+ desc 'Get raw snippet file contents from the repository' do
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[snippets]
+ end
params do
use :raw_file_params
end
@@ -202,6 +242,10 @@ module API
desc 'Get the user agent details for a snippet' do
success Entities::UserAgentDetail
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[snippets]
end
params do
requires :id, type: Integer, desc: 'The ID of a snippet'
diff --git a/lib/api/statistics.rb b/lib/api/statistics.rb
index a12a2ed08d7..1af83c0737a 100644
--- a/lib/api/statistics.rb
+++ b/lib/api/statistics.rb
@@ -10,7 +10,7 @@ module API
MergeRequest, Note, Snippet, Key, Milestone].freeze
desc 'Get the current application statistics' do
- success Entities::ApplicationStatistics
+ success code: 200, model: Entities::ApplicationStatistics
end
get "application/statistics", urgency: :low do
counts = Gitlab::Database::Count.approximate_counts(COUNTED_ITEMS)
diff --git a/lib/api/submodules.rb b/lib/api/submodules.rb
index 2b51ab91c40..6638ac57f69 100644
--- a/lib/api/submodules.rb
+++ b/lib/api/submodules.rb
@@ -18,17 +18,34 @@ module API
end
params do
- requires :id, type: String, desc: 'The project ID'
+ requires :id,
+ type: String,
+ desc: 'The ID or URL-encoded path of a project',
+ documentation: { example: 'gitlab-org/gitlab' }
end
- resource :projects, requirements: Files::FILE_ENDPOINT_REQUIREMENTS do
+ resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Update existing submodule reference in repository' do
- success Entities::Commit
+ success code: 200, model: Entities::CommitDetail
+ failure [
+ { code: 404, message: '404 Project Not Found' },
+ { code: 401, message: '401 Unauthorized' },
+ { code: 400, message: 'The repository is empty' }
+ ]
end
params do
- requires :submodule, type: String, desc: 'Url encoded full path to submodule.'
- requires :commit_sha, type: String, desc: 'Commit sha to update the submodule to.'
- requires :branch, type: String, desc: 'Name of the branch to commit into.'
- optional :commit_message, type: String, desc: 'Commit message. If no message is provided a default one will be set.'
+ requires :submodule,
+ type: String,
+ desc: 'Url encoded full path to submodule.',
+ documentation: { example: 'gitlab-org/gitlab-shell' }
+ requires :commit_sha,
+ type: String,
+ desc: 'Commit sha to update the submodule to.',
+ documentation: { example: 'ed899a2f4b50b4370feeea94676502b42383c746' }
+ requires :branch, type: String, desc: 'Name of the branch to commit into.', documentation: { example: 'main' }
+ optional :commit_message,
+ type: String,
+ desc: 'Commit message. If no message is provided a default one will be set.',
+ documentation: { example: 'Commit message' }
end
put ":id/repository/submodules/:submodule", requirements: Files::FILE_ENDPOINT_REQUIREMENTS do
authorize! :push_code, user_project
diff --git a/lib/api/suggestions.rb b/lib/api/suggestions.rb
index 0697169b49a..6260983087f 100644
--- a/lib/api/suggestions.rb
+++ b/lib/api/suggestions.rb
@@ -9,9 +9,10 @@ module API
resource :suggestions do
desc 'Apply suggestion patch in the Merge Request it was created' do
success Entities::Suggestion
+ tags %w[suggestions]
end
params do
- requires :id, type: String, desc: 'The suggestion ID'
+ requires :id, type: Integer, desc: 'The ID of the suggestion'
optional :commit_message, type: String, desc: "A custom commit message to use instead of the default generated message or the project's default message"
end
put ':id/apply', urgency: :low do
@@ -26,9 +27,10 @@ module API
desc 'Apply multiple suggestion patches in the Merge Request where they were created' do
success Entities::Suggestion
+ tags %w[suggestions]
end
params do
- requires :ids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: "An array of suggestion ID's"
+ requires :ids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: "An array of the suggestion IDs"
optional :commit_message, type: String, desc: "A custom commit message to use instead of the default generated message or the project's default message"
end
put 'batch_apply', urgency: :low do
diff --git a/lib/api/system_hooks.rb b/lib/api/system_hooks.rb
index 804cedfefe9..f2019d785a0 100644
--- a/lib/api/system_hooks.rb
+++ b/lib/api/system_hooks.rb
@@ -4,6 +4,8 @@ module API
class SystemHooks < ::API::Base
include PaginationParams
+ system_hooks_tags = %w[system_hooks]
+
feature_category :integrations
before do
@@ -19,12 +21,13 @@ module API
end
params :hook_parameters do
- optional :token, type: String, desc: 'The token used to validate payloads'
- optional :push_events, type: Boolean, desc: "Trigger hook on push events"
- optional :tag_push_events, type: Boolean, desc: "Trigger hook on tag push events"
- optional :merge_requests_events, type: Boolean, desc: "Trigger hook on tag push events"
- optional :repository_update_events, type: Boolean, desc: "Trigger hook on repository update 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 isn't returned in the response"
+ optional :push_events, type: Boolean, desc: 'When true, the hook fires on push events'
+ optional :tag_push_events, type: Boolean, desc: 'When true, the hook fires on new tags being pushed'
+ optional :merge_requests_events, type: Boolean, desc: 'Trigger hook on merge requests events'
+ optional :repository_update_events, type: Boolean, desc: 'Trigger hook on repository update events'
+ optional :enable_ssl_verification, type: Boolean, desc: 'Do SSL verification when triggering the hook'
use :url_variables
end
end
@@ -32,8 +35,11 @@ module API
resource :hooks do
mount ::API::Hooks::UrlVariables
- desc 'Get the list of system hooks' do
+ desc 'List system hooks' do
+ detail 'Get a list of all system hooks'
success Entities::Hook
+ is_array true
+ tags system_hooks_tags
end
params do
use :pagination
@@ -42,8 +48,13 @@ module API
present paginate(SystemHook.all), with: Entities::Hook
end
- desc 'Get a hook' do
+ desc 'Get system hook' do
+ detail 'Get a system hook by its ID. Introduced in GitLab 14.9.'
success Entities::Hook
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags system_hooks_tags
end
params do
requires :hook_id, type: Integer, desc: 'The ID of the system hook'
@@ -52,8 +63,15 @@ module API
present find_hook, with: Entities::Hook
end
- desc 'Create a new system hook' do
+ desc 'Add new system hook' do
+ detail 'Add a new system hook'
success Entities::Hook
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags system_hooks_tags
end
params do
use :requires_url
@@ -66,11 +84,18 @@ module API
save_hook(hook, Entities::Hook)
end
- desc 'Update an existing system hook' do
+ desc 'Edit system hook' do
+ detail 'Edits a system hook'
success Entities::Hook
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags system_hooks_tags
end
params do
- requires :hook_id, type: Integer, desc: "The ID of the hook to update"
+ requires :hook_id, type: Integer, desc: 'The ID of the system hook'
use :optional_url
use :hook_parameters
end
@@ -90,8 +115,13 @@ module API
kind: 'system_hooks'
}
- desc 'Delete a hook' do
+ desc 'Delete system hook' do
+ detail 'Deletes a system hook'
success Entities::Hook
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags system_hooks_tags
end
params do
requires :hook_id, type: Integer, desc: 'The ID of the system hook'
diff --git a/lib/api/tags.rb b/lib/api/tags.rb
index c8ac68189f5..b412a17bc6f 100644
--- a/lib/api/tags.rb
+++ b/lib/api/tags.rb
@@ -7,17 +7,25 @@ module API
TAG_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(tag_name: API::NO_SLASH_URL_PART_REGEX)
before do
- authorize! :download_code, user_project
+ authorize! :read_code, user_project
not_found! unless user_project.repo_exists?
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a project repository tags' do
- success Entities::Tag
+ is_array true
+ success code: 200, model: Entities::Tag
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags %w[tags]
end
params do
optional :sort, type: String, values: %w[asc desc], default: 'desc',
@@ -46,7 +54,12 @@ module API
end
desc 'Get a single repository tag' do
- success Entities::Tag
+ success code: 200, model: Entities::Tag
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[tags]
end
params do
requires :tag_name, type: String, desc: 'The name of the tag'
@@ -59,12 +72,18 @@ module API
end
desc 'Create a new repository tag' do
- success Entities::Tag
+ success code: 201, model: Entities::Tag
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[tags]
end
params do
- requires :tag_name, type: String, desc: 'The name of the tag'
- requires :ref, type: String, desc: 'The commit sha or branch name'
- optional :message, type: String, desc: 'Specifying a message creates an annotated tag'
+ requires :tag_name, type: String, desc: 'The name of the tag', documentation: { example: 'v.1.0.0' }
+ requires :ref, type: String, desc: 'The commit sha or branch name', documentation: { example: '2695effb5807a22ff3d138d593fd856244e155e7' }
+ optional :message, type: String, desc: 'Specifying a message creates an annotated tag', documentation: { example: 'Release 1.0.0' }
end
post ':id/repository/tags', :release_orchestration do
authorize_admin_tag
@@ -81,7 +100,15 @@ module API
end
end
- desc 'Delete a repository tag'
+ desc 'Delete a repository tag' do
+ success code: 204
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' },
+ { code: 412, message: 'Precondition failed' }
+ ]
+ tags %w[tags]
+ end
params do
requires :tag_name, type: String, desc: 'The name of the tag'
end
diff --git a/lib/api/terraform/modules/v1/packages.rb b/lib/api/terraform/modules/v1/packages.rb
index 267d41e5fb9..5624784228e 100644
--- a/lib/api/terraform/modules/v1/packages.rb
+++ b/lib/api/terraform/modules/v1/packages.rb
@@ -21,7 +21,7 @@ module API
module_version: SEMVER_REGEX
}.freeze
- feature_category :infrastructure_as_code
+ feature_category :package_registry
urgency :low
after_validation do
@@ -92,11 +92,29 @@ module API
authorize_read_package!(package || module_namespace)
end
+ desc 'List versions for a module' do
+ detail 'List versions for a module'
+ success code: 200, model: Entities::Terraform::ModuleVersions
+ failure [
+ { code: 403, message: 'Forbidden' }
+ ]
+ is_array true
+ tags %w[terraform_registry]
+ end
get 'versions' do
presenter = ::Terraform::ModulesPresenter.new(packages, params[:module_system])
present presenter, with: ::API::Entities::Terraform::ModuleVersions
end
+ desc 'Get download location for the latest version of a module' do
+ detail 'Download the latest version of a module'
+ success code: 302
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[terraform_registry]
+ end
get 'download' do
latest_version = packages.order_version.last&.version
@@ -115,6 +133,15 @@ module API
redirect(download_path)
end
+ desc 'Get details about the latest version of a module' do
+ detail 'Get details about the latest version of a module'
+ success code: 200, model: Entities::Terraform::ModuleVersion
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[terraform_registry]
+ end
get do
latest_package = packages.order_version.last
@@ -133,6 +160,15 @@ module API
not_found! unless package && package_file
end
+ desc 'Get download location for specific version of a module' do
+ detail 'Download specific version of a module'
+ success code: 204
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[terraform_registry]
+ end
get 'download' do
module_file_path = api_v4_packages_terraform_modules_v1_module_version_file_path(
module_namespace: params[:module_namespace],
@@ -154,6 +190,15 @@ module API
accept.token_types(:deploy_token_from_jwt, :job_token_from_jwt, :personal_access_token_from_jwt).sent_through(:token_param)
end
+ desc 'Download specific version of a module' do
+ detail 'Download specific version of a module'
+ success File
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[terraform_registry]
+ end
get do
track_package_event('pull_package', :terraform_module, project: package.project, namespace: module_namespace, user: current_user)
@@ -166,6 +211,15 @@ module API
# format: false is required, otherwise grape splits the semver version into 2 params:
# params[:module_version] and params[:format],
# thus leading to an invalid/not found module version
+ desc 'Get details about specific version of a module' do
+ detail 'Get details about specific version of a module'
+ success code: 200, model: Entities::Terraform::ModuleVersion
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[terraform_registry]
+ end
get format: false do
presenter = ::Terraform::ModuleVersionPresenter.new(package, params[:module_system])
present presenter, with: ::API::Entities::Terraform::ModuleVersion
@@ -189,6 +243,11 @@ module API
desc 'Workhorse authorize Terraform Module package file' do
detail 'This feature was introduced in GitLab 13.11'
+ success code: 200
+ failure [
+ { code: 403, message: 'Forbidden' }
+ ]
+ tags %w[terraform_registry]
end
put 'authorize' do
@@ -200,10 +259,19 @@ module API
desc 'Upload Terraform Module package file' do
detail 'This feature was introduced in GitLab 13.11'
+ success code: 201
+ failure [
+ { code: 400, message: 'Invalid file' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ consumes %w[multipart/form-data]
+ tags %w[terraform_registry]
end
params do
- requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)', documentation: { type: 'file' }
end
put do
diff --git a/lib/api/terraform/state.rb b/lib/api/terraform/state.rb
index a19919b5e76..577d011ebad 100644
--- a/lib/api/terraform/state.rb
+++ b/lib/api/terraform/state.rb
@@ -27,13 +27,21 @@ module API
increment_unique_values('p_terraform_state_api_unique_users', current_user.id)
if Feature.enabled?(:route_hll_to_snowplow_phase2, user_project&.namespace)
- Gitlab::Tracking.event('API::Terraform::State', 'p_terraform_state_api_unique_users',
- namespace: user_project&.namespace, user: current_user)
+ Gitlab::Tracking.event(
+ 'API::Terraform::State',
+ 'terraform_state_api_request',
+ namespace: user_project&.namespace,
+ user: current_user,
+ project: user_project,
+ label: 'redis_hll_counters.terraform.p_terraform_state_api_unique_users_monthly',
+ context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll,
+ event: 'p_terraform_state_api_unique_users').to_context]
+ )
end
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
@@ -49,7 +57,19 @@ module API
end
end
- desc 'Get a terraform state by its name'
+ desc 'Get a Terraform state by its name' do
+ detail 'Get a Terraform state by its name'
+ success [
+ { code: 200 },
+ { code: 204, message: 'Empty state' }
+ ]
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Validation failure' }
+ ]
+ tags %w[terraform_state]
+ end
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
get do
remote_state_handler.find_with_lock do |state|
@@ -60,7 +80,18 @@ module API
end
end
- desc 'Add a new terraform state or update an existing one'
+ desc 'Add a new Terraform state or update an existing one' do
+ detail 'Add a new Terraform state or update an existing one'
+ success [
+ { code: 200 },
+ { code: 204, message: 'No data provided' }
+ ]
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 422, message: 'Validation failure' }
+ ]
+ tags %w[terraform_state]
+ end
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
post do
authorize! :admin_terraform_state, user_project
@@ -76,7 +107,16 @@ module API
status :ok
end
- desc 'Delete a terraform state of a certain name'
+ desc 'Delete a Terraform state of a certain name' do
+ detail 'Delete a Terraform state of a certain name'
+ success code: 200
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Validation failure' }
+ ]
+ tags %w[terraform_state]
+ end
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
delete do
authorize! :admin_terraform_state, user_project
@@ -89,7 +129,17 @@ module API
status :ok
end
- desc 'Lock a terraform state of a certain name'
+ desc 'Lock a Terraform state of a certain name' do
+ detail 'Lock a Terraform state of a certain name'
+ success code: 200
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 409, message: 'Conflict' },
+ { code: 422, message: 'Validation failure' }
+ ]
+ tags %w[terraform_state]
+ end
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
params do
requires :ID, type: String, limit: 255, desc: 'Terraform state lock ID'
@@ -128,7 +178,17 @@ module API
end
end
- desc 'Unlock a terraform state of a certain name'
+ desc 'Unlock a Terraform state of a certain name' do
+ detail 'Unlock a Terraform state of a certain name'
+ success code: 200
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 409, message: 'Conflict' },
+ { code: 422, message: 'Validation failure' }
+ ]
+ tags %w[terraform_state]
+ end
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
params do
optional :ID, type: String, limit: 255, desc: 'Terraform state lock ID'
diff --git a/lib/api/terraform/state_version.rb b/lib/api/terraform/state_version.rb
index ca37c786666..f98aeb5860e 100644
--- a/lib/api/terraform/state_version.rb
+++ b/lib/api/terraform/state_version.rb
@@ -14,7 +14,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
@@ -42,7 +42,15 @@ module API
end
end
- desc 'Get a terraform state version'
+ desc 'Get a Terraform state version' do
+ detail 'Get a Terraform state version'
+ success File
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[terraform_state]
+ end
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
get do
find_version(params[:serial]) do |version|
@@ -52,7 +60,15 @@ module API
end
end
- desc 'Delete a terraform state version'
+ desc 'Delete a Terraform state version' do
+ detail 'Delete a Terraform state version'
+ success code: 204
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[terraform_state]
+ end
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
delete do
authorize! :admin_terraform_state, user_project
diff --git a/lib/api/topics.rb b/lib/api/topics.rb
index 38cfdc44021..b16b40244d4 100644
--- a/lib/api/topics.rb
+++ b/lib/api/topics.rb
@@ -11,7 +11,9 @@ module API
success Entities::Projects::Topic
end
params do
- optional :search, type: String, desc: 'Return list of topics matching the search criteria'
+ optional :search, type: String,
+ desc: 'Return list of topics matching the search criteria',
+ documentation: { example: 'search' }
optional :without_projects, type: Boolean, desc: 'Return list of topics without assigned projects'
use :pagination
end
@@ -42,7 +44,8 @@ module API
requires :name, type: String, desc: 'Slug (name)'
requires :title, type: String, desc: 'Title'
optional :description, type: String, desc: 'Description'
- optional :avatar, type: ::API::Validations::Types::WorkhorseFile, desc: 'Avatar image for topic'
+ optional :avatar, type: ::API::Validations::Types::WorkhorseFile, desc: 'Avatar image for topic',
+ documentation: { type: 'file' }
end
post 'topics' do
authenticated_as_admin!
@@ -65,7 +68,8 @@ module API
optional :name, type: String, desc: 'Slug (name)'
optional :title, type: String, desc: 'Title'
optional :description, type: String, desc: 'Description'
- optional :avatar, type: ::API::Validations::Types::WorkhorseFile, desc: 'Avatar image for topic'
+ optional :avatar, type: ::API::Validations::Types::WorkhorseFile, desc: 'Avatar image for topic',
+ documentation: { type: 'file' }
end
put 'topics/:id' do
authenticated_as_admin!
diff --git a/lib/api/unleash.rb b/lib/api/unleash.rb
index 1fbd7cf5afc..38ce4bd7f32 100644
--- a/lib/api/unleash.rb
+++ b/lib/api/unleash.rb
@@ -4,14 +4,16 @@ module API
class Unleash < ::API::Base
include PaginationParams
+ unleash_tags = %w[unleash_api]
+
feature_category :feature_flags
namespace :feature_flags do
resource :unleash, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
params do
requires :project_id, type: String, desc: 'The ID of a project'
- optional :instance_id, type: String, desc: 'The Instance ID of Unleash Client'
- optional :app_name, type: String, desc: 'The Application Name of Unleash Client'
+ optional :instance_id, type: String, desc: 'The instance ID of Unleash Client'
+ optional :app_name, type: String, desc: 'The application name of Unleash Client'
end
route_param :project_id do
before do
@@ -23,26 +25,22 @@ module API
status :ok
end
- desc 'Get a list of features (deprecated, v2 client support)'
- get 'features' do
- if ::Feature.enabled?(:cache_unleash_client_api, project)
- present_feature_flags
- else
- present :version, 1
- present :features, feature_flags, with: ::API::Entities::UnleashFeature
- end
+ desc 'Get a list of features (deprecated, v2 client support)' do
+ is_array true
+ tags unleash_tags
+ end
+ get 'features', urgency: :low do
+ present_feature_flags
end
# We decrease the urgency of this endpoint until the maxmemory issue of redis-cache has been resolved.
# See https://gitlab.com/gitlab-org/gitlab/-/issues/365575#note_1033611872 for more information.
- desc 'Get a list of features'
+ desc 'Get a list of features' do
+ is_array true
+ tags unleash_tags
+ end
get 'client/features', urgency: :low do
- if ::Feature.enabled?(:cache_unleash_client_api, project)
- present_feature_flags
- else
- present :version, 1
- present :features, feature_flags, with: ::API::Entities::UnleashFeature
- end
+ present_feature_flags
end
post 'client/register' do
@@ -50,7 +48,7 @@ module API
status :ok
end
- post 'client/metrics' do
+ post 'client/metrics', urgency: :low do
# not supported yet
status :ok
end
diff --git a/lib/api/user_counts.rb b/lib/api/user_counts.rb
index 388aa5e375c..e9420f1e2b7 100644
--- a/lib/api/user_counts.rb
+++ b/lib/api/user_counts.rb
@@ -8,17 +8,12 @@ module API
resource :user_counts do
desc 'Return the user specific counts' do
detail 'Assigned open issues, assigned MRs and pending todos count'
+ success Entities::UserCounts
end
get do
unauthorized! unless current_user
- {
- merge_requests: current_user.assigned_open_merge_requests_count, # @deprecated
- assigned_issues: current_user.assigned_open_issues_count,
- assigned_merge_requests: current_user.assigned_open_merge_requests_count,
- review_requested_merge_requests: current_user.review_requested_open_merge_requests_count,
- todos: current_user.todos_pending_count
- }
+ present current_user, with: Entities::UserCounts
end
end
end
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 7f44e46f1ca..72c121bca03 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -8,9 +8,18 @@ module API
allow_access_with_scope :read_user, if: -> (request) { request.get? || request.head? }
- feature_category :users, ['/users/:id/custom_attributes', '/users/:id/custom_attributes/:key']
-
- urgency :medium, ['/users/:id/custom_attributes', '/users/:id/custom_attributes/:key']
+ feature_category :users,
+ %w[
+ /users/:id/custom_attributes
+ /users/:id/custom_attributes/:key
+ /users/:id/associations_count
+ ]
+
+ urgency :medium,
+ %w[
+ /users/:id/custom_attributes
+ /users/:id/custom_attributes/:key
+ ]
resource :users, requirements: { uid: /[0-9]*/, id: /[0-9]*/ } do
include CustomAttributesEndpoints
@@ -20,16 +29,10 @@ module API
end
helpers Helpers::UsersHelpers
+ helpers Gitlab::Tracking::Helpers::WeakPasswordErrorEvent
helpers do
# rubocop: disable CodeReuse/ActiveRecord
- def find_user_by_id(params)
- id = params[:user_id] || params[:id]
- User.find_by(id: id) || not_found!('User')
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- # rubocop: disable CodeReuse/ActiveRecord
def reorder_users(users)
if params[:order_by] && params[:sort]
users.reorder(order_options_with_tie_breaker)
@@ -75,6 +78,31 @@ module API
end
end
+ resources ':id/associations_count' do
+ helpers do
+ def present_entity(result)
+ present result,
+ with: ::API::Entities::UserAssociationsCount
+ end
+ end
+
+ desc "Returns a list of a specified user's count of projects, groups, issues and merge requests."
+ params do
+ requires :id,
+ type: Integer,
+ desc: 'ID of the user to query.'
+ end
+ get do
+ authenticate!
+
+ user = find_user_by_id(params)
+ forbidden! unless can?(current_user, :get_user_associations_count, user)
+ not_found!('User') unless user
+
+ present_entity(user)
+ end
+ end
+
desc 'Get the list of users' do
success Entities::UserBasic
end
@@ -279,6 +307,8 @@ module API
.by_username(user.username)
.any?
+ track_weak_password_error(user, 'API::Users', 'create')
+
render_validation_error!(user)
end
end
@@ -324,6 +354,7 @@ module API
if result[:status] == :success
present user, with: Entities::UserWithAdmin, current_user: current_user
else
+ track_weak_password_error(user, 'API::Users', 'update')
render_validation_error!(user)
end
end
@@ -402,16 +433,16 @@ module API
success Entities::SSHKey
end
params do
- requires :id, type: Integer, desc: 'The ID of the user'
+ requires :user_id, type: Integer, desc: 'The ID of the user'
requires :key, type: String, desc: 'The new SSH key'
requires :title, type: String, desc: 'The title of the new SSH key'
optional :expires_at, type: DateTime, desc: 'The expiration date of the SSH key in ISO 8601 format (YYYY-MM-DDTHH:MM:SSZ)'
end
# rubocop: disable CodeReuse/ActiveRecord
- post ":id/keys", feature_category: :authentication_and_authorization do
+ post ":user_id/keys", feature_category: :authentication_and_authorization do
authenticated_as_admin!
- user = User.find_by(id: params.delete(:id))
+ user = User.find_by(id: params.delete(:user_id))
not_found!('User') unless user
key = ::Keys::CreateService.new(current_user, declared_params(include_missing: false).merge(user: user)).execute
diff --git a/lib/api/v3/github.rb b/lib/api/v3/github.rb
index c86b7785ce2..e4a26838746 100644
--- a/lib/api/v3/github.rb
+++ b/lib/api/v3/github.rb
@@ -58,7 +58,7 @@ module API
project = find_project!(
::Gitlab::Jira::Dvcs.restore_full_path(**params.slice(:namespace, :project).symbolize_keys)
)
- not_found! unless can?(current_user, :download_code, project)
+ not_found! unless can?(current_user, :read_code, project)
project
end
diff --git a/lib/api/validations/validators/email_or_email_list.rb b/lib/api/validations/validators/email_or_email_list.rb
index da665f39130..715a29c613d 100644
--- a/lib/api/validations/validators/email_or_email_list.rb
+++ b/lib/api/validations/validators/email_or_email_list.rb
@@ -9,7 +9,12 @@ module API
return unless value
- return if value.split(',').map { |v| ValidateEmail.valid?(v) }.all?
+ case value
+ when String
+ return if value.split(',').map { |v| ValidateEmail.valid?(v) }.all?
+ when Array
+ return if value.map { |v| ValidateEmail.valid?(v) }.all?
+ end
raise Grape::Exceptions::Validation.new(
params: [@scope.full_name(attr_name)],
diff --git a/lib/api/wikis.rb b/lib/api/wikis.rb
index bb8ad5c4285..2058f5de706 100644
--- a/lib/api/wikis.rb
+++ b/lib/api/wikis.rb
@@ -28,6 +28,11 @@ module API
desc 'Get a list of wiki pages' do
success Entities::WikiPageBasic
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[wikis]
+ is_array true
end
params do
optional :with_content, type: Boolean, default: false, desc: "Include pages' content"
@@ -47,6 +52,10 @@ module API
desc 'Get a wiki page' do
success Entities::WikiPage
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[wikis]
end
params do
requires :slug, type: String, desc: 'The slug of a wiki page'
@@ -67,6 +76,12 @@ module API
desc 'Create a wiki page' do
success Entities::WikiPage
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags %w[wikis]
end
params do
requires :title, type: String, desc: 'Title of a wiki page'
@@ -88,6 +103,12 @@ module API
desc 'Update a wiki page' do
success Entities::WikiPage
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags %w[wikis]
end
params do
optional :title, type: String, desc: 'Title of a wiki page'
@@ -110,7 +131,14 @@ module API
end
end
- desc 'Delete a wiki page'
+ desc 'Delete a wiki page' do
+ success code: 204
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[wikis]
+ end
params do
requires :slug, type: String, desc: 'The slug of a wiki page'
end
@@ -131,6 +159,10 @@ module API
desc 'Upload an attachment to the wiki repository' do
detail 'This feature was introduced in GitLab 11.3.'
success Entities::WikiAttachment
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[wikis]
end
params do
requires :file, types: [Rack::Multipart::UploadedFile, ::API::Validations::Types::WorkhorseFile], desc: 'The attachment file to be uploaded', documentation: { type: 'file' }