Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2018-11-07 18:47:59 +0300
committerDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2018-11-28 17:15:15 +0300
commitd2f55f9a7ab37242e66f4ae90b95e976682e92a6 (patch)
tree1fdc6d7405908bae754d83a8cd9a7eae060ae274
parentb3bb56d4f4d168b1f85afb0170608e53e7f790f4 (diff)
Add instance-level maven endpoint for download
Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
-rw-r--r--doc/user/project/packages/maven_repository.md25
-rw-r--r--ee/app/finders/packages/maven_package_finder.rb16
-rw-r--r--ee/app/services/packages/find_or_create_maven_package_service.rb2
-rw-r--r--ee/changelogs/unreleased/7769-instance-level-maven-endpoint.yml5
-rw-r--r--ee/lib/api/maven_packages.rb37
-rw-r--r--ee/spec/finders/packages/maven_package_finder_spec.rb28
-rw-r--r--ee/spec/requests/api/maven_packages_spec.rb100
7 files changed, 200 insertions, 13 deletions
diff --git a/doc/user/project/packages/maven_repository.md b/doc/user/project/packages/maven_repository.md
index a84761006ea..0e369131c64 100644
--- a/doc/user/project/packages/maven_repository.md
+++ b/doc/user/project/packages/maven_repository.md
@@ -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)
diff --git a/ee/app/finders/packages/maven_package_finder.rb b/ee/app/finders/packages/maven_package_finder.rb
index 7c970a262b8..6297b5325a4 100644
--- a/ee/app/finders/packages/maven_package_finder.rb
+++ b/ee/app/finders/packages/maven_package_finder.rb
@@ -1,10 +1,10 @@
# 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
diff --git a/ee/app/services/packages/find_or_create_maven_package_service.rb b/ee/app/services/packages/find_or_create_maven_package_service.rb
index 141f31a2169..1e43bf863b5 100644
--- a/ee/app/services/packages/find_or_create_maven_package_service.rb
+++ b/ee/app/services/packages/find_or_create_maven_package_service.rb
@@ -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
diff --git a/ee/changelogs/unreleased/7769-instance-level-maven-endpoint.yml b/ee/changelogs/unreleased/7769-instance-level-maven-endpoint.yml
new file mode 100644
index 00000000000..8c7a8b74be7
--- /dev/null
+++ b/ee/changelogs/unreleased/7769-instance-level-maven-endpoint.yml
@@ -0,0 +1,5 @@
+---
+title: Add an instance-level endpoint for downloading maven packages
+merge_request: 8274
+author:
+type: added
diff --git a/ee/lib/api/maven_packages.rb b/ee/lib/api/maven_packages.rb
index c386e6d7243..070b484f21a 100644
--- a/ee/lib/api/maven_packages.rb
+++ b/ee/lib/api/maven_packages.rb
@@ -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!
diff --git a/ee/spec/finders/packages/maven_package_finder_spec.rb b/ee/spec/finders/packages/maven_package_finder_spec.rb
index eb198f527c2..0e1792e58ef 100644
--- a/ee/spec/finders/packages/maven_package_finder_spec.rb
+++ b/ee/spec/finders/packages/maven_package_finder_spec.rb
@@ -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
diff --git a/ee/spec/requests/api/maven_packages_spec.rb b/ee/spec/requests/api/maven_packages_spec.rb
index b59f5a2dec4..582bfbd8435 100644
--- a/ee/spec/requests/api/maven_packages_spec.rb
+++ b/ee/spec/requests/api/maven_packages_spec.rb
@@ -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 }