Commit d2f55f9a authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Add instance-level maven endpoint for download

Signed-off-by: default avatarDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
parent b3bb56d4
......@@ -119,6 +119,31 @@ on the home page of your project.
If you have a self-hosted GitLab installation, replace `gitlab.com` with your
domain name.
## Instance level Maven endpoint
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/8274) in GitLab Premium 11.6.
If you rely on many packages, it might be inefficient to include the `repository` section
with a unique URL for each package. Instead, you can use the instance level endpoint for
all maven packages stored in GitLab. Only packages you have access to
will be available for download. Here's how the relevant `repository` section of
your `pom.xml` would look like:
```xml
<repositories>
<repository>
<id>gitlab-maven</id>
<url>https://gitlab.com/api/v4/packages/maven</url>
</repository>
</repositories>
```
If you have a self-hosted GitLab installation, replace `gitlab.com` with your
domain name.
You still need a project specific URL for uploading a package
in the `distributionManagement` section.
## Uploading packages
Once you have set up the [authorization](#authorizing-with-the-gitlab-maven-repository)
......
# frozen_string_literal: true
class Packages::MavenPackageFinder
attr_reader :project, :path
attr_reader :path, :project
def initialize(project, path)
@project = project
def initialize(path, project = nil)
@path = path
@project = project
end
def execute
......@@ -17,9 +17,17 @@ class Packages::MavenPackageFinder
private
def scope
if project
project.packages
else
::Packages::Package.all
end
end
# rubocop: disable CodeReuse/ActiveRecord
def packages
project.packages.joins(:maven_metadatum)
scope.joins(:maven_metadatum)
.where(packages_maven_metadata: { path: path })
end
# rubocop: enable CodeReuse/ActiveRecord
......
......@@ -5,7 +5,7 @@ module Packages
def execute
package = ::Packages::MavenPackageFinder
.new(project, params[:path]).execute
.new(params[:path], project).execute
unless package
if params[:file_name] == MAVEN_METADATA_FILE
......
---
title: Add an instance-level endpoint for downloading maven packages
merge_request: 8274
author:
type: added
......@@ -12,7 +12,6 @@ module API
before do
require_packages_enabled!
authenticate_non_get!
authorize_packages_feature!
end
helpers do
......@@ -54,10 +53,44 @@ module API
end
end
desc 'Download the maven package file at instance level' do
detail 'This feature was introduced in GitLab 11.6'
end
params do
requires :path, type: String, desc: 'Package path'
requires :file_name, type: String, desc: 'Package file name'
end
route_setting :authentication, job_token_allowed: true
get 'packages/maven/*path/:file_name', requirements: MAVEN_ENDPOINT_REQUIREMENTS do
file_name, format = extract_format(params[:file_name])
package = ::Packages::MavenPackageFinder.new(params[:path]).execute!
forbidden! unless package.project.feature_available?(:packages)
authorize!(:read_package, package.project)
package_file = ::Packages::PackageFileFinder
.new(package, file_name).execute!
case format
when 'md5'
package_file.file_md5
when 'sha1'
package_file.file_sha1
when nil
present_carrierwave_file!(package_file.file)
end
end
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
before do
authorize_packages_feature!
end
desc 'Download the maven package file' do
detail 'This feature was introduced in GitLab 11.3'
end
......@@ -72,7 +105,7 @@ module API
file_name, format = extract_format(params[:file_name])
package = ::Packages::MavenPackageFinder
.new(user_project, params[:path]).execute!
.new(params[:path], user_project).execute!
package_file = ::Packages::PackageFileFinder
.new(package, file_name).execute!
......
......@@ -6,16 +6,32 @@ describe Packages::MavenPackageFinder do
let(:package) { create(:maven_package, project: project) }
describe '#execute!' do
it 'returns a package' do
finder = described_class.new(project, package.maven_metadatum.path)
context 'within the project' do
it 'returns a package' do
finder = described_class.new(package.maven_metadatum.path, project)
expect(finder.execute!).to eq(package)
expect(finder.execute!).to eq(package)
end
it 'raises an error' do
finder = described_class.new('com/example/my-app/1.0-SNAPSHOT', project)
expect { finder.execute! }.to raise_error(ActiveRecord::RecordNotFound)
end
end
it 'raises an error' do
finder = described_class.new(project, 'com/example/my-app/1.0-SNAPSHOT')
context 'across all projects' do
it 'returns a package' do
finder = described_class.new(package.maven_metadatum.path)
expect(finder.execute!).to eq(package)
end
it 'raises an error' do
finder = described_class.new('com/example/my-app/1.0-SNAPSHOT')
expect { finder.execute! }.to raise_error(ActiveRecord::RecordNotFound)
expect { finder.execute! }.to raise_error(ActiveRecord::RecordNotFound)
end
end
end
end
......@@ -15,6 +15,106 @@ describe API::MavenPackages do
stub_licensed_features(packages: true)
end
describe 'GET /api/v4/packages/maven/*path/:file_name' do
let(:package) { create(:maven_package, project: project) }
let(:maven_metadatum) { package.maven_metadatum }
let(:package_file_xml) { package.package_files.find_by(file_type: 'xml') }
context 'a public project' do
it 'returns the file' do
download_file(package_file_xml.file_name)
expect(response).to have_gitlab_http_status(200)
expect(response.content_type.to_s).to eq('application/octet-stream')
end
it 'returns sha1 of the file' do
download_file(package_file_xml.file_name + '.sha1')
expect(response).to have_gitlab_http_status(200)
expect(response.content_type.to_s).to eq('text/plain')
expect(response.body).to eq(package_file_xml.file_sha1)
end
end
context 'internal project' do
before do
project.team.truncate
project.update!(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
end
it 'returns the file' do
download_file_with_token(package_file_xml.file_name)
expect(response).to have_gitlab_http_status(200)
expect(response.content_type.to_s).to eq('application/octet-stream')
end
it 'denies download when no private token' do
download_file(package_file_xml.file_name)
expect(response).to have_gitlab_http_status(403)
end
it 'allows download with job token' do
download_file(package_file_xml.file_name, job_token: job.token)
expect(response).to have_gitlab_http_status(200)
expect(response.content_type.to_s).to eq('application/octet-stream')
end
end
context 'private project' do
before do
project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
end
it 'returns the file' do
download_file_with_token(package_file_xml.file_name)
expect(response).to have_gitlab_http_status(200)
expect(response.content_type.to_s).to eq('application/octet-stream')
end
it 'denies download when not enough permissions' do
project.add_guest(user)
download_file_with_token(package_file_xml.file_name)
expect(response).to have_gitlab_http_status(403)
end
it 'denies download when no private token' do
download_file(package_file_xml.file_name)
expect(response).to have_gitlab_http_status(403)
end
it 'allows download with job token' do
download_file(package_file_xml.file_name, job_token: job.token)
expect(response).to have_gitlab_http_status(200)
expect(response.content_type.to_s).to eq('application/octet-stream')
end
end
it 'rejects request if feature is not in the license' do
stub_licensed_features(packages: false)
download_file(package_file_xml.file_name)
expect(response).to have_gitlab_http_status(403)
end
def download_file(file_name, params = {}, request_headers = headers)
get api("/packages/maven/#{maven_metadatum.path}/#{file_name}"), params, request_headers
end
def download_file_with_token(file_name, params = {}, request_headers = headers_with_token)
download_file(file_name, params, request_headers)
end
end
describe 'GET /api/v4/projects/:id/packages/maven/*path/:file_name' do
let(:package) { create(:maven_package, project: project) }
let(:maven_metadatum) { package.maven_metadatum }
......
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