503 lines
24 KiB
Ruby
503 lines
24 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module API
|
|
module Conan
|
|
module V2
|
|
class ProjectPackages < ::API::Base
|
|
MAX_FILES_COUNT = MAX_PACKAGE_REVISIONS_COUNT = 1000
|
|
|
|
before do
|
|
if Feature.disabled?(:conan_package_revisions_support, Feature.current_request)
|
|
not_found!("'conan_package_revisions_support' feature flag is disabled")
|
|
end
|
|
end
|
|
|
|
helpers do
|
|
include Gitlab::Utils::StrongMemoize
|
|
def package_files(finder_params)
|
|
::Packages::Conan::PackageFilesFinder
|
|
.new(package, **finder_params)
|
|
.execute
|
|
.limit(MAX_FILES_COUNT)
|
|
.select(:file_name)
|
|
end
|
|
|
|
def track_conan_package_event(event)
|
|
track_package_event(event, :conan, category: 'API::ConanPackages', project: project,
|
|
namespace: project.namespace)
|
|
end
|
|
|
|
def destroy_package_entity(entity, event_name)
|
|
track_conan_package_event(event_name)
|
|
|
|
entity.transaction do
|
|
::Packages::MarkPackageFilesForDestructionService.new(entity.package_files).execute
|
|
destroy_conditionally!(entity) do
|
|
entity.destroy
|
|
|
|
# Conan cli expects 200 status code when deleting
|
|
status 200
|
|
end
|
|
end
|
|
end
|
|
|
|
def recipe_revision
|
|
package.conan_recipe_revisions.find_by_revision(params[:recipe_revision])
|
|
end
|
|
strong_memoize_attr :recipe_revision
|
|
|
|
def package_revisions
|
|
package.conan_package_revisions
|
|
.by_recipe_revision_and_package_reference(params[:recipe_revision],
|
|
params[:conan_package_reference])
|
|
end
|
|
|
|
def package_revision
|
|
package_revisions.find_by_revision(params[:package_revision])
|
|
end
|
|
strong_memoize_attr :package_revision
|
|
end
|
|
|
|
params do
|
|
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/conan/v2' do
|
|
include ::API::Concerns::Packages::Conan::SharedEndpoints
|
|
params do
|
|
with(type: String) do
|
|
requires :package_name, regexp: PACKAGE_COMPONENT_REGEX,
|
|
desc: 'Package name', documentation: { example: 'my-package' }
|
|
requires :package_version, regexp: PACKAGE_COMPONENT_REGEX,
|
|
desc: 'Package version', documentation: { example: '1.0' }
|
|
requires :package_username, regexp: CONAN_REVISION_USER_CHANNEL_REGEX,
|
|
desc: 'Package username', documentation: { example: 'my-group+my-project' }
|
|
requires :package_channel, regexp: CONAN_REVISION_USER_CHANNEL_REGEX,
|
|
desc: 'Package channel', documentation: { example: 'stable' }
|
|
end
|
|
end
|
|
namespace 'conans/:package_name/:package_version/:package_username/:package_channel',
|
|
requirements: PACKAGE_REQUIREMENTS do
|
|
after_validation do
|
|
check_username_channel
|
|
end
|
|
|
|
namespace 'latest' do
|
|
desc 'Get the latest recipe revision' do
|
|
detail 'This feature was introduced in GitLab 17.11'
|
|
success code: 200, model: ::API::Entities::Packages::Conan::Revision
|
|
failure [
|
|
{ code: 400, message: 'Bad Request' },
|
|
{ code: 401, message: 'Unauthorized' },
|
|
{ code: 403, message: 'Forbidden' },
|
|
{ code: 404, message: 'Not Found' }
|
|
]
|
|
tags %w[conan_packages]
|
|
end
|
|
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true
|
|
route_setting :authorization, job_token_policies: :read_packages,
|
|
allow_public_access_for_enabled_project_features: :package_registry
|
|
get urgency: :low do
|
|
not_found!('Package') unless package
|
|
|
|
revision = package.conan_recipe_revisions.order_by_id_desc.first
|
|
|
|
not_found!('Revision') unless revision.present?
|
|
|
|
present revision, with: ::API::Entities::Packages::Conan::Revision
|
|
end
|
|
end
|
|
namespace 'revisions' do
|
|
desc 'Get the list of revisions' do
|
|
detail 'This feature was introduced in GitLab 17.11'
|
|
success code: 200, model: ::API::Entities::Packages::Conan::RecipeRevisions
|
|
failure [
|
|
{ code: 400, message: 'Bad Request' },
|
|
{ code: 401, message: 'Unauthorized' },
|
|
{ code: 403, message: 'Forbidden' },
|
|
{ code: 404, message: 'Not Found' }
|
|
]
|
|
tags %w[conan_packages]
|
|
end
|
|
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true
|
|
route_setting :authorization, job_token_policies: :read_packages,
|
|
allow_public_access_for_enabled_project_features: :package_registry
|
|
get urgency: :low do
|
|
not_found!('Package') unless package
|
|
|
|
present package, with: ::API::Entities::Packages::Conan::RecipeRevisions
|
|
end
|
|
params do
|
|
requires :recipe_revision, type: String, regexp: Gitlab::Regex.conan_revision_regex_v2,
|
|
desc: 'Recipe revision', documentation: { example: 'df28fd816be3a119de5ce4d374436b25' }
|
|
end
|
|
namespace ':recipe_revision' do
|
|
desc 'Delete recipe revision' do
|
|
detail 'This feature was introduced in GitLab 18.1'
|
|
success code: 200
|
|
failure [
|
|
{ code: 400, message: 'Bad Request' },
|
|
{ code: 401, message: 'Unauthorized' },
|
|
{ code: 403, message: 'Forbidden' },
|
|
{ code: 404, message: 'Not Found' }
|
|
]
|
|
tags %w[conan_packages]
|
|
end
|
|
|
|
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true
|
|
route_setting :authorization, job_token_policies: :admin_packages
|
|
|
|
delete urgency: :low do
|
|
authorize_destroy_package!(project)
|
|
|
|
not_found!('Package') unless package
|
|
|
|
not_found!('Revision') unless recipe_revision
|
|
|
|
if package.conan_recipe_revisions.one?
|
|
track_conan_package_event('delete_package')
|
|
destroy_conditionally!(package) do |package|
|
|
::Packages::MarkPackageForDestructionService.new(container: package,
|
|
current_user: current_user).execute
|
|
|
|
# Conan cli expects 200 status code when deleting a recipe revision
|
|
status 200
|
|
end
|
|
else
|
|
if recipe_revision.package_files.size > MAX_FILES_COUNT
|
|
unprocessable_entity! "Cannot delete more than #{MAX_FILES_COUNT} files"
|
|
end
|
|
|
|
destroy_package_entity(recipe_revision, 'delete_recipe_revision')
|
|
end
|
|
end
|
|
|
|
namespace 'files' do
|
|
desc 'List recipe files' do
|
|
detail 'This feature was introduced in GitLab 17.11'
|
|
success code: 200, model: ::API::Entities::Packages::Conan::FilesList
|
|
failure [
|
|
{ code: 400, message: 'Bad Request' },
|
|
{ code: 401, message: 'Unauthorized' },
|
|
{ code: 403, message: 'Forbidden' },
|
|
{ code: 404, message: 'Not Found' }
|
|
]
|
|
tags %w[conan_packages]
|
|
end
|
|
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true
|
|
route_setting :authorization, job_token_policies: :read_packages,
|
|
allow_public_access_for_enabled_project_features: :package_registry
|
|
get urgency: :low do
|
|
not_found!('Package') unless package
|
|
|
|
files = package_files(conan_file_type: :recipe_file, recipe_revision: params[:recipe_revision])
|
|
not_found!('Recipe files') if files.empty?
|
|
|
|
present({ files: }, with: ::API::Entities::Packages::Conan::FilesList)
|
|
end
|
|
|
|
params do
|
|
requires :file_name, type: String, desc: 'Package file name', values: CONAN_FILES,
|
|
documentation: { example: 'conanfile.py' }
|
|
end
|
|
namespace ':file_name', requirements: FILE_NAME_REQUIREMENTS do
|
|
desc 'Download recipe files' do
|
|
detail 'This feature was introduced in GitLab 17.8'
|
|
success code: 200
|
|
failure [
|
|
{ code: 400, message: 'Bad Request' },
|
|
{ code: 401, message: 'Unauthorized' },
|
|
{ code: 403, message: 'Forbidden' },
|
|
{ code: 404, message: 'Not Found' }
|
|
]
|
|
tags %w[conan_packages]
|
|
end
|
|
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true
|
|
route_setting :authorization, job_token_policies: :read_packages,
|
|
allow_public_access_for_enabled_project_features: :package_registry
|
|
get urgency: :low do
|
|
download_package_file(:recipe_file)
|
|
end
|
|
|
|
desc 'Upload recipe package files' do
|
|
detail 'This feature was introduced in GitLab 17.10'
|
|
success code: 200
|
|
failure [
|
|
{ code: 400, message: 'Bad Request' },
|
|
{ code: 401, message: 'Unauthorized' },
|
|
{ code: 403, message: 'Forbidden' },
|
|
{ code: 404, message: 'Not Found' }
|
|
]
|
|
tags %w[conan_packages]
|
|
end
|
|
|
|
params do
|
|
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
|
|
route_setting :authorization, job_token_policies: :admin_packages
|
|
|
|
put urgency: :low do
|
|
upload_package_file(:recipe_file)
|
|
end
|
|
|
|
desc 'Workhorse authorize the conan recipe file' do
|
|
detail 'This feature was introduced in GitLab 17.10'
|
|
success code: 200
|
|
failure [
|
|
{ code: 400, message: 'Bad Request' },
|
|
{ code: 401, message: 'Unauthorized' },
|
|
{ code: 403, message: 'Forbidden' },
|
|
{ code: 404, message: 'Not Found' }
|
|
]
|
|
tags %w[conan_packages]
|
|
end
|
|
|
|
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true
|
|
route_setting :authorization, job_token_policies: :admin_packages
|
|
|
|
put 'authorize', urgency: :low do
|
|
authorize_workhorse!(subject: project, maximum_size: project.actual_limits.conan_max_file_size)
|
|
end
|
|
end
|
|
end
|
|
|
|
desc 'Get package references metadata' do
|
|
detail 'This feature was introduced in GitLab 18.1'
|
|
success code: 200
|
|
failure [
|
|
{ code: 400, message: 'Bad Request' },
|
|
{ code: 401, message: 'Unauthorized' },
|
|
{ code: 403, message: 'Forbidden' },
|
|
{ code: 404, message: 'Not Found' }
|
|
]
|
|
tags %w[conan_packages]
|
|
end
|
|
|
|
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true
|
|
route_setting :authorization, job_token_policies: :read_packages,
|
|
allow_public_access_for_enabled_project_features: :package_registry
|
|
|
|
get 'search', urgency: :low do
|
|
check_username_channel
|
|
|
|
authorize_read_package!(project)
|
|
not_found!('Package') unless package
|
|
not_found!('Revision') unless recipe_revision.present?
|
|
|
|
recipe_revision.conan_package_references.pluck_reference_and_info.to_h
|
|
end
|
|
|
|
params do
|
|
requires :conan_package_reference, type: String,
|
|
regexp: Gitlab::Regex.conan_package_reference_regex, desc: 'Package reference',
|
|
documentation: { example: '5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9' }
|
|
end
|
|
namespace 'packages/:conan_package_reference' do
|
|
namespace 'latest' do
|
|
desc 'Get the latest package revision' do
|
|
detail 'This feature was introduced in GitLab 17.11'
|
|
success code: 200, model: ::API::Entities::Packages::Conan::Revision
|
|
failure [
|
|
{ code: 400, message: 'Bad Request' },
|
|
{ code: 401, message: 'Unauthorized' },
|
|
{ code: 403, message: 'Forbidden' },
|
|
{ code: 404, message: 'Not Found' }
|
|
]
|
|
tags %w[conan_packages]
|
|
end
|
|
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true
|
|
route_setting :authorization, job_token_policies: :read_packages,
|
|
allow_public_access_for_enabled_project_features: :package_registry
|
|
get urgency: :low do
|
|
not_found!('Package') unless package
|
|
|
|
revision = package_revisions.order_by_id_desc.first
|
|
|
|
not_found!('Revision') unless revision.present?
|
|
|
|
present revision, with: ::API::Entities::Packages::Conan::Revision
|
|
end
|
|
end
|
|
namespace 'revisions' do
|
|
desc 'Get the list of package revisions' do
|
|
detail 'This feature was introduced in GitLab 18.0'
|
|
success code: 200, model: ::API::Entities::Packages::Conan::PackageRevisions
|
|
failure [
|
|
{ code: 400, message: 'Bad Request' },
|
|
{ code: 401, message: 'Unauthorized' },
|
|
{ code: 403, message: 'Forbidden' },
|
|
{ code: 404, message: 'Not Found' }
|
|
]
|
|
tags %w[conan_packages]
|
|
end
|
|
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true
|
|
route_setting :authorization, job_token_policies: :read_packages,
|
|
allow_public_access_for_enabled_project_features: :package_registry
|
|
get urgency: :low do
|
|
not_found!('Package') unless package
|
|
|
|
revisions = package_revisions
|
|
.order_by_id_desc
|
|
.limit(MAX_PACKAGE_REVISIONS_COUNT)
|
|
|
|
package_reference = "#{package.conan_recipe}##{params[:recipe_revision]}:" \
|
|
"#{params[:conan_package_reference]}"
|
|
present({ package_reference: package_reference, package_revisions: revisions },
|
|
with: ::API::Entities::Packages::Conan::PackageRevisions)
|
|
end
|
|
|
|
params do
|
|
requires :package_revision, type: String, regexp: Gitlab::Regex.conan_revision_regex_v2,
|
|
desc: 'Package revision', documentation: { example: '3bdd2d8c8e76c876ebd1ac0469a4e72c' }
|
|
end
|
|
namespace ':package_revision' do
|
|
desc 'Delete package revision' do
|
|
detail 'This feature was introduced in GitLab 18.1'
|
|
success code: 200
|
|
failure [
|
|
{ code: 400, message: 'Bad Request' },
|
|
{ code: 401, message: 'Unauthorized' },
|
|
{ code: 403, message: 'Forbidden' },
|
|
{ code: 404, message: 'Not Found' }
|
|
]
|
|
tags %w[conan_packages]
|
|
end
|
|
|
|
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true
|
|
route_setting :authorization, job_token_policies: :admin_packages
|
|
|
|
delete urgency: :low do
|
|
authorize_destroy_package!(project)
|
|
|
|
not_found!('Package') unless package
|
|
|
|
not_found!('Package Revision') unless package_revision
|
|
|
|
if package_revision.package_files.size > MAX_FILES_COUNT
|
|
unprocessable_entity! "Cannot delete more than #{MAX_FILES_COUNT} files"
|
|
end
|
|
|
|
if package_revisions.one?
|
|
destroy_package_entity(package_revision.package_reference, 'delete_package_reference')
|
|
else
|
|
destroy_package_entity(package_revision, 'delete_package_revision')
|
|
end
|
|
end
|
|
namespace 'files' do
|
|
desc 'List package files' do
|
|
detail 'This feature was introduced in GitLab 18.0'
|
|
success code: 200, model: ::API::Entities::Packages::Conan::FilesList
|
|
failure [
|
|
{ code: 400, message: 'Bad Request' },
|
|
{ code: 401, message: 'Unauthorized' },
|
|
{ code: 403, message: 'Forbidden' },
|
|
{ code: 404, message: 'Not Found' }
|
|
]
|
|
tags %w[conan_packages]
|
|
end
|
|
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true
|
|
route_setting :authorization, job_token_policies: :read_packages,
|
|
allow_public_access_for_enabled_project_features: :package_registry
|
|
get urgency: :low do
|
|
not_found!('Package') unless package
|
|
|
|
files = package_files(conan_file_type: :package_file,
|
|
recipe_revision: params[:recipe_revision],
|
|
conan_package_reference: params[:conan_package_reference],
|
|
package_revision: params[:package_revision])
|
|
|
|
not_found!('Package files') if files.empty?
|
|
|
|
present({ files: }, with: ::API::Entities::Packages::Conan::FilesList)
|
|
end
|
|
|
|
params do
|
|
requires :file_name, type: String, desc: 'Package file name', values: CONAN_FILES,
|
|
documentation: { example: 'conaninfo.txt' }
|
|
end
|
|
namespace ':file_name', requirements: FILE_NAME_REQUIREMENTS do
|
|
desc 'Download package files' do
|
|
detail 'This feature was introduced in GitLab 17.11'
|
|
success code: 200
|
|
failure [
|
|
{ code: 400, message: 'Bad Request' },
|
|
{ code: 401, message: 'Unauthorized' },
|
|
{ code: 403, message: 'Forbidden' },
|
|
{ code: 404, message: 'Not Found' }
|
|
]
|
|
tags %w[conan_packages]
|
|
end
|
|
route_setting :authentication, job_token_allowed: true,
|
|
basic_auth_personal_access_token: true
|
|
route_setting :authorization, job_token_policies: :read_packages,
|
|
allow_public_access_for_enabled_project_features: :package_registry
|
|
get urgency: :low do
|
|
download_package_file(:package_file)
|
|
end
|
|
|
|
desc 'Upload package files' do
|
|
detail 'This feature was introduced in GitLab 17.11'
|
|
success code: 200
|
|
failure [
|
|
{ code: 400, message: 'Bad Request' },
|
|
{ code: 401, message: 'Unauthorized' },
|
|
{ code: 403, message: 'Forbidden' },
|
|
{ code: 404, message: 'Not Found' }
|
|
]
|
|
tags %w[conan_packages]
|
|
end
|
|
|
|
params do
|
|
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
|
|
route_setting :authorization, job_token_policies: :admin_packages
|
|
|
|
put urgency: :low do
|
|
upload_package_file(:package_file)
|
|
end
|
|
|
|
desc 'Workhorse authorize the conan package file' do
|
|
detail 'This feature was introduced in GitLab 17.11'
|
|
success code: 200
|
|
failure [
|
|
{ code: 400, message: 'Bad Request' },
|
|
{ code: 401, message: 'Unauthorized' },
|
|
{ code: 403, message: 'Forbidden' },
|
|
{ code: 404, message: 'Not Found' }
|
|
]
|
|
tags %w[conan_packages]
|
|
end
|
|
|
|
route_setting :authentication, job_token_allowed: true,
|
|
basic_auth_personal_access_token: true
|
|
route_setting :authorization, job_token_policies: :admin_packages
|
|
|
|
put 'authorize', urgency: :low do
|
|
authorize_workhorse!(subject: project,
|
|
maximum_size: project.actual_limits.conan_max_file_size)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|