Commit 9dacf17d authored by Steve Abrams's avatar Steve Abrams Committed by Thong Kuah

Conan download_urls endpoints

Endpoints that return the file download urls for
conan package files to the conan client.
parent a48a780d
# frozen_string_literal: true # frozen_string_literal: true
# Conan Package Manager Client API
#
# These API endpoints are not consumed directly by users, so there is no documentation for the
# individual endpoints. They are called by the Conan package manager client when users run commands
# like `conan install` or `conan upload`. The usage of the GitLab Conan repository is documented here:
# https://docs.gitlab.com/ee/user/packages/conan_repository/#installing-a-package
#
# Technical debt: https://gitlab.com/gitlab-org/gitlab/issues/35798
module API module API
class ConanPackages < Grape::API class ConanPackages < Grape::API
helpers ::API::Helpers::PackagesHelpers helpers ::API::Helpers::PackagesHelpers
...@@ -108,26 +116,34 @@ module API ...@@ -108,26 +116,34 @@ module API
detail 'This feature was introduced in GitLab 12.5' detail 'This feature was introduced in GitLab 12.5'
end end
get 'packages/:conan_package_reference/digest' do get 'packages/:conan_package_reference/digest' do
authorize!(:read_package, project) present_package_download_urls
presenter = ConanPackagePresenter.new(recipe, current_user, project)
render_api_error!("No recipe manifest found", 404) if presenter.package_urls.empty?
present presenter, with: EE::API::Entities::ConanPackage::ConanPackageManifest
end end
desc 'Recipe Digest' do desc 'Recipe Digest' do
detail 'This feature was introduced in GitLab 12.5' detail 'This feature was introduced in GitLab 12.5'
end end
get 'digest' do get 'digest' do
authorize!(:read_package, project) present_recipe_download_urls
end
presenter = ConanPackagePresenter.new(recipe, current_user, project)
render_api_error!("No recipe manifest found", 404) if presenter.recipe_urls.empty? # Get the download urls
#
# returns the download urls for the existing recipe or package in the registry
#
# the manifest is a hash of { filename: url }
# where the url is the download url for the file
desc 'Package Download Urls' do
detail 'This feature was introduced in GitLab 12.5'
end
get 'packages/:conan_package_reference/download_urls' do
present_package_download_urls
end
present presenter, with: EE::API::Entities::ConanPackage::ConanRecipeManifest desc 'Recipe Download Urls' do
detail 'This feature was introduced in GitLab 12.5'
end
get 'download_urls' do
present_recipe_download_urls
end end
# Get the upload urls # Get the upload urls
...@@ -205,6 +221,26 @@ module API ...@@ -205,6 +221,26 @@ module API
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
include ::API::Helpers::RelatedResourcesHelpers include ::API::Helpers::RelatedResourcesHelpers
def present_package_download_urls
authorize!(:read_package, project)
presenter = ConanPackagePresenter.new(recipe, current_user, project)
render_api_error!("No recipe manifest found", 404) if presenter.package_urls.empty?
present presenter, with: EE::API::Entities::ConanPackage::ConanPackageManifest
end
def present_recipe_download_urls
authorize!(:read_package, project)
presenter = ConanPackagePresenter.new(recipe, current_user, project)
render_api_error!("No recipe manifest found", 404) if presenter.recipe_urls.empty?
present presenter, with: EE::API::Entities::ConanPackage::ConanRecipeManifest
end
def recipe_upload_urls(file_names) def recipe_upload_urls(file_names)
{ upload_urls: Hash[ { upload_urls: Hash[
file_names.collect do |file_name| file_names.collect do |file_name|
......
...@@ -234,10 +234,45 @@ describe API::ConanPackages do ...@@ -234,10 +234,45 @@ describe API::ConanPackages do
end end
end end
shared_examples 'recipe download_urls' do
let(:recipe_path) { package.conan_recipe_path }
it 'returns the download_urls for the recipe files' do
expected_response = {
'conanfile.py' => "#{Settings.gitlab.base_url}/api/v4/packages/conan/v1/files/#{package.conan_recipe_path}/0/export/conanfile.py",
'conanmanifest.txt' => "#{Settings.gitlab.base_url}/api/v4/packages/conan/v1/files/#{package.conan_recipe_path}/0/export/conanmanifest.txt"
}
allow(presenter).to receive(:recipe_urls) { expected_response }
subject
expect(json_response).to eq(expected_response)
end
end
shared_examples 'package download_urls' do
let(:recipe_path) { package.conan_recipe_path }
it 'returns the download_urls for the package files' do
expected_response = {
'conaninfo.txt' => "#{Settings.gitlab.base_url}/api/v4/packages/conan/v1/files/#{package.conan_recipe_path}/0/package/123456789/0/conaninfo.txt",
'conanmanifest.txt' => "#{Settings.gitlab.base_url}/api/v4/packages/conan/v1/files/#{package.conan_recipe_path}/0/package/123456789/0/conanmanifest.txt",
'conan_package.tgz' => "#{Settings.gitlab.base_url}/api/v4/packages/conan/v1/files/#{package.conan_recipe_path}/0/package/123456789/0/conan_package.tgz"
}
allow(presenter).to receive(:package_urls) { expected_response }
subject
expect(json_response).to eq(expected_response)
end
end
context 'recipe endpoints' do context 'recipe endpoints' do
let(:jwt) { build_jwt(personal_access_token) } let(:jwt) { build_jwt(personal_access_token) }
let(:headers) { build_auth_headers(jwt.encoded) } let(:headers) { build_auth_headers(jwt.encoded) }
let(:package_id) { '123456789' } let(:conan_package_reference) { '123456789' }
let(:presenter) { double('ConanPackagePresenter') } let(:presenter) { double('ConanPackagePresenter') }
before do before do
...@@ -271,10 +306,10 @@ describe API::ConanPackages do ...@@ -271,10 +306,10 @@ describe API::ConanPackages do
end end
end end
describe 'GET /api/v4/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel/packages/:package_id' do describe 'GET /api/v4/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel/packages/:conan_package_reference' do
let(:recipe_path) { package.conan_recipe_path } let(:recipe_path) { package.conan_recipe_path }
subject { get api("/packages/conan/v1/conans/#{recipe_path}/packages/#{package_id}"), headers: headers } subject { get api("/packages/conan/v1/conans/#{recipe_path}/packages/#{conan_package_reference}"), headers: headers }
it_behaves_like 'rejects invalid recipe' it_behaves_like 'rejects invalid recipe'
it_behaves_like 'rejects recipe for invalid project' it_behaves_like 'rejects recipe for invalid project'
...@@ -302,48 +337,31 @@ describe API::ConanPackages do ...@@ -302,48 +337,31 @@ describe API::ConanPackages do
it_behaves_like 'rejects invalid recipe' it_behaves_like 'rejects invalid recipe'
it_behaves_like 'rejects recipe for invalid project' it_behaves_like 'rejects recipe for invalid project'
it_behaves_like 'recipe download_urls'
context 'with existing package' do
let(:recipe_path) { package.conan_recipe_path }
it 'returns the download urls for each package file' do
expected_response = {
'conanfile.py' => "#{Settings.gitlab.base_url}/api/v4/packages/conan/v1/files/#{package.conan_recipe_path}/0/export/conanfile.py",
'conanmanifest.txt' => "#{Settings.gitlab.base_url}/api/v4/packages/conan/v1/files/#{package.conan_recipe_path}/0/export/conanmanifest.txt"
}
allow(presenter).to receive(:recipe_urls) { expected_response }
subject
expect(json_response).to eq(expected_response)
end
end
end end
describe 'GET /api/v4/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel/packages/:package_id/digest' do describe 'GET /api/v4/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel/packages/:conan_package_reference/download_urls' do
subject { get api("/packages/conan/v1/conans/#{recipe_path}/packages/#{package_id}/digest"), headers: headers } subject { get api("/packages/conan/v1/conans/#{recipe_path}/packages/#{conan_package_reference}/download_urls"), headers: headers }
it_behaves_like 'rejects invalid recipe' it_behaves_like 'rejects invalid recipe'
it_behaves_like 'rejects recipe for invalid project' it_behaves_like 'rejects recipe for invalid project'
it_behaves_like 'package download_urls'
end
context 'with existing package' do describe 'GET /api/v4/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel/download_urls' do
let(:recipe_path) { package.conan_recipe_path } subject { get api("/packages/conan/v1/conans/#{recipe_path}/download_urls"), headers: headers }
it 'returns the download urls for the files' do
expected_response = {
'conaninfo.txt' => "#{Settings.gitlab.base_url}/api/v4/packages/conan/v1/files/#{package.conan_recipe_path}/0/package/123456789/0/conaninfo.txt",
'conanmanifest.txt' => "#{Settings.gitlab.base_url}/api/v4/packages/conan/v1/files/#{package.conan_recipe_path}/0/package/123456789/0/conanmanifest.txt",
'conan_package.tgz' => "#{Settings.gitlab.base_url}/api/v4/packages/conan/v1/files/#{package.conan_recipe_path}/0/package/123456789/0/conan_package.tgz"
}
allow(presenter).to receive(:package_urls) { expected_response } it_behaves_like 'rejects invalid recipe'
it_behaves_like 'rejects recipe for invalid project'
it_behaves_like 'recipe download_urls'
end
subject describe 'GET /api/v4/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel/packages/:conan_package_reference/digest' do
subject { get api("/packages/conan/v1/conans/#{recipe_path}/packages/#{conan_package_reference}/digest"), headers: headers }
expect(json_response).to eq(expected_response) it_behaves_like 'rejects invalid recipe'
end it_behaves_like 'rejects recipe for invalid project'
end it_behaves_like 'package download_urls'
end end
describe 'POST /api/v4/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel/upload_urls' do describe 'POST /api/v4/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel/upload_urls' do
...@@ -370,7 +388,7 @@ describe API::ConanPackages do ...@@ -370,7 +388,7 @@ describe API::ConanPackages do
end end
end end
describe 'POST /api/v4/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel/packages/:package_id/upload_urls' do describe 'POST /api/v4/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel/packages/:conan_package_reference/upload_urls' do
let(:recipe_path) { package.conan_recipe_path } let(:recipe_path) { package.conan_recipe_path }
let(:params) do let(:params) do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment