Commit ee5bc846 authored by Michael Kozono's avatar Michael Kozono

Merge branch '10io-organize-by-packages-type' into 'master'

Organize packages API code using namespaces

See merge request gitlab-org/gitlab!23076
parents c3ac8a24 be223703
# frozen_string_literal: true
module Packages
module Conan
class PackageFinder
attr_reader :current_user, :query
def initialize(current_user, params)
@current_user = current_user
@query = params[:query]
end
def execute
packages_for_current_user.with_name_like(query).order_name_asc if query
end
private
def packages
Packages::Package.conan
end
def packages_for_current_user
packages.for_projects(projects_visible_to_current_user)
end
def projects_visible_to_current_user
::Project.public_or_visible_to_user(current_user)
end
end
end
end
# frozen_string_literal: true
module Packages
class ConanPackageFinder
attr_reader :current_user, :query
def initialize(current_user, params)
@current_user = current_user
@query = params[:query]
end
def execute
packages_for_current_user.with_name_like(query).order_name_asc if query
end
private
def packages
Packages::Package.conan
end
def packages_for_current_user
packages.for_projects(projects_visible_to_current_user)
end
def projects_visible_to_current_user
::Project.public_or_visible_to_user(current_user)
end
end
end
# frozen_string_literal: true
module Packages
module Maven
class PackageFinder
attr_reader :path, :current_user, :project, :group
def initialize(path, current_user, project: nil, group: nil)
@path = path
@current_user = current_user
@project = project
@group = group
end
def execute
packages_with_path.last
end
def execute!
packages_with_path.last!
end
private
def base
if project
packages_for_a_single_project
elsif group
packages_for_multiple_projects
else
packages
end
end
def packages_with_path
base.only_maven_packages_with_path(path)
end
# Produces a query that returns all packages.
def packages
::Packages::Package.all
end
# Produces a query that retrieves packages from a single project.
def packages_for_a_single_project
project.packages
end
# Produces a query that retrieves packages from multiple projects that
# the current user can view within a group.
def packages_for_multiple_projects
::Packages::Package.for_projects(projects_visible_to_current_user)
end
# Returns the projects that the current user can view within a group.
def projects_visible_to_current_user
::Project
.in_namespace(group.self_and_descendants.select(:id))
.public_or_visible_to_user(current_user)
end
end
end
end
# frozen_string_literal: true
class Packages::MavenPackageFinder
attr_reader :path, :current_user, :project, :group
def initialize(path, current_user, project: nil, group: nil)
@path = path
@current_user = current_user
@project = project
@group = group
end
def execute
packages_with_path.last
end
def execute!
packages_with_path.last!
end
private
def base
if project
packages_for_a_single_project
elsif group
packages_for_multiple_projects
else
packages
end
end
def packages_with_path
base.only_maven_packages_with_path(path)
end
# Produces a query that returns all packages.
def packages
::Packages::Package.all
end
# Produces a query that retrieves packages from a single project.
def packages_for_a_single_project
project.packages
end
# Produces a query that retrieves packages from multiple projects that
# the current user can view within a group.
def packages_for_multiple_projects
::Packages::Package.for_projects(projects_visible_to_current_user)
end
# Returns the projects that the current user can view within a group.
def projects_visible_to_current_user
::Project
.in_namespace(group.self_and_descendants.select(:id))
.public_or_visible_to_user(current_user)
end
end
# frozen_string_literal: true
module Packages
module Npm
class PackageFinder
attr_reader :project, :package_name
delegate :find_by_version, to: :execute
def initialize(project, package_name)
@project = project
@package_name = package_name
end
def execute
packages
end
private
def packages
project.packages
.npm
.with_name(package_name)
.last_of_each_version
.preload_files
end
end
end
end
# frozen_string_literal: true
class Packages::NpmPackagesFinder
attr_reader :project, :package_name
delegate :find_by_version, to: :execute
def initialize(project, package_name)
@project = project
@package_name = package_name
end
def execute
packages
end
private
def packages
project.packages
.npm
.with_name(package_name)
.last_of_each_version
.preload_files
end
end
# frozen_string_literal: true
class ConanPackagePresenter
include API::Helpers::RelatedResourcesHelpers
include Gitlab::Utils::StrongMemoize
def initialize(recipe, user, project)
@recipe = recipe
@user = user
@project = project
end
def recipe_urls
map_package_files do |package_file|
build_recipe_file_url(package_file) if package_file.conan_file_metadatum.recipe_file?
end
end
def recipe_snapshot
map_package_files do |package_file|
package_file.file_md5 if package_file.conan_file_metadatum.recipe_file?
end
end
def package_urls
map_package_files do |package_file|
build_package_file_url(package_file) if package_file.conan_file_metadatum.package_file?
end
end
def package_snapshot
map_package_files do |package_file|
package_file.file_md5 if package_file.conan_file_metadatum.package_file?
end
end
private
def build_recipe_file_url(package_file)
expose_url(
api_v4_packages_conan_v1_files_export_path(
package_name: package.name,
package_version: package.version,
package_username: package.conan_metadatum.package_username,
package_channel: package.conan_metadatum.package_channel,
recipe_revision: package_file.conan_file_metadatum.recipe_revision,
file_name: package_file.file_name
)
)
end
def build_package_file_url(package_file)
expose_url(
api_v4_packages_conan_v1_files_package_path(
package_name: package.name,
package_version: package.version,
package_username: package.conan_metadatum.package_username,
package_channel: package.conan_metadatum.package_channel,
recipe_revision: package_file.conan_file_metadatum.recipe_revision,
conan_package_reference: package_file.conan_file_metadatum.conan_package_reference,
package_revision: package_file.conan_file_metadatum.package_revision,
file_name: package_file.file_name
)
)
end
def map_package_files
package_files.to_a.map do |package_file|
key = package_file.file_name
value = yield(package_file)
next unless key && value
[key, value]
end.compact.to_h
end
def package_files
return unless package
@package_files ||= package.package_files.with_conan_file_metadata
end
def package
strong_memoize(:package) do
name, version = @recipe.split('@')[0].split('/')
@project.packages.with_name(name).with_version(version).order_created.last
end
end
end
# frozen_string_literal: true
class NpmPackagePresenter
include API::Helpers::RelatedResourcesHelpers
attr_reader :name, :packages
NPM_VALID_DEPENDENCY_TYPES = %i[dependencies devDependencies bundleDependencies peerDependencies deprecated].freeze
def initialize(name, packages)
@name = name
@packages = packages
end
def versions
package_versions = {}
packages.each do |package|
package_file = package.package_files.last
next unless package_file
package_versions[package.version] = build_package_version(package, package_file)
end
package_versions
end
def dist_tags
build_package_tags.tap { |t| t["latest"] ||= sorted_versions.last }
end
private
def build_package_tags
Hash[
package_tags.map { |tag| [tag.name, tag.package.version] }
]
end
def build_package_version(package, package_file)
{
name: package.name,
version: package.version,
dist: {
shasum: package_file.file_sha1,
tarball: tarball_url(package, package_file)
}
}.tap do |package_version|
package_version.merge!(build_package_dependencies(package))
end
end
def tarball_url(package, package_file)
expose_url "#{api_v4_projects_path(id: package.project_id)}" \
"/packages/npm/#{package.name}" \
"/-/#{package_file.file_name}"
end
def build_package_dependencies(package)
return {} if package.dependency_links.empty?
dependencies = Hash.new { |h, key| h[key] = {} }
dependency_links = package.dependency_links
.with_dependency_type(NPM_VALID_DEPENDENCY_TYPES)
.includes_dependency
dependency_links.find_each do |dependency_link|
dependency = dependency_link.dependency
dependencies[dependency_link.dependency_type][dependency.name] = dependency.version_pattern
end
dependencies
end
def sorted_versions
versions = packages.map(&:version).compact
VersionSorter.sort(versions)
end
def package_tags
Packages::Tag.for_packages(packages)
.preload_package
end
end
# frozen_string_literal: true
module Packages
module Conan
class PackagePresenter
include API::Helpers::RelatedResourcesHelpers
include Gitlab::Utils::StrongMemoize
def initialize(recipe, user, project)
@recipe = recipe
@user = user
@project = project
end
def recipe_urls
map_package_files do |package_file|
build_recipe_file_url(package_file) if package_file.conan_file_metadatum.recipe_file?
end
end
def recipe_snapshot
map_package_files do |package_file|
package_file.file_md5 if package_file.conan_file_metadatum.recipe_file?
end
end
def package_urls
map_package_files do |package_file|
build_package_file_url(package_file) if package_file.conan_file_metadatum.package_file?
end
end
def package_snapshot
map_package_files do |package_file|
package_file.file_md5 if package_file.conan_file_metadatum.package_file?
end
end
private
def build_recipe_file_url(package_file)
expose_url(
api_v4_packages_conan_v1_files_export_path(
package_name: package.name,
package_version: package.version,
package_username: package.conan_metadatum.package_username,
package_channel: package.conan_metadatum.package_channel,
recipe_revision: package_file.conan_file_metadatum.recipe_revision,
file_name: package_file.file_name
)
)
end
def build_package_file_url(package_file)
expose_url(
api_v4_packages_conan_v1_files_package_path(
package_name: package.name,
package_version: package.version,
package_username: package.conan_metadatum.package_username,
package_channel: package.conan_metadatum.package_channel,
recipe_revision: package_file.conan_file_metadatum.recipe_revision,
conan_package_reference: package_file.conan_file_metadatum.conan_package_reference,
package_revision: package_file.conan_file_metadatum.package_revision,
file_name: package_file.file_name
)
)
end
def map_package_files
package_files.to_a.map do |package_file|
key = package_file.file_name
value = yield(package_file)
next unless key && value
[key, value]
end.compact.to_h
end
def package_files
return unless package
@package_files ||= package.package_files.with_conan_file_metadata
end
def package
strong_memoize(:package) do
name, version = @recipe.split('@')[0].split('/')
@project.packages.with_name(name).with_version(version).order_created.last
end
end
end
end
end
# frozen_string_literal: true
module Packages
module Npm
class PackagePresenter
include API::Helpers::RelatedResourcesHelpers
attr_reader :name, :packages
NPM_VALID_DEPENDENCY_TYPES = %i[dependencies devDependencies bundleDependencies peerDependencies deprecated].freeze
def initialize(name, packages)
@name = name
@packages = packages
end
def versions
package_versions = {}
packages.each do |package|
package_file = package.package_files.last
next unless package_file
package_versions[package.version] = build_package_version(package, package_file)
end
package_versions
end
def dist_tags
build_package_tags.tap { |t| t["latest"] ||= sorted_versions.last }
end
private
def build_package_tags
Hash[
package_tags.map { |tag| [tag.name, tag.package.version] }
]
end
def build_package_version(package, package_file)
{
name: package.name,
version: package.version,
dist: {
shasum: package_file.file_sha1,
tarball: tarball_url(package, package_file)
}
}.tap do |package_version|
package_version.merge!(build_package_dependencies(package))
end
end
def tarball_url(package, package_file)
expose_url "#{api_v4_projects_path(id: package.project_id)}" \
"/packages/npm/#{package.name}" \
"/-/#{package_file.file_name}"
end
def build_package_dependencies(package)
return {} if package.dependency_links.empty?
dependencies = Hash.new { |h, key| h[key] = {} }
dependency_links = package.dependency_links
.with_dependency_type(NPM_VALID_DEPENDENCY_TYPES)
.includes_dependency
dependency_links.find_each do |dependency_link|
dependency = dependency_link.dependency
dependencies[dependency_link.dependency_type][dependency.name] = dependency.version_pattern
end
dependencies
end
def sorted_versions
versions = packages.map(&:version).compact
VersionSorter.sort(versions)
end
def package_tags
Packages::Tag.for_packages(packages)
.preload_package
end
end
end
end
......@@ -37,7 +37,7 @@ module Packages
end
def search_packages(query)
Packages::ConanPackageFinder.new(current_user, query: query).execute.map(&:conan_recipe)
::Packages::Conan::PackageFinder.new(current_user, query: query).execute.map(&:conan_recipe)
end
def search_for_single_package(query)
......
# frozen_string_literal: true
module Packages
class CreateMavenPackageService < BaseService
def execute
app_group, _, app_name = params[:name].rpartition('/')
app_group.tr!('/', '.')
package = project.packages.create!(
name: params[:name],
version: params[:version],
package_type: :maven,
maven_metadatum_attributes: {
path: params[:path],
app_group: app_group,
app_name: app_name,
app_version: params[:version]
}
)
build = params[:build]
package.create_build_info!(pipeline: build.pipeline) if build.present?
package
end
end
end
# frozen_string_literal: true
module Packages
class FindOrCreateMavenPackageService < BaseService
MAVEN_METADATA_FILE = 'maven-metadata.xml'.freeze
def execute
package = ::Packages::MavenPackageFinder
.new(params[:path], current_user, project: project).execute
unless package
if params[:file_name] == MAVEN_METADATA_FILE
# Maven uploads several files during `mvn deploy` in next order:
# - my-company/my-app/1.0-SNAPSHOT/my-app.jar
# - my-company/my-app/1.0-SNAPSHOT/my-app.pom
# - my-company/my-app/1.0-SNAPSHOT/maven-metadata.xml
# - my-company/my-app/maven-metadata.xml
#
# The last xml file does not have VERSION in URL because it contains
# information about all versions.
package_name, version = params[:path], nil
else
package_name, _, version = params[:path].rpartition('/')
end
package_params = {
name: package_name,
path: params[:path],
version: version,
build: params[:build]
}
package = ::Packages::CreateMavenPackageService
.new(project, current_user, package_params).execute
end
package
end
end
end
# frozen_string_literal: true
module Packages
module Maven
class CreatePackageService < BaseService
def execute
app_group, _, app_name = params[:name].rpartition('/')
app_group.tr!('/', '.')
package = project.packages.create!(
name: params[:name],
version: params[:version],
package_type: :maven,
maven_metadatum_attributes: {
path: params[:path],
app_group: app_group,
app_name: app_name,
app_version: params[:version]
}
)
build = params[:build]
package.create_build_info!(pipeline: build.pipeline) if build.present?
package
end
end
end
end
# frozen_string_literal: true
module Packages
module Maven
class FindOrCreatePackageService < BaseService
MAVEN_METADATA_FILE = 'maven-metadata.xml'.freeze
def execute
package = ::Packages::Maven::PackageFinder
.new(params[:path], current_user, project: project).execute
unless package
if params[:file_name] == MAVEN_METADATA_FILE
# Maven uploads several files during `mvn deploy` in next order:
# - my-company/my-app/1.0-SNAPSHOT/my-app.jar
# - my-company/my-app/1.0-SNAPSHOT/my-app.pom
# - my-company/my-app/1.0-SNAPSHOT/maven-metadata.xml
# - my-company/my-app/maven-metadata.xml
#
# The last xml file does not have VERSION in URL because it contains
# information about all versions.
package_name, version = params[:path], nil
else
package_name, _, version = params[:path].rpartition('/')
end
package_params = {
name: package_name,
path: params[:path],
version: version,
build: params[:build]
}
package = ::Packages::Maven::CreatePackageService
.new(project, current_user, package_params).execute
end
package
end
end
end
end
......@@ -101,7 +101,7 @@ module API
get 'packages/:conan_package_reference' do
authorize!(:read_package, project)
presenter = ConanPackagePresenter.new(recipe, current_user, project)
presenter = ::Packages::Conan::PackagePresenter.new(recipe, current_user, project)
present presenter, with: EE::API::Entities::ConanPackage::ConanPackageSnapshot
end
......@@ -113,7 +113,7 @@ module API
get do
authorize!(:read_package, project)
presenter = ConanPackagePresenter.new(recipe, current_user, project)
presenter = ::Packages::Conan::PackagePresenter.new(recipe, current_user, project)
present presenter, with: EE::API::Entities::ConanPackage::ConanRecipeSnapshot
end
......@@ -297,7 +297,7 @@ module API
def present_package_download_urls
authorize!(:read_package, project)
presenter = ConanPackagePresenter.new(recipe, current_user, project)
presenter = ::Packages::Conan::PackagePresenter.new(recipe, current_user, project)
render_api_error!("No recipe manifest found", 404) if presenter.package_urls.empty?
......@@ -307,7 +307,7 @@ module API
def present_recipe_download_urls
authorize!(:read_package, project)
presenter = ConanPackagePresenter.new(recipe, current_user, project)
presenter = ::Packages::Conan::PackagePresenter.new(recipe, current_user, project)
render_api_error!("No recipe manifest found", 404) if presenter.recipe_urls.empty?
......
......@@ -66,7 +66,7 @@ module API
authorize_read_package!(project)
package = ::Packages::MavenPackageFinder
package = ::Packages::Maven::PackageFinder
.new(params[:path], current_user, project: project).execute!
authorize_packages_feature!(package.project)
......@@ -103,7 +103,7 @@ module API
not_found!('Group') unless can?(current_user, :read_group, group)
package = ::Packages::MavenPackageFinder
package = ::Packages::Maven::PackageFinder
.new(params[:path], current_user, group: group).execute!
authorize_packages_feature!(package.project)
......@@ -144,7 +144,7 @@ module API
file_name, format = extract_format(params[:file_name])
package = ::Packages::MavenPackageFinder
package = ::Packages::Maven::PackageFinder
.new(params[:path], current_user, project: user_project).execute!
package_file = ::Packages::PackageFileFinder
......@@ -203,7 +203,7 @@ module API
uploaded_file = UploadedFile.from_params(params, :file, ::Packages::PackageFileUploader.workhorse_local_upload_path)
bad_request!('Missing package file!') unless uploaded_file
package = ::Packages::FindOrCreateMavenPackageService
package = ::Packages::Maven::FindOrCreatePackageService
.new(user_project, current_user, params.merge(build: current_authenticated_job)).execute
case format
......
......@@ -39,10 +39,10 @@ module API
authorize_read_package!(project_by_package_name)
authorize_packages_feature!(project_by_package_name)
packages = ::Packages::NpmPackagesFinder.new(project_by_package_name, package_name)
packages = ::Packages::Npm::PackageFinder.new(project_by_package_name, package_name)
.execute
present NpmPackagePresenter.new(package_name, packages),
present ::Packages::Npm::PackagePresenter.new(package_name, packages),
with: EE::API::Entities::NpmPackageTag
end
......@@ -65,7 +65,7 @@ module API
authorize_create_package!(project_by_package_name)
package = ::Packages::NpmPackagesFinder
package = ::Packages::Npm::PackageFinder
.new(project_by_package_name, package_name)
.find_by_version(version)
not_found!('Package') unless package
......@@ -112,10 +112,10 @@ module API
authorize_read_package!(project_by_package_name)
authorize_packages_feature!(project_by_package_name)
packages = ::Packages::NpmPackagesFinder
packages = ::Packages::Npm::PackageFinder
.new(project_by_package_name, package_name).execute
present NpmPackagePresenter.new(package_name, packages),
present ::Packages::Npm::PackagePresenter.new(package_name, packages),
with: EE::API::Entities::NpmPackage
end
......
# frozen_string_literal: true
require 'spec_helper'
describe Packages::ConanPackageFinder do
describe ::Packages::Conan::PackageFinder do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public) }
......
# frozen_string_literal: true
require 'spec_helper'
describe Packages::MavenPackageFinder do
describe ::Packages::Maven::PackageFinder do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:project) { create(:project, namespace: group) }
......
# frozen_string_literal: true
require 'spec_helper'
describe Packages::NpmPackagesFinder do
describe ::Packages::Npm::PackageFinder do
let(:package) { create(:npm_package) }
let(:project) { package.project }
let(:package_name) { package.name }
......
......@@ -2,7 +2,7 @@
require 'spec_helper'
describe ConanPackagePresenter do
describe ::Packages::Conan::PackagePresenter do
let(:user) { create(:user) }
let(:project) { create(:project) }
......
......@@ -2,7 +2,7 @@
require 'spec_helper'
describe NpmPackagePresenter do
describe ::Packages::Npm::PackagePresenter do
let_it_be(:project) { create(:project) }
let_it_be(:package_name) { "@#{project.root_namespace.path}/test" }
let!(:package1) { create(:npm_package, version: '1.0.4', project: project, name: package_name) }
......@@ -19,21 +19,21 @@ describe NpmPackagePresenter do
it { expect(subject[package1.version]).to match_schema('public_api/v4/packages/npm_package_version', dir: 'ee') }
it { expect(subject[package2.version]).to match_schema('public_api/v4/packages/npm_package_version', dir: 'ee') }
NpmPackagePresenter::NPM_VALID_DEPENDENCY_TYPES.each do |dependency_type|
described_class::NPM_VALID_DEPENDENCY_TYPES.each do |dependency_type|
it { expect(subject.dig(package1.version, dependency_type)).to be nil }
it { expect(subject.dig(package2.version, dependency_type)).to be nil }
end
end
context 'for packages with dependencies' do
NpmPackagePresenter::NPM_VALID_DEPENDENCY_TYPES.each do |dependency_type|
described_class::NPM_VALID_DEPENDENCY_TYPES.each do |dependency_type|
let!("package_dependency_link_for_#{dependency_type}") { create(:packages_dependency_link, package: package1, dependency_type: dependency_type) }
end
it { is_expected.to be_a(Hash) }
it { expect(subject[package1.version]).to match_schema('public_api/v4/packages/npm_package_version', dir: 'ee') }
it { expect(subject[package2.version]).to match_schema('public_api/v4/packages/npm_package_version', dir: 'ee') }
NpmPackagePresenter::NPM_VALID_DEPENDENCY_TYPES.each do |dependency_type|
described_class::NPM_VALID_DEPENDENCY_TYPES.each do |dependency_type|
it { expect(subject.dig(package1.version, dependency_type.to_s)).to be_any }
end
end
......
......@@ -2,7 +2,7 @@
require 'spec_helper'
describe Packages::Nuget::ServiceIndexPresenter do
describe ::Packages::Nuget::ServiceIndexPresenter do
let_it_be(:project) { create(:project) }
let_it_be(:presenter) { described_class.new(project) }
......
......@@ -236,7 +236,7 @@ describe API::ConanPackages do
end
it 'returns not found' do
allow(ConanPackagePresenter).to receive(:new)
allow(::Packages::Conan::PackagePresenter).to receive(:new)
.with(
'aa/bb@%{project}/ccc' % { project: ::Packages::ConanMetadatum.package_username_from(full_path: project.full_path) },
user,
......@@ -292,10 +292,10 @@ describe API::ConanPackages do
let(:jwt) { build_jwt(personal_access_token) }
let(:headers) { build_token_auth_header(jwt.encoded) }
let(:conan_package_reference) { '123456789' }
let(:presenter) { double('ConanPackagePresenter') }
let(:presenter) { double('::Packages::Conan::PackagePresenter') }
before do
allow(ConanPackagePresenter).to receive(:new)
allow(::Packages::Conan::PackagePresenter).to receive(:new)
.with(package.conan_recipe, user, package.project)
.and_return(presenter)
end
......
......@@ -519,7 +519,7 @@ describe API::NpmPackages do
expect(response).to match_response_schema('public_api/v4/packages/npm_package', dir: 'ee')
expect(json_response['name']).to eq(package.name)
expect(json_response['versions'][package.version]).to match_schema('public_api/v4/packages/npm_package_version', dir: 'ee')
NpmPackagePresenter::NPM_VALID_DEPENDENCY_TYPES.each do |dependency_type|
::Packages::Npm::PackagePresenter::NPM_VALID_DEPENDENCY_TYPES.each do |dependency_type|
expect(json_response.dig('versions', package.version, dependency_type.to_s)).to be_any
end
expect(json_response['dist-tags']).to match_schema('public_api/v4/packages/npm_package_tags', dir: 'ee')
......
# frozen_string_literal: true
require 'spec_helper'
describe Packages::CreateMavenPackageService do
describe Packages::Maven::CreatePackageService do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:app_name) { 'my-app'.freeze }
let(:version) { '1.0-SNAPSHOT'.freeze }
let(:app_name) { 'my-app' }
let(:version) { '1.0-SNAPSHOT' }
let(:path) { "my/company/app/#{app_name}" }
let(:path_with_version) { "#{path}/#{version}" }
......
# frozen_string_literal: true
require 'spec_helper'
describe Packages::Maven::FindOrCreatePackageService do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:app_name) { 'my-app' }
let_it_be(:version) { '1.0-SNAPSHOT' }
let_it_be(:path) { "my/company/app/#{app_name}" }
let_it_be(:path_with_version) { "#{path}/#{version}" }
let_it_be(:params) do
{
path: path_with_version,
name: path,
version: version
}
end
describe '#execute' do
subject { described_class.new(project, user, params).execute }
context 'without any existing package' do
it 'creates a package' do
expect { subject }.to change { Packages::Package.count }.by(1)
end
end
context 'with an existing package' do
let_it_be(:existing_package) { create(:maven_package, name: path, version: version, project: project) }
it { is_expected.to eq existing_package }
it "doesn't create a new package" do
expect { subject }
.to not_change { Packages::Package.count }
end
end
end
end
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