Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-02-11 03:12:21 +00:00
parent 18ad304adc
commit 9fbfd2ebf4
46 changed files with 663 additions and 87 deletions

View File

@ -16,7 +16,9 @@ class Projects::TagsController < Projects::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def index def index
begin begin
tags_params[:sort] = tags_params[:sort].presence || sort_value_recently_updated tags_params = params
.permit(:search, :sort, :per_page, :page_token, :page)
.with_defaults(sort: sort_value_recently_updated)
@sort = tags_params[:sort] @sort = tags_params[:sort]
@search = tags_params[:search] @search = tags_params[:search]
@ -101,10 +103,6 @@ class Projects::TagsController < Projects::ApplicationController
private private
def tags_params
params.permit(:search, :sort, :per_page, :page_token, :page)
end
# TODO: remove this with the release creation moved to it's own form https://gitlab.com/gitlab-org/gitlab/-/issues/214245 # TODO: remove this with the release creation moved to it's own form https://gitlab.com/gitlab-org/gitlab/-/issues/214245
def find_evidence_pipeline def find_evidence_pipeline
evidence_pipeline_sha = @project.repository.commit(params[:ref])&.sha evidence_pipeline_sha = @project.repository.commit(params[:ref])&.sha

View File

@ -63,12 +63,17 @@ class Packages::Package < ApplicationRecord
validates :name, format: { with: Gitlab::Regex.package_name_regex }, unless: -> { conan? || generic? || debian? } validates :name, format: { with: Gitlab::Regex.package_name_regex }, unless: -> { conan? || generic? || debian? }
validates :name, validates :name,
uniqueness: { scope: %i[project_id version package_type] }, unless: -> { conan? || debian_package? } uniqueness: {
validate :unique_debian_package_name, if: :debian_package? scope: %i[project_id version package_type],
conditions: -> { not_pending_destruction}
},
unless: -> { pending_destruction? || conan? || debian_package? }
validate :unique_debian_package_name, if: :debian_package?
validate :valid_conan_package_recipe, if: :conan? validate :valid_conan_package_recipe, if: :conan?
validate :valid_composer_global_name, if: :composer? validate :valid_composer_global_name, if: :composer?
validate :npm_package_already_taken, if: :npm? validate :npm_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 :name, format: { with: Gitlab::Regex.helm_package_regex }, if: :helm? validates :name, format: { with: Gitlab::Regex.helm_package_regex }, if: :helm?
@ -320,6 +325,7 @@ class Packages::Package < ApplicationRecord
recipe_exists = project.packages recipe_exists = project.packages
.conan .conan
.includes(:conan_metadatum) .includes(:conan_metadatum)
.not_pending_destruction
.with_name(name) .with_name(name)
.with_version(version) .with_version(version)
.with_conan_channel(conan_metadatum.package_channel) .with_conan_channel(conan_metadatum.package_channel)
@ -334,9 +340,14 @@ class Packages::Package < ApplicationRecord
# .default_scoped is required here due to a bug in rails that leaks # .default_scoped is required here due to a bug in rails that leaks
# the scope and adds `self` to the query incorrectly # the scope and adds `self` to the query incorrectly
# See https://github.com/rails/rails/pull/35186 # See https://github.com/rails/rails/pull/35186
if Packages::Package.default_scoped.composer.with_name(name).where.not(project_id: project_id).exists? package_exists = Packages::Package.default_scoped
errors.add(:name, 'is already taken by another project') .composer
end .not_pending_destruction
.with_name(name)
.where.not(project_id: project_id)
.exists?
errors.add(:name, 'is already taken by another project') if package_exists
end end
def npm_package_already_taken def npm_package_already_taken
@ -361,6 +372,7 @@ class Packages::Package < ApplicationRecord
package_exists = debian_publication.distribution.packages package_exists = debian_publication.distribution.packages
.with_name(name) .with_name(name)
.with_version(version) .with_version(version)
.not_pending_destruction
.id_not_in(id) .id_not_in(id)
.exists? .exists?

View File

