Commit 4c617286 authored by Steve Abrams's avatar Steve Abrams Committed by Kerri Miller

Update NuGet to use a unique version regex

Change NuGet to custom regex from semver regex
to allow for extended versions such as 1.1.1.1
parent f2e77c33
...@@ -37,7 +37,8 @@ class Packages::Package < ApplicationRecord ...@@ -37,7 +37,8 @@ class Packages::Package < ApplicationRecord
validate :package_already_taken, if: :npm? validate :package_already_taken, if: :npm?
validates :name, format: { with: Gitlab::Regex.conan_recipe_component_regex }, if: :conan? validates :name, format: { with: Gitlab::Regex.conan_recipe_component_regex }, if: :conan?
validates :name, format: { with: Gitlab::Regex.generic_package_name_regex }, if: :generic? validates :name, format: { with: Gitlab::Regex.generic_package_name_regex }, if: :generic?
validates :version, format: { with: Gitlab::Regex.semver_regex }, if: -> { npm? || nuget? } validates :version, format: { with: Gitlab::Regex.semver_regex }, if: :npm?
validates :version, format: { with: Gitlab::Regex.nuget_version_regex }, if: :nuget?
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?
......
---
title: Update NuGet version validation to allow for extended versions
merge_request: 44335
author:
type: fixed
...@@ -46,6 +46,12 @@ module Gitlab ...@@ -46,6 +46,12 @@ module Gitlab
maven_app_name_regex maven_app_name_regex
end end
def nuget_version_regex
@nuget_version_regex ||= /
\A#{_semver_major_minor_patch_regex}(\.\d*)?#{_semver_prerelease_build_regex}\z
/x.freeze
end
def pypi_version_regex def pypi_version_regex
# See the official regex: https://github.com/pypa/packaging/blob/16.7/packaging/version.py#L159 # See the official regex: https://github.com/pypa/packaging/blob/16.7/packaging/version.py#L159
...@@ -101,16 +107,29 @@ module Gitlab ...@@ -101,16 +107,29 @@ module Gitlab
# reordered to be greedy. Without this change, the unbounded regex would # reordered to be greedy. Without this change, the unbounded regex would
# only partially match "v0.0.0-20201230123456-abcdefabcdef". # only partially match "v0.0.0-20201230123456-abcdefabcdef".
@unbounded_semver_regex ||= / @unbounded_semver_regex ||= /
#{_semver_major_minor_patch_regex}#{_semver_prerelease_build_regex}
/x.freeze
end
def semver_regex
@semver_regex ||= Regexp.new("\\A#{::Gitlab::Regex.unbounded_semver_regex.source}\\z", ::Gitlab::Regex.unbounded_semver_regex.options)
end
# These partial semver regexes are intended for use in composing other
# regexes rather than being used alone.
def _semver_major_minor_patch_regex
@_semver_major_minor_patch_regex ||= /
(?<major>0|[1-9]\d*) (?<major>0|[1-9]\d*)
\.(?<minor>0|[1-9]\d*) \.(?<minor>0|[1-9]\d*)
\.(?<patch>0|[1-9]\d*) \.(?<patch>0|[1-9]\d*)
(?:-(?<prerelease>(?:\d*[a-zA-Z-][0-9a-zA-Z-]*|[1-9]\d*|0)(?:\.(?:\d*[a-zA-Z-][0-9a-zA-Z-]*|[1-9]\d*|0))*))?
(?:\+(?<build>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?
/x.freeze /x.freeze
end end
def semver_regex def _semver_prerelease_build_regex
@semver_regex ||= Regexp.new("\\A#{::Gitlab::Regex.unbounded_semver_regex.source}\\z", ::Gitlab::Regex.unbounded_semver_regex.options) @_semver_prerelease_build_regex ||= /
(?:-(?<prerelease>(?:\d*[a-zA-Z-][0-9a-zA-Z-]*|[1-9]\d*|0)(?:\.(?:\d*[a-zA-Z-][0-9a-zA-Z-]*|[1-9]\d*|0))*))?
(?:\+(?<build>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?
/x.freeze
end end
def prefixed_semver_regex def prefixed_semver_regex
......
...@@ -347,6 +347,22 @@ RSpec.describe Gitlab::Regex do ...@@ -347,6 +347,22 @@ RSpec.describe Gitlab::Regex do
it { is_expected.not_to match('%2e%2e%2f1.2.3') } it { is_expected.not_to match('%2e%2e%2f1.2.3') }
end end
describe '.nuget_version_regex' do
subject { described_class.nuget_version_regex }
it { is_expected.to match('1.2.3') }
it { is_expected.to match('1.2.3.4') }
it { is_expected.to match('1.2.3.4-stable.1') }
it { is_expected.to match('1.2.3-beta') }
it { is_expected.to match('1.2.3-alpha.3') }
it { is_expected.to match('1.0.7+r3456') }
it { is_expected.not_to match('1') }
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') }
it { is_expected.not_to match('%2e%2e%2f1.2.3') }
end
describe '.pypi_version_regex' do describe '.pypi_version_regex' do
subject { described_class.pypi_version_regex } subject { described_class.pypi_version_regex }
......
...@@ -271,7 +271,12 @@ RSpec.describe Packages::Package, type: :model do ...@@ -271,7 +271,12 @@ RSpec.describe Packages::Package, type: :model do
end 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
context 'nuget package' do
it_behaves_like 'validating version to be SemVer compliant for', :nuget_package
it { is_expected.to allow_value('1.2.3.4').for(:version) }
end
end end
describe '#package_already_taken' do describe '#package_already_taken' 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