Commit 6b6e8755 authored by Douglas Barbosa Alexandre's avatar Douglas Barbosa Alexandre

Merge branch '7769-instance-level-maven-endpoint' into 'master'

Resolve "Instance level Maven endpoint"

Closes #7769

See merge request gitlab-org/gitlab-ee!8274
parents 1c969280 d2f55f9a
...@@ -119,6 +119,31 @@ on the home page of your project. ...@@ -119,6 +119,31 @@ on the home page of your project.
If you have a self-hosted GitLab installation, replace `gitlab.com` with your If you have a self-hosted GitLab installation, replace `gitlab.com` with your
domain name. 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 ## Uploading packages
Once you have set up the [authorization](#authorizing-with-the-gitlab-maven-repository) Once you have set up the [authorization](#authorizing-with-the-gitlab-maven-repository)
......
# frozen_string_literal: true # frozen_string_literal: true
class Packages::MavenPackageFinder class Packages::MavenPackageFinder
attr_reader :project, :path attr_reader :path, :project
def initialize(project, path) def initialize(path, project = nil)
@project = project
@path = path @path = path
@project = project
end end
def execute def execute
...@@ -17,9 +17,17 @@ class Packages::MavenPackageFinder ...@@ -17,9 +17,17 @@ class Packages::MavenPackageFinder
private private
def scope
if project
project.packages
else
::Packages::Package.all
end
end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def packages def packages
project.packages.joins(:maven_metadatum) scope.joins(:maven_metadatum)
.where(packages_maven_metadata: { path: path }) .where(packages_maven_metadata: { path: path })
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
......
...@@ -5,7 +5,7 @@ module Packages ...@@ -5,7 +5,7 @@ module Packages
def execute def execute
package = ::Packages::MavenPackageFinder package = ::Packages::MavenPackageFinder
.new(project, params[:path]).execute .new(params[:path], project).execute
unless package unless package
if params[:file_name] == MAVEN_METADATA_FILE 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 ...@@ -12,7 +12,6 @@ module API
before do before do
require_packages_enabled! require_packages_enabled!
authenticate_non_get! authenticate_non_get!
authorize_packages_feature!
end end
helpers do helpers do
...@@ -54,10 +53,44 @@ module API ...@@ -54,10 +53,44 @@ module API
end end
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 params do
requires :id, type: String, desc: 'The ID of a project' requires :id, type: String, desc: 'The ID of a project'
end end
resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
before do
authorize_packages_feature!
end
desc 'Download the maven package file' do desc 'Download the maven package file' do
detail 'This feature was introduced in GitLab 11.3' detail 'This feature was introduced in GitLab 11.3'
end end
...@@ -72,7 +105,7 @@ module API ...@@ -72,7 +105,7 @@ module API
file_name, format = extract_format(params[:file_name]) file_name, format = extract_format(params[:file_name])
package = ::Packages::MavenPackageFinder package = ::Packages::MavenPackageFinder
.new(user_project, params[:path]).execute! .new(params[:path], user_project).execute!
package_file = ::Packages::PackageFileFinder package_file = ::Packages::PackageFileFinder
.new(package, file_name).execute! .new(package, file_name).execute!
......
...@@ -6,16 +6,32 @@ describe Packages::MavenPackageFinder do ...@@ -6,16 +6,32 @@ describe Packages::MavenPackageFinder do
let(:package) { create(:maven_package, project: project) } let(:package) { create(:maven_package, project: project) }
describe '#execute!' do describe '#execute!' do
context 'within the project' do
it 'returns a package' do it 'returns a package' do
finder = described_class.new(project, package.maven_metadatum.path) finder = described_class.new(package.maven_metadatum.path, project)
expect(finder.execute!).to eq(package) expect(finder.execute!).to eq(package)
end end
it 'raises an error' do it 'raises an error' do
finder = described_class.new(project, 'com/example/my-app/1.0-SNAPSHOT') finder = described_class.new('com/example/my-app/1.0-SNAPSHOT', project)
expect { finder.execute! }.to raise_error(ActiveRecord::RecordNotFound) expect { finder.execute! }.to raise_error(ActiveRecord::RecordNotFound)
end end
end end
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)
end
end
end
end end
...@@ -15,6 +15,106 @@ describe API::MavenPackages do ...@@ -15,6 +15,106 @@ describe API::MavenPackages do
stub_licensed_features(packages: true) stub_licensed_features(packages: true)
end 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 describe 'GET /api/v4/projects/:id/packages/maven/*path/:file_name' do
let(:package) { create(:maven_package, project: project) } let(:package) { create(:maven_package, project: project) }
let(:maven_metadatum) { package.maven_metadatum } 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