@ -2641,6 +2641,7 @@ class Project < ApplicationRecord
Packages::Package.with_name(package_name) Packages::Package.with_name(package_name)
.with_version(package_version) .with_version(package_version)
.with_package_type(package_type) .with_package_type(package_type)
.not_pending_destruction
.for_projects( .for_projects(
root_ancestor.all_projects root_ancestor.all_projects
.id_not_in(id) .id_not_in(id)

View File

@ -11,6 +11,7 @@ module Packages
project project
.packages .packages
.with_package_type(package_type) .with_package_type(package_type)
.not_pending_destruction
.find_or_create_by!(name: name, version: version) do |package| .find_or_create_by!(name: name, version: version) do |package|
package.status = params[:status] if params[:status] package.status = params[:status] if params[:status]
package.creator = package_creator package.creator = package_creator

View File

@ -11,6 +11,7 @@ module Packages
.with_name(params[:name]) .with_name(params[:name])
.with_version(params[:version]) .with_version(params[:version])
.with_debian_codename(params[:distribution_name]) .with_debian_codename(params[:distribution_name])
.not_pending_destruction
.first .first
package ||= create_package!( package ||= create_package!(

View File

@ -68,6 +68,7 @@ module Packages
package = project_packages.with_package_type(:helm) package = project_packages.with_package_type(:helm)
.with_name(metadata['name']) .with_name(metadata['name'])
.with_version(metadata['version']) .with_version(metadata['version'])
.not_pending_destruction
.last .last
package || temp_package package || temp_package
end end

View File

@ -33,6 +33,7 @@ module Packages
.npm .npm
.with_name(name) .with_name(name)
.with_version(version) .with_version(version)
.not_pending_destruction
.exists? .exists?
end end

View File

@ -98,6 +98,7 @@ module Packages
.nuget .nuget
.with_name(package_name) .with_name(package_name)
.with_version(package_version) .with_version(package_version)
.not_pending_destruction
.first .first
end end
end end

View File

@ -91,6 +91,7 @@ module Packages
.rubygems .rubygems
.with_name(gemspec.name) .with_name(gemspec.name)
.with_version(gemspec.version.to_s) .with_version(gemspec.version.to_s)
.not_pending_destruction
.last .last
package || temp_package package || temp_package
end end

View File

@ -29,6 +29,7 @@ module Packages
.for_projects(project.root_namespace.all_projects.id_not_in(project.id)) .for_projects(project.root_namespace.all_projects.id_not_in(project.id))
.with_package_type(:terraform_module) .with_package_type(:terraform_module)
.with_name(name) .with_name(name)
.not_pending_destruction
.exists? .exists?
end end
@ -37,6 +38,7 @@ module Packages
.with_package_type(:terraform_module) .with_package_type(:terraform_module)
.with_name(name) .with_name(name)
.with_version(params[:module_version]) .with_version(params[:module_version])
.not_pending_destruction
.exists? .exists?
end end

View File

@ -69,27 +69,24 @@ module QuickActions
Gitlab::QuickActions::Extractor.new(self.class.command_definitions) Gitlab::QuickActions::Extractor.new(self.class.command_definitions)
end end
# rubocop: disable CodeReuse/ActiveRecord
def extract_users(params) def extract_users(params)
return [] if params.nil? return [] if params.blank?
args = params.split(' ').uniq # We are using the a simple User.by_username query here rather than a ReferenceExtractor
users = extract_references(params, :user) # because the needs here are much simpler: we only deal in usernames, and
# want to also handle bare usernames. The ReferenceExtractor also has
# different behaviour, and will return all group members for groups named
# using a user-style reference, which is not in scope here.
args = params.split(/\s|,/).select(&:present?).uniq - ['and']
usernames = (args - ['me']).map { _1.delete_prefix('@') }
found = User.by_username(usernames).to_a.select { can?(:read_user_profile, _1) }
found_names = found.map(&:username).to_set
missing = args.reject { |arg| arg == 'me' || found_names.include?(arg.delete_prefix('@')) }.map { "'#{_1}'" }
if users.empty? failed_parse(format(_("Failed to find users for %{missing}"), missing: missing.to_sentence)) if missing.present?
users =
if params.strip == 'me'
[current_user]
else
User.where(username: args)
end
end
failed_parse(format(_("Failed to find users for '%{params}'"), params: params)) unless users.size == args.size found + [current_user].select { args.include?('me') }
users
end end
# rubocop: enable CodeReuse/ActiveRecord
def find_milestones(project, params = {}) def find_milestones(project, params = {})
group_ids = project.group.self_and_ancestors.select(:id) if project.group group_ids = project.group.self_and_ancestors.select(:id) if project.group
@ -194,6 +191,10 @@ module QuickActions
user: current_user user: current_user
) )
end end
def can?(ability, object)
Ability.allowed?(current_user, ability, object)
end
end end
end end

View File

@ -1,15 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Gitlab
class Experiment
class Configuration
def self.deprecated(*args, version:, stack: 0)
# do nothing here
end
end
end
end
Gitlab::Experiment.configure do |config| Gitlab::Experiment.configure do |config|
# The base experiment class that will be instantiated when using the # The base experiment class that will be instantiated when using the
# `experiment` DSL, is our ApplicationExperiment. If a custom experiment # `experiment` DSL, is our ApplicationExperiment. If a custom experiment
@ -81,4 +71,31 @@ Gitlab::Experiment.configure do |config|
) )
)) ))
end end
# Deprecation warnings resolution for 0.7.0
#
# We're working through deprecation warnings one by one in:
# https://gitlab.com/gitlab-org/gitlab/-/issues/350944
#
config.singleton_class.prepend(Module.new do
# Disable all deprecations in non dev/test environments.
#
def deprecated(*args, version:, stack: 0)
super if Gitlab.dev_or_test_env?
end
# Maintain a list of resolved deprecations to ensure that no new uses appear.
#
# Once a resolved deprecation warning has been added here, any future use will
# raise an exception.
#
ActiveSupport::Deprecation.disallowed_warnings += [
# 'Gitlab::Experiment 0.8 (instead use `control`)', # don't use `use`
# 'Gitlab::Experiment 0.8 (instead use `candidate`)', # don't use `try`
# 'Gitlab::Experiment 0.8 (instead use `variant(:variant_name)`)', # don't use `try(:variant_name)`
# 'Gitlab::Experiment 0.8 (instead use `assigned(:candidate)`)', # don't use variant(:variant_name) to assign
# 'Gitlab::Experiment 0.8 (instead use `assigned`)', # don't use variant.name to get the assigned variant
# 'Gitlab::Experiment 0.8, instead register variants using:', # don't use public `*_behavior` methods
]
end)
end end

View File

@ -0,0 +1,28 @@
# frozen_string_literal: true
class FixUniquePackagesIndexExcludingPendingDestructionStatus < Gitlab::Database::Migration[1.0]
disable_ddl_transaction!
GO_UNIQUE_INDEX_NAME = 'index_packages_on_project_id_name_version_unique_when_golang'
GENERIC_UNIQUE_INDEX_NAME = 'index_packages_on_project_id_name_version_unique_when_generic'
HELM_UNIQUE_INDEX_NAME = 'index_packages_on_project_id_name_version_unique_when_helm'
NEW_GO_UNIQUE_INDEX_NAME = 'idx_packages_on_project_id_name_version_unique_when_golang'
NEW_GENERIC_UNIQUE_INDEX_NAME = 'idx_packages_on_project_id_name_version_unique_when_generic'
NEW_HELM_UNIQUE_INDEX_NAME = 'idx_packages_on_project_id_name_version_unique_when_helm'
def up
add_concurrent_index :packages_packages, [:project_id, :name, :version], unique: true, name: NEW_GO_UNIQUE_INDEX_NAME, where: 'package_type = 8 AND status != 4'
add_concurrent_index :packages_packages, [:project_id, :name, :version], unique: true, name: NEW_GENERIC_UNIQUE_INDEX_NAME, where: 'package_type = 7 AND status != 4'
add_concurrent_index :packages_packages, [:project_id, :name, :version], unique: true, name: NEW_HELM_UNIQUE_INDEX_NAME, where: 'package_type = 11 AND status != 4'
remove_concurrent_index_by_name :packages_packages, GO_UNIQUE_INDEX_NAME
remove_concurrent_index_by_name :packages_packages, GENERIC_UNIQUE_INDEX_NAME
remove_concurrent_index_by_name :packages_packages, HELM_UNIQUE_INDEX_NAME
end
def down
# no-op
# We can't guarantee that the old index can be recreated since it targets a set larger that the new index.
end
end

View File

@ -0,0 +1 @@
dac90da1a8c5af69610dd103c8db9cd70a395ad5f9addafb554a853d6acd2a6e

View File

