summaryrefslogtreecommitdiff
path: root/lib/api
diff options
context:
space:
mode:
Diffstat (limited to 'lib/api')
-rw-r--r--lib/api/api.rb6
-rw-r--r--lib/api/branches.rb4
-rw-r--r--lib/api/ci/runner.rb4
-rw-r--r--lib/api/commit_statuses.rb6
-rw-r--r--lib/api/commits.rb9
-rw-r--r--lib/api/composer_packages.rb4
-rw-r--r--lib/api/concerns/packages/conan_endpoints.rb2
-rw-r--r--lib/api/concerns/packages/debian_distribution_endpoints.rb152
-rw-r--r--lib/api/concerns/packages/debian_package_endpoints.rb (renamed from lib/api/concerns/packages/debian_endpoints.rb)34
-rw-r--r--lib/api/concerns/packages/nuget_endpoints.rb5
-rw-r--r--lib/api/debian_group_packages.rb10
-rw-r--r--lib/api/debian_project_packages.rb35
-rw-r--r--lib/api/entities/basic_project_details.rb31
-rw-r--r--lib/api/entities/commit.rb1
-rw-r--r--lib/api/entities/group_detail.rb6
-rw-r--r--lib/api/entities/issue_basic.rb2
-rw-r--r--lib/api/entities/label_basic.rb2
-rw-r--r--lib/api/entities/merge_request_basic.rb6
-rw-r--r--lib/api/entities/package.rb8
-rw-r--r--lib/api/entities/packages/debian/distribution.rb23
-rw-r--r--lib/api/entities/project.rb19
-rw-r--r--lib/api/entities/project_repository_storage.rb16
-rw-r--r--lib/api/entities/runner.rb1
-rw-r--r--lib/api/entities/snippet.rb10
-rw-r--r--lib/api/entities/user_preferences.rb2
-rw-r--r--lib/api/feature_flag_scopes.rb160
-rw-r--r--lib/api/feature_flags.rb58
-rw-r--r--lib/api/generic_packages.rb4
-rw-r--r--lib/api/group_avatar.rb21
-rw-r--r--lib/api/group_container_repositories.rb2
-rw-r--r--lib/api/group_export.rb6
-rw-r--r--lib/api/group_packages.rb2
-rw-r--r--lib/api/groups.rb2
-rw-r--r--lib/api/helm_packages.rb56
-rw-r--r--lib/api/helpers.rb12
-rw-r--r--lib/api/helpers/label_helpers.rb15
-rw-r--r--lib/api/helpers/packages/basic_auth_helpers.rb8
-rw-r--r--lib/api/helpers/packages/conan/api_helpers.rb4
-rw-r--r--lib/api/helpers/projects_helpers.rb6
-rw-r--r--lib/api/helpers/runner.rb25
-rw-r--r--lib/api/helpers/services_helpers.rb52
-rw-r--r--lib/api/internal/base.rb13
-rw-r--r--lib/api/invitations.rb1
-rw-r--r--lib/api/jobs.rb1
-rw-r--r--lib/api/lint.rb6
-rw-r--r--lib/api/maven_packages.rb10
-rw-r--r--lib/api/members.rb2
-rw-r--r--lib/api/merge_requests.rb11
-rw-r--r--lib/api/npm_project_packages.rb4
-rw-r--r--lib/api/nuget_group_packages.rb4
-rw-r--r--lib/api/nuget_project_packages.rb8
-rw-r--r--lib/api/project_container_repositories.rb10
-rw-r--r--lib/api/project_debian_distributions.rb37
-rw-r--r--lib/api/project_export.rb6
-rw-r--r--lib/api/project_packages.rb4
-rw-r--r--lib/api/project_snippets.rb4
-rw-r--r--lib/api/project_templates.rb2
-rw-r--r--lib/api/projects.rb15
-rw-r--r--lib/api/pypi_packages.rb78
-rw-r--r--lib/api/rubygem_packages.rb4
-rw-r--r--lib/api/settings.rb2
-rw-r--r--lib/api/snippets.rb4
-rw-r--r--lib/api/tags.rb85
-rw-r--r--lib/api/terraform/modules/v1/packages.rb4
-rw-r--r--lib/api/unleash.rb5
-rw-r--r--lib/api/users.rb14
66 files changed, 697 insertions, 468 deletions
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 54e5cc5c8d0..2a3033753f7 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -52,8 +52,6 @@ module API
api_endpoint = env['api.endpoint']
feature_category = api_endpoint.options[:for].try(:feature_category_for_app, api_endpoint).to_s
- header[Gitlab::Metrics::RequestsRackMiddleware::FEATURE_CATEGORY_HEADER] = feature_category
-
Gitlab::ApplicationContext.push(
user: -> { @current_user },
project: -> { @project },
@@ -170,11 +168,11 @@ module API
mount ::API::ErrorTracking
mount ::API::Events
mount ::API::FeatureFlags
- mount ::API::FeatureFlagScopes
mount ::API::FeatureFlagsUserLists
mount ::API::Features
mount ::API::Files
mount ::API::FreezePeriods
+ mount ::API::GroupAvatar
mount ::API::GroupBoards
mount ::API::GroupClusters
mount ::API::GroupExport
@@ -224,10 +222,12 @@ module API
mount ::API::NpmInstancePackages
mount ::API::GenericPackages
mount ::API::GoProxy
+ mount ::API::HelmPackages
mount ::API::Pages
mount ::API::PagesDomains
mount ::API::ProjectClusters
mount ::API::ProjectContainerRepositories
+ mount ::API::ProjectDebianDistributions
mount ::API::ProjectEvents
mount ::API::ProjectExport
mount ::API::ProjectImport
diff --git a/lib/api/branches.rb b/lib/api/branches.rb
index 1ee120f982a..0db5bb82296 100644
--- a/lib/api/branches.rb
+++ b/lib/api/branches.rb
@@ -17,6 +17,10 @@ module API
authorize! :download_code, user_project
end
+ rescue_from Gitlab::Git::Repository::NoRepository do
+ not_found!
+ end
+
helpers do
params :filter_params do
optional :search, type: String, desc: 'Return list of branches matching the search criteria'
diff --git a/lib/api/ci/runner.rb b/lib/api/ci/runner.rb
index 33980b38e2b..c4e0b699524 100644
--- a/lib/api/ci/runner.rb
+++ b/lib/api/ci/runner.rb
@@ -98,6 +98,9 @@ module API
optional :architecture, type: String, desc: %q(Runner's architecture)
optional :executor, type: String, desc: %q(Runner's executor)
optional :features, type: Hash, desc: %q(Runner's features)
+ optional :config, type: Hash, desc: %q(Runner's config) do
+ optional :gpus, type: String, desc: %q(GPUs enabled)
+ end
end
optional :session, type: Hash, desc: %q(Runner's session data) do
optional :url, type: String, desc: %q(Session's url)
@@ -165,7 +168,6 @@ module API
params do
requires :token, type: String, desc: %q(Runners's authentication token)
requires :id, type: Integer, desc: %q(Job's ID)
- optional :trace, type: String, desc: %q(Job's full trace)
optional :state, type: String, desc: %q(Job's status: success, failed)
optional :checksum, type: String, desc: %q(Job's trace CRC32 checksum)
optional :failure_reason, type: String, desc: %q(Job's failure_reason)
diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb
index e199111c975..27fee7fdea2 100644
--- a/lib/api/commit_statuses.rb
+++ b/lib/api/commit_statuses.rb
@@ -96,10 +96,8 @@ module API
protected: user_project.protected_for?(ref)
)
- optional_attributes =
- attributes_for_keys(%w[target_url description coverage])
-
- status.update(optional_attributes) if optional_attributes.any?
+ updatable_optional_attributes = %w[target_url description coverage]
+ status.assign_attributes(attributes_for_keys(updatable_optional_attributes))
if status.valid?
status.update_older_statuses_retried! if Feature.enabled?(:ci_fix_commit_status_retried, user_project, default_enabled: :yaml)
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
index bd9f83ac24c..541a37b0abe 100644
--- a/lib/api/commits.rb
+++ b/lib/api/commits.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require 'mime/types'
module API
@@ -41,6 +40,7 @@ module API
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'
optional :order, type: String, desc: 'List commits in order', default: 'default', values: %w[default topo]
+ optional :trailers, type: Boolean, desc: 'Parse and include Git trailers for every commit', default: false
use :pagination
end
get ':id/repository/commits' do
@@ -62,7 +62,8 @@ module API
after: after,
all: all,
first_parent: first_parent,
- order: order)
+ order: order,
+ trailers: params[:trailers])
serializer = with_stats ? Entities::CommitWithStats : Entities::Commit
@@ -203,6 +204,7 @@ module API
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
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'
end
post ':id/repository/commits/:sha/cherry_pick', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
authorize_push_to_branch!(params[:branch])
@@ -216,7 +218,8 @@ module API
commit: commit,
start_branch: params[:branch],
branch_name: params[:branch],
- dry_run: params[:dry_run]
+ dry_run: params[:dry_run],
+ message: params[:message]
}
result = ::Commits::CherryPickService
diff --git a/lib/api/composer_packages.rb b/lib/api/composer_packages.rb
index 115a6b8ac4f..7b3750b37ee 100644
--- a/lib/api/composer_packages.rb
+++ b/lib/api/composer_packages.rb
@@ -137,7 +137,7 @@ module API
bad_request!
end
- track_package_event('push_package', :composer)
+ track_package_event('push_package', :composer, project: authorized_user_project, user: current_user, namespace: authorized_user_project.namespace)
::Packages::Composer::CreatePackageService
.new(authorized_user_project, current_user, declared_params.merge(build: current_authenticated_job))
@@ -161,7 +161,7 @@ module API
not_found! unless metadata
- track_package_event('pull_package', :composer)
+ track_package_event('pull_package', :composer, project: unauthorized_user_project, namespace: unauthorized_user_project.namespace)
send_git_archive unauthorized_user_project.repository, ref: metadata.target_sha, format: 'zip', append_sha: true
end
diff --git a/lib/api/concerns/packages/conan_endpoints.rb b/lib/api/concerns/packages/conan_endpoints.rb
index eb762be8285..3194cdebde8 100644
--- a/lib/api/concerns/packages/conan_endpoints.rb
+++ b/lib/api/concerns/packages/conan_endpoints.rb
@@ -255,7 +255,7 @@ module API
delete do
authorize!(:destroy_package, project)
- track_package_event('delete_package', :conan, category: 'API::ConanPackages')
+ track_package_event('delete_package', :conan, category: 'API::ConanPackages', user: current_user, project: project, namespace: project.namespace)
package.destroy
end
diff --git a/lib/api/concerns/packages/debian_distribution_endpoints.rb b/lib/api/concerns/packages/debian_distribution_endpoints.rb
new file mode 100644
index 00000000000..4670c3e3521
--- /dev/null
+++ b/lib/api/concerns/packages/debian_distribution_endpoints.rb
@@ -0,0 +1,152 @@
+# frozen_string_literal: true
+
+module API
+ module Concerns
+ module Packages
+ module DebianDistributionEndpoints
+ extend ActiveSupport::Concern
+
+ included do
+ include PaginationParams
+
+ feature_category :package_registry
+
+ helpers ::API::Helpers::PackagesHelpers
+ helpers ::API::Helpers::Packages::BasicAuthHelpers
+ include ::API::Helpers::Authentication
+
+ namespace 'debian_distributions' do
+ helpers do
+ params :optional_distribution_params do
+ optional :suite, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Suite'
+ optional :origin, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Origin'
+ optional :label, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Label'
+ optional :version, type: String, regexp: Gitlab::Regex.debian_version_regex, desc: 'The Debian Version'
+ optional :description, type: String, desc: 'The Debian Description'
+ optional :valid_time_duration_seconds, type: Integer, desc: 'The duration before the Release file should be considered expired by the client'
+
+ optional :components, type: Array[String],
+ coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
+ regexp: Gitlab::Regex.debian_component_regex,
+ desc: 'The list of Components'
+ optional :architectures, type: Array[String],
+ coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
+ regexp: Gitlab::Regex.debian_architecture_regex,
+ desc: 'The list of Architectures'
+ end
+ end
+
+ authenticate_with do |accept|
+ accept.token_types(:personal_access_token, :deploy_token, :job_token)
+ .sent_through(:http_basic_auth)
+ end
+
+ content_type :json, 'application/json'
+ format :json
+
+ # POST {projects|groups}/:id/debian_distributions
+ desc 'Create a Debian Distribution' do
+ detail 'This feature was introduced in 14.0'
+ success ::API::Entities::Packages::Debian::Distribution
+ end
+
+ params do
+ requires :codename, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Codename'
+ use :optional_distribution_params
+ end
+ post '/' do
+ authorize_create_package!(project_or_group)
+
+ distribution_params = declared_params(include_missing: false)
+ result = ::Packages::Debian::CreateDistributionService.new(project_or_group, current_user, distribution_params).execute
+ distribution = result.payload[:distribution]
+
+ if result.success?
+ present distribution, with: ::API::Entities::Packages::Debian::Distribution
+ else
+ render_validation_error!(distribution)
+ end
+ end
+
+ # GET {projects|groups}/:id/debian_distributions
+ desc 'Get a list of Debian Distributions' do
+ detail 'This feature was introduced in 14.0'
+ success ::API::Entities::Packages::Debian::Distribution
+ end
+
+ params do
+ use :pagination
+ optional :codename, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Codename'
+ use :optional_distribution_params
+ end
+ get '/' do
+ distribution_params = declared_params(include_missing: false)
+ distributions = ::Packages::Debian::DistributionsFinder.new(project_or_group, distribution_params).execute
+
+ present paginate(distributions), with: ::API::Entities::Packages::Debian::Distribution
+ end
+
+ # GET {projects|groups}/:id/debian_distributions/:codename
+ desc 'Get a Debian Distribution' do
+ detail 'This feature was introduced in 14.0'
+ success ::API::Entities::Packages::Debian::Distribution
+ end
+
+ params do
+ requires :codename, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Codename'
+ end
+ get '/:codename' do
+ distribution = ::Packages::Debian::DistributionsFinder.new(project_or_group, codename: params[:codename]).execute.last!
+
+ present distribution, with: ::API::Entities::Packages::Debian::Distribution
+ end
+
+ # PUT {projects|groups}/:id/debian_distributions/:codename
+ desc 'Update a Debian Distribution' do
+ detail 'This feature was introduced in 14.0'
+ success ::API::Entities::Packages::Debian::Distribution
+ end
+
+ params do
+ requires :codename, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Codename'
+ use :optional_distribution_params
+ end
+ put '/:codename' do
+ authorize_create_package!(project_or_group)
+
+ distribution = ::Packages::Debian::DistributionsFinder.new(project_or_group, codename: params[:codename]).execute.last!
+ distribution_params = declared_params(include_missing: false).except(:codename)
+ result = ::Packages::Debian::UpdateDistributionService.new(distribution, distribution_params).execute
+ distribution = result.payload[:distribution]
+
+ if result.success?
+ present distribution, with: ::API::Entities::Packages::Debian::Distribution
+ else
+ render_validation_error!(distribution)
+ end
+ end
+
+ # DELETE {projects|groups}/:id/debian_distributions/:codename
+ desc 'Delete a Debian Distribution' do
+ detail 'This feature was introduced in 14.0'
+ end
+
+ params do
+ requires :codename, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Codename'
+ use :optional_distribution_params
+ end
+ delete '/:codename' do
+ authorize_destroy_package!(project_or_group)
+
+ distribution = ::Packages::Debian::DistributionsFinder.new(project_or_group, codename: params[:codename]).execute.last!
+
+ accepted! if distribution.destroy
+
+ render_api_error!('Failed to delete distribution', 400)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/concerns/packages/debian_endpoints.rb b/lib/api/concerns/packages/debian_package_endpoints.rb
index 6fc7c439464..c79ae3068b4 100644
--- a/lib/api/concerns/packages/debian_endpoints.rb
+++ b/lib/api/concerns/packages/debian_package_endpoints.rb
@@ -3,7 +3,7 @@
module API
module Concerns
module Packages
- module DebianEndpoints
+ module DebianPackageEndpoints
extend ActiveSupport::Concern
DISTRIBUTION_REGEX = %r{[a-zA-Z0-9][a-zA-Z0-9.-]*}.freeze
@@ -32,23 +32,17 @@ module API
helpers ::API::Helpers::PackagesHelpers
helpers ::API::Helpers::Packages::BasicAuthHelpers
+ include ::API::Helpers::Authentication
- format :txt
- content_type :txt, 'text/plain'
-
- rescue_from ArgumentError do |e|
- render_api_error!(e.message, 400)
- end
-
- rescue_from ActiveRecord::RecordInvalid do |e|
- render_api_error!(e.message, 400)
- end
+ namespace 'packages/debian' do
+ authenticate_with do |accept|
+ accept.token_types(:personal_access_token, :deploy_token, :job_token)
+ .sent_through(:http_basic_auth)
+ end
- before do
- require_packages_enabled!
- end
+ format :txt
+ content_type :txt, 'text/plain'
- namespace 'packages/debian' do
params do
requires :distribution, type: String, desc: 'The Debian Codename', regexp: Gitlab::Regex.debian_distribution_regex
end
@@ -59,7 +53,7 @@ module API
detail 'This feature was introduced in GitLab 13.5'
end
- route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
+ route_setting :authentication, authenticate_non_public: true
get 'Release.gpg' do
not_found!
end
@@ -69,7 +63,7 @@ module API
detail 'This feature was introduced in GitLab 13.5'
end
- route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
+ route_setting :authentication, authenticate_non_public: true
get 'Release' do
# https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
'TODO Release'
@@ -80,7 +74,7 @@ module API
detail 'This feature was introduced in GitLab 13.5'
end
- route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
+ route_setting :authentication, authenticate_non_public: true
get 'InRelease' do
not_found!
end
@@ -96,7 +90,7 @@ module API
detail 'This feature was introduced in GitLab 13.5'
end
- route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
+ route_setting :authentication, authenticate_non_public: true
get 'Packages' do
# https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
'TODO Packages'
@@ -119,7 +113,7 @@ module API
detail 'This feature was introduced in GitLab 13.5'
end
- route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
+ route_setting :authentication, authenticate_non_public: true
get ':file_name', requirements: FILE_NAME_REQUIREMENTS do
# https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
'TODO File'
diff --git a/lib/api/concerns/packages/nuget_endpoints.rb b/lib/api/concerns/packages/nuget_endpoints.rb
index 5364eeb1880..208daeb3037 100644
--- a/lib/api/concerns/packages/nuget_endpoints.rb
+++ b/lib/api/concerns/packages/nuget_endpoints.rb
@@ -58,7 +58,8 @@ module API
end
get 'index', format: :json do
authorize_read_package!(project_or_group)
- track_package_event('cli_metadata', :nuget, category: 'API::NugetPackages')
+
+ track_package_event('cli_metadata', :nuget, **snowplow_gitlab_standard_context.merge(category: 'API::NugetPackages'))
present ::Packages::Nuget::ServiceIndexPresenter.new(project_or_group),
with: ::API::Entities::Nuget::ServiceIndex
@@ -117,7 +118,7 @@ module API
results = search_packages(params[:q], search_options)
- track_package_event('search_package', :nuget, category: 'API::NugetPackages')
+ track_package_event('search_package', :nuget, **snowplow_gitlab_standard_context.merge(category: 'API::NugetPackages'))
present ::Packages::Nuget::SearchResultsPresenter.new(results),
with: ::API::Entities::Nuget::SearchResults
diff --git a/lib/api/debian_group_packages.rb b/lib/api/debian_group_packages.rb
index 06edab662bf..c6116a8b28f 100644
--- a/lib/api/debian_group_packages.rb
+++ b/lib/api/debian_group_packages.rb
@@ -7,6 +7,14 @@ module API
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ rescue_from ArgumentError do |e|
+ render_api_error!(e.message, 400)
+ end
+
+ rescue_from ActiveRecord::RecordInvalid do |e|
+ render_api_error!(e.message, 400)
+ end
+
before do
require_packages_enabled!
@@ -16,7 +24,7 @@ module API
end
namespace ':id/-' do
- include ::API::Concerns::Packages::DebianEndpoints
+ include ::API::Concerns::Packages::DebianPackageEndpoints
end
end
end
diff --git a/lib/api/debian_project_packages.rb b/lib/api/debian_project_packages.rb
index 0ed828fd639..70ddf9dea37 100644
--- a/lib/api/debian_project_packages.rb
+++ b/lib/api/debian_project_packages.rb
@@ -7,7 +7,15 @@ module API
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- before do
+ rescue_from ArgumentError do |e|
+ render_api_error!(e.message, 400)
+ end
+
+ rescue_from ActiveRecord::RecordInvalid do |e|
+ render_api_error!(e.message, 400)
+ end
+
+ after_validation do
require_packages_enabled!
not_found! unless ::Feature.enabled?(:debian_packages, user_project)
@@ -16,13 +24,20 @@ module API
end
namespace ':id' do
- include ::API::Concerns::Packages::DebianEndpoints
+ helpers do
+ def project_or_group
+ user_project
+ end
+ end
+
+ include ::API::Concerns::Packages::DebianPackageEndpoints
params do
requires :file_name, type: String, desc: 'The file name'
end
namespace 'packages/debian/:file_name', requirements: FILE_NAME_REQUIREMENTS do
+ format :txt
content_type :json, Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE
# PUT {projects|groups}/:id/packages/debian/:file_name
@@ -35,8 +50,22 @@ module API
authorize_upload!(authorized_user_project)
bad_request!('File is too large') if authorized_user_project.actual_limits.exceeded?(:debian_max_file_size, params[:file].size)
- track_package_event('push_package', :debian)
+ file_params = {
+ file: params['file'],
+ file_name: params['file_name'],
+ file_sha1: params['file.sha1'],
+ file_md5: params['file.md5']
+ }
+
+ package = ::Packages::Debian::FindOrCreateIncomingService.new(authorized_user_project, current_user).execute
+
+ package_file = ::Packages::Debian::CreatePackageFileService.new(package, file_params).execute
+
+ if params['file_name'].end_with? '.changes'
+ ::Packages::Debian::ProcessChangesWorker.perform_async(package_file.id, current_user.id) # rubocop:disable CodeReuse/Worker
+ end
+ track_package_event('push_package', :debian, user: current_user, project: authorized_user_project, namespace: authorized_user_project.namespace)
created!
rescue ObjectStorage::RemoteStoreError => e
Gitlab::ErrorTracking.track_exception(e, extra: { file_name: params[:file_name], project_id: authorized_user_project.id })
diff --git a/lib/api/entities/basic_project_details.rb b/lib/api/entities/basic_project_details.rb
index 2de49d6ed40..c75b74b4368 100644
--- a/lib/api/entities/basic_project_details.rb
+++ b/lib/api/entities/basic_project_details.rb
@@ -4,15 +4,13 @@ module API
module Entities
class BasicProjectDetails < Entities::ProjectIdentity
include ::API::ProjectsRelationBuilder
+ include Gitlab::Utils::StrongMemoize
expose :default_branch, if: -> (project, options) { Ability.allowed?(options[:current_user], :download_code, project) }
# Avoids an N+1 query: https://github.com/mbleigh/acts-as-taggable-on/issues/91#issuecomment-168273770
- expose :tag_list do |project|
- # Tags is a preloaded association. If we perform then sorting
- # through the database, it will trigger a new query, ending up
- # in an N+1 if we have several projects
- project.tags.pluck(:name).sort # rubocop:disable CodeReuse/ActiveRecord
- end
+
+ expose :topic_names, as: :tag_list
+ expose :topic_names, as: :topics
expose :ssh_url_to_repo, :http_url_to_repo, :web_url, :readme_url
@@ -40,16 +38,29 @@ module API
# rubocop: disable CodeReuse/ActiveRecord
def self.preload_relation(projects_relation, options = {})
- # Preloading tags, should be done with using only `:tags`,
- # as `:tags` are defined as: `has_many :tags, through: :taggings`
- # N+1 is solved then by using `subject.tags.map(&:name)`
+ # Preloading topics, should be done with using only `:topics`,
+ # as `:topics` are defined as: `has_many :topics, through: :taggings`
+ # N+1 is solved then by using `subject.topics.map(&:name)`
# MR describing the solution: https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/20555
projects_relation.preload(:project_feature, :route)
- .preload(:import_state, :tags)
+ .preload(:import_state, :topics)
.preload(:auto_devops)
.preload(namespace: [:route, :owner])
end
# rubocop: enable CodeReuse/ActiveRecord
+
+ private
+
+ alias_method :project, :object
+
+ def topic_names
+ # Topics is a preloaded association. If we perform then sorting
+ # through the database, it will trigger a new query, ending up
+ # in an N+1 if we have several projects
+ strong_memoize(:topic_names) do
+ project.topics.pluck(:name).sort # rubocop:disable CodeReuse/ActiveRecord
+ end
+ end
end
end
end
diff --git a/lib/api/entities/commit.rb b/lib/api/entities/commit.rb
index 3eaf896f1ac..fd23c23b980 100644
--- a/lib/api/entities/commit.rb
+++ b/lib/api/entities/commit.rb
@@ -9,6 +9,7 @@ module API
expose :safe_message, as: :message
expose :author_name, :author_email, :authored_date
expose :committer_name, :committer_email, :committed_date
+ expose :trailers
expose :web_url do |commit, _options|
Gitlab::UrlBuilder.build(commit)
diff --git a/lib/api/entities/group_detail.rb b/lib/api/entities/group_detail.rb
index e63a3fc1334..408254a89be 100644
--- a/lib/api/entities/group_detail.rb
+++ b/lib/api/entities/group_detail.rb
@@ -29,11 +29,7 @@ module API
end
def projects_limit
- if ::Feature.enabled?(:limit_projects_in_groups_api, default_enabled: true)
- GroupProjectsFinder::DEFAULT_PROJECTS_LIMIT
- else
- nil
- end
+ GroupProjectsFinder::DEFAULT_PROJECTS_LIMIT
end
end
end
diff --git a/lib/api/entities/issue_basic.rb b/lib/api/entities/issue_basic.rb
index d27cc5498bd..6c332870228 100644
--- a/lib/api/entities/issue_basic.rb
+++ b/lib/api/entities/issue_basic.rb
@@ -23,7 +23,7 @@ module API
expose :issue_type,
as: :type,
format_with: :upcase,
- documentation: { type: "String", desc: "One of #{Issue.issue_types.keys.map(&:upcase)}" }
+ documentation: { type: "String", desc: "One of #{::Issue.issue_types.keys.map(&:upcase)}" }
expose :assignee, using: ::API::Entities::UserBasic do |issue|
issue.assignees.first
diff --git a/lib/api/entities/label_basic.rb b/lib/api/entities/label_basic.rb
index 00ecea26ec3..ed52688638e 100644
--- a/lib/api/entities/label_basic.rb
+++ b/lib/api/entities/label_basic.rb
@@ -3,7 +3,7 @@
module API
module Entities
class LabelBasic < Grape::Entity
- expose :id, :name, :color, :description, :description_html, :text_color, :remove_on_close
+ expose :id, :name, :color, :description, :description_html, :text_color
end
end
end
diff --git a/lib/api/entities/merge_request_basic.rb b/lib/api/entities/merge_request_basic.rb
index cf8d03bf176..d5cf2f653db 100644
--- a/lib/api/entities/merge_request_basic.rb
+++ b/lib/api/entities/merge_request_basic.rb
@@ -36,7 +36,11 @@ module API
merge_request.labels.map(&:title).sort
end
end
- expose :work_in_progress?, as: :work_in_progress
+ expose :draft?, as: :draft
+
+ # [Deprecated] see draft
+ #
+ expose :draft?, as: :work_in_progress
expose :milestone, using: Entities::Milestone
expose :merge_when_pipeline_succeeds
diff --git a/lib/api/entities/package.rb b/lib/api/entities/package.rb
index 2f60a0bf6bd..1efd457aa5f 100644
--- a/lib/api/entities/package.rb
+++ b/lib/api/entities/package.rb
@@ -25,8 +25,12 @@ module API
expose :status
expose :_links do
- expose :web_path do |package|
- ::Gitlab::Routing.url_helpers.project_package_path(package.project, package)
+ 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
end
expose :delete_api_path, if: can_destroy(:package, &:project) do |package|
diff --git a/lib/api/entities/packages/debian/distribution.rb b/lib/api/entities/packages/debian/distribution.rb
new file mode 100644
index 00000000000..97a3c479f40
--- /dev/null
+++ b/lib/api/entities/packages/debian/distribution.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ module Packages
+ module Debian
+ class Distribution < Grape::Entity
+ expose :id
+ expose :codename
+ expose :suite
+ expose :origin
+ expose :label
+ expose :version
+ expose :description
+ expose :valid_time_duration_seconds
+
+ expose :component_names, as: :components
+ expose :architecture_names, as: :architectures
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/entities/project.rb b/lib/api/entities/project.rb
index 442013c07dd..68d91fc6970 100644
--- a/lib/api/entities/project.rb
+++ b/lib/api/entities/project.rb
@@ -43,7 +43,6 @@ module API
expose :visibility
expose :owner, using: Entities::UserBasic, unless: ->(project, options) { project.group }
expose :resolve_outdated_diff_discussions
- expose :container_registry_enabled
expose :container_expiration_policy, using: Entities::ContainerExpirationPolicy,
if: -> (project, _) { project.container_expiration_policy }
@@ -54,6 +53,13 @@ module API
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) do |project, options|
+ if ::Feature.enabled?(:read_container_registry_access_level, project.namespace, default_enabled: :yaml)
+ project.feature_available?(:container_registry, options[:current_user])
+ else
+ project.read_attribute(:container_registry_enabled)
+ end
+ end
expose :service_desk_enabled
expose :service_desk_address
@@ -89,6 +95,7 @@ module API
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
expose :public_builds, as: :public_jobs
expose :build_git_strategy, if: lambda { |project, options| options[:user_can_admin_project] } do |project, options|
project.build_allow_git_fetch ? 'fetch' : 'clone'
@@ -108,6 +115,7 @@ module API
expose :remove_source_branch_after_merge
expose :printing_merge_request_link_enabled
expose :merge_method
+ expose :squash_option
expose :suggestion_commit_message
expose :statistics, using: 'API::Entities::ProjectStatistics', if: -> (project, options) {
options[:statistics] && Ability.allowed?(options[:current_user], :read_statistics, project)
@@ -120,12 +128,13 @@ module API
expose :repository_storage, if: ->(project, options) {
Ability.allowed?(options[:current_user], :change_repository_storage, project)
}
+ expose :keep_latest_artifacts_available?, as: :keep_latest_artifact
# rubocop: disable CodeReuse/ActiveRecord
def self.preload_relation(projects_relation, options = {})
- # Preloading tags, should be done with using only `:tags`,
- # as `:tags` are defined as: `has_many :tags, through: :taggings`
- # N+1 is solved then by using `subject.tags.map(&:name)`
+ # Preloading topics, should be done with using only `:topics`,
+ # as `:topics` are defined as: `has_many :topics, through: :taggings`
+ # N+1 is solved then by using `subject.topics.map(&:name)`
# MR describing the solution: https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/20555
super(projects_relation).preload(group: :namespace_settings)
.preload(:ci_cd_settings)
@@ -136,7 +145,7 @@ module API
.preload(project_group_links: { group: :route },
fork_network: :root_project,
fork_network_member: :forked_from_project,
- forked_from_project: [:route, :forks, :tags, :group, :project_feature, namespace: [:route, :owner]])
+ forked_from_project: [:route, :topics, :group, :project_feature, namespace: [:route, :owner]])
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/lib/api/entities/project_repository_storage.rb b/lib/api/entities/project_repository_storage.rb
new file mode 100644
index 00000000000..0816bebde2c
--- /dev/null
+++ b/lib/api/entities/project_repository_storage.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class ProjectRepositoryStorage < Grape::Entity
+ include Gitlab::Routing
+
+ expose :disk_path do |project|
+ project.repository.disk_path
+ end
+
+ expose :id, as: :project_id
+ expose :repository_storage, :created_at
+ end
+ end
+end
diff --git a/lib/api/entities/runner.rb b/lib/api/entities/runner.rb
index 6165b54cddb..e78f14cf920 100644
--- a/lib/api/entities/runner.rb
+++ b/lib/api/entities/runner.rb
@@ -8,6 +8,7 @@ module API
expose :ip_address
expose :active
expose :instance_type?, as: :is_shared
+ expose :runner_type
expose :name
expose :online?, as: :online
expose :status
diff --git a/lib/api/entities/snippet.rb b/lib/api/entities/snippet.rb
index f05e593a302..af885aaf0eb 100644
--- a/lib/api/entities/snippet.rb
+++ b/lib/api/entities/snippet.rb
@@ -5,16 +5,22 @@ module API
class Snippet < BasicSnippet
expose :author, using: Entities::UserBasic
expose :file_name do |snippet|
- snippet.file_name_on_repo || snippet.file_name
+ snippet_files.first || snippet.file_name
end
expose :files do |snippet, options|
- snippet.list_files.map do |file|
+ snippet_files.map do |file|
{
path: file,
raw_url: Gitlab::UrlBuilder.build(snippet, file: file, ref: snippet.repository.root_ref)
}
end
end
+
+ private
+
+ def snippet_files
+ @snippet_files ||= object.list_files
+ end
end
end
end
diff --git a/lib/api/entities/user_preferences.rb b/lib/api/entities/user_preferences.rb
index 7a6df9b6c59..ceee6c610d3 100644
--- a/lib/api/entities/user_preferences.rb
+++ b/lib/api/entities/user_preferences.rb
@@ -3,7 +3,7 @@
module API
module Entities
class UserPreferences < Grape::Entity
- expose :id, :user_id, :view_diffs_file_by_file
+ expose :id, :user_id, :view_diffs_file_by_file, :show_whitespace_in_diffs
end
end
end
diff --git a/lib/api/feature_flag_scopes.rb b/lib/api/feature_flag_scopes.rb
deleted file mode 100644
index 3f3bf4d9f42..00000000000
--- a/lib/api/feature_flag_scopes.rb
+++ /dev/null
@@ -1,160 +0,0 @@
-# frozen_string_literal: true
-
-module API
- class FeatureFlagScopes < ::API::Base
- include PaginationParams
-
- ENVIRONMENT_SCOPE_ENDPOINT_REQUIREMENTS = FeatureFlags::FEATURE_FLAG_ENDPOINT_REQUIREMENTS
- .merge(environment_scope: API::NO_SLASH_URL_PART_REGEX)
-
- feature_category :feature_flags
-
- before do
- authorize_read_feature_flags!
- end
-
- params do
- requires :id, type: String, desc: 'The ID of a project'
- end
- resource 'projects/:id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- resource :feature_flag_scopes do
- desc 'Get all effective feature flags under the environment' do
- detail 'This feature was introduced in GitLab 12.5'
- success ::API::Entities::FeatureFlag::DetailedLegacyScope
- end
- params do
- requires :environment, type: String, desc: 'The environment name'
- end
- get do
- present scopes_for_environment, with: ::API::Entities::FeatureFlag::DetailedLegacyScope
- end
- end
-
- params do
- requires :name, type: String, desc: 'The name of the feature flag'
- end
- resource 'feature_flags/:name', requirements: FeatureFlags::FEATURE_FLAG_ENDPOINT_REQUIREMENTS do
- resource :scopes do
- desc 'Get all scopes of a feature flag' do
- detail 'This feature was introduced in GitLab 12.5'
- success ::API::Entities::FeatureFlag::LegacyScope
- end
- params do
- use :pagination
- end
- get do
- present paginate(feature_flag.scopes), with: ::API::Entities::FeatureFlag::LegacyScope
- end
-
- desc 'Create a scope of a feature flag' do
- detail 'This feature was introduced in GitLab 12.5'
- success ::API::Entities::FeatureFlag::LegacyScope
- end
- params do
- requires :environment_scope, type: String, desc: 'The environment scope of the scope'
- requires :active, type: Boolean, desc: 'Whether the scope is active'
- requires :strategies, type: JSON, desc: 'The strategies of the scope'
- end
- post do
- authorize_update_feature_flag!
-
- result = ::FeatureFlags::UpdateService
- .new(user_project, current_user, scopes_attributes: [declared_params])
- .execute(feature_flag)
-
- if result[:status] == :success
- present scope, with: ::API::Entities::FeatureFlag::LegacyScope
- else
- render_api_error!(result[:message], result[:http_status])
- end
- end
-
- params do
- requires :environment_scope, type: String, desc: 'URL-encoded environment scope'
- end
- resource ':environment_scope', requirements: ENVIRONMENT_SCOPE_ENDPOINT_REQUIREMENTS do
- desc 'Get a scope of a feature flag' do
- detail 'This feature was introduced in GitLab 12.5'
- success ::API::Entities::FeatureFlag::LegacyScope
- end
- get do
- present scope, with: ::API::Entities::FeatureFlag::LegacyScope
- end
-
- desc 'Update a scope of a feature flag' do
- detail 'This feature was introduced in GitLab 12.5'
- success ::API::Entities::FeatureFlag::LegacyScope
- end
- params do
- optional :active, type: Boolean, desc: 'Whether the scope is active'
- optional :strategies, type: JSON, desc: 'The strategies of the scope'
- end
- put do
- authorize_update_feature_flag!
-
- scope_attributes = declared_params.merge(id: scope.id)
-
- result = ::FeatureFlags::UpdateService
- .new(user_project, current_user, scopes_attributes: [scope_attributes])
- .execute(feature_flag)
-
- if result[:status] == :success
- updated_scope = result[:feature_flag].scopes
- .find { |scope| scope.environment_scope == params[:environment_scope] }
-
- present updated_scope, with: ::API::Entities::FeatureFlag::LegacyScope
- else
- render_api_error!(result[:message], result[:http_status])
- end
- end
-
- desc 'Delete a scope from a feature flag' do
- detail 'This feature was introduced in GitLab 12.5'
- success ::API::Entities::FeatureFlag::LegacyScope
- end
- delete do
- authorize_update_feature_flag!
-
- param = { scopes_attributes: [{ id: scope.id, _destroy: true }] }
-
- result = ::FeatureFlags::UpdateService
- .new(user_project, current_user, param)
- .execute(feature_flag)
-
- if result[:status] == :success
- status :no_content
- else
- render_api_error!(result[:message], result[:http_status])
- end
- end
- end
- end
- end
- end
-
- helpers do
- def authorize_read_feature_flags!
- authorize! :read_feature_flag, user_project
- end
-
- def authorize_update_feature_flag!
- authorize! :update_feature_flag, feature_flag
- end
-
- def feature_flag
- @feature_flag ||= user_project.operations_feature_flags
- .find_by_name!(params[:name])
- end
-
- def scope
- @scope ||= feature_flag.scopes
- .find_by_environment_scope!(CGI.unescape(params[:environment_scope]))
- end
-
- def scopes_for_environment
- Operations::FeatureFlagScope
- .for_unleash_client(user_project, params[:environment])
- end
- end
- end
-end
diff --git a/lib/api/feature_flags.rb b/lib/api/feature_flags.rb
index 6fdc4535be3..fb5858bc10b 100644
--- a/lib/api/feature_flags.rb
+++ b/lib/api/feature_flags.rb
@@ -90,56 +90,11 @@ module API
end
get do
authorize_read_feature_flag!
+ exclude_legacy_flags_check!
present_entity(feature_flag)
end
- desc 'Enable a strategy for a feature flag on an environment' do
- detail 'This feature was introduced in GitLab 12.5'
- success ::API::Entities::FeatureFlag
- end
- params do
- requires :environment_scope, type: String, desc: 'The environment scope of the feature flag'
- requires :strategy, type: JSON, desc: 'The strategy to be enabled on the scope'
- end
- post :enable do
- not_found! unless Feature.enabled?(:feature_flag_api, user_project)
- render_api_error!('Version 2 flags not supported', :unprocessable_entity) if new_version_flag_present?
-
- result = ::FeatureFlags::EnableService
- .new(user_project, current_user, params).execute
-
- if result[:status] == :success
- status :ok
- present_entity(result[:feature_flag])
- else
- render_api_error!(result[:message], result[:http_status])
- end
- end
-
- desc 'Disable a strategy for a feature flag on an environment' do
- detail 'This feature is going to be introduced in GitLab 12.5 if `feature_flag_api` feature flag is removed'
- success ::API::Entities::FeatureFlag
- end
- params do
- requires :environment_scope, type: String, desc: 'The environment scope of the feature flag'
- requires :strategy, type: JSON, desc: 'The strategy to be disabled on the scope'
- end
- post :disable do
- not_found! unless Feature.enabled?(:feature_flag_api, user_project)
- render_api_error!('Version 2 flags not supported', :unprocessable_entity) if feature_flag.new_version_flag?
-
- result = ::FeatureFlags::DisableService
- .new(user_project, current_user, params).execute
-
- if result[:status] == :success
- status :ok
- present_entity(result[:feature_flag])
- else
- render_api_error!(result[:message], result[:http_status])
- end
- end
-
desc 'Update a feature flag' do
detail 'This feature was introduced in GitLab 13.2'
success ::API::Entities::FeatureFlag
@@ -162,6 +117,7 @@ module API
end
put do
authorize_update_feature_flag!
+ exclude_legacy_flags_check!
render_api_error!('PUT operations are not supported for legacy feature flags', :unprocessable_entity) if feature_flag.legacy_flag?
attrs = declared_params(include_missing: false)
@@ -232,6 +188,10 @@ module API
@feature_flag ||= user_project.operations_feature_flags.find_by_name!(params[:feature_flag_name])
end
+ def project
+ @project ||= feature_flag.project
+ end
+
def new_version_flag_present?
user_project.operations_feature_flags.new_version_flag.find_by_name(params[:name]).present?
end
@@ -245,6 +205,12 @@ module API
hash[key] = yield(hash[key]) if hash.key?(key)
hash
end
+
+ def exclude_legacy_flags_check!
+ if feature_flag.legacy_flag?
+ not_found!
+ end
+ end
end
end
end
diff --git a/lib/api/generic_packages.rb b/lib/api/generic_packages.rb
index d0680ad7bc5..a57d6bbcd2a 100644
--- a/lib/api/generic_packages.rb
+++ b/lib/api/generic_packages.rb
@@ -62,7 +62,7 @@ module API
authorize_upload!(project)
bad_request!('File is too large') if max_file_size_exceeded?
- ::Gitlab::Tracking.event(self.options[:for].name, 'push_package')
+ ::Gitlab::Tracking.event(self.options[:for].name, 'push_package', user: current_user, project: project, namespace: project.namespace)
create_package_file_params = declared_params.merge(build: current_authenticated_job)
::Packages::Generic::CreatePackageFileService
@@ -96,7 +96,7 @@ module API
package = ::Packages::Generic::PackageFinder.new(project).execute!(params[:package_name], params[:package_version])
package_file = ::Packages::PackageFileFinder.new(package, params[:file_name]).execute!
- ::Gitlab::Tracking.event(self.options[:for].name, 'pull_package')
+ ::Gitlab::Tracking.event(self.options[:for].name, 'pull_package', user: current_user, project: project, namespace: project.namespace)
present_carrierwave_file!(package_file.file)
end
diff --git a/lib/api/group_avatar.rb b/lib/api/group_avatar.rb
new file mode 100644
index 00000000000..ddf6787f913
--- /dev/null
+++ b/lib/api/group_avatar.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module API
+ class GroupAvatar < ::API::Base
+ helpers Helpers::GroupsHelpers
+
+ feature_category :subgroups
+
+ resource :groups do
+ desc 'Download the group avatar' do
+ detail 'This feature was introduced in GitLab 14.0'
+ end
+ params do
+ requires :id, type: String, desc: 'The group id'
+ end
+ get ':id/avatar' do
+ present_carrierwave_file!(user_group.avatar)
+ end
+ end
+ end
+end
diff --git a/lib/api/group_container_repositories.rb b/lib/api/group_container_repositories.rb
index 4fede0ad583..96175f31696 100644
--- a/lib/api/group_container_repositories.rb
+++ b/lib/api/group_container_repositories.rb
@@ -31,7 +31,7 @@ module API
user: current_user, subject: user_group
).execute
- track_package_event('list_repositories', :container)
+ track_package_event('list_repositories', :container, user: current_user, namespace: user_group)
present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags], tags_count: params[:tags_count]
end
diff --git a/lib/api/group_export.rb b/lib/api/group_export.rb
index 6134515032f..7e4fdba6033 100644
--- a/lib/api/group_export.rb
+++ b/lib/api/group_export.rb
@@ -23,7 +23,11 @@ module API
check_rate_limit! :group_download_export, [current_user, user_group]
if user_group.export_file_exists?
- present_carrierwave_file!(user_group.export_file)
+ if user_group.export_archive_exists?
+ present_carrierwave_file!(user_group.export_file)
+ else
+ render_api_error!('The group export file is not available yet', 404)
+ end
else
render_api_error!('404 Not found or has expired', 404)
end
diff --git a/lib/api/group_packages.rb b/lib/api/group_packages.rb
index ab4e91ff925..d9010dfd329 100644
--- a/lib/api/group_packages.rb
+++ b/lib/api/group_packages.rb
@@ -43,7 +43,7 @@ module API
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
+ present paginate(packages), with: ::API::Entities::Package, user: current_user, group: true, namespace: user_group.root_ancestor
end
end
end
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index 1a604e70bf1..0efb8b57885 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -372,7 +372,7 @@ module API
expires_at: params[:expires_at]
}
- result = ::Groups::GroupLinks::CreateService.new(shared_with_group, current_user, group_link_create_params).execute(shared_group)
+ result = ::Groups::GroupLinks::CreateService.new(shared_group, shared_with_group, current_user, group_link_create_params).execute
shared_group.preload_shared_group_links
if result[:status] == :success
diff --git a/lib/api/helm_packages.rb b/lib/api/helm_packages.rb
new file mode 100644
index 00000000000..dc5630a1395
--- /dev/null
+++ b/lib/api/helm_packages.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+###
+# API endpoints for the Helm package registry
+module API
+ class HelmPackages < ::API::Base
+ helpers ::API::Helpers::PackagesHelpers
+ helpers ::API::Helpers::Packages::BasicAuthHelpers
+ include ::API::Helpers::Authentication
+
+ feature_category :package_registry
+
+ FILE_NAME_REQUIREMENTS = {
+ file_name: API::NO_SLASH_URL_PART_REGEX
+ }.freeze
+
+ content_type :binary, 'application/octet-stream'
+
+ authenticate_with do |accept|
+ accept.token_types(:personal_access_token, :deploy_token, :job_token)
+ .sent_through(:http_basic_auth)
+ end
+
+ before do
+ require_packages_enabled!
+ end
+
+ after_validation do
+ not_found! unless Feature.enabled?(:helm_packages, authorized_user_project)
+ end
+
+ params do
+ requires :id, type: String, desc: 'The ID or full path of a project'
+ end
+ resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ namespace ':id/packages/helm' do
+ desc 'Download a chart' do
+ detail 'This feature was introduced in GitLab 14.0'
+ end
+ params do
+ requires :channel, type: String, desc: 'Helm channel', regexp: Gitlab::Regex.helm_channel_regex
+ requires :file_name, type: String, desc: 'Helm package file name'
+ end
+ get ":channel/charts/:file_name.tgz", requirements: FILE_NAME_REQUIREMENTS do
+ authorize_read_package!(authorized_user_project)
+
+ package_file = Packages::Helm::PackageFilesFinder.new(authorized_user_project, params[:channel], file_name: "#{params[:file_name]}.tgz").execute.last!
+
+ track_package_event('pull_package', :helm, project: authorized_user_project, namespace: authorized_user_project.namespace)
+
+ present_carrierwave_file!(package_file.file)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 632717e1b73..6ce04be373f 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -74,6 +74,11 @@ module API
save_current_user_in_env(@current_user) if @current_user
+ if @current_user
+ ::Gitlab::Database::LoadBalancing::RackMiddleware
+ .stick_or_unstick(env, :user, @current_user.id)
+ end
+
@current_user
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
@@ -482,9 +487,8 @@ module API
def handle_api_exception(exception)
if report_exception?(exception)
define_params_for_grape_middleware
- Gitlab::ApplicationContext.with_context(user: current_user) do
- Gitlab::ErrorTracking.track_exception(exception)
- end
+ Gitlab::ApplicationContext.push(user: current_user)
+ Gitlab::ErrorTracking.track_exception(exception)
end
# This is used with GrapeLogging::Loggers::ExceptionLogger
@@ -599,6 +603,7 @@ module API
:custom_attributes,
:last_activity_after,
:last_activity_before,
+ :topic,
:repository_storage)
.symbolize_keys
.compact
@@ -611,7 +616,6 @@ module API
finder_params[:user] = params.delete(:user) if params[:user]
finder_params[:id_after] = sanitize_id_param(params[:id_after]) if params[:id_after]
finder_params[:id_before] = sanitize_id_param(params[:id_before]) if params[:id_before]
- finder_params[:tag] = params[:topic] if params[:topic].present?
finder_params
end
diff --git a/lib/api/helpers/label_helpers.rb b/lib/api/helpers/label_helpers.rb
index 796b8928243..da0ee8f207e 100644
--- a/lib/api/helpers/label_helpers.rb
+++ b/lib/api/helpers/label_helpers.rb
@@ -5,34 +5,27 @@ module API
module LabelHelpers
extend Grape::API::Helpers
- params :optional_label_params do
- optional :description, type: String, desc: 'The description of the label'
- optional :remove_on_close, type: Boolean, desc: 'Whether the label should be removed from an issue when the issue is closed'
- end
-
params :label_create_params do
requires :name, type: String, desc: 'The name of the label to be created'
requires :color, type: String, desc: "The color of the label given in 6-digit hex notation with leading '#' sign (e.g. #FFAABB) or one of the allowed CSS color names"
-
- use :optional_label_params
+ optional :description, type: String, desc: 'The description of label to be created'
end
params :label_update_params do
optional :new_name, type: String, desc: 'The new name of the label'
optional :color, type: String, desc: "The new color of the label given in 6-digit hex notation with leading '#' sign (e.g. #FFAABB) or one of the allowed CSS color names"
-
- use :optional_label_params
+ optional :description, type: String, desc: 'The new description of label'
end
params :project_label_update_params do
use :label_update_params
optional :priority, type: Integer, desc: 'The priority of the label', allow_blank: true
- at_least_one_of :new_name, :color, :description, :priority, :remove_on_close
+ at_least_one_of :new_name, :color, :description, :priority
end
params :group_label_update_params do
use :label_update_params
- at_least_one_of :new_name, :color, :description, :remove_on_close
+ at_least_one_of :new_name, :color, :description
end
def find_label(parent, id_or_title, params = { include_ancestor_groups: true })
diff --git a/lib/api/helpers/packages/basic_auth_helpers.rb b/lib/api/helpers/packages/basic_auth_helpers.rb
index c32ce199dd6..6c381d85cd8 100644
--- a/lib/api/helpers/packages/basic_auth_helpers.rb
+++ b/lib/api/helpers/packages/basic_auth_helpers.rb
@@ -22,6 +22,14 @@ module API
unauthorized_user_project || not_found!
end
+ def unauthorized_user_group
+ @unauthorized_user_group ||= find_group(params[:id])
+ end
+
+ def unauthorized_user_group!
+ unauthorized_user_group || not_found!
+ end
+
def authorized_user_project
@authorized_user_project ||= authorized_project_find!
end
diff --git a/lib/api/helpers/packages/conan/api_helpers.rb b/lib/api/helpers/packages/conan/api_helpers.rb
index b18f52b5be6..4b6dac39348 100644
--- a/lib/api/helpers/packages/conan/api_helpers.rb
+++ b/lib/api/helpers/packages/conan/api_helpers.rb
@@ -155,7 +155,7 @@ module API
conan_package_reference: params[:conan_package_reference]
).execute!
- track_package_event('pull_package', :conan, category: 'API::ConanPackages') if params[:file_name] == ::Packages::Conan::FileMetadatum::PACKAGE_BINARY
+ track_package_event('pull_package', :conan, category: 'API::ConanPackages', user: current_user, project: project, namespace: project.namespace) if params[:file_name] == ::Packages::Conan::FileMetadatum::PACKAGE_BINARY
present_carrierwave_file!(package_file.file)
end
@@ -170,7 +170,7 @@ module API
def track_push_package_event
if params[:file_name] == ::Packages::Conan::FileMetadatum::PACKAGE_BINARY && params[:file].size > 0 # rubocop: disable Style/ZeroLengthPredicate
- track_package_event('push_package', :conan, category: 'API::ConanPackages')
+ track_package_event('push_package', :conan, category: 'API::ConanPackages', user: current_user, project: project, namespace: project.namespace)
end
end
diff --git a/lib/api/helpers/projects_helpers.rb b/lib/api/helpers/projects_helpers.rb
index d9c0b4f67c8..69a83043617 100644
--- a/lib/api/helpers/projects_helpers.rb
+++ b/lib/api/helpers/projects_helpers.rb
@@ -16,6 +16,7 @@ module API
optional :build_coverage_regex, type: String, desc: 'Test coverage parsing'
optional :ci_config_path, type: String, desc: 'The path to CI config file. Defaults to `.gitlab-ci.yml`'
optional :service_desk_enabled, type: Boolean, desc: 'Disable or enable the service desk'
+ optional :keep_latest_artifact, type: Boolean, desc: 'Indicates if the latest artifact should be kept for this project.'
# TODO: remove in API v5, replaced by *_access_level
optional :issues_enabled, type: Boolean, desc: 'Flag indication if the issue tracker is enabled'
@@ -51,7 +52,8 @@ module API
optional :only_allow_merge_if_pipeline_succeeds, type: Boolean, desc: 'Only allow to merge if builds succeed'
optional :allow_merge_on_skipped_pipeline, type: Boolean, desc: 'Allow to merge if pipeline is skipped'
optional :only_allow_merge_if_all_discussions_are_resolved, type: Boolean, desc: 'Only allow to merge if all discussions are resolved'
- optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The list of tags for a project'
+ optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'Deprecated: Use :topics instead'
+ optional :topics, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The list of topics for a project'
# TODO: remove rubocop disable - https://gitlab.com/gitlab-org/gitlab/issues/14960
optional :avatar, type: File, desc: 'Avatar image for project' # rubocop:disable Scalability/FileUploads
optional :printing_merge_request_link_enabled, type: Boolean, desc: 'Show link to create/view merge request when pushing from the command line'
@@ -146,6 +148,7 @@ module API
:shared_runners_enabled,
:snippets_access_level,
:tag_list,
+ :topics,
:visibility,
:wiki_access_level,
:avatar,
@@ -154,6 +157,7 @@ module API
:compliance_framework_setting,
:packages_enabled,
:service_desk_enabled,
+ :keep_latest_artifact,
# TODO: remove in API v5, replaced by *_access_level
:issues_enabled,
diff --git a/lib/api/helpers/runner.rb b/lib/api/helpers/runner.rb
index 6f25cf507bc..9ec9b5e1e35 100644
--- a/lib/api/helpers/runner.rb
+++ b/lib/api/helpers/runner.rb
@@ -25,6 +25,7 @@ module API
return get_runner_ip unless params['info'].present?
attributes_for_keys(%w(name version revision platform architecture), params['info'])
+ .merge(get_runner_config_from_request)
.merge(get_runner_ip)
end
@@ -33,8 +34,15 @@ module API
end
def current_runner
+ token = params[:token]
+
+ if token
+ ::Gitlab::Database::LoadBalancing::RackMiddleware
+ .stick_or_unstick(env, :runner, token)
+ end
+
strong_memoize(:current_runner) do
- ::Ci::Runner.find_by_token(params[:token].to_s)
+ ::Ci::Runner.find_by_token(token.to_s)
end
end
@@ -64,8 +72,15 @@ module API
end
def current_job
+ id = params[:id]
+
+ if id
+ ::Gitlab::Database::LoadBalancing::RackMiddleware
+ .stick_or_unstick(env, :build, id)
+ end
+
strong_memoize(:current_job) do
- ::Ci::Build.find_by_id(params[:id])
+ ::Ci::Build.find_by_id(id)
end
end
@@ -91,6 +106,12 @@ module API
def track_ci_minutes_usage!(_build, _runner)
# noop: overridden in EE
end
+
+ private
+
+ def get_runner_config_from_request
+ { config: attributes_for_keys(%w(gpus), params.dig('info', 'config')) }
+ end
end
end
end
diff --git a/lib/api/helpers/services_helpers.rb b/lib/api/helpers/services_helpers.rb
index d123db8e3df..ca13ea0789a 100644
--- a/lib/api/helpers/services_helpers.rb
+++ b/lib/api/helpers/services_helpers.rb
@@ -777,41 +777,41 @@ module API
::Integrations::Asana,
::Integrations::Assembla,
::Integrations::Bamboo,
+ ::Integrations::Bugzilla,
+ ::Integrations::Buildkite,
::Integrations::Campfire,
::Integrations::Confluence,
+ ::Integrations::CustomIssueTracker,
::Integrations::Datadog,
+ ::Integrations::Discord,
+ ::Integrations::DroneCi,
::Integrations::EmailsOnPush,
- ::BugzillaService,
- ::BuildkiteService,
- ::CustomIssueTrackerService,
- ::DiscordService,
- ::DroneCiService,
- ::EwmService,
- ::ExternalWikiService,
- ::FlowdockService,
- ::HangoutsChatService,
- ::IrkerService,
- ::JenkinsService,
- ::JiraService,
- ::MattermostSlashCommandsService,
- ::SlackSlashCommandsService,
- ::PackagistService,
- ::PipelinesEmailService,
- ::PivotaltrackerService,
- ::PrometheusService,
- ::PushoverService,
- ::RedmineService,
- ::YoutrackService,
- ::SlackService,
- ::MattermostService,
- ::MicrosoftTeamsService,
- ::TeamcityService
+ ::Integrations::Ewm,
+ ::Integrations::ExternalWiki,
+ ::Integrations::Flowdock,
+ ::Integrations::HangoutsChat,
+ ::Integrations::Irker,
+ ::Integrations::Jenkins,
+ ::Integrations::Jira,
+ ::Integrations::Mattermost,
+ ::Integrations::MattermostSlashCommands,
+ ::Integrations::MicrosoftTeams,
+ ::Integrations::Packagist,
+ ::Integrations::PipelinesEmail,
+ ::Integrations::Pivotaltracker,
+ ::Integrations::Pushover,
+ ::Integrations::Redmine,
+ ::Integrations::Slack,
+ ::Integrations::SlackSlashCommands,
+ ::Integrations::Teamcity,
+ ::Integrations::Youtrack,
+ ::PrometheusService
]
end
def self.development_service_classes
[
- ::MockCiService,
+ ::Integrations::MockCi,
::MockMonitoringService
]
end
diff --git a/lib/api/internal/base.rb b/lib/api/internal/base.rb
index e16149185c9..ee0ddccc8d4 100644
--- a/lib/api/internal/base.rb
+++ b/lib/api/internal/base.rb
@@ -10,8 +10,6 @@ module API
api_endpoint = env['api.endpoint']
feature_category = api_endpoint.options[:for].try(:feature_category_for_app, api_endpoint).to_s
- header[Gitlab::Metrics::RequestsRackMiddleware::FEATURE_CATEGORY_HEADER] = feature_category
-
Gitlab::ApplicationContext.push(
user: -> { actor&.user },
project: -> { project },
@@ -169,18 +167,15 @@ module API
end
#
- # Get a ssh key using the fingerprint
+ # Check whether an SSH key is known to GitLab
#
- # rubocop: disable CodeReuse/ActiveRecord
get '/authorized_keys', feature_category: :source_code_management do
- fingerprint = params.fetch(:fingerprint) do
- Gitlab::InsecureKeyFingerprint.new(params.fetch(:key)).fingerprint
- end
- key = Key.find_by(fingerprint: fingerprint)
+ fingerprint = Gitlab::InsecureKeyFingerprint.new(params.fetch(:key)).fingerprint
+
+ key = Key.find_by_fingerprint(fingerprint)
not_found!('Key') if key.nil?
present key, with: Entities::SSHKey
end
- # rubocop: enable CodeReuse/ActiveRecord
#
# Discover user by ssh key, user id or username
diff --git a/lib/api/invitations.rb b/lib/api/invitations.rb
index 0d562cc18f8..46d8c0c958d 100644
--- a/lib/api/invitations.rb
+++ b/lib/api/invitations.rb
@@ -23,6 +23,7 @@ module API
requires :email, types: [String, Array[String]], email_or_email_list: true, desc: 'The email address to invite, or multiple emails separated by comma'
requires :access_level, type: Integer, values: Gitlab::Access.all_values, desc: 'A valid access level (defaults: `30`, developer access level)'
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'
end
post ":id/invitations" do
params[:source] = find_source(source_type, params[:id])
diff --git a/lib/api/jobs.rb b/lib/api/jobs.rb
index cf65bfdfd0e..723a5b0fa3a 100644
--- a/lib/api/jobs.rb
+++ b/lib/api/jobs.rb
@@ -3,7 +3,6 @@
module API
class Jobs < ::API::Base
include PaginationParams
-
before { authenticate! }
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
diff --git a/lib/api/lint.rb b/lib/api/lint.rb
index 945cdf3edb2..3580a7b5e24 100644
--- a/lib/api/lint.rb
+++ b/lib/api/lint.rb
@@ -11,7 +11,11 @@ module API
optional :include_merged_yaml, type: Boolean, desc: 'Whether or not to include merged CI config yaml in the response'
end
post '/lint' do
- unauthorized! if (Gitlab::CurrentSettings.signup_disabled? || Gitlab::CurrentSettings.signup_limited?) && current_user.nil?
+ if Feature.enabled?(:security_ci_lint_authorization)
+ unauthorized! if (Gitlab::CurrentSettings.signup_disabled? || Gitlab::CurrentSettings.signup_limited?) && current_user.nil?
+ else
+ unauthorized! if Gitlab::CurrentSettings.signup_disabled? && current_user.nil?
+ end
result = Gitlab::Ci::YamlProcessor.new(params[:content], user: current_user).execute
diff --git a/lib/api/maven_packages.rb b/lib/api/maven_packages.rb
index 22f7b07809b..9e5705abe88 100644
--- a/lib/api/maven_packages.rb
+++ b/lib/api/maven_packages.rb
@@ -24,8 +24,6 @@ module API
helpers do
def path_exists?(path)
- # return true when FF disabled so that processing the request is not stopped
- return true unless Feature.enabled?(:check_maven_path_first, default_enabled: :yaml)
return false if path.blank?
Packages::Maven::Metadatum.with_path(path)
@@ -132,7 +130,7 @@ module API
when 'sha1'
package_file.file_sha1
else
- track_package_event('pull_package', :maven) if jar_file?(format)
+ track_package_event('pull_package', :maven, project: project, namespace: project.namespace) if jar_file?(format)
present_carrierwave_file_with_head_support!(package_file.file)
end
end
@@ -172,7 +170,7 @@ module API
when 'sha1'
package_file.file_sha1
else
- track_package_event('pull_package', :maven) if jar_file?(format)
+ track_package_event('pull_package', :maven, project: package.project, namespace: package.project.namespace) if jar_file?(format)
present_carrierwave_file_with_head_support!(package_file.file)
end
@@ -210,7 +208,7 @@ module API
when 'sha1'
package_file.file_sha1
else
- track_package_event('pull_package', :maven) if jar_file?(format)
+ track_package_event('pull_package', :maven, project: user_project, namespace: user_project.namespace) if jar_file?(format)
present_carrierwave_file_with_head_support!(package_file.file)
end
@@ -266,7 +264,7 @@ module API
when 'md5'
''
else
- track_package_event('push_package', :maven) if jar_file?(format)
+ track_package_event('push_package', :maven, user: current_user, project: user_project, namespace: user_project.namespace) if jar_file?(format)
file_params = {
file: params[:file],
diff --git a/lib/api/members.rb b/lib/api/members.rb
index a1a733ea7ae..0956806da5b 100644
--- a/lib/api/members.rb
+++ b/lib/api/members.rb
@@ -93,6 +93,7 @@ module API
requires :access_level, type: Integer, desc: 'A valid access level (defaults: `30`, developer access level)'
requires :user_id, types: [Integer, String], 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: 'members-api'
end
# rubocop: disable CodeReuse/ActiveRecord
post ":id/members" do
@@ -116,6 +117,7 @@ module API
not_allowed! # This currently can only be reached in EE
elsif member.valid? && member.persisted?
present_members(member)
+ Gitlab::Tracking.event(::Members::CreateService.name, 'create_member', label: params[:invite_source], property: 'existing_user', user: current_user)
else
render_validation_error!(member)
end
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 931d2322c98..a9617482557 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -436,14 +436,11 @@ module API
mr_params = declared_params(include_missing: false)
mr_params[:force_remove_source_branch] = mr_params.delete(:remove_source_branch) if mr_params.has_key?(:remove_source_branch)
mr_params = convert_parameters_from_legacy_format(mr_params)
+ mr_params[:use_specialized_service] = true
- service = if mr_params.one? && (mr_params.keys & %i[assignee_id assignee_ids]).one?
- ::MergeRequests::UpdateAssigneesService
- else
- ::MergeRequests::UpdateService
- end
-
- merge_request = service.new(project: user_project, current_user: current_user, params: mr_params).execute(merge_request)
+ merge_request = ::MergeRequests::UpdateService
+ .new(project: user_project, current_user: current_user, params: mr_params)
+ .execute(merge_request)
handle_merge_request_errors!(merge_request)
diff --git a/lib/api/npm_project_packages.rb b/lib/api/npm_project_packages.rb
index 887084dc9ae..7ff4439ce04 100644
--- a/lib/api/npm_project_packages.rb
+++ b/lib/api/npm_project_packages.rb
@@ -32,7 +32,7 @@ module API
package_file = ::Packages::PackageFileFinder
.new(package, params[:file_name]).execute!
- track_package_event('pull_package', package, category: 'API::NpmPackages')
+ track_package_event('pull_package', package, category: 'API::NpmPackages', project: project, namespace: project.namespace)
present_carrierwave_file!(package_file.file)
end
@@ -48,7 +48,7 @@ module API
put ':package_name', requirements: ::API::Helpers::Packages::Npm::NPM_ENDPOINT_REQUIREMENTS do
authorize_create_package!(project)
- track_package_event('push_package', :npm, category: 'API::NpmPackages')
+ track_package_event('push_package', :npm, category: 'API::NpmPackages', project: project, user: current_user, namespace: project.namespace)
created_package = ::Packages::Npm::CreatePackageService
.new(project, current_user, params.merge(build: current_authenticated_job)).execute
diff --git a/lib/api/nuget_group_packages.rb b/lib/api/nuget_group_packages.rb
index a80de06d6b0..eb55e4cbf70 100644
--- a/lib/api/nuget_group_packages.rb
+++ b/lib/api/nuget_group_packages.rb
@@ -38,6 +38,10 @@ module API
def require_authenticated!
unauthorized! unless current_user
end
+
+ def snowplow_gitlab_standard_context
+ { namespace: find_authorized_group! }
+ end
end
params do
diff --git a/lib/api/nuget_project_packages.rb b/lib/api/nuget_project_packages.rb
index 73ecc140959..5bae08d4dae 100644
--- a/lib/api/nuget_project_packages.rb
+++ b/lib/api/nuget_project_packages.rb
@@ -36,6 +36,10 @@ module API
def project_or_group
authorized_user_project
end
+
+ def snowplow_gitlab_standard_context
+ { project: authorized_user_project, namespace: authorized_user_project.namespace }
+ end
end
params do
@@ -69,7 +73,7 @@ module API
package_file = ::Packages::CreatePackageFileService.new(package, file_params.merge(build: current_authenticated_job))
.execute
- track_package_event('push_package', :nuget, category: 'API::NugetPackages')
+ track_package_event('push_package', :nuget, category: 'API::NugetPackages', user: current_user, project: package.project, namespace: package.project.namespace)
::Packages::Nuget::ExtractionWorker.perform_async(package_file.id) # rubocop:disable CodeReuse/Worker
@@ -118,7 +122,7 @@ module API
not_found!('Package') unless package_file
- track_package_event('pull_package', :nuget, category: 'API::NugetPackages')
+ track_package_event('pull_package', :nuget, category: 'API::NugetPackages', project: package_file.project, namespace: package_file.project.namespace)
# nuget and dotnet don't support 302 Moved status codes, supports_direct_download has to be set to false
present_carrierwave_file!(package_file.file, supports_direct_download: false)
diff --git a/lib/api/project_container_repositories.rb b/lib/api/project_container_repositories.rb
index 2580f7adbc9..28cfa9e3ae0 100644
--- a/lib/api/project_container_repositories.rb
+++ b/lib/api/project_container_repositories.rb
@@ -31,7 +31,7 @@ module API
user: current_user, subject: user_project
).execute
- track_package_event('list_repositories', :container)
+ track_package_event('list_repositories', :container, user: current_user, project: user_project, namespace: user_project.namespace)
present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags], tags_count: params[:tags_count]
end
@@ -46,7 +46,7 @@ module API
authorize_admin_container_image!
DeleteContainerRepositoryWorker.perform_async(current_user.id, repository.id) # rubocop:disable CodeReuse/Worker
- track_package_event('delete_repository', :container)
+ track_package_event('delete_repository', :container, user: current_user, project: user_project, namespace: user_project.namespace)
status :accepted
end
@@ -63,7 +63,7 @@ module API
authorize_read_container_image!
tags = Kaminari.paginate_array(repository.tags)
- track_package_event('list_tags', :container)
+ track_package_event('list_tags', :container, user: current_user, project: user_project, namespace: user_project.namespace)
present paginate(tags), with: Entities::ContainerRegistry::Tag
end
@@ -92,7 +92,7 @@ module API
declared_params.except(:repository_id).merge(container_expiration_policy: false))
# rubocop:enable CodeReuse/Worker
- track_package_event('delete_tag_bulk', :container)
+ track_package_event('delete_tag_bulk', :container, user: current_user, project: user_project, namespace: user_project.namespace)
status :accepted
end
@@ -128,7 +128,7 @@ module API
.execute(repository)
if result[:status] == :success
- track_package_event('delete_tag', :container)
+ track_package_event('delete_tag', :container, user: current_user, project: user_project, namespace: user_project.namespace)
status :ok
else
diff --git a/lib/api/project_debian_distributions.rb b/lib/api/project_debian_distributions.rb
new file mode 100644
index 00000000000..58edf51f4f7
--- /dev/null
+++ b/lib/api/project_debian_distributions.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module API
+ class ProjectDebianDistributions < ::API::Base
+ params do
+ requires :id, type: String, desc: 'The ID of a project'
+ end
+
+ resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ rescue_from ArgumentError do |e|
+ render_api_error!(e.message, 400)
+ end
+
+ rescue_from ActiveRecord::RecordInvalid do |e|
+ render_api_error!(e.message, 400)
+ end
+
+ after_validation do
+ require_packages_enabled!
+
+ not_found! unless ::Feature.enabled?(:debian_packages, user_project)
+
+ authorize_read_package!
+ end
+
+ namespace ':id' do
+ helpers do
+ def project_or_group
+ user_project
+ end
+ end
+
+ include ::API::Concerns::Packages::DebianDistributionEndpoints
+ end
+ end
+ end
+end
diff --git a/lib/api/project_export.rb b/lib/api/project_export.rb
index 76b3dea723a..4041e130f9e 100644
--- a/lib/api/project_export.rb
+++ b/lib/api/project_export.rb
@@ -30,7 +30,11 @@ module API
check_rate_limit! :project_download_export, [current_user, user_project]
if user_project.export_file_exists?
- present_carrierwave_file!(user_project.export_file)
+ if user_project.export_archive_exists?
+ present_carrierwave_file!(user_project.export_file)
+ else
+ render_api_error!('The project export file is not available yet', 404)
+ end
else
render_api_error!('404 Not found or has expired', 404)
end
diff --git a/lib/api/project_packages.rb b/lib/api/project_packages.rb
index babc7b9dd58..276cbe50e42 100644
--- a/lib/api/project_packages.rb
+++ b/lib/api/project_packages.rb
@@ -41,7 +41,7 @@ module API
declared_params.slice(:order_by, :sort, :package_type, :package_name, :include_versionless, :status)
).execute
- present paginate(packages), with: ::API::Entities::Package, user: current_user
+ present paginate(packages), with: ::API::Entities::Package, user: current_user, namespace: user_project.root_ancestor
end
desc 'Get a single project package' do
@@ -55,7 +55,7 @@ module API
package = ::Packages::PackageFinder
.new(user_project, params[:package_id]).execute
- present package, with: ::API::Entities::Package, user: current_user
+ present package, with: ::API::Entities::Package, user: current_user, namespace: user_project.root_ancestor
end
desc 'Remove a package' do
diff --git a/lib/api/project_snippets.rb b/lib/api/project_snippets.rb
index 899984fe0ba..084492fd503 100644
--- a/lib/api/project_snippets.rb
+++ b/lib/api/project_snippets.rb
@@ -75,7 +75,7 @@ module API
snippet_params = process_create_params(declared_params(include_missing: false))
- service_response = ::Snippets::CreateService.new(user_project, current_user, snippet_params).execute
+ service_response = ::Snippets::CreateService.new(project: user_project, current_user: current_user, params: snippet_params).execute
snippet = service_response.payload[:snippet]
if service_response.success?
@@ -116,7 +116,7 @@ module API
snippet_params = process_update_params(declared_params(include_missing: false))
- service_response = ::Snippets::UpdateService.new(user_project, current_user, snippet_params).execute(snippet)
+ service_response = ::Snippets::UpdateService.new(project: user_project, current_user: current_user, params: snippet_params).execute(snippet)
snippet = service_response.payload[:snippet]
if service_response.success?
diff --git a/lib/api/project_templates.rb b/lib/api/project_templates.rb
index 5d6f67ccbae..acf9bfece65 100644
--- a/lib/api/project_templates.rb
+++ b/lib/api/project_templates.rb
@@ -26,7 +26,7 @@ module API
use :pagination
end
get ':id/templates/:type' do
- templates = TemplateFinder.all_template_names_array(user_project, params[:type])
+ templates = TemplateFinder.all_template_names(user_project, params[:type]).values.flatten
present paginate(::Kaminari.paginate_array(templates)), with: Entities::TemplatesList
end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 4e8786fbe1f..83c335a3248 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -61,7 +61,7 @@ module API
# Temporarily introduced for upload API: https://gitlab.com/gitlab-org/gitlab/-/issues/325788
def project_attachment_size(user_project)
return PROJECT_ATTACHMENT_SIZE_EXEMPT if exempt_from_global_attachment_size?(user_project)
- return user_project.max_attachment_size if Feature.enabled?(:enforce_max_attachment_size_upload_api, user_project)
+ return user_project.max_attachment_size if Feature.enabled?(:enforce_max_attachment_size_upload_api, user_project, default_enabled: :yaml)
PROJECT_ATTACHMENT_SIZE_EXEMPT
end
@@ -234,6 +234,7 @@ module API
params do
optional :name, type: String, desc: 'The name of the project'
optional :path, type: String, desc: 'The path of the repository'
+ optional :default_branch, type: String, desc: 'The default branch of the project'
at_least_one_of :name, :path
use :optional_create_project_params
use :create_params
@@ -660,6 +661,18 @@ module API
render_api_error!("Failed to transfer project #{user_project.errors.messages}", 400)
end
end
+
+ desc 'Show the storage information' do
+ success Entities::ProjectRepositoryStorage
+ end
+ params do
+ requires :id, type: String, desc: 'ID of a project'
+ end
+ get ':id/storage', feature_category: :projects do
+ authenticated_as_admin!
+
+ present user_project, with: Entities::ProjectRepositoryStorage, current_user: current_user
+ end
end
end
end
diff --git a/lib/api/pypi_packages.rb b/lib/api/pypi_packages.rb
index 73b2f658825..7c5f8bb4d99 100644
--- a/lib/api/pypi_packages.rb
+++ b/lib/api/pypi_packages.rb
@@ -28,6 +28,73 @@ module API
require_packages_enabled!
end
+ helpers do
+ params :package_download do
+ requires :file_identifier, type: String, desc: 'The PyPi package file identifier', file_path: true
+ requires :sha256, type: String, desc: 'The PyPi package sha256 check sum'
+ end
+
+ params :package_name do
+ requires :package_name, type: String, file_path: true, desc: 'The PyPi package name'
+ end
+ end
+
+ params do
+ requires :id, type: Integer, desc: 'The ID of a group'
+ end
+ resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ after_validation do
+ unauthorized_user_group!
+ end
+
+ namespace ':id/-/packages/pypi' do
+ params do
+ use :package_download
+ end
+
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
+ get 'files/:sha256/*file_identifier' do
+ group = unauthorized_user_group!
+
+ filename = "#{params[:file_identifier]}.#{params[:format]}"
+ package = Packages::Pypi::PackageFinder.new(current_user, group, { filename: filename, sha256: params[:sha256] }).execute
+ package_file = ::Packages::PackageFileFinder.new(package, filename, with_file_name_like: false).execute
+
+ track_package_event('pull_package', :pypi)
+
+ present_carrierwave_file!(package_file.file, supports_direct_download: true)
+ end
+
+ desc 'The PyPi Simple Endpoint' do
+ detail 'This feature was introduced in GitLab 12.10'
+ end
+
+ params do
+ use :package_name
+ end
+
+ # An Api entry point but returns an HTML file instead of JSON.
+ # 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
+ group = find_authorized_group!
+ authorize_read_package!(group)
+
+ track_package_event('list_package', :pypi)
+
+ packages = Packages::Pypi::PackagesFinder.new(current_user, group, { package_name: params[:package_name] }).execute!
+ presenter = ::Packages::Pypi::PackagePresenter.new(packages, group)
+
+ # Adjusts grape output format
+ # to be HTML
+ content_type "text/html; charset=utf-8"
+ env['api.format'] = :binary
+
+ body presenter.body
+ end
+ end
+ end
+
params do
requires :id, type: Integer, desc: 'The ID of a project'
end
@@ -43,8 +110,7 @@ module API
end
params do
- requires :file_identifier, type: String, desc: 'The PyPi package file identifier', file_path: true
- requires :sha256, type: String, desc: 'The PyPi package sha256 check sum'
+ use :package_download
end
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
@@ -55,7 +121,7 @@ module API
package = Packages::Pypi::PackageFinder.new(current_user, project, { filename: filename, sha256: params[:sha256] }).execute
package_file = ::Packages::PackageFileFinder.new(package, filename, with_file_name_like: false).execute
- track_package_event('pull_package', :pypi)
+ track_package_event('pull_package', :pypi, project: project, namespace: project.namespace)
present_carrierwave_file!(package_file.file, supports_direct_download: true)
end
@@ -65,7 +131,7 @@ module API
end
params do
- requires :package_name, type: String, file_path: true, desc: 'The PyPi package name'
+ use :package_name
end
# An Api entry point but returns an HTML file instead of JSON.
@@ -74,7 +140,7 @@ module API
get 'simple/*package_name', format: :txt do
authorize_read_package!(authorized_user_project)
- track_package_event('list_package', :pypi)
+ track_package_event('list_package', :pypi, project: authorized_user_project, namespace: authorized_user_project.namespace)
packages = Packages::Pypi::PackagesFinder.new(current_user, authorized_user_project, { package_name: params[:package_name] }).execute!
presenter = ::Packages::Pypi::PackagePresenter.new(packages, authorized_user_project)
@@ -105,7 +171,7 @@ module API
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)
- track_package_event('push_package', :pypi)
+ track_package_event('push_package', :pypi, project: authorized_user_project, user: current_user, namespace: authorized_user_project.namespace)
::Packages::Pypi::CreatePackageService
.new(authorized_user_project, current_user, declared_params.merge(build: current_authenticated_job))
diff --git a/lib/api/rubygem_packages.rb b/lib/api/rubygem_packages.rb
index 1d17148e0df..d7f9c584c67 100644
--- a/lib/api/rubygem_packages.rb
+++ b/lib/api/rubygem_packages.rb
@@ -70,7 +70,7 @@ module API
user_project, params[:file_name]
).last!
- track_package_event('pull_package', :rubygems)
+ track_package_event('pull_package', :rubygems, project: user_project, namespace: user_project.namespace)
present_carrierwave_file!(package_file.file)
end
@@ -97,7 +97,7 @@ module API
authorize_upload!(user_project)
bad_request!('File is too large') if user_project.actual_limits.exceeded?(:rubygems_max_file_size, params[:file].size)
- track_package_event('push_package', :rubygems)
+ track_package_event('push_package', :rubygems, user: current_user, project: user_project, namespace: user_project.namespace)
package_file = nil
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index 372bc7b3d8f..b4f8320cb74 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -46,7 +46,7 @@ module API
optional :asset_proxy_allowlist, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Assets that match these domain(s) will NOT be proxied. Wildcards allowed. Your GitLab installation URL is automatically allowed.'
optional :container_registry_token_expire_delay, type: Integer, desc: 'Authorization token duration (minutes)'
optional :default_artifacts_expire_in, type: String, desc: "Set the default expiration time for each job's artifacts"
- optional :default_ci_config_path, type: String, desc: 'The instance default CI configuration path for new projects'
+ optional :default_ci_config_path, type: String, desc: 'The instance default CI/CD configuration file and path for new projects'
optional :default_project_creation, type: Integer, values: ::Gitlab::Access.project_creation_values, desc: 'Determine if developers can create projects in the group'
optional :default_branch_protection, type: Integer, values: ::Gitlab::Access.protection_values, desc: 'Determine if developers can push to master'
optional :default_group_visibility, type: String, values: Gitlab::VisibilityLevel.string_values, desc: 'The default group visibility'
diff --git a/lib/api/snippets.rb b/lib/api/snippets.rb
index 52b597fb788..b506192fe1c 100644
--- a/lib/api/snippets.rb
+++ b/lib/api/snippets.rb
@@ -84,7 +84,7 @@ module API
attrs = process_create_params(declared_params(include_missing: false))
- service_response = ::Snippets::CreateService.new(nil, current_user, attrs).execute
+ service_response = ::Snippets::CreateService.new(project: nil, current_user: current_user, params: attrs).execute
snippet = service_response.payload[:snippet]
if service_response.success?
@@ -126,7 +126,7 @@ module API
attrs = process_update_params(declared_params(include_missing: false))
- service_response = ::Snippets::UpdateService.new(nil, current_user, attrs).execute(snippet)
+ service_response = ::Snippets::UpdateService.new(project: nil, current_user: current_user, params: attrs).execute(snippet)
snippet = service_response.payload[:snippet]
diff --git a/lib/api/tags.rb b/lib/api/tags.rb
index e77d7e34de3..6c8e2c69a6d 100644
--- a/lib/api/tags.rb
+++ b/lib/api/tags.rb
@@ -51,35 +51,22 @@ module API
end
desc 'Create a new repository tag' do
- detail 'This optional release_description parameter was deprecated in GitLab 11.7.'
success Entities::Tag
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'
- optional :release_description, type: String, desc: 'Specifying release notes stored in the GitLab database (deprecated in GitLab 11.7)'
end
post ':id/repository/tags', :release_orchestration do
+ deprecate_release_notes unless params[:release_description].blank?
+
authorize_admin_tag
result = ::Tags::CreateService.new(user_project, current_user)
.execute(params[:tag_name], params[:ref], params[:message])
if result[:status] == :success
- # Release creation with Tags API was deprecated in GitLab 11.7
- if params[:release_description].present?
- release_create_params = {
- tag: params[:tag_name],
- name: params[:tag_name], # Name can be specified in new API
- description: params[:release_description]
- }
-
- ::Releases::CreateService
- .new(user_project, current_user, release_create_params)
- .execute
- end
-
present result[:tag],
with: Entities::Tag,
project: user_project
@@ -109,74 +96,6 @@ module API
end
end
end
-
- desc 'Add a release note to a tag' do
- detail 'This feature was deprecated in GitLab 11.7.'
- success Entities::TagRelease
- end
- params do
- requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
- requires :description, type: String, desc: 'Release notes with markdown support'
- end
- post ':id/repository/tags/:tag_name/release', requirements: TAG_ENDPOINT_REQUIREMENTS, feature_category: :release_orchestration do
- authorize_create_release!
-
- ##
- # Legacy API does not support tag auto creation.
- not_found!('Tag') unless user_project.repository.find_tag(params[:tag])
-
- release_create_params = {
- tag: params[:tag],
- name: params[:tag], # Name can be specified in new API
- description: params[:description]
- }
-
- result = ::Releases::CreateService
- .new(user_project, current_user, release_create_params)
- .execute
-
- if result[:status] == :success
- present result[:release], with: Entities::TagRelease
- else
- render_api_error!(result[:message], result[:http_status])
- end
- end
-
- desc "Update a tag's release note" do
- detail 'This feature was deprecated in GitLab 11.7.'
- success Entities::TagRelease
- end
- params do
- requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
- requires :description, type: String, desc: 'Release notes with markdown support'
- end
- put ':id/repository/tags/:tag_name/release', requirements: TAG_ENDPOINT_REQUIREMENTS, feature_category: :release_orchestration do
- authorize_update_release!
-
- result = ::Releases::UpdateService
- .new(user_project, current_user, declared_params(include_missing: false))
- .execute
-
- if result[:status] == :success
- present result[:release], with: Entities::TagRelease
- else
- render_api_error!(result[:message], result[:http_status])
- end
- end
- end
-
- helpers do
- def authorize_create_release!
- authorize! :create_release, user_project
- end
-
- def authorize_update_release!
- authorize! :update_release, release
- end
-
- def release
- @release ||= user_project.releases.find_by_tag(params[:tag])
- end
end
end
end
diff --git a/lib/api/terraform/modules/v1/packages.rb b/lib/api/terraform/modules/v1/packages.rb
index 34e77e09800..aa59b6a4fee 100644
--- a/lib/api/terraform/modules/v1/packages.rb
+++ b/lib/api/terraform/modules/v1/packages.rb
@@ -124,7 +124,7 @@ module API
end
get do
- track_package_event('pull_package', :terraform_module)
+ track_package_event('pull_package', :terraform_module, project: package.project, namespace: module_namespace, user: current_user)
present_carrierwave_file!(package_file.file)
end
@@ -183,7 +183,7 @@ module API
render_api_error!(result[:message], result[:http_status]) if result[:status] == :error
- track_package_event('push_package', :terraform_module)
+ track_package_event('push_package', :terraform_module, project: authorized_user_project, user: current_user, namespace: authorized_user_project.namespace)
created!
rescue ObjectStorage::RemoteStoreError => e
diff --git a/lib/api/unleash.rb b/lib/api/unleash.rb
index 3148c56339a..37fe540cde1 100644
--- a/lib/api/unleash.rb
+++ b/lib/api/unleash.rb
@@ -69,10 +69,7 @@ module API
def feature_flags
return [] unless unleash_app_name.present?
- legacy_flags = Operations::FeatureFlagScope.for_unleash_client(project, unleash_app_name)
- new_version_flags = Operations::FeatureFlag.for_unleash_client(project, unleash_app_name)
-
- legacy_flags + new_version_flags
+ Operations::FeatureFlag.for_unleash_client(project, unleash_app_name)
end
end
end
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 565a3544da2..2608fb87e22 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -241,7 +241,7 @@ module API
authenticated_as_admin!
params = declared_params(include_missing: false)
- user = ::Users::CreateService.new(current_user, params).execute(skip_authorization: true)
+ user = ::Users::AuthorizedCreateService.new(current_user, params).execute
if user.persisted?
present user, with: Entities::UserWithAdmin, current_user: current_user
@@ -1025,7 +1025,9 @@ module API
detail 'This feature was introduced in GitLab 13.10.'
end
params do
- requires :view_diffs_file_by_file, type: Boolean, desc: 'Flag indicating the user sees only one file diff per page'
+ optional :view_diffs_file_by_file, type: Boolean, desc: 'Flag indicating the user sees only one file diff per page'
+ optional :show_whitespace_in_diffs, type: Boolean, desc: 'Flag indicating the user sees whitespace changes in diffs'
+ at_least_one_of :view_diffs_file_by_file, :show_whitespace_in_diffs
end
put "preferences", feature_category: :users do
authenticate!
@@ -1043,6 +1045,14 @@ module API
end
end
+ desc "Get the current user's preferences" do
+ success Entities::UserPreferences
+ detail 'This feature was introduced in GitLab 14.0.'
+ end
+ get "preferences", feature_category: :users do
+ present current_user.user_preference, with: Entities::UserPreferences
+ end
+
desc 'Get a single email address owned by the currently authenticated user' do
success Entities::Email
end