lib/api/conan/v2/project_packages.rb (381 lines of code) (raw):
# 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 recipe_revision
package.conan_recipe_revisions.find_by_revision(params[:recipe_revision])
end
strong_memoize_attr :recipe_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
track_conan_package_event('delete_recipe_revision')
if recipe_revision.package_files.size > MAX_FILES_COUNT
unprocessable_entity! "Cannot delete more than #{MAX_FILES_COUNT} files"
end
recipe_revision.transaction do
::Packages::MarkPackageFilesForDestructionService.new(recipe_revision.package_files).execute
destroy_conditionally!(recipe_revision) do |recipe_revision|
recipe_revision.destroy
# Conan cli expects 200 status code when deleting a recipe revision
status 200
end
end
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
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.conan_package_revisions
.by_recipe_revision_and_package_reference(params[:recipe_revision],
params[:conan_package_reference]).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
package_revisions = package
.conan_package_revisions
.by_recipe_revision_and_package_reference(params[:recipe_revision],
params[:conan_package_reference])
.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_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
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