@ -25322,6 +25322,12 @@ CREATE INDEX idx_packages_debian_group_component_files_on_architecture_id ON pac
CREATE INDEX idx_packages_debian_project_component_files_on_architecture_id ON packages_debian_project_component_files USING btree (architecture_id); CREATE INDEX idx_packages_debian_project_component_files_on_architecture_id ON packages_debian_project_component_files USING btree (architecture_id);
CREATE UNIQUE INDEX idx_packages_on_project_id_name_version_unique_when_generic ON packages_packages USING btree (project_id, name, version) WHERE ((package_type = 7) AND (status <> 4));
CREATE UNIQUE INDEX idx_packages_on_project_id_name_version_unique_when_golang ON packages_packages USING btree (project_id, name, version) WHERE ((package_type = 8) AND (status <> 4));
CREATE UNIQUE INDEX idx_packages_on_project_id_name_version_unique_when_helm ON packages_packages USING btree (project_id, name, version) WHERE ((package_type = 11) AND (status <> 4));
CREATE INDEX idx_packages_packages_on_project_id_name_version_package_type ON packages_packages USING btree (project_id, name, version, package_type); CREATE INDEX idx_packages_packages_on_project_id_name_version_package_type ON packages_packages USING btree (project_id, name, version, package_type);
CREATE INDEX idx_pkgs_debian_group_distribution_keys_on_distribution_id ON packages_debian_group_distribution_keys USING btree (distribution_id); CREATE INDEX idx_pkgs_debian_group_distribution_keys_on_distribution_id ON packages_debian_group_distribution_keys USING btree (distribution_id);
@ -27190,12 +27196,6 @@ CREATE INDEX index_packages_maven_metadata_on_path ON packages_maven_metadata US
CREATE INDEX index_packages_nuget_dl_metadata_on_dependency_link_id ON packages_nuget_dependency_link_metadata USING btree (dependency_link_id); CREATE INDEX index_packages_nuget_dl_metadata_on_dependency_link_id ON packages_nuget_dependency_link_metadata USING btree (dependency_link_id);
CREATE UNIQUE INDEX index_packages_on_project_id_name_version_unique_when_generic ON packages_packages USING btree (project_id, name, version) WHERE (package_type = 7);
CREATE UNIQUE INDEX index_packages_on_project_id_name_version_unique_when_golang ON packages_packages USING btree (project_id, name, version) WHERE (package_type = 8);
CREATE UNIQUE INDEX index_packages_on_project_id_name_version_unique_when_helm ON packages_packages USING btree (project_id, name, version) WHERE (package_type = 11);
CREATE INDEX index_packages_package_file_build_infos_on_package_file_id ON packages_package_file_build_infos USING btree (package_file_id); CREATE INDEX index_packages_package_file_build_infos_on_package_file_id ON packages_package_file_build_infos USING btree (package_file_id);
CREATE INDEX index_packages_package_file_build_infos_on_pipeline_id ON packages_package_file_build_infos USING btree (pipeline_id); CREATE INDEX index_packages_package_file_build_infos_on_pipeline_id ON packages_package_file_build_infos USING btree (pipeline_id);

View File

