Commit 53062bfc authored by Vitali Tatarintev's avatar Vitali Tatarintev

Merge branch '235490-generic-packages/generic-type' into 'master'

Add new "Generic" package type

See merge request gitlab-org/gitlab!40061
parents facdfab1 a05fb90f
...@@ -38,8 +38,12 @@ class Packages::Package < ApplicationRecord ...@@ -38,8 +38,12 @@ class Packages::Package < ApplicationRecord
validates :version, format: { with: Gitlab::Regex.conan_recipe_component_regex }, if: :conan? validates :version, format: { with: Gitlab::Regex.conan_recipe_component_regex }, if: :conan?
validates :version, format: { with: Gitlab::Regex.maven_version_regex }, if: -> { version? && maven? } validates :version, format: { with: Gitlab::Regex.maven_version_regex }, if: -> { version? && maven? }
validates :version, format: { with: Gitlab::Regex.pypi_version_regex }, if: :pypi? validates :version, format: { with: Gitlab::Regex.pypi_version_regex }, if: :pypi?
validates :version,
presence: true,
format: { with: Gitlab::Regex.generic_package_version_regex },
if: :generic?
enum package_type: { maven: 1, npm: 2, conan: 3, nuget: 4, pypi: 5, composer: 6 } enum package_type: { maven: 1, npm: 2, conan: 3, nuget: 4, pypi: 5, composer: 6, generic: 7 }
scope :with_name, ->(name) { where(name: name) } scope :with_name, ->(name) { where(name: name) }
scope :with_name_like, ->(name) { where(arel_table[:name].matches(name)) } scope :with_name_like, ->(name) { where(arel_table[:name].matches(name)) }
......
---
title: Add new "generic" package type
merge_request: 40061
author:
type: added
# frozen_string_literal: true
class AddUniqueIndexForGenericPackages < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
INDEX_NAME = 'index_packages_on_project_id_name_version_unique_when_generic'
PACKAGE_TYPE_GENERIC = 7
disable_ddl_transaction!
def up
add_concurrent_index :packages_packages, [:project_id, :name, :version], unique: true, where: "package_type = #{PACKAGE_TYPE_GENERIC}", name: INDEX_NAME
end
def down
remove_concurrent_index_by_name(:packages_packages, INDEX_NAME)
end
end
# frozen_string_literal: true
class AddGenericPackageMaxFileSizeToPlanLimits < ActiveRecord::Migration[6.0]
DOWNTIME = false
def change
add_column(:plan_limits, :generic_packages_max_file_size, :bigint, default: 5.gigabytes, null: false)
end
end
ddf3452bb44437324d20c9db03e998f8903f5ff9732d29cf85dd5d579507952d
\ No newline at end of file
4f3528d7df6e61c8b14911644f9223ac5f6e678184d1c8370d1e9a60389cd60c
\ No newline at end of file
...@@ -14195,7 +14195,8 @@ CREATE TABLE public.plan_limits ( ...@@ -14195,7 +14195,8 @@ CREATE TABLE public.plan_limits (
maven_max_file_size bigint DEFAULT 52428800 NOT NULL, maven_max_file_size bigint DEFAULT 52428800 NOT NULL,
npm_max_file_size bigint DEFAULT 52428800 NOT NULL, npm_max_file_size bigint DEFAULT 52428800 NOT NULL,
nuget_max_file_size bigint DEFAULT 52428800 NOT NULL, nuget_max_file_size bigint DEFAULT 52428800 NOT NULL,
pypi_max_file_size bigint DEFAULT 52428800 NOT NULL pypi_max_file_size bigint DEFAULT 52428800 NOT NULL,
generic_packages_max_file_size bigint DEFAULT '5368709120'::bigint NOT NULL
); );
CREATE SEQUENCE public.plan_limits_id_seq CREATE SEQUENCE public.plan_limits_id_seq
...@@ -20414,6 +20415,8 @@ CREATE INDEX index_packages_maven_metadata_on_package_id_and_path ON public.pack ...@@ -20414,6 +20415,8 @@ CREATE INDEX index_packages_maven_metadata_on_package_id_and_path ON public.pack
CREATE INDEX index_packages_nuget_dl_metadata_on_dependency_link_id ON public.packages_nuget_dependency_link_metadata USING btree (dependency_link_id); CREATE INDEX index_packages_nuget_dl_metadata_on_dependency_link_id ON public.packages_nuget_dependency_link_metadata USING btree (dependency_link_id);
CREATE UNIQUE INDEX index_packages_on_project_id_name_version_unique_when_generic ON public.packages_packages USING btree (project_id, name, version) WHERE (package_type = 7);
CREATE INDEX index_packages_package_files_file_store_is_null ON public.packages_package_files USING btree (id) WHERE (file_store IS NULL); CREATE INDEX index_packages_package_files_file_store_is_null ON public.packages_package_files USING btree (id) WHERE (file_store IS NULL);
CREATE INDEX index_packages_package_files_on_file_store ON public.packages_package_files USING btree (file_store); CREATE INDEX index_packages_package_files_on_file_store ON public.packages_package_files USING btree (file_store);
......
...@@ -10565,6 +10565,11 @@ enum PackageTypeEnum { ...@@ -10565,6 +10565,11 @@ enum PackageTypeEnum {
""" """
CONAN CONAN
"""
Packages from the generic package manager
"""
GENERIC
""" """
Packages from the maven package manager Packages from the maven package manager
""" """
......
...@@ -31806,6 +31806,12 @@ ...@@ -31806,6 +31806,12 @@
"description": "Packages from the composer package manager", "description": "Packages from the composer package manager",
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "deprecationReason": null
},
{
"name": "GENERIC",
"description": "Packages from the generic package manager",
"isDeprecated": false,
"deprecationReason": null
} }
], ],
"possibleTypes": null "possibleTypes": null
...@@ -104,6 +104,10 @@ module Gitlab ...@@ -104,6 +104,10 @@ module Gitlab
\b (?# word boundary) \b (?# word boundary)
/ix.freeze /ix.freeze
end end
def generic_package_version_regex
/\A\d+\.\d+\.\d+\z/
end
end end
extend self extend self
......
...@@ -121,6 +121,12 @@ FactoryBot.define do ...@@ -121,6 +121,12 @@ FactoryBot.define do
conan_metadatum { build(:conan_metadatum, package: nil) } conan_metadatum { build(:conan_metadatum, package: nil) }
end end
end end
factory :generic_package do
sequence(:name) { |n| "generic-package-#{n}" }
version { '1.0.0' }
package_type { :generic }
end
end end
factory :composer_metadatum, class: 'Packages::Composer::Metadatum' do factory :composer_metadatum, class: 'Packages::Composer::Metadatum' do
......
...@@ -4,6 +4,6 @@ require 'spec_helper' ...@@ -4,6 +4,6 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['PackageTypeEnum'] do RSpec.describe GitlabSchema.types['PackageTypeEnum'] do
it 'exposes all package types' do it 'exposes all package types' do
expect(described_class.values.keys).to contain_exactly(*%w[MAVEN NPM CONAN NUGET PYPI COMPOSER]) expect(described_class.values.keys).to contain_exactly(*%w[MAVEN NPM CONAN NUGET PYPI COMPOSER GENERIC])
end end
end end
...@@ -426,4 +426,21 @@ RSpec.describe Gitlab::Regex do ...@@ -426,4 +426,21 @@ RSpec.describe Gitlab::Regex do
it { is_expected.not_to match('1.2') } it { is_expected.not_to match('1.2') }
it { is_expected.not_to match('1./2.3') } it { is_expected.not_to match('1./2.3') }
end end
describe '.generic_package_version_regex' do
subject { described_class.generic_package_version_regex }
it { is_expected.to match('1.2.3') }
it { is_expected.to match('1.3.350') }
it { is_expected.not_to match('1.3.350-20201230123456') }
it { is_expected.not_to match('..1.2.3') }
it { is_expected.not_to match(' 1.2.3') }
it { is_expected.not_to match("1.2.3 \r\t") }
it { is_expected.not_to match("\r\t 1.2.3") }
it { is_expected.not_to match('1.2.3-4/../../') }
it { is_expected.not_to match('1.2.3-4%2e%2e%') }
it { is_expected.not_to match('../../../../../1.2.3') }
it { is_expected.not_to match('%2e%2e%2f1.2.3') }
it { is_expected.not_to match('') }
end
end end
...@@ -236,6 +236,25 @@ RSpec.describe Packages::Package, type: :model do ...@@ -236,6 +236,25 @@ RSpec.describe Packages::Package, type: :model do
it { is_expected.not_to allow_value('%2e%2e%2f1.2.3').for(:version) } it { is_expected.not_to allow_value('%2e%2e%2f1.2.3').for(:version) }
end end
context 'generic package' do
subject { build_stubbed(:generic_package) }
it { is_expected.to validate_presence_of(:version) }
it { is_expected.to allow_value('1.2.3').for(:version) }
it { is_expected.to allow_value('1.3.350').for(:version) }
it { is_expected.not_to allow_value('1.3.350-20201230123456').for(:version) }
it { is_expected.not_to allow_value('..1.2.3').for(:version) }
it { is_expected.not_to allow_value(' 1.2.3').for(:version) }
it { is_expected.not_to allow_value("1.2.3 \r\t").for(:version) }
it { is_expected.not_to allow_value("\r\t 1.2.3").for(:version) }
it { is_expected.not_to allow_value('1.2.3-4/../../').for(:version) }
it { is_expected.not_to allow_value('1.2.3-4%2e%2e%').for(:version) }
it { is_expected.not_to allow_value('../../../../../1.2.3').for(:version) }
it { is_expected.not_to allow_value('%2e%2e%2f1.2.3').for(:version) }
it { is_expected.not_to allow_value('').for(:version) }
it { is_expected.not_to allow_value(nil).for(:version) }
end
it_behaves_like 'validating version to be SemVer compliant for', :npm_package it_behaves_like 'validating version to be SemVer compliant for', :npm_package
it_behaves_like 'validating version to be SemVer compliant for', :nuget_package it_behaves_like 'validating version to be SemVer compliant for', :nuget_package
end end
...@@ -552,11 +571,17 @@ RSpec.describe Packages::Package, type: :model do ...@@ -552,11 +571,17 @@ RSpec.describe Packages::Package, type: :model do
describe 'plan_limits' do describe 'plan_limits' do
Packages::Package.package_types.keys.without('composer').each do |pt| Packages::Package.package_types.keys.without('composer').each do |pt|
plan_limit_name = if pt == 'generic'
"#{pt}_packages_max_file_size"
else
"#{pt}_max_file_size"
end
context "File size limits for #{pt}" do context "File size limits for #{pt}" do
let(:package) { create("#{pt}_package") } let(:package) { create("#{pt}_package") }
it "plan_limits includes column #{pt}_max_file_size" do it "plan_limits includes column #{plan_limit_name}" do
expect { package.project.actual_limits.send("#{pt}_max_file_size") } expect { package.project.actual_limits.send(plan_limit_name) }
.not_to raise_error(NoMethodError) .not_to raise_error(NoMethodError)
end end
end end
......
...@@ -161,6 +161,7 @@ RSpec.shared_examples 'filters on each package_type' do |is_project: false| ...@@ -161,6 +161,7 @@ RSpec.shared_examples 'filters on each package_type' do |is_project: false|
let_it_be(:package4) { create(:nuget_package, project: project) } let_it_be(:package4) { create(:nuget_package, project: project) }
let_it_be(:package5) { create(:pypi_package, project: project) } let_it_be(:package5) { create(:pypi_package, project: project) }
let_it_be(:package6) { create(:composer_package, project: project) } let_it_be(:package6) { create(:composer_package, project: project) }
let_it_be(:package7) { create(:generic_package, project: project) }
Packages::Package.package_types.keys.each do |package_type| Packages::Package.package_types.keys.each do |package_type|
context "for package type #{package_type}" do context "for package type #{package_type}" do
......
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