Commit b8c5c14d authored by David Fernandez's avatar David Fernandez

Extract nuget metadata and persist it

Extract:
  * project url
  * license url
  * icon url
and persist them using `Packages::NugetMetadtum`.

Expose them in the search and metadata endpoints.
parent d8ed2944
# frozen_string_literal: true
class CreatePackagesNugetMetadata < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
LICENSE_URL_CONSTRAINT_NAME = 'packages_nuget_metadata_license_url_constraint'
PROJECT_URL_CONSTRAINT_NAME = 'packages_nuget_metadata_project_url_constraint'
ICON_URL_CONSTRAINT_NAME = 'packages_nuget_metadata_icon_url_constraint'
def up
unless table_exists?(:packages_nuget_metadata)
with_lock_retries do
create_table :packages_nuget_metadata, id: false do |t|
t.references :package, primary_key: true, default: nil, index: false, foreign_key: { to_table: :packages_packages, on_delete: :cascade }, type: :bigint
t.text :license_url
t.text :project_url
t.text :icon_url
end
end
end
add_text_limit :packages_nuget_metadata, :license_url, 255, constraint_name: LICENSE_URL_CONSTRAINT_NAME
add_text_limit :packages_nuget_metadata, :project_url, 255, constraint_name: PROJECT_URL_CONSTRAINT_NAME
add_text_limit :packages_nuget_metadata, :icon_url, 255, constraint_name: ICON_URL_CONSTRAINT_NAME
end
def down
drop_table :packages_nuget_metadata
end
end
......@@ -4654,6 +4654,16 @@ CREATE TABLE public.packages_nuget_dependency_link_metadata (
CONSTRAINT packages_nuget_dependency_link_metadata_target_framework_constr CHECK ((char_length(target_framework) <= 255))
);
CREATE TABLE public.packages_nuget_metadata (
package_id bigint NOT NULL,
license_url text,
project_url text,
icon_url text,
CONSTRAINT packages_nuget_metadata_icon_url_constraint CHECK ((char_length(icon_url) <= 255)),
CONSTRAINT packages_nuget_metadata_license_url_constraint CHECK ((char_length(license_url) <= 255)),
CONSTRAINT packages_nuget_metadata_project_url_constraint CHECK ((char_length(project_url) <= 255))
);
CREATE TABLE public.packages_package_files (
id bigint NOT NULL,
package_id bigint NOT NULL,
......@@ -8535,6 +8545,9 @@ ALTER TABLE ONLY public.packages_maven_metadata
ALTER TABLE ONLY public.packages_nuget_dependency_link_metadata
ADD CONSTRAINT packages_nuget_dependency_link_metadata_pkey PRIMARY KEY (dependency_link_id);
ALTER TABLE ONLY public.packages_nuget_metadata
ADD CONSTRAINT packages_nuget_metadata_pkey PRIMARY KEY (package_id);
ALTER TABLE ONLY public.packages_package_files
ADD CONSTRAINT packages_package_files_pkey PRIMARY KEY (id);
......@@ -12598,6 +12611,9 @@ ALTER TABLE ONLY public.serverless_domain_cluster
ALTER TABLE ONLY public.ci_job_variables
ADD CONSTRAINT fk_rails_fbf3b34792 FOREIGN KEY (job_id) REFERENCES public.ci_builds(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.packages_nuget_metadata
ADD CONSTRAINT fk_rails_fc0c19f5b4 FOREIGN KEY (package_id) REFERENCES public.packages_packages(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.cluster_groups
ADD CONSTRAINT fk_rails_fdb8648a96 FOREIGN KEY (cluster_id) REFERENCES public.clusters(id) ON DELETE CASCADE;
......@@ -13801,6 +13817,7 @@ COPY "schema_migrations" (version) FROM STDIN;
20200429181955
20200429182245
20200430103158
20200430130048
20200505164958
20200505171834
20200505172405
......
# frozen_string_literal: true
class Packages::Nuget::Metadatum < ApplicationRecord
belongs_to :package, -> { where(package_type: :nuget) }, inverse_of: :nuget_metadatum
validates :package, presence: true
validates :license_url, public_url: { allow_blank: true }
validates :project_url, public_url: { allow_blank: true }
validates :icon_url, public_url: { allow_blank: true }
validate :ensure_at_least_one_field_supplied
validate :ensure_nuget_package_type
private
def ensure_at_least_one_field_supplied
return if license_url? || project_url? || icon_url?
errors.add(:base, _('Nuget metadatum must have at least license_url, project_url or icon_url set'))
end
def ensure_nuget_package_type
return if package&.nuget?
errors.add(:base, _('Package type must be NuGet'))
end
end
......@@ -12,6 +12,7 @@ class Packages::Package < ApplicationRecord
has_one :conan_metadatum, inverse_of: :package, class_name: 'Packages::Conan::Metadatum'
has_one :pypi_metadatum, inverse_of: :package, class_name: 'Packages::Pypi::Metadatum'
has_one :maven_metadatum, inverse_of: :package, class_name: 'Packages::Maven::Metadatum'
has_one :nuget_metadatum, inverse_of: :package, class_name: 'Packages::Nuget::Metadatum'
has_one :build_info, inverse_of: :package
accepts_nested_attributes_for :conan_metadatum
......
......@@ -47,10 +47,19 @@ module Packages
package_version: package.version,
archive_url: archive_url_for(package),
summary: BLANK_STRING,
tags: tags_for(package)
tags: tags_for(package),
metadatum: metadatum_for(package)
}
end
def metadatum_for(package)
metadatum = package.nuget_metadatum
return {} unless metadatum
metadatum.slice(:project_url, :license_url, :icon_url)
.compact
end
def base_path_for(package)
api_v4_projects_packages_nuget_path(id: package.project_id)
end
......
......@@ -28,7 +28,8 @@ module Packages
summary: '',
total_downloads: 0,
verified: true,
tags: tags_for(latest_package)
tags: tags_for(latest_package),
metadatum: metadatum_for(latest_package)
}
end
end
......
......@@ -9,7 +9,10 @@ module Packages
XPATHS = {
package_name: '//xmlns:package/xmlns:metadata/xmlns:id',
package_version: '//xmlns:package/xmlns:metadata/xmlns:version'
package_version: '//xmlns:package/xmlns:metadata/xmlns:version',
license_url: '//xmlns:package/xmlns:metadata/xmlns:licenseUrl',
project_url: '//xmlns:package/xmlns:metadata/xmlns:projectUrl',
icon_url: '//xmlns:package/xmlns:metadata/xmlns:iconUrl'
}.freeze
XPATH_DEPENDENCIES = '//xmlns:package/xmlns:metadata/xmlns:dependencies/xmlns:dependency'
......@@ -45,8 +48,9 @@ module Packages
def extract_metadata(file)
doc = Nokogiri::XML(file)
XPATHS.map { |key, query| [key, doc.xpath(query).text] }
XPATHS.map { |key, query| [key, doc.xpath(query).text.presence] }
.to_h
.compact
.tap do |metadata|
metadata[:package_dependencies] = extract_dependencies(doc)
metadata[:package_tags] = extract_tags(doc)
......
# frozen_string_literal: true
module Packages
module Nuget
class SyncMetadatumService
include Gitlab::Utils::StrongMemoize
def initialize(package, metadata)
@package = package
@metadata = metadata
end
def execute
if blank_metadata?
metadatum.destroy! if metadatum.persisted?
else
metadatum.update!(
license_url: license_url,
project_url: project_url,
icon_url: icon_url
)
end
end
private
def metadatum
strong_memoize(:metadatum) do
@package.nuget_metadatum || @package.build_nuget_metadatum
end
end
def blank_metadata?
project_url.blank? && license_url.blank? && icon_url.blank?
end
def project_url
@metadata[:project_url]
end
def license_url
@metadata[:license_url]
end
def icon_url
@metadata[:icon_url]
end
end
end
end
......@@ -37,8 +37,14 @@ module Packages
private
def update_package(package)
::Packages::UpdateTagsService.new(package, package_tags)
::Packages::Nuget::SyncMetadatumService
.new(package, metadata.slice(:project_url, :license_url, :icon_url))
.execute
::Packages::UpdateTagsService
.new(package, package_tags)
.execute
rescue => e
raise InvalidMetadataError, e.message
end
def valid_metadata?
......
---
title: Add Nuget metadatum support in GitLab Packages
merge_request: 30994
author:
type: added
# frozen_string_literal: true
module EE
module API
module Entities
module Nuget
class Metadatum < Grape::Entity
expose :project_url, as: :projectUrl, expose_nil: false
expose :license_url, as: :licenseUrl, expose_nil: false
expose :icon_url, as: :iconUrl, expose_nil: false
end
end
end
end
end
......@@ -13,6 +13,7 @@ module EE
expose :tags
expose :archive_url, as: :packageContent
expose :summary
expose :metadatum, using: EE::API::Entities::Nuget::Metadatum, merge: true
end
end
end
......
......@@ -15,6 +15,7 @@ module EE
expose :version
expose :versions, using: EE::API::Entities::Nuget::SearchResultVersion
expose :tags
expose :metadatum, using: EE::API::Entities::Nuget::Metadatum, merge: true
end
end
end
......
......@@ -47,6 +47,12 @@ FactoryBot.define do
after :create do |package|
create :package_file, :nuget, package: package, file_name: "#{package.name}.#{package.version}.nupkg"
end
trait(:with_metadatum) do
after :build do |pkg|
pkg.nuget_metadatum = build(:nuget_metadatum)
end
end
end
factory :pypi_package do
......@@ -242,6 +248,14 @@ FactoryBot.define do
required_python { '>=2.7' }
end
factory :nuget_metadatum, class: 'Packages::Nuget::Metadatum' do
package { create(:nuget_package) }
license_url { 'http://www.gitlab.com' }
project_url { 'http://www.gitlab.com' }
icon_url { 'http://www.gitlab.com' }
end
factory :conan_file_metadatum, class: 'Packages::Conan::FileMetadatum' do
package_file
recipe_revision { '0' }
......
......@@ -15,6 +15,9 @@
"packageContent": { "type": "string" },
"summary": { "const": "" },
"tags": { "type": "string" },
"projectUrl": { "type": "string" },
"licenseUrl": { "type": "string" },
"iconUrl": { "type": "string" },
"version": { "type": "string" }
}
}
......
......@@ -31,6 +31,9 @@
"packageContent": { "type": "string" },
"summary": { "const": "" },
"tags": { "type": "string" },
"projectUrl": { "type": "string" },
"licenseUrl": { "type": "string" },
"iconUrl": { "type": "string" },
"version": { "type": "string" }
}
}
......
......@@ -17,6 +17,9 @@
"totalDownloads": { "const": 0 },
"verified": { "const": true },
"tags": { "type": "string" },
"projectUrl": { "type": "string" },
"licenseUrl": { "type": "string" },
"iconUrl": { "type": "string" },
"versions": {
"type": "array",
"items": {
......
# frozen_string_literal: true
require 'spec_helper'
describe EE::API::Entities::Nuget::Metadatum do
let(:metadatum) do
{
project_url: 'http://sandbox.com/project',
license_url: 'http://sandbox.com/license',
icon_url: 'http://sandbox.com/icon'
}
end
let(:expected) do
{
'projectUrl': 'http://sandbox.com/project',
'licenseUrl': 'http://sandbox.com/license',
'iconUrl': 'http://sandbox.com/icon'
}
end
let(:entity) { described_class.new(metadatum) }
subject { entity.as_json }
it { is_expected.to eq(expected) }
%i[project_url license_url icon_url].each do |optional_field|
context "metadatum without #{optional_field}" do
let(:metadatum_without_a_field) { metadatum.except(optional_field) }
let(:expected_without_a_field) { expected.except(optional_field.to_s.camelize(:lower).to_sym) }
let(:entity) { described_class.new(metadatum_without_a_field) }
it { is_expected.to eq(expected_without_a_field) }
end
end
end
......@@ -12,7 +12,12 @@ describe EE::API::Entities::Nuget::PackageMetadataCatalogEntry do
package_version: '1.2.3',
tags: 'tag1 tag2 tag3',
archive_url: 'http://sandbox.com/archive/package',
summary: 'Summary'
summary: 'Summary',
metadatum: {
project_url: 'http://sandbox.com/project',
license_url: 'http://sandbox.com/license',
icon_url: 'http://sandbox.com/icon'
}
}
end
......@@ -25,7 +30,10 @@ describe EE::API::Entities::Nuget::PackageMetadataCatalogEntry do
'dependencyGroups': [],
'tags': 'tag1 tag2 tag3',
'packageContent': 'http://sandbox.com/archive/package',
'summary': 'Summary'
'summary': 'Summary',
'projectUrl': 'http://sandbox.com/project',
'licenseUrl': 'http://sandbox.com/license',
'iconUrl': 'http://sandbox.com/icon'
}
end
......
......@@ -19,10 +19,14 @@ describe EE::API::Entities::Nuget::SearchResult do
summary: 'Summary',
total_downloads: 100,
verified: true,
tags: 'tag1 tag2 tag3'
tags: 'tag1 tag2 tag3',
metadatum: {
project_url: 'http://sandbox.com/project',
license_url: 'http://sandbox.com/license',
icon_url: 'http://sandbox.com/icon'
}
}
end
let(:expected) do
{
'@type': 'Package',
......@@ -34,6 +38,9 @@ describe EE::API::Entities::Nuget::SearchResult do
'verified': true,
'version': '1.2.3',
'tags': 'tag1 tag2 tag3',
'projectUrl': 'http://sandbox.com/project',
'licenseUrl': 'http://sandbox.com/license',
'iconUrl': 'http://sandbox.com/icon',
'versions': [
{
'@id': 'http://sandbox.com/json/package',
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Packages::Nuget::Metadatum, type: :model do
describe 'relationships' do
it { is_expected.to belong_to(:package).inverse_of(:nuget_metadatum) }
end
describe 'validations' do
it { is_expected.to validate_presence_of(:package) }
%i[license_url project_url icon_url].each do |url|
describe "##{url}" do
it { is_expected.to allow_value('http://sandbox.com').for(url) }
it { is_expected.to allow_value('https://sandbox.com').for(url) }
it { is_expected.not_to allow_value('123').for(url) }
it { is_expected.not_to allow_value('sandbox.com').for(url) }
end
describe '#ensure_at_least_one_field_supplied' do
subject { build(:nuget_metadatum) }
it 'rejects unfilled metadatum' do
subject.attributes = { license_url: nil, project_url: nil, icon_url: nil }
expect(subject).not_to be_valid
expect(subject.errors).to contain_exactly('Nuget metadatum must have at least license_url, project_url or icon_url set')
end
end
describe '#ensure_nuget_package_type' do
subject { build(:nuget_metadatum) }
it 'rejects if not linked to a nuget package' do
subject.package = build(:npm_package)
expect(subject).not_to be_valid
expect(subject.errors).to contain_exactly('Package type must be NuGet')
end
end
end
end
end
......@@ -11,6 +11,7 @@ RSpec.describe Packages::Package, type: :model do
it { is_expected.to have_many(:tags).inverse_of(:package) }
it { is_expected.to have_one(:conan_metadatum).inverse_of(:package) }
it { is_expected.to have_one(:maven_metadatum).inverse_of(:package) }
it { is_expected.to have_one(:nuget_metadatum).inverse_of(:package) }
end
describe '.sort_by_attribute' do
......
......@@ -3,7 +3,7 @@
require 'spec_helper'
describe Packages::Nuget::PackageMetadataPresenter do
let_it_be(:package) { create(:nuget_package) }
let_it_be(:package) { create(:nuget_package, :with_metadatum) }
let_it_be(:tag1) { create(:packages_tag, name: 'tag1', package: package) }
let_it_be(:tag2) { create(:packages_tag, name: 'tag2', package: package) }
let_it_be(:presenter) { described_class.new(package) }
......@@ -37,6 +37,10 @@ describe Packages::Nuget::PackageMetadataPresenter do
expect(entry[:package_name]).to eq package.name
expect(entry[:package_version]).to eq package.version
expect(entry[:tags].split(::Packages::Tag::NUGET_TAGS_SEPARATOR)).to contain_exactly('tag1', 'tag2')
%i[project_url license_url icon_url].each do |field|
expect(entry.dig(:metadatum, field)).to eq(package.nuget_metadatum.send(field))
end
end
end
end
......@@ -3,7 +3,7 @@
require 'spec_helper'
describe Packages::Nuget::PackagesMetadataPresenter do
let_it_be(:packages) { create_list(:nuget_package, 5, name: 'Dummy.Package') }
let_it_be(:packages) { create_list(:nuget_package, 5, :with_metadatum, name: 'Dummy.Package') }
let_it_be(:presenter) { described_class.new(packages) }
describe '#count' do
......@@ -51,6 +51,10 @@ describe Packages::Nuget::PackagesMetadataPresenter do
%i[authors summary].each { |field| expect(catalog_entry[field]).to be_blank }
expect(catalog_entry[:dependencies]).to eq []
expect(catalog_entry[:tags].split(::Packages::Tag::NUGET_TAGS_SEPARATOR)).to contain_exactly('tag1', 'tag2')
%i[project_url license_url icon_url].each do |field|
expect(catalog_entry.dig(:metadatum, field)).not_to be_blank
end
end
end
end
......
......@@ -4,7 +4,7 @@ require 'spec_helper'
describe Packages::Nuget::SearchResultsPresenter do
let_it_be(:project) { create(:project) }
let_it_be(:package_a) { create(:nuget_package, project: project, name: 'DummyPackageA') }
let_it_be(:package_a) { create(:nuget_package, :with_metadatum, project: project, name: 'DummyPackageA') }
let_it_be(:tag1) { create(:packages_tag, package: package_a, name: 'tag1') }
let_it_be(:tag2) { create(:packages_tag, package: package_a, name: 'tag2') }
let_it_be(:packages_b) { create_list(:nuget_package, 5, project: project, name: 'DummyPackageB') }
......@@ -24,13 +24,13 @@ describe Packages::Nuget::SearchResultsPresenter do
it 'returns the proper data structure' do
expect(data.size).to eq 3
pkg_a, pkg_b, pkg_c = data
expect_package_result(pkg_a, package_a.name, [package_a.version], %w(tag1 tag2))
expect_package_result(pkg_a, package_a.name, [package_a.version], %w(tag1 tag2), with_metadatum: true)
expect_package_result(pkg_b, packages_b.first.name, packages_b.map(&:version))
expect_package_result(pkg_c, packages_c.first.name, packages_c.map(&:version))
end
# rubocop:disable Metrics/AbcSize
def expect_package_result(package_json, name, versions, tags = [])
def expect_package_result(package_json, name, versions, tags = [], with_metadatum: false)
expect(package_json[:type]).to eq 'Package'
expect(package_json[:authors]).to be_blank
expect(package_json[:name]).to eq(name)
......@@ -49,6 +49,10 @@ describe Packages::Nuget::SearchResultsPresenter do
else
expect(package_json[:tags]).to be_blank
end
%i[project_url license_url icon_url].each do |field|
expect(package_json.dig(:metadatum, field)).to with_metadatum ? be_present : be_blank
end
end
# rubocop:enable Metrics/AbcSize
end
......
......@@ -204,7 +204,7 @@ describe API::NugetPackages do
describe 'GET /api/v4/projects/:id/packages/nuget/metadata/*package_name/index' do
let_it_be(:package_name) { 'Dummy.Package' }
let_it_be(:packages) { create_list(:nuget_package, 5, name: package_name, project: project) }
let_it_be(:packages) { create_list(:nuget_package, 5, :with_metadatum, name: package_name, project: project) }
let_it_be(:tags) { packages.each { |pkg| create(:packages_tag, package: pkg, name: 'test') } }
let(:url) { "/projects/#{project.id}/packages/nuget/metadata/#{package_name}/index.json" }
......@@ -265,7 +265,7 @@ describe API::NugetPackages do
describe 'GET /api/v4/projects/:id/packages/nuget/metadata/*package_name/*package_version' do
let_it_be(:package_name) { 'Dummy.Package' }
let_it_be(:package) { create(:nuget_package, name: 'Dummy.Package', project: project) }
let_it_be(:package) { create(:nuget_package, :with_metadatum, name: 'Dummy.Package', project: project) }
let_it_be(:tag) { create(:packages_tag, package: package, name: 'test') }
let(:url) { "/projects/#{project.id}/packages/nuget/metadata/#{package_name}/#{package.version}.json" }
......@@ -448,7 +448,7 @@ describe API::NugetPackages do
end
describe 'GET /api/v4/projects/:id/packages/nuget/query' do
let_it_be(:package_a) { create(:nuget_package, name: 'Dummy.PackageA', project: project) }
let_it_be(:package_a) { create(:nuget_package, :with_metadatum, name: 'Dummy.PackageA', project: project) }
let_it_be(:tag) { create(:packages_tag, package: package_a, name: 'test') }
let_it_be(:packages_b) { create_list(:nuget_package, 5, name: 'Dummy.PackageB', project: project) }
let_it_be(:packages_c) { create_list(:nuget_package, 5, name: 'Dummy.PackageC', project: project) }
......
......@@ -53,6 +53,18 @@ describe Packages::Nuget::MetadataExtractionService do
end
end
context 'with a nuspec file with metadata' do
let_it_be(:nuspec_filepath) { 'nuget/with_metadata.nuspec' }
before do
allow(service).to receive(:nuspec_file).and_return(fixture_file(nuspec_filepath, dir: 'ee'))
end
it { expect(subject[:license_url]).to eq('https://opensource.org/licenses/MIT') }
it { expect(subject[:project_url]).to eq('https://gitlab.com/gitlab-org/gitlab') }
it { expect(subject[:icon_url]).to eq('https://opensource.org/files/osi_keyhole_300X300_90ppi_0.png') }
end
context 'with invalid package file id' do
let(:package_file) { OpenStruct.new(id: 555) }
......
# frozen_string_literal: true
require 'spec_helper'
describe Packages::Nuget::SyncMetadatumService do
let_it_be(:package, reload: true) { create(:nuget_package) }
let_it_be(:metadata) do
{
project_url: 'https://test.org/test',
license_url: 'https://test.org/MIT',
icon_url: 'https://test.org/icon.png'
}
end
let(:service) { described_class.new(package, metadata) }
let(:nuget_metadatum) { package.nuget_metadatum }
describe '#execute' do
subject { service.execute }
RSpec.shared_examples 'saving metadatum attributes' do
it 'saves nuget metadatum' do
subject
metadata.each do |attribute, expected_value|
expect(nuget_metadatum.send(attribute)).to eq(expected_value)
end
end
end
it 'creates a nuget metadatum' do
expect { subject }
.to change { package.nuget_metadatum.present? }.from(false).to(true)
end
it_behaves_like 'saving metadatum attributes'
context 'with exisiting nuget metadatum' do
let_it_be(:package) { create(:nuget_package, :with_metadatum) }
it 'does not create a nuget metadatum' do
expect { subject }.to change { ::Packages::Nuget::Metadatum.count }.by(0)
end
it_behaves_like 'saving metadatum attributes'
context 'with empty metadata' do
let_it_be(:metadata) { {} }
it 'destroys the nuget metadatum' do
expect { subject }
.to change { package.reload.nuget_metadatum.present? }.from(true).to(false)
end
end
end
end
end
......@@ -12,6 +12,12 @@ describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_redis_
let(:package_version) { '1.0.0' }
let(:package_file_name) { 'dummyproject.dummypackage.1.0.0.nupkg' }
RSpec.shared_examples 'raising an' do |error_class|
it "raises an #{error_class}" do
expect { subject }.to raise_error(error_class)
end
end
describe '#execute' do
subject { service.execute }
......@@ -65,8 +71,10 @@ describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_redis_
it 'updates package and package file' do
expect { subject }
.to change { Packages::Dependency.count }.by(1)
.to change { ::Packages::Package.count }.by(1)
.and change { Packages::Dependency.count }.by(1)
.and change { Packages::DependencyLink.count }.by(1)
.and change { ::Packages::Nuget::Metadatum.count }.by(0)
expect(package.reload.name).to eq(package_name)
expect(package.version).to eq(package_version)
......@@ -92,6 +100,7 @@ describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_redis_
.and change { Packages::Dependency.count }.by(0)
.and change { Packages::DependencyLink.count }.by(0)
.and change { Packages::Nuget::DependencyLinkMetadatum.count }.by(0)
.and change { ::Packages::Nuget::Metadatum.count }.by(0)
expect(package_file.reload.file_name).to eq(package_file_name)
expect(package_file.package).to eq(existing_package)
end
......@@ -129,6 +138,29 @@ describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_redis_
expect(existing_package.tags.map(&:name)).to contain_exactly(*expected_tags)
end
end
it 'creates nuget metadatum' do
expect { subject }
.to change { ::Packages::Package.count }.by(1)
.and change { ::Packages::Nuget::Metadatum.count }.by(1)
metadatum = package_file.reload.package.nuget_metadatum
expect(metadatum.license_url).to eq('https://opensource.org/licenses/MIT')
expect(metadatum.project_url).to eq('https://gitlab.com/gitlab-org/gitlab')
expect(metadatum.icon_url).to eq('https://opensource.org/files/osi_keyhole_300X300_90ppi_0.png')
end
context 'with too long url' do
let_it_be(:too_long_url) { "http://localhost/#{'bananas' * 50}" }
let(:metadata) { { package_name: package_name, package_version: package_version, license_url: too_long_url } }
before do
allow(service).to receive(:metadata).and_return(metadata)
end
it_behaves_like 'raising an', ::Packages::Nuget::UpdatePackageFromMetadataService::InvalidMetadataError
end
end
context 'with nuspec file with dependencies' do
......@@ -163,9 +195,7 @@ describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_redis_
allow_any_instance_of(Zip::File).to receive(:glob).and_return([])
end
it 'raises an error' do
expect { subject }.to raise_error(::Packages::Nuget::MetadataExtractionService::ExtractionError)
end
it_behaves_like 'raising an', ::Packages::Nuget::MetadataExtractionService::ExtractionError
end
context 'with package file with a blank package name' do
......@@ -173,9 +203,7 @@ describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_redis_
allow(service).to receive(:package_name).and_return('')
end
it 'raises an error' do
expect { subject }.to raise_error(::Packages::Nuget::UpdatePackageFromMetadataService::InvalidMetadataError)
end
it_behaves_like 'raising an', ::Packages::Nuget::UpdatePackageFromMetadataService::InvalidMetadataError
end
context 'with package file with a blank package version' do
......@@ -183,9 +211,7 @@ describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_redis_
allow(service).to receive(:package_version).and_return('')
end
it 'raises an error' do
expect { subject }.to raise_error(::Packages::Nuget::UpdatePackageFromMetadataService::InvalidMetadataError)
end
it_behaves_like 'raising an', ::Packages::Nuget::UpdatePackageFromMetadataService::InvalidMetadataError
end
context 'with an invalid package version' do
......
......@@ -14513,6 +14513,9 @@ msgstr ""
msgid "Now you can access the merge request navigation tabs at the top, where they’re easier to find."
msgstr ""
msgid "Nuget metadatum must have at least license_url, project_url or icon_url set"
msgstr ""
msgid "Number of %{itemTitle}"
msgstr ""
......
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