@ -23,10 +23,10 @@ Gitaly Cluster and [Geo](../geo/index.md) both provide redundancy. However the r
The following table outlines the major differences between Gitaly Cluster and Geo: The following table outlines the major differences between Gitaly Cluster and Geo:
| Tool | Nodes | Locations | Latency tolerance | Failover | Consistency | Provides redundancy for | | Tool | Nodes | Locations | Latency tolerance | Failover | Consistency | Provides redundancy for |
|:---------------|:---------|:----------|:-------------------|:----------------------------------------------------------------------------|:-----------------------------------------|:------------------------| |:---------------|:---------|:----------|:------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------|:--------------------------------------|:------------------------|
| Gitaly Cluster | Multiple | Single | Approximately 1 ms | [Automatic](praefect.md#automatic-failover-and-primary-election-strategies) | [Strong](index.md#strong-consistency) | Data storage in Git | | Gitaly Cluster | Multiple | Single | [Less than 1 second, ideally single-digit milliseconds](praefect.md#network-latency-and-connectivity) | [Automatic](praefect.md#automatic-failover-and-primary-election-strategies) | [Strong](index.md#strong-consistency) | Data storage in Git |
| Geo | Multiple | Multiple | Up to one minute | [Manual](../geo/disaster_recovery/index.md) | Eventual | Entire GitLab instance | | Geo | Multiple | Multiple | Up to one minute | [Manual](../geo/disaster_recovery/index.md) | Eventual | Entire GitLab instance |
For more information, see: For more information, see:

View File

@ -39,10 +39,26 @@ NOTE:
If not set in GitLab, feature flags are read as false from the console and Praefect uses their If not set in GitLab, feature flags are read as false from the console and Praefect uses their
default value. The default value depends on the GitLab version. default value. The default value depends on the GitLab version.
### Network connectivity ### Network latency and connectivity
Gitaly Cluster [components](index.md#components) need to communicate with each other over many Network latency for Gitaly Cluster should ideally be measurable in single-digit milliseconds. Latency is particularly
routes. Your firewall rules must allow the following for Gitaly Cluster to function properly: important for:
- Gitaly node health checks. Nodes must be able to respond within 1 second.
- Reference transactions that enforce [strong consistency](index.md#strong-consistency). Lower latencies mean Gitaly
nodes can agree on changes faster.
Achieving acceptable latency between Gitaly nodes:
- On physical networks generally means high bandwidth, single location connections.
- On the cloud generally means within the same region, including allowing cross availability zone replication. These links
are designed for this type of synchronization. Latency of less than 2ms should be sufficient for Gitaly Cluster.
If you can't provide low network latencies for replication (for example, between distant locations), consider Geo. For
more information, see [How does Gitaly Cluster compare to Geo](faq.md#how-does-gitaly-cluster-compare-to-geo).
Gitaly Cluster [components](index.md#components) communicate with each other over many routes. Your firewall rules must
allow the following for Gitaly Cluster to function properly:
| From | To | Default port | TLS port | | From | To | Default port | TLS port |
|:-----------------------|:-----------------------|:-------------|:---------| |:-----------------------|:-----------------------|:-------------|:---------|

View File

@ -145,6 +145,7 @@ module API
.with_conan_username(params[:package_username]) .with_conan_username(params[:package_username])
.with_conan_channel(params[:package_channel]) .with_conan_channel(params[:package_channel])
.order_created .order_created
.not_pending_destruction
.last .last
end end
end end

View File

@ -14921,7 +14921,7 @@ msgstr ""
msgid "Failed to find import label for Jira import." msgid "Failed to find import label for Jira import."
msgstr "" msgstr ""
msgid "Failed to find users for '%{params}'" msgid "Failed to find users for %{missing}"
msgstr "" msgstr ""
msgid "Failed to generate export, please try again later." msgid "Failed to generate export, please try again later."

View File

@ -17,6 +17,14 @@ RSpec.describe Projects::TagsController do
expect(assigns(:tags).map(&:name)).to include('v1.1.0', 'v1.0.0') expect(assigns(:tags).map(&:name)).to include('v1.1.0', 'v1.0.0')
end end
context 'default sort for tags' do
it 'sorts tags by recently updated' do
subject
expect(assigns(:sort)).to eq('updated_desc')
end
end
context 'when Gitaly is unavailable' do context 'when Gitaly is unavailable' do
where(:format) do where(:format) do
[:html, :atom] [:html, :atom]

View File

@ -391,4 +391,29 @@ RSpec.describe ApplicationExperiment, :experiment do
end end
end end
end end
context "with deprecation warnings" do
before do
Gitlab::Experiment::Configuration.instance_variable_set(:@__dep_versions, nil) # clear the internal memoization
allow(ActiveSupport::Deprecation).to receive(:new).and_call_original
end
it "doesn't warn on non dev/test environments" do
allow(Gitlab).to receive(:dev_or_test_env?).and_return(false)
expect { experiment(:example) { |e| e.use { } } }.not_to raise_error
expect(ActiveSupport::Deprecation).not_to have_received(:new).with(anything, 'Gitlab::Experiment')
end
it "warns on dev and test environments" do
allow(Gitlab).to receive(:dev_or_test_env?).and_return(true)
# This will eventually raise an ActiveSupport::Deprecation exception,
# it's ok to change it when that happens.
expect { experiment(:example) { |e| e.use { } } }.not_to raise_error
expect(ActiveSupport::Deprecation).to have_received(:new).with(anything, 'Gitlab::Experiment')
end
end
end end

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Instance integrations', :js do
include_context 'instance integration activation'
it_behaves_like 'integration settings form' do
let(:integrations) { Integration.find_or_initialize_all_non_project_specific(Integration.for_instance) }
def navigate_to_integration(integration)
visit_instance_integration(integration.title)
end
end
end

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Group integrations', :js do
include_context 'group integration activation'
it_behaves_like 'integration settings form' do
let(:integrations) { Integration.find_or_initialize_all_non_project_specific(Integration.for_group(group)) }
def navigate_to_integration(integration)
visit_group_integration(integration.title)
end
end
end

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Project integrations', :js do
include_context 'project integration activation'
it_behaves_like 'integration settings form' do
let(:integrations) { project.find_or_initialize_integrations }
def navigate_to_integration(integration)
visit_project_integration(integration.title)
end
end
end

View File

@ -475,6 +475,15 @@ RSpec.describe Packages::Package, type: :model do
end end
end end
shared_examples 'validating both if the first package is pending destruction' do
before do
package.status = :pending_destruction
end
it_behaves_like 'validating the first package'
it_behaves_like 'validating the second package'
end
context 'following the naming convention' do context 'following the naming convention' do
let(:name) { "@#{group.path}/test" } let(:name) { "@#{group.path}/test" }
@ -503,6 +512,7 @@ RSpec.describe Packages::Package, type: :model do
it_behaves_like 'validating the first package' it_behaves_like 'validating the first package'
it_behaves_like 'not validating the second package', field_with_error: :name it_behaves_like 'not validating the second package', field_with_error: :name
it_behaves_like 'validating both if the first package is pending destruction'
end end
end end
@ -531,6 +541,7 @@ RSpec.describe Packages::Package, type: :model do
it_behaves_like 'validating the first package' it_behaves_like 'validating the first package'
it_behaves_like 'not validating the second package', field_with_error: :base it_behaves_like 'not validating the second package', field_with_error: :base
it_behaves_like 'validating both if the first package is pending destruction'
end end
end end
end end
@ -563,6 +574,7 @@ RSpec.describe Packages::Package, type: :model do
it_behaves_like 'validating the first package' it_behaves_like 'validating the first package'
it_behaves_like 'not validating the second package', field_with_error: :name it_behaves_like 'not validating the second package', field_with_error: :name
it_behaves_like 'validating both if the first package is pending destruction'
end end
end end
@ -591,6 +603,7 @@ RSpec.describe Packages::Package, type: :model do
it_behaves_like 'validating the first package' it_behaves_like 'validating the first package'
it_behaves_like 'validating the second package' it_behaves_like 'validating the second package'
it_behaves_like 'validating both if the first package is pending destruction'
end end
end end
end end
@ -598,19 +611,53 @@ RSpec.describe Packages::Package, type: :model do
end end
context "recipe uniqueness for conan packages" do context "recipe uniqueness for conan packages" do
let!(:package) { create('conan_package') } let_it_be(:package) { create(:conan_package) }
it "will allow a conan package with same project, name, version and package_type" do it "will allow a conan package with same project, name, version and package_type" do
new_package = build('conan_package', project: package.project, name: package.name, version: package.version) new_package = build(:conan_package, project: package.project, name: package.name, version: package.version)
new_package.conan_metadatum.package_channel = 'beta' new_package.conan_metadatum.package_channel = 'beta'
expect(new_package).to be_valid expect(new_package).to be_valid
end end
it "will not allow a conan package with same recipe (name, version, metadatum.package_channel, metadatum.package_username, and package_type)" do it "will not allow a conan package with same recipe (name, version, metadatum.package_channel, metadatum.package_username, and package_type)" do
new_package = build('conan_package', project: package.project, name: package.name, version: package.version) new_package = build(:conan_package, project: package.project, name: package.name, version: package.version)
expect(new_package).not_to be_valid expect(new_package).not_to be_valid
expect(new_package.errors.to_a).to include("Package recipe already exists") expect(new_package.errors.to_a).to include("Package recipe already exists")
end end
context 'with pending destruction package' do
let_it_be(:package) { create(:conan_package, :pending_destruction) }
it 'will allow a conan package with same recipe (name, version, metadatum.package_channel, metadatum.package_username, and package_type)' do
new_package = build(:conan_package, project: package.project, name: package.name, version: package.version)
expect(new_package).to be_valid
end
end
end
describe '#valid_composer_global_name' do
let_it_be(:package) { create(:composer_package) }
context 'with different name and different project' do
let(:new_package) { build(:composer_package, name: 'different_name') }
it { expect(new_package).to be_valid }
end
context 'with same name and different project' do
let(:new_package) { build(:composer_package, name: package.name) }
it 'will not validate second package' do
expect(new_package).not_to be_valid
expect(new_package.errors.to_a).to include('Name is already taken by another project')
end
context 'with pending destruction package' do
let_it_be(:package) { create(:composer_package, :pending_destruction) }
it { expect(new_package).to be_valid }
end
end
end end
describe "#unique_debian_package_name" do describe "#unique_debian_package_name" do
@ -632,6 +679,16 @@ RSpec.describe Packages::Package, type: :model do
new_package = build(:debian_package, project: package.project, name: package.name, version: package.version, published_in: nil) new_package = build(:debian_package, project: package.project, name: package.name, version: package.version, published_in: nil)
expect(new_package).to be_valid expect(new_package).to be_valid
end end
context 'with pending_destruction package' do
let!(:package) { create(:debian_package, :pending_destruction) }
it "will allow a Debian package with same project, name, version and distribution" do
new_package = build(:debian_package, project: package.project, name: package.name, version: package.version)
new_package.debian_publication.distribution = package.debian_publication.distribution
expect(new_package).to be_valid
end
end
end end
Packages::Package.package_types.keys.without('conan', 'debian').each do |pt| Packages::Package.package_types.keys.without('conan', 'debian').each do |pt|
@ -1267,4 +1324,16 @@ RSpec.describe Packages::Package, type: :model do
end end
end end
end end
context 'with identical pending destruction package' do
described_class.package_types.keys.each do |package_format|
context "for package format #{package_format}" do
let_it_be(:package_pending_destruction) { create("#{package_format}_package", :pending_destruction) }
let(:new_package) { build("#{package_format}_package", name: package_pending_destruction.name, version: package_pending_destruction.version, project: package_pending_destruction.project) }
it { expect(new_package).to be_valid }
end
end
end
end end

View File

@ -7159,7 +7159,7 @@ RSpec.describe Project, factory_default: :keep do
describe '#package_already_taken?' do describe '#package_already_taken?' do
let_it_be(:namespace) { create(:namespace, path: 'test') } let_it_be(:namespace) { create(:namespace, path: 'test') }
let_it_be(:project) { create(:project, :public, namespace: namespace) } let_it_be(:project) { create(:project, :public, namespace: namespace) }
let_it_be(:package) { create(:npm_package, project: project, name: "@#{namespace.path}/foo", version: '1.2.3') } let_it_be_with_reload(:package) { create(:npm_package, project: project, name: "@#{namespace.path}/foo", version: '1.2.3') }
subject { project.package_already_taken?(package_name, package_version, package_type: :npm) } subject { project.package_already_taken?(package_name, package_version, package_type: :npm) }
@ -7198,6 +7198,23 @@ RSpec.describe Project, factory_default: :keep do
expect(result).to be false expect(result).to be false
end end
end end
context 'with a pending_destruction package' do
before do
package.pending_destruction!
end
where(:package_name, :package_version, :expected_result) do
'@test/bar' | '1.2.3' | false
'@test/bar' | '5.5.5' | false
'@test/foo' | '1.2.3' | false
'@test/foo' | '5.5.5' | false
end
with_them do
it { is_expected.to eq expected_result}
end
end
end end
end end

View File

@ -327,6 +327,35 @@ RSpec.describe API::ComposerPackages do
it_behaves_like 'rejects Composer access with unknown project id' it_behaves_like 'rejects Composer access with unknown project id'
end end
context 'with existing package' do
include_context 'Composer api project access', 'PRIVATE', :developer, true, true
let_it_be_with_reload(:existing_package) { create(:composer_package, name: package_name, version: '1.2.99', project: project) }
let(:params) { { tag: 'v1.2.99' } }
before do
project.add_maintainer(user)
end
it 'does not create a new package' do
expect { subject }
.to change { project.packages.composer.count }.by(0)
expect(response).to have_gitlab_http_status(:created)
end
context 'marked as pending_destruction' do
it 'does create a new package' do
existing_package.pending_destruction!
expect { subject }
.to change { project.packages.composer.count }.by(1)
expect(response).to have_gitlab_http_status(:created)
end
end
end
context 'with no tag or branch params' do context 'with no tag or branch params' do
let(:headers) { basic_auth_header(user.username, personal_access_token.token) } let(:headers) { basic_auth_header(user.username, personal_access_token.token) }

View File

@ -426,6 +426,33 @@ RSpec.describe API::GenericPackages do
it_behaves_like 'a package tracking event', described_class.name, 'push_package' it_behaves_like 'a package tracking event', described_class.name, 'push_package'
end end
context 'with existing package' do
let_it_be(:package_name) { 'mypackage' }
let_it_be(:package_version) { '1.2.3' }
let_it_be_with_reload(:existing_package) { create(:generic_package, name: package_name, version: package_version, project: project) }
let(:headers) { workhorse_headers.merge(personal_access_token_header) }
it 'does not create a new package' do
expect { upload_file(params, headers, package_name: package_name, package_version: package_version) }
.to change { project.packages.generic.count }.by(0)
.and change { Packages::PackageFile.count }.by(1)
expect(response).to have_gitlab_http_status(:created)
end
context 'marked as pending_destruction' do
it 'does create a new package' do
existing_package.pending_destruction!
expect { upload_file(params, headers, package_name: package_name, package_version: package_version) }
.to change { project.packages.generic.count }.by(1)
.and change { Packages::PackageFile.count }.by(1)
expect(response).to have_gitlab_http_status(:created)
end
end
end
it 'rejects request without a file from workhorse' do it 'rejects request without a file from workhorse' do
headers = workhorse_headers.merge(personal_access_token_header) headers = workhorse_headers.merge(personal_access_token_header)
upload_file({}, headers) upload_file({}, headers)

View File

@ -230,6 +230,35 @@ RSpec.describe API::PypiPackages do
it_behaves_like 'returning response status', :bad_request it_behaves_like 'returning response status', :bad_request
end end
context 'with existing package' do
let_it_be_with_reload(:existing_package) { create(:pypi_package, name: 'sample-project', version: '1.0.0', project: project) }
let(:headers) { basic_auth_header(user.username, personal_access_token.token).merge(workhorse_headers) }
before do
project.add_maintainer(user)
end
it 'does not create a new package', :aggregate_failures do
expect { subject }
.to change { project.packages.pypi.count }.by(0)
.and change { Packages::PackageFile.count }.by(1)
.and change { Packages::Pypi::Metadatum.count }.by(0)
expect(response).to have_gitlab_http_status(:created)
end
context 'marked as pending_destruction' do
it 'does create a new package', :aggregate_failures do
existing_package.pending_destruction!
expect { subject }
.to change { project.packages.pypi.count }.by(1)
.and change { Packages::PackageFile.count }.by(1)
.and change { Packages::Pypi::Metadatum.count }.by(1)
expect(response).to have_gitlab_http_status(:created)
end
end
end
end end
context 'file download endpoint' do context 'file download endpoint' do

View File

@ -401,6 +401,28 @@ RSpec.describe API::Terraform::Modules::V1::Packages do
.and change { Packages::PackageFile.count }.by(0) .and change { Packages::PackageFile.count }.by(0)
expect(response).to have_gitlab_http_status(:error) expect(response).to have_gitlab_http_status(:error)
end end
context 'with an existing package' do
let_it_be_with_reload(:existing_package) { create(:terraform_module_package, name: 'mymodule/mysystem', version: '1.0.0', project: project) }
it 'does not create a new package' do
expect { subject }
.to change { project.packages.count }.by(0)
.and change { Packages::PackageFile.count }.by(0)
expect(response).to have_gitlab_http_status(:forbidden)
end
context 'marked as pending_destruction' do
it 'does create a new package' do
existing_package.pending_destruction!
expect { subject }
.to change { project.packages.count }.by(1)
.and change { Packages::PackageFile.count }.by(1)
expect(response).to have_gitlab_http_status(:created)
end
end
end
end end
end end
end end

View File

@ -88,13 +88,23 @@ RSpec.describe Packages::Composer::CreatePackageService do
end end
context 'belonging to another project' do context 'belonging to another project' do
let(:other_project) { create(:project) } let(:other_project) { create(:project)}
let!(:other_package) { create(:composer_package, name: package_name, version: 'dev-master', project: other_project) } let!(:other_package) { create(:composer_package, name: package_name, version: 'dev-master', project: other_project) }
it 'fails with an error' do it 'fails with an error' do
expect { subject } expect { subject }
.to raise_error(/is already taken/) .to raise_error(/is already taken/)
end end
context 'with pending_destruction package' do
let!(:other_package) { create(:composer_package, :pending_destruction, name: package_name, version: 'dev-master', project: other_project) }
it 'creates the package' do
expect { subject }
.to change { Packages::Package.composer.count }.by(1)
.and change { Packages::Composer::Metadatum.count }.by(1)
end
end
end end
context 'same name but of different type' do context 'same name but of different type' do

View File

@ -32,8 +32,6 @@ RSpec.describe Packages::Debian::FindOrCreatePackageService do
end end
context 'run twice' do context 'run twice' do
let(:subject2) { service.execute }
let(:package2) { service.execute.payload[:package] } let(:package2) { service.execute.payload[:package] }
it 'returns the same object' do it 'returns the same object' do
@ -42,6 +40,16 @@ RSpec.describe Packages::Debian::FindOrCreatePackageService do
expect(package2.id).to eq(package.id) expect(package2.id).to eq(package.id)
end end
context 'with package marked as pending_destruction' do
it 'creates a new package' do
expect { subject }.to change { ::Packages::Package.count }.by(1)
package.pending_destruction!
expect { package2 }.to change { ::Packages::Package.count }.by(1)
expect(package2.id).not_to eq(package.id)
end
end
end end
context 'with non-existing distribution' do context 'with non-existing distribution' do

View File

@ -25,6 +25,30 @@ RSpec.describe Packages::Debian::ProcessChangesService do
expect(created_package.version).to eq '1.2.3~alpha2' expect(created_package.version).to eq '1.2.3~alpha2'
expect(created_package.creator).to eq user expect(created_package.creator).to eq user
end end
context 'with existing package' do
let_it_be_with_reload(:existing_package) { create(:debian_package, name: 'sample', version: '1.2.3~alpha2', project: distribution.project) }
before do
existing_package.update!(debian_distribution: distribution)
end
it 'does not create a package' do
expect { subject.execute }
.to not_change { Packages::Package.count }
.and not_change { Packages::PackageFile.count }
end
context 'marked as pending_destruction' do
it 'creates a package' do
existing_package.pending_destruction!
expect { subject.execute }
.to change { Packages::Package.count }.by(1)
.and not_change { Packages::PackageFile.count }
end
end
end
end end
context 'with invalid package file' do context 'with invalid package file' do

View File

@ -83,6 +83,23 @@ RSpec.describe Packages::Generic::FindOrCreatePackageService do
expect(package.reload.original_build_info.pipeline).to eq(pipeline) expect(package.reload.original_build_info.pipeline).to eq(pipeline)
end end
end end
context 'when a pending_destruction package exists', :aggregate_failures do
let!(:package) { project.packages.generic.create!(params.merge(status: :pending_destruction)) }
it 'creates a new package' do
service = described_class.new(project, user, params)
expect { service.execute }.to change { project.packages.generic.count }.by(1)
package = project.packages.generic.last
expect(package.creator).to eq(user)
expect(package.name).to eq('mypackage')
expect(package.version).to eq('0.0.1')
expect(package.original_build_info).to be_nil
end
end
end end
end end
end end

View File

@ -53,6 +53,19 @@ RSpec.describe Packages::Helm::ProcessFileService do
expect(package_file.helm_file_metadatum.channel).to eq(channel) expect(package_file.helm_file_metadatum.channel).to eq(channel)
expect(package_file.helm_file_metadatum.metadata).to eq(expected) expect(package_file.helm_file_metadatum.metadata).to eq(expected)
end end
context 'marked as pending_destruction' do
before do
existing_package.pending_destruction!
end
it 'reuses the processing package' do
expect { execute }
.to not_change { Packages::Package.count }
.and not_change { Packages::PackageFile.count }
.and change { Packages::Helm::FileMetadatum.count }.by(1)
end
end
end end
context 'with a valid file' do context 'with a valid file' do

View File

@ -81,6 +81,14 @@ RSpec.describe Packages::Maven::FindOrCreatePackageService do
let!(:existing_package) { create(:maven_package, name: path, version: version, project: project) } let!(:existing_package) { create(:maven_package, name: path, version: version, project: project) }
it_behaves_like 'reuse existing package' it_behaves_like 'reuse existing package'
context 'marked as pending_destruction' do
before do
existing_package.pending_destruction!
end
it_behaves_like 'create package'
end
end end
context 'without existing package' do context 'without existing package' do

View File

@ -112,6 +112,20 @@ RSpec.describe Packages::Npm::CreatePackageService do
it { expect(subject[:http_status]).to eq 403 } it { expect(subject[:http_status]).to eq 403 }
it { expect(subject[:message]).to be 'Package already exists.' } it { expect(subject[:message]).to be 'Package already exists.' }
context 'marked as pending_destruction' do
before do
existing_package.pending_destruction!
end
it 'creates a new package' do
expect { subject }
.to change { Packages::Package.count }.by(1)
.and change { Packages::Package.npm.count }.by(1)
.and change { Packages::Tag.count }.by(1)
.and change { Packages::Npm::Metadatum.count }.by(1)
end
end
end end
describe 'max file size validation' do describe 'max file size validation' do

View File

@ -106,6 +106,20 @@ RSpec.describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_
it_behaves_like 'taking the lease' it_behaves_like 'taking the lease'
it_behaves_like 'not updating the package if the lease is taken' it_behaves_like 'not updating the package if the lease is taken'
context 'marked as pending_destruction' do
before do
existing_package.pending_destruction!
end
it 'reuses the processing package', :aggregate_failures do
expect { subject }
.to not_change { ::Packages::Package.count }
.and change { Packages::Dependency.count }.by(1)
.and change { Packages::DependencyLink.count }.by(1)
.and change { ::Packages::Nuget::Metadatum.count }.by(0)
end
end
end end
context 'with a nuspec file with metadata' do context 'with a nuspec file with metadata' do

View File

@ -72,6 +72,27 @@ RSpec.describe Packages::Pypi::CreatePackageService do
.and change { Packages::PackageFile.count }.by(0) .and change { Packages::PackageFile.count }.by(0)
.and raise_error(/File name has already been taken/) .and raise_error(/File name has already been taken/)
end end
context 'with a pending_destruction package', :aggregate_failures do
before do
Packages::Package.pypi.last.pending_destruction!
end
it 'creates a new package' do
expect { subject }
.to change { Packages::Package.pypi.count }.by(1)
.and change { Packages::PackageFile.count }.by(1)
expect(created_package.name).to eq 'foo'
expect(created_package.version).to eq '1.0'
expect(created_package.pypi_metadatum.required_python).to eq '>=2.7'
expect(created_package.package_files.size).to eq 1
expect(created_package.package_files.first.file_name).to eq 'foo.tgz'
expect(created_package.package_files.first.file_sha256).to eq 'abc'
expect(created_package.package_files.first.file_md5).to eq 'def'
end
end
end end
context 'without an existing file' do context 'without an existing file' do

View File

@ -85,6 +85,28 @@ RSpec.describe Packages::Rubygems::ProcessGemService do
end end
end end
context 'when the package already exists marked as pending_destruction' do
let_it_be_with_reload(:existing_package) { create(:rubygems_package, name: 'package', version: '0.0.1', project: package.project) }
let(:sub_service) { double }
before do
expect(Packages::Rubygems::MetadataExtractionService).to receive(:new).with(package, gemspec).and_return(sub_service)
expect(Packages::Rubygems::CreateGemspecService).to receive(:new).with(package, gemspec).and_return(sub_service)
expect(Packages::Rubygems::CreateDependenciesService).to receive(:new).with(package, gemspec).and_return(sub_service)
expect(sub_service).to receive(:execute).exactly(3).times.and_return(true)
existing_package.pending_destruction!
end
it 'reuses the processing package' do
expect { subject }
.to not_change { package.project.packages.count }
.and not_change { existing_package.package_files.count }
end
end
context 'sub-service failure' do context 'sub-service failure' do
before do before do
expect(Packages::Rubygems::MetadataExtractionService).to receive(:new).with(package, gemspec).and_raise(::Packages::Rubygems::ProcessGemService::ExtractionError.new('failure')) expect(Packages::Rubygems::MetadataExtractionService).to receive(:new).with(package, gemspec).and_raise(::Packages::Rubygems::ProcessGemService::ExtractionError.new('failure'))

View File

@ -6,8 +6,6 @@ RSpec.describe Packages::TerraformModule::CreatePackageService do
let_it_be(:project) { create(:project, namespace: namespace) } let_it_be(:project) { create(:project, namespace: namespace) }
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:sha256) { '440e5e148a25331bbd7991575f7d54933c0ebf6cc735a18ee5066ac1381bb590' } let_it_be(:sha256) { '440e5e148a25331bbd7991575f7d54933c0ebf6cc735a18ee5066ac1381bb590' }
let_it_be(:temp_file) { Tempfile.new('test') }
let_it_be(:file) { UploadedFile.new(temp_file.path, sha256: sha256) }
let(:overrides) { {} } let(:overrides) { {} }
@ -16,7 +14,7 @@ RSpec.describe Packages::TerraformModule::CreatePackageService do
module_name: 'foo', module_name: 'foo',
module_system: 'bar', module_system: 'bar',
module_version: '1.0.1', module_version: '1.0.1',
file: file, file: UploadedFile.new(Tempfile.new('test').path, sha256: sha256),
file_name: 'foo-bar-1.0.1.tgz' file_name: 'foo-bar-1.0.1.tgz'
}.merge(overrides) }.merge(overrides)
end end
@ -24,7 +22,7 @@ RSpec.describe Packages::TerraformModule::CreatePackageService do
subject { described_class.new(project, user, params).execute } subject { described_class.new(project, user, params).execute }
describe '#execute' do describe '#execute' do
context 'valid package' do shared_examples 'creating a package' do
it 'creates a package' do it 'creates a package' do
expect { subject } expect { subject }
.to change { ::Packages::Package.count }.by(1) .to change { ::Packages::Package.count }.by(1)
@ -32,12 +30,24 @@ RSpec.describe Packages::TerraformModule::CreatePackageService do
end end
end end
context 'valid package' do
it_behaves_like 'creating a package'
end
context 'package already exists elsewhere' do context 'package already exists elsewhere' do
let(:project2) { create(:project, namespace: namespace) } let(:project2) { create(:project, namespace: namespace) }
let!(:existing_package) { create(:terraform_module_package, project: project2, name: 'foo/bar', version: '1.0.0') } let!(:existing_package) { create(:terraform_module_package, project: project2, name: 'foo/bar', version: '1.0.0') }
it { expect(subject[:http_status]).to eq 403 } it { expect(subject[:http_status]).to eq 403 }
it { expect(subject[:message]).to be 'Access Denied' } it { expect(subject[:message]).to be 'Access Denied' }
context 'marked as pending_destruction' do
before do
existing_package.pending_destruction!
end
it_behaves_like 'creating a package'
end
end end
context 'version already exists' do context 'version already exists' do
@ -45,6 +55,14 @@ RSpec.describe Packages::TerraformModule::CreatePackageService do
it { expect(subject[:http_status]).to eq 403 } it { expect(subject[:http_status]).to eq 403 }
it { expect(subject[:message]).to be 'Package version already exists.' } it { expect(subject[:message]).to be 'Package version already exists.' }
context 'marked as pending_destruction' do
before do
existing_version.pending_destruction!
end
it_behaves_like 'creating a package'
end
end end
context 'with empty version' do context 'with empty version' do

View File

@ -11,13 +11,14 @@ RSpec.describe QuickActions::InterpretService do
let_it_be(:developer2) { create(:user) } let_it_be(:developer2) { create(:user) }
let_it_be(:developer3) { create(:user) } let_it_be(:developer3) { create(:user) }
let_it_be_with_reload(:issue) { create(:issue, project: project) } let_it_be_with_reload(:issue) { create(:issue, project: project) }
let(:milestone) { create(:milestone, project: project, title: '9.10') }
let(:commit) { create(:commit, project: project) }
let_it_be(:inprogress) { create(:label, project: project, title: 'In Progress') } let_it_be(:inprogress) { create(:label, project: project, title: 'In Progress') }
let_it_be(:helmchart) { create(:label, project: project, title: 'Helm Chart Registry') } let_it_be(:helmchart) { create(:label, project: project, title: 'Helm Chart Registry') }
let_it_be(:bug) { create(:label, project: project, title: 'Bug') } let_it_be(:bug) { create(:label, project: project, title: 'Bug') }
let(:service) { described_class.new(project, developer) } let(:milestone) { create(:milestone, project: project, title: '9.10') }
let(:commit) { create(:commit, project: project) }
subject(:service) { described_class.new(project, developer) }
before_all do before_all do
public_project.add_developer(developer) public_project.add_developer(developer)
@ -970,6 +971,32 @@ RSpec.describe QuickActions::InterpretService do
it_behaves_like 'assign_reviewer command' it_behaves_like 'assign_reviewer command'
end end
context 'with a private user' do
let(:ref) { create(:user, :unconfirmed).to_reference }
let(:content) { "/assign_reviewer #{ref}" }
it_behaves_like 'failed command', 'a parse error' do
let(:match_msg) { eq "Could not apply assign_reviewer command. Failed to find users for '#{ref}'." }
end
end
context 'with a private user, bare username' do
let(:ref) { create(:user, :unconfirmed).username }
let(:content) { "/assign_reviewer #{ref}" }
it_behaves_like 'failed command', 'a parse error' do
let(:match_msg) { eq "Could not apply assign_reviewer command. Failed to find users for '#{ref}'." }
end
end
context 'with @all' do
let(:content) { "/assign_reviewer @all" }
it_behaves_like 'failed command', 'a parse error' do
let(:match_msg) { eq "Could not apply assign_reviewer command. Failed to find users for '@all'." }
end
end
context 'with an incorrect user' do context 'with an incorrect user' do
let(:content) { '/assign_reviewer @abcd1234' } let(:content) { '/assign_reviewer @abcd1234' }
@ -997,11 +1024,10 @@ RSpec.describe QuickActions::InterpretService do
end end
context 'with extra text' do context 'with extra text' do
let(:arg) { "@#{developer.username} do it!" } let(:content) { "/assign_reviewer #{developer.to_reference} do it!" }
let(:content) { "/assign_reviewer #{arg}" }
it_behaves_like 'failed command', 'a parse error' do it_behaves_like 'failed command', 'a parse error' do
let(:match_msg) { eq "Could not apply assign_reviewer command. Failed to find users for '#{arg}'." } let(:match_msg) { eq "Could not apply assign_reviewer command. Failed to find users for 'do' and 'it!'." }
end end
end end
end end
@ -2451,7 +2477,8 @@ RSpec.describe QuickActions::InterpretService do
it 'tells us why we cannot do that' do it 'tells us why we cannot do that' do
_, explanations = service.explain(content, merge_request) _, explanations = service.explain(content, merge_request)
expect(explanations).to eq ["Problem with assign command: Failed to find users for '#{arg}'."] expect(explanations)
.to contain_exactly "Problem with assign command: Failed to find users for 'to', 'this', and 'issue'."
end end
end end
end end

View File

@ -26,7 +26,3 @@ RSpec.configure do |config|
stub_snowplow stub_snowplow
end end
end end
# Once you've resolved a given deprecation, you can disallow it here, which
# will raise an exception if it's used anywhere.
ActiveSupport::Deprecation.disallowed_warnings << "`experiment_group?` is deprecated"

View File

@ -1,24 +1,14 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'spec_helper' RSpec.shared_examples 'integration settings form' do
RSpec.describe 'Integrations settings form', :js do
include IntegrationsHelper include IntegrationsHelper
include_context 'project integration activation'
# Github integration is EE, so let's remove it here.
integration_names = Integration.available_integration_names - %w[github]
integrations = integration_names.map do |name|
Integration.integration_name_to_model(name).new
end
# Note: these specs don't validate channel fields # Note: these specs don't validate channel fields
# which are present on a few integrations # which are present on a few integrations
integrations.each do |integration| it 'displays all the integrations' do
it "shows on #{integration.title}" do aggregate_failures do
visit_project_integration(integration.title) integrations.each do |integration|
navigate_to_integration(integration)
aggregate_failures do
page.within('form.integration-settings-form') do page.within('form.integration-settings-form') do
expect(page).to have_field('Active', type: 'checkbox', wait: 0), expect(page).to have_field('Active', type: 'checkbox', wait: 0),
"#{integration.title} active field not present" "#{integration.title} active field not present"
@ -43,6 +33,8 @@ RSpec.describe 'Integrations settings form', :js do
end end
end end
private
def normalize_title(title, integration) def normalize_title(title, integration)
return 'Merge request' if integration.is_a?(Integrations::Jira) && title == 'merge_request' return 'Merge request' if integration.is_a?(Integrations::Jira) && title == 'merge_request'

View File

@ -777,6 +777,32 @@ RSpec.shared_examples 'uploads a package file' do
subject subject
end end
context 'with existing package' do
let!(:existing_package) { create(:conan_package, name: 'foo', version: 'bar', project: project) }
before do
existing_package.conan_metadatum.update!(package_username: project.full_path.tr('/', '+'), package_channel: 'baz')
end
it 'does not create a new package' do
expect { subject }
.to not_change { project.packages.count }
.and not_change { Packages::Conan::Metadatum.count }
.and change { Packages::PackageFile.count }.by(1)
end
context 'marked as pending_destruction' do
it 'does not create a new package' do
existing_package.pending_destruction!
expect { subject }
.to change { project.packages.count }.by(1)
.and change { Packages::Conan::Metadatum.count }.by(1)
.and change { Packages::PackageFile.count }.by(1)
end
end
end
end end
end end

View File

@ -57,6 +57,18 @@ RSpec.describe Packages::Go::SyncPackagesWorker, type: :worker do
it_behaves_like 'it creates a package', '', 'v1.0.3' it_behaves_like 'it creates a package', '', 'v1.0.3'
it_behaves_like 'it creates a package', 'mod', 'v1.0.3' it_behaves_like 'it creates a package', 'mod', 'v1.0.3'
it_behaves_like 'it creates a package', 'v2', 'v2.0.0' it_behaves_like 'it creates a package', 'v2', 'v2.0.0'
context 'marked as pending_destruction' do
before do
project.packages.each(&:pending_destruction!)
end
it_behaves_like 'it creates a package', '', 'v1.0.1'
it_behaves_like 'it creates a package', '', 'v1.0.2'
it_behaves_like 'it creates a package', '', 'v1.0.3'
it_behaves_like 'it creates a package', 'mod', 'v1.0.3'
it_behaves_like 'it creates a package', 'v2', 'v2.0.0'
end
end end
context 'with a package that exceeds project limits' do context 'with a package that exceeds project limits' do