Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
16e3c17d3f
commit
8fd149139d
|
@ -40,7 +40,7 @@ export const fetchProjects = ({ commit, state }, search) => {
|
|||
);
|
||||
} else {
|
||||
// The .catch() is due to the API method not handling a rejection properly
|
||||
Api.projects(search, { order_by: 'id' }, callback).catch(() => {
|
||||
Api.projects(search, { order_by: 'similarity' }, callback).catch(() => {
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ module Clusters
|
|||
belongs_to :group, class_name: '::Group', optional: false
|
||||
|
||||
validates :config, json_schema: { filename: 'cluster_agent_authorization_configuration' }
|
||||
|
||||
delegate :project, to: :agent
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Clusters
|
||||
module Agents
|
||||
class ImplicitAuthorization
|
||||
attr_reader :agent
|
||||
|
||||
delegate :id, to: :agent, prefix: true
|
||||
delegate :project, to: :agent
|
||||
|
||||
def initialize(agent:)
|
||||
@agent = agent
|
||||
end
|
||||
|
||||
def config
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -21,11 +21,7 @@ module Packages
|
|||
|
||||
try_obtain_lease do
|
||||
@package_file.transaction do
|
||||
if use_new_package_file_updater?
|
||||
new_execute
|
||||
else
|
||||
legacy_execute
|
||||
end
|
||||
process_package_update
|
||||
end
|
||||
end
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
|
@ -34,7 +30,7 @@ module Packages
|
|||
|
||||
private
|
||||
|
||||
def new_execute
|
||||
def process_package_update
|
||||
package_to_destroy = nil
|
||||
target_package = @package_file.package
|
||||
|
||||
|
@ -50,36 +46,11 @@ module Packages
|
|||
end
|
||||
|
||||
update_package(target_package)
|
||||
|
||||
::Packages::UpdatePackageFileService.new(@package_file, package_id: target_package.id, file_name: package_filename)
|
||||
.execute
|
||||
|
||||
package_to_destroy&.destroy!
|
||||
end
|
||||
|
||||
def legacy_execute
|
||||
if existing_package
|
||||
package = link_to_existing_package
|
||||
elsif symbol_package?
|
||||
raise InvalidMetadataError, 'symbol package is invalid, matching package does not exist'
|
||||
else
|
||||
package = update_linked_package
|
||||
end
|
||||
|
||||
update_package(package)
|
||||
|
||||
# Updating file_name updates the path where the file is stored.
|
||||
# We must pass the file again so that CarrierWave can handle the update
|
||||
@package_file.update!(
|
||||
file_name: package_filename,
|
||||
file: @package_file.file
|
||||
)
|
||||
end
|
||||
|
||||
def use_new_package_file_updater?
|
||||
::Feature.enabled?(:packages_nuget_new_package_file_updater, @package_file.project, default_enabled: :yaml)
|
||||
end
|
||||
|
||||
def update_package(package)
|
||||
return if symbol_package?
|
||||
|
||||
|
|
|
@ -1,34 +1,38 @@
|
|||
= form_for @application_setting, url: network_admin_application_settings_path(anchor: 'js-import-export-limits-settings'), html: { class: 'fieldset-form' } do |f|
|
||||
= form_errors(@application_setting)
|
||||
|
||||
%fieldset
|
||||
= html_escape(_("Set any rate limit to %{code_open}0%{code_close} to disable the limit.")) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
|
||||
|
||||
|
||||
%fieldset
|
||||
.form-group
|
||||
= f.label :project_import_limit, _('Max Project Import requests per minute per user'), class: 'label-bold'
|
||||
= f.label :project_import_limit, _('Maximum project import requests per minute'), class: 'label-bold'
|
||||
= f.number_field :project_import_limit, class: 'form-control gl-form-input'
|
||||
|
||||
%fieldset
|
||||
.form-group
|
||||
= f.label :project_export_limit, _('Max Project Export requests per minute per user'), class: 'label-bold'
|
||||
= f.label :project_export_limit, _('Maximum project export requests per minute'), class: 'label-bold'
|
||||
= f.number_field :project_export_limit, class: 'form-control gl-form-input'
|
||||
|
||||
%fieldset
|
||||
.form-group
|
||||
= f.label :project_download_export_limit, _('Max Project Export Download requests per minute per user'), class: 'label-bold'
|
||||
= f.label :project_download_export_limit, _('Maximum project export download requests per minute'), class: 'label-bold'
|
||||
= f.number_field :project_download_export_limit, class: 'form-control gl-form-input'
|
||||
|
||||
%fieldset
|
||||
.form-group
|
||||
= f.label :group_import_limit, _('Max Group Import requests per minute per user'), class: 'label-bold'
|
||||
= f.label :group_import_limit, _('Maximum group import requests per minute'), class: 'label-bold'
|
||||
= f.number_field :group_import_limit, class: 'form-control gl-form-input'
|
||||
|
||||
%fieldset
|
||||
.form-group
|
||||
= f.label :group_export_limit, _('Max Group Export requests per minute per user'), class: 'label-bold'
|
||||
= f.label :group_export_limit, _('Maximum group export requests per minute'), class: 'label-bold'
|
||||
= f.number_field :group_export_limit, class: 'form-control gl-form-input'
|
||||
|
||||
%fieldset
|
||||
.form-group
|
||||
= f.label :group_download_export_limit, _('Max Group Export Download requests per minute per user'), class: 'label-bold'
|
||||
= f.label :group_download_export_limit, _('Maximum group export download requests per minute'), class: 'label-bold'
|
||||
= f.number_field :group_download_export_limit, class: 'form-control gl-form-input'
|
||||
|
||||
= f.submit _('Save changes'), class: "gl-button btn btn-confirm", data: { qa_selector: 'save_changes_button' }
|
||||
|
|
|
@ -110,11 +110,12 @@
|
|||
%section.settings.as-import-export-limits.no-animate#js-import-export-limits-settings{ class: ('expanded' if expanded_by_default?) }
|
||||
.settings-header
|
||||
%h4
|
||||
= _('Import/Export Rate Limits')
|
||||
= _('Import and export rate limits')
|
||||
%button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded_by_default? ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Configure limits for Project/Group Import/Export.')
|
||||
= _('Set per-user rate limits for imports and exports of projects and groups.')
|
||||
= link_to _('Learn more.'), help_page_path('user/admin_area/settings/import_export_rate_limits.md'), target: '_blank', rel: 'noopener noreferrer'
|
||||
.settings-content
|
||||
= render 'import_export_limits'
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
= _('Who can see this group?')
|
||||
- visibility_docs_path = help_page_path('public_access/public_access')
|
||||
- docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: visibility_docs_path }
|
||||
= s_('Check the %{docs_link_start}documentation%{docs_link_end}.').html_safe % { docs_link_start: docs_link_start, docs_link_end: '</a>'.html_safe }
|
||||
= _('%{docs_link_start}Learn about visibility levels.%{docs_link_end}').html_safe % { docs_link_start: docs_link_start, docs_link_end: '</a>'.html_safe }
|
||||
- if can_change_visibility_level
|
||||
= render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: visibility_level, form_model: form_model)
|
||||
- else
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: group_authorized_agents
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69047
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/340166
|
||||
milestone: '14.3'
|
||||
type: development
|
||||
group: group::configure
|
||||
default_enabled: false
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: packages_nuget_new_package_file_updater
|
||||
introduced_by_url:
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/336511
|
||||
milestone: '14.2'
|
||||
type: development
|
||||
group: group::package
|
||||
default_enabled: true
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/321258
|
|||
milestone: '13.9'
|
||||
type: development
|
||||
group: group::container security
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -54,7 +54,7 @@ To install the app in Jira:
|
|||
|
||||
1. Click **Upload**.
|
||||
|
||||
If the install was successful, you should see the **GitLab for Jira** app under **Manage apps**.
|
||||
If the install was successful, you should see the **GitLab.com for Jira Cloud** app under **Manage apps**.
|
||||
You can also click **Getting Started** to open the configuration page rendered from your GitLab instance.
|
||||
|
||||
_Note that any changes to the app descriptor requires you to uninstall then reinstall the app._
|
||||
|
|
|
@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
NOTE:
|
||||
Only Jira users with administrator level access are able to install or configure
|
||||
the GitLab app for Jira Cloud.
|
||||
the GitLab.com for Jira Cloud app.
|
||||
|
||||
## GitLab.com for Jira Cloud app **(FREE SAAS)**
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ To simplify administration, we recommend that a GitLab group maintainer or group
|
|||
|
||||
| Jira usage | GitLab.com customers need | GitLab self-managed customers need |
|
||||
|------------|---------------------------|------------------------------------|
|
||||
| [Atlassian cloud](https://www.atlassian.com/cloud) | The [GitLab.com for Jira Cloud](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud?hosting=cloud&tab=overview) application installed from the [Atlassian Marketplace](https://marketplace.atlassian.com). This offers real-time sync between GitLab and Jira. For more information, see the documentation for the [GitLab.com for Jira Cloud app](connect-app.md). | The [GitLab.com for Jira Cloud](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud?hosting=cloud&tab=overview), using a workaround process. See the documentation for [installing the GitLab Jira Cloud application for self-managed instances](connect-app.md#install-the-gitlabcom-for-jira-cloud-app-for-self-managed-instances) for more information. |
|
||||
| [Atlassian cloud](https://www.atlassian.com/cloud) | The [GitLab.com for Jira Cloud app](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud?hosting=cloud&tab=overview) installed from the [Atlassian Marketplace](https://marketplace.atlassian.com). This offers real-time sync between GitLab.com and Jira. For more information, see the documentation for the [GitLab.com for Jira Cloud app](connect-app.md). | The [GitLab.com for Jira Cloud app](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud?hosting=cloud&tab=overview), using a workaround process. See the documentation for [installing the GitLab.com for Jira Cloud app for self-managed instances](connect-app.md#install-the-gitlabcom-for-jira-cloud-app-for-self-managed-instances) for more information. |
|
||||
| Your own server | The [Jira DVCS (distributed version control system) connector](dvcs.md). This syncs data hourly. | The [Jira DVCS Connector](dvcs.md). |
|
||||
|
||||
Each GitLab project can be configured to connect to an entire Jira instance. That means after
|
||||
|
|
|
@ -40,7 +40,7 @@ displays in the [development panel](https://support.atlassian.com/jira-software-
|
|||
To set up the Jira development panel integration:
|
||||
|
||||
- *If your installation uses Jira Cloud,* use the
|
||||
[GitLab for Jira app](connect-app.md).
|
||||
[GitLab.com for Jira Cloud app](connect-app.md).
|
||||
- *If either your Jira or GitLab installation is self-managed,* use the
|
||||
[Jira DVCS (distributed version control system) connector](dvcs.md).
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 18 KiB |
|
@ -5,28 +5,26 @@ group: Import
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Project/group import/export rate limits **(FREE SELF)**
|
||||
# Rate limits for imports and exports of project and groups **(FREE SELF)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35728) in GitLab 13.2.
|
||||
|
||||
The following table includes configurable rate limits. The following table includes limits on a
|
||||
per minute per user basis:
|
||||
You can configure the rate limits for imports and exports of projects and groups:
|
||||
|
||||
| Limit | Default (per minute per user) |
|
||||
|--------------------------|-------------------------------|
|
||||
| Project Import | 6 |
|
||||
| Project Export | 6 |
|
||||
| Project Export Download | 1 |
|
||||
| Group Import | 6 |
|
||||
| Group Export | 6 |
|
||||
| Group Export Download | 1 |
|
||||
To change a rate limit:
|
||||
|
||||
All rate limits are:
|
||||
1. On the top bar, select **Menu > Admin**.
|
||||
1. On the left sidebar, select **Settings > Network**, then expand **Import and export rate limits**.
|
||||
1. Change the value of any rate limit. The rate limits are per minute per user, not per IP address.
|
||||
Set to `0` to disable a rate limit.
|
||||
|
||||
- Configurable through the top bar at **Menu > Admin > Settings > Network > Import/Export Rate Limits**
|
||||
- Applied per minute per user
|
||||
- Not applied per IP address
|
||||
- Active by default. To disable, set the option to `0`
|
||||
- Logged to `auth.log` file if exceed rate limit
|
||||
| Limit | Default |
|
||||
|-------------------------|---------|
|
||||
| Project Import | 6 |
|
||||
| Project Export | 6 |
|
||||
| Project Export Download | 1 |
|
||||
| Group Import | 6 |
|
||||
| Group Export | 6 |
|
||||
| Group Export Download | 1 |
|
||||
|
||||
![Import/Export rate limits](img/import_export_rate_limits_v13_2.png)
|
||||
When a user exceeds a rate limit, it is logged in `auth.log`.
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module Entities
|
||||
module Clusters
|
||||
class AgentAuthorization < Grape::Entity
|
||||
expose :agent_id, as: :id
|
||||
expose :project, with: Entities::ProjectIdentity, as: :config_project
|
||||
expose :config, as: :configuration
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -559,6 +559,9 @@ msgstr ""
|
|||
msgid "%{doc_link_start}Advanced search%{doc_link_end} is enabled."
|
||||
msgstr ""
|
||||
|
||||
msgid "%{docs_link_start}Learn about visibility levels.%{docs_link_end}"
|
||||
msgstr ""
|
||||
|
||||
msgid "%{due_date} (Past due)"
|
||||
msgstr ""
|
||||
|
||||
|
@ -8514,9 +8517,6 @@ msgstr ""
|
|||
msgid "Configure limit for notes created per minute by web and API requests."
|
||||
msgstr ""
|
||||
|
||||
msgid "Configure limits for Project/Group Import/Export."
|
||||
msgstr ""
|
||||
|
||||
msgid "Configure limits for web and API requests."
|
||||
msgstr ""
|
||||
|
||||
|
@ -17001,6 +17001,9 @@ msgstr ""
|
|||
msgid "Import an exported GitLab project"
|
||||
msgstr ""
|
||||
|
||||
msgid "Import and export rate limits"
|
||||
msgstr ""
|
||||
|
||||
msgid "Import failed due to a GitHub error: %{original}"
|
||||
msgstr ""
|
||||
|
||||
|
@ -17079,9 +17082,6 @@ msgstr ""
|
|||
msgid "Import timed out. Import took longer than %{import_jobs_expiration} seconds"
|
||||
msgstr ""
|
||||
|
||||
msgid "Import/Export Rate Limits"
|
||||
msgstr ""
|
||||
|
||||
msgid "ImportButtons|Connect repositories from"
|
||||
msgstr ""
|
||||
|
||||
|
@ -20654,24 +20654,6 @@ msgstr ""
|
|||
msgid "Max 20 characters"
|
||||
msgstr ""
|
||||
|
||||
msgid "Max Group Export Download requests per minute per user"
|
||||
msgstr ""
|
||||
|
||||
msgid "Max Group Export requests per minute per user"
|
||||
msgstr ""
|
||||
|
||||
msgid "Max Group Import requests per minute per user"
|
||||
msgstr ""
|
||||
|
||||
msgid "Max Project Export Download requests per minute per user"
|
||||
msgstr ""
|
||||
|
||||
msgid "Max Project Export requests per minute per user"
|
||||
msgstr ""
|
||||
|
||||
msgid "Max Project Import requests per minute per user"
|
||||
msgstr ""
|
||||
|
||||
msgid "Max authenticated API requests per period per user"
|
||||
msgstr ""
|
||||
|
||||
|
@ -20777,6 +20759,15 @@ msgstr ""
|
|||
msgid "Maximum files in a diff"
|
||||
msgstr ""
|
||||
|
||||
msgid "Maximum group export download requests per minute"
|
||||
msgstr ""
|
||||
|
||||
msgid "Maximum group export requests per minute"
|
||||
msgstr ""
|
||||
|
||||
msgid "Maximum group import requests per minute"
|
||||
msgstr ""
|
||||
|
||||
msgid "Maximum import size"
|
||||
msgstr ""
|
||||
|
||||
|
@ -20822,6 +20813,15 @@ msgstr ""
|
|||
msgid "Maximum page size"
|
||||
msgstr ""
|
||||
|
||||
msgid "Maximum project export download requests per minute"
|
||||
msgstr ""
|
||||
|
||||
msgid "Maximum project export requests per minute"
|
||||
msgstr ""
|
||||
|
||||
msgid "Maximum project import requests per minute"
|
||||
msgstr ""
|
||||
|
||||
msgid "Maximum push size"
|
||||
msgstr ""
|
||||
|
||||
|
@ -30628,6 +30628,9 @@ msgstr ""
|
|||
msgid "Set an instance-wide domain that will be available to all clusters when installing Knative."
|
||||
msgstr ""
|
||||
|
||||
msgid "Set any rate limit to %{code_open}0%{code_close} to disable the limit."
|
||||
msgstr ""
|
||||
|
||||
msgid "Set default and restrict visibility levels. Configure import sources and git access protocol."
|
||||
msgstr ""
|
||||
|
||||
|
@ -30655,6 +30658,9 @@ msgstr ""
|
|||
msgid "Set parent epic to an epic"
|
||||
msgstr ""
|
||||
|
||||
msgid "Set per-user rate limits for imports and exports of projects and groups."
|
||||
msgstr ""
|
||||
|
||||
msgid "Set projects and maximum size limits, session duration, user options, and check feature availability for namespace plan."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -142,7 +142,13 @@ describe('Global Search Store Actions', () => {
|
|||
actions.fetchProjects({ commit: mockCommit, state });
|
||||
|
||||
expect(Api.groupProjects).not.toHaveBeenCalled();
|
||||
expect(Api.projects).toHaveBeenCalled();
|
||||
expect(Api.projects).toHaveBeenCalledWith(
|
||||
state.query.search,
|
||||
{
|
||||
order_by: 'similarity',
|
||||
},
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe API::Entities::Clusters::AgentAuthorization do
|
||||
let_it_be(:authorization) { create(:agent_group_authorization) }
|
||||
|
||||
subject { described_class.new(authorization).as_json }
|
||||
|
||||
it 'includes basic fields' do
|
||||
expect(subject).to include(
|
||||
id: authorization.agent_id,
|
||||
config_project: a_hash_including(id: authorization.agent.project_id),
|
||||
configuration: authorization.config
|
||||
)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Clusters::Agents::ImplicitAuthorization do
|
||||
let_it_be(:agent) { create(:cluster_agent) }
|
||||
|
||||
subject { described_class.new(agent: agent) }
|
||||
|
||||
it { expect(subject.agent).to eq(agent) }
|
||||
it { expect(subject.agent_id).to eq(agent.id) }
|
||||
it { expect(subject.project).to eq(agent.project) }
|
||||
it { expect(subject.config).to be_nil }
|
||||
end
|
|
@ -5,7 +5,7 @@ require 'spec_helper'
|
|||
RSpec.describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_redis_shared_state do
|
||||
include ExclusiveLeaseHelpers
|
||||
|
||||
let(:package) { create(:nuget_package, :processing, :with_symbol_package) }
|
||||
let!(:package) { create(:nuget_package, :processing, :with_symbol_package) }
|
||||
let(:package_file) { package.package_files.first }
|
||||
let(:service) { described_class.new(package_file) }
|
||||
let(:package_name) { 'DummyProject.DummyPackage' }
|
||||
|
@ -63,28 +63,152 @@ RSpec.describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples 'handling all conditions' do
|
||||
context 'with no existing package' do
|
||||
let(:package_id) { package.id }
|
||||
|
||||
it 'updates package and package file', :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)
|
||||
|
||||
expect(package.reload.name).to eq(package_name)
|
||||
expect(package.version).to eq(package_version)
|
||||
expect(package).to be_default
|
||||
expect(package_file.reload.file_name).to eq(package_file_name)
|
||||
# hard reset needed to properly reload package_file.file
|
||||
expect(Packages::PackageFile.find(package_file.id).file.size).not_to eq 0
|
||||
end
|
||||
|
||||
it_behaves_like 'taking the lease'
|
||||
|
||||
it_behaves_like 'not updating the package if the lease is taken'
|
||||
end
|
||||
|
||||
context 'with existing package' do
|
||||
let!(:existing_package) { create(:nuget_package, project: package.project, name: package_name, version: package_version) }
|
||||
let(:package_id) { existing_package.id }
|
||||
|
||||
it 'link existing package and updates package file', :aggregate_failures do
|
||||
expect(service).to receive(:try_obtain_lease).and_call_original
|
||||
|
||||
expect { subject }
|
||||
.to change { ::Packages::Package.count }.by(-1)
|
||||
.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
|
||||
|
||||
it_behaves_like 'taking the lease'
|
||||
|
||||
it_behaves_like 'not updating the package if the lease is taken'
|
||||
end
|
||||
|
||||
context 'with a nuspec file with metadata' do
|
||||
let(:nuspec_filepath) { 'packages/nuget/with_metadata.nuspec' }
|
||||
let(:expected_tags) { %w(foo bar test tag1 tag2 tag3 tag4 tag5) }
|
||||
|
||||
before do
|
||||
allow_next_instance_of(Packages::Nuget::MetadataExtractionService) do |service|
|
||||
allow(service)
|
||||
.to receive(:nuspec_file_content).and_return(fixture_file(nuspec_filepath))
|
||||
end
|
||||
end
|
||||
|
||||
it 'creates tags' do
|
||||
expect(service).to receive(:try_obtain_lease).and_call_original
|
||||
expect { subject }.to change { ::Packages::Tag.count }.by(8)
|
||||
expect(package.reload.tags.map(&:name)).to contain_exactly(*expected_tags)
|
||||
end
|
||||
|
||||
context 'with existing package and tags' do
|
||||
let!(:existing_package) { create(:nuget_package, project: package.project, name: 'DummyProject.WithMetadata', version: '1.2.3') }
|
||||
let!(:tag1) { create(:packages_tag, package: existing_package, name: 'tag1') }
|
||||
let!(:tag2) { create(:packages_tag, package: existing_package, name: 'tag2') }
|
||||
let!(:tag3) { create(:packages_tag, package: existing_package, name: 'tag_not_in_metadata') }
|
||||
|
||||
it 'creates tags and deletes those not in metadata' do
|
||||
expect(service).to receive(:try_obtain_lease).and_call_original
|
||||
expect { subject }.to change { ::Packages::Tag.count }.by(5)
|
||||
expect(existing_package.tags.map(&:name)).to contain_exactly(*expected_tags)
|
||||
end
|
||||
end
|
||||
|
||||
it 'creates nuget metadatum', :aggregate_failures do
|
||||
expect { subject }
|
||||
.to not_change { ::Packages::Package.count }
|
||||
.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
|
||||
let(:nuspec_filepath) { 'packages/nuget/with_dependencies.nuspec' }
|
||||
let(:package_name) { 'Test.Package' }
|
||||
let(:package_version) { '3.5.2' }
|
||||
let(:package_file_name) { 'test.package.3.5.2.nupkg' }
|
||||
|
||||
before do
|
||||
allow_next_instance_of(Packages::Nuget::MetadataExtractionService) do |service|
|
||||
allow(service)
|
||||
.to receive(:nuspec_file_content).and_return(fixture_file(nuspec_filepath))
|
||||
end
|
||||
end
|
||||
|
||||
it 'updates package and package file', :aggregate_failures do
|
||||
expect { subject }
|
||||
.to not_change { ::Packages::Package.count }
|
||||
.and change { Packages::Dependency.count }.by(4)
|
||||
.and change { Packages::DependencyLink.count }.by(4)
|
||||
.and change { Packages::Nuget::DependencyLinkMetadatum.count }.by(2)
|
||||
|
||||
expect(package.reload.name).to eq(package_name)
|
||||
expect(package.version).to eq(package_version)
|
||||
expect(package).to be_default
|
||||
expect(package_file.reload.file_name).to eq(package_file_name)
|
||||
# hard reset needed to properly reload package_file.file
|
||||
expect(Packages::PackageFile.find(package_file.id).file.size).not_to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context 'with package file not containing a nuspec file' do
|
||||
before do
|
||||
allow_next_instance_of(Zip::File) do |file|
|
||||
allow(file).to receive(:glob).and_return([])
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'raising an', ::Packages::Nuget::MetadataExtractionService::ExtractionError
|
||||
end
|
||||
|
||||
context 'with a symbol package' do
|
||||
let(:package_file) { package.package_files.last }
|
||||
let(:package_file_name) { 'dummyproject.dummypackage.1.0.0.snupkg' }
|
||||
|
||||
context 'with no existing package' do
|
||||
let(:package_id) { package.id }
|
||||
|
||||
it 'updates package and package file', :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)
|
||||
|
||||
expect(package.reload.name).to eq(package_name)
|
||||
expect(package.version).to eq(package_version)
|
||||
expect(package).to be_default
|
||||
expect(package_file.reload.file_name).to eq(package_file_name)
|
||||
# hard reset needed to properly reload package_file.file
|
||||
expect(Packages::PackageFile.find(package_file.id).file.size).not_to eq 0
|
||||
end
|
||||
|
||||
it_behaves_like 'taking the lease'
|
||||
|
||||
it_behaves_like 'not updating the package if the lease is taken'
|
||||
it_behaves_like 'raising an', ::Packages::Nuget::UpdatePackageFromMetadataService::InvalidMetadataError
|
||||
end
|
||||
|
||||
context 'with existing package' do
|
||||
|
@ -93,6 +217,8 @@ RSpec.describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_
|
|||
|
||||
it 'link existing package and updates package file', :aggregate_failures do
|
||||
expect(service).to receive(:try_obtain_lease).and_call_original
|
||||
expect(::Packages::Nuget::SyncMetadatumService).not_to receive(:new)
|
||||
expect(::Packages::UpdateTagsService).not_to receive(:new)
|
||||
|
||||
expect { subject }
|
||||
.to change { ::Packages::Package.count }.by(-1)
|
||||
|
@ -108,189 +234,42 @@ RSpec.describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_
|
|||
|
||||
it_behaves_like 'not updating the package if the lease is taken'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a nuspec file with metadata' do
|
||||
let(:nuspec_filepath) { 'packages/nuget/with_metadata.nuspec' }
|
||||
let(:expected_tags) { %w(foo bar test tag1 tag2 tag3 tag4 tag5) }
|
||||
context 'with an invalid package name' do
|
||||
invalid_names = [
|
||||
'',
|
||||
'My/package',
|
||||
'../../../my_package',
|
||||
'%2e%2e%2fmy_package'
|
||||
]
|
||||
|
||||
invalid_names.each do |invalid_name|
|
||||
before do
|
||||
allow_next_instance_of(Packages::Nuget::MetadataExtractionService) do |service|
|
||||
allow(service)
|
||||
.to receive(:nuspec_file_content).and_return(fixture_file(nuspec_filepath))
|
||||
end
|
||||
allow(service).to receive(:package_name).and_return(invalid_name)
|
||||
end
|
||||
|
||||
it 'creates tags' do
|
||||
expect(service).to receive(:try_obtain_lease).and_call_original
|
||||
expect { subject }.to change { ::Packages::Tag.count }.by(8)
|
||||
expect(package.reload.tags.map(&:name)).to contain_exactly(*expected_tags)
|
||||
end
|
||||
|
||||
context 'with existing package and tags' do
|
||||
let!(:existing_package) { create(:nuget_package, project: package.project, name: 'DummyProject.WithMetadata', version: '1.2.3') }
|
||||
let!(:tag1) { create(:packages_tag, package: existing_package, name: 'tag1') }
|
||||
let!(:tag2) { create(:packages_tag, package: existing_package, name: 'tag2') }
|
||||
let!(:tag3) { create(:packages_tag, package: existing_package, name: 'tag_not_in_metadata') }
|
||||
|
||||
it 'creates tags and deletes those not in metadata' do
|
||||
expect(service).to receive(:try_obtain_lease).and_call_original
|
||||
expect { subject }.to change { ::Packages::Tag.count }.by(5)
|
||||
expect(existing_package.tags.map(&:name)).to contain_exactly(*expected_tags)
|
||||
end
|
||||
end
|
||||
|
||||
it 'creates nuget metadatum', :aggregate_failures do
|
||||
expect { subject }
|
||||
.to not_change { ::Packages::Package.count }
|
||||
.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
|
||||
let(:nuspec_filepath) { 'packages/nuget/with_dependencies.nuspec' }
|
||||
let(:package_name) { 'Test.Package' }
|
||||
let(:package_version) { '3.5.2' }
|
||||
let(:package_file_name) { 'test.package.3.5.2.nupkg' }
|
||||
|
||||
before do
|
||||
allow_next_instance_of(Packages::Nuget::MetadataExtractionService) do |service|
|
||||
allow(service)
|
||||
.to receive(:nuspec_file_content).and_return(fixture_file(nuspec_filepath))
|
||||
end
|
||||
end
|
||||
|
||||
it 'updates package and package file', :aggregate_failures do
|
||||
expect { subject }
|
||||
.to not_change { ::Packages::Package.count }
|
||||
.and change { Packages::Dependency.count }.by(4)
|
||||
.and change { Packages::DependencyLink.count }.by(4)
|
||||
.and change { Packages::Nuget::DependencyLinkMetadatum.count }.by(2)
|
||||
|
||||
expect(package.reload.name).to eq(package_name)
|
||||
expect(package.version).to eq(package_version)
|
||||
expect(package).to be_default
|
||||
expect(package_file.reload.file_name).to eq(package_file_name)
|
||||
# hard reset needed to properly reload package_file.file
|
||||
expect(Packages::PackageFile.find(package_file.id).file.size).not_to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context 'with package file not containing a nuspec file' do
|
||||
before do
|
||||
allow_next_instance_of(Zip::File) do |file|
|
||||
allow(file).to receive(:glob).and_return([])
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'raising an', ::Packages::Nuget::MetadataExtractionService::ExtractionError
|
||||
end
|
||||
|
||||
context 'with a symbol package' do
|
||||
let(:package_file) { package.package_files.last }
|
||||
let(:package_file_name) { 'dummyproject.dummypackage.1.0.0.snupkg' }
|
||||
|
||||
context 'with no existing package' do
|
||||
let(:package_id) { package.id }
|
||||
|
||||
it_behaves_like 'raising an', ::Packages::Nuget::UpdatePackageFromMetadataService::InvalidMetadataError
|
||||
end
|
||||
|
||||
context 'with existing package' do
|
||||
let!(:existing_package) { create(:nuget_package, project: package.project, name: package_name, version: package_version) }
|
||||
let(:package_id) { existing_package.id }
|
||||
|
||||
it 'link existing package and updates package file', :aggregate_failures do
|
||||
expect(service).to receive(:try_obtain_lease).and_call_original
|
||||
expect(::Packages::Nuget::SyncMetadatumService).not_to receive(:new)
|
||||
expect(::Packages::UpdateTagsService).not_to receive(:new)
|
||||
|
||||
expect { subject }
|
||||
.to change { ::Packages::Package.count }.by(-1)
|
||||
.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
|
||||
|
||||
it_behaves_like 'taking the lease'
|
||||
|
||||
it_behaves_like 'not updating the package if the lease is taken'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an invalid package name' do
|
||||
invalid_names = [
|
||||
'',
|
||||
'My/package',
|
||||
'../../../my_package',
|
||||
'%2e%2e%2fmy_package'
|
||||
]
|
||||
|
||||
invalid_names.each do |invalid_name|
|
||||
before do
|
||||
allow(service).to receive(:package_name).and_return(invalid_name)
|
||||
end
|
||||
|
||||
it_behaves_like 'raising an', ::Packages::Nuget::UpdatePackageFromMetadataService::InvalidMetadataError
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an invalid package version' do
|
||||
invalid_versions = [
|
||||
'',
|
||||
'555',
|
||||
'1.2',
|
||||
'1./2.3',
|
||||
'../../../../../1.2.3',
|
||||
'%2e%2e%2f1.2.3'
|
||||
]
|
||||
|
||||
invalid_versions.each do |invalid_version|
|
||||
before do
|
||||
allow(service).to receive(:package_version).and_return(invalid_version)
|
||||
end
|
||||
|
||||
it_behaves_like 'raising an', ::Packages::Nuget::UpdatePackageFromMetadataService::InvalidMetadataError
|
||||
end
|
||||
it_behaves_like 'raising an', ::Packages::Nuget::UpdatePackageFromMetadataService::InvalidMetadataError
|
||||
end
|
||||
end
|
||||
|
||||
context 'with packages_nuget_new_package_file_updater enabled' do
|
||||
before do
|
||||
expect(service).not_to receive(:legacy_execute)
|
||||
context 'with an invalid package version' do
|
||||
invalid_versions = [
|
||||
'',
|
||||
'555',
|
||||
'1.2',
|
||||
'1./2.3',
|
||||
'../../../../../1.2.3',
|
||||
'%2e%2e%2f1.2.3'
|
||||
]
|
||||
|
||||
invalid_versions.each do |invalid_version|
|
||||
before do
|
||||
allow(service).to receive(:package_version).and_return(invalid_version)
|
||||
end
|
||||
|
||||
it_behaves_like 'raising an', ::Packages::Nuget::UpdatePackageFromMetadataService::InvalidMetadataError
|
||||
end
|
||||
|
||||
it_behaves_like 'handling all conditions'
|
||||
end
|
||||
|
||||
context 'with packages_nuget_new_package_file_updater disabled' do
|
||||
before do
|
||||
stub_feature_flags(packages_nuget_new_package_file_updater: false)
|
||||
expect(::Packages::UpdatePackageFileService)
|
||||
.not_to receive(:new).with(package_file, instance_of(Hash)).and_call_original
|
||||
expect(service).not_to receive(:new_execute)
|
||||
end
|
||||
|
||||
it_behaves_like 'handling all conditions'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -23,12 +23,39 @@ module CycleAnalyticsHelpers
|
|||
end
|
||||
end
|
||||
|
||||
def select_event_label(sel)
|
||||
page.within(sel) do
|
||||
find('.dropdown-toggle').click
|
||||
page.find(".dropdown-menu").all(".dropdown-item")[1].click
|
||||
end
|
||||
end
|
||||
|
||||
def fill_in_custom_label_stage_fields
|
||||
index = page.all('[data-testid="value-stream-stage-fields"]').length
|
||||
last_stage = page.all('[data-testid="value-stream-stage-fields"]').last
|
||||
|
||||
within last_stage do
|
||||
find('[name*="custom-stage-name-"]').fill_in with: "Cool custom label stage - name #{index}"
|
||||
select_dropdown_option_by_value "custom-stage-start-event-", :issue_label_added
|
||||
select_dropdown_option_by_value "custom-stage-end-event-", :issue_label_removed
|
||||
|
||||
select_event_label("[data-testid*='custom-stage-start-event-label-']")
|
||||
select_event_label("[data-testid*='custom-stage-end-event-label-']")
|
||||
end
|
||||
end
|
||||
|
||||
def add_custom_stage_to_form
|
||||
page.find_button(s_('CreateValueStreamForm|Add another stage')).click
|
||||
|
||||
fill_in_custom_stage_fields
|
||||
end
|
||||
|
||||
def add_custom_label_stage_to_form
|
||||
page.find_button(s_('CreateValueStreamForm|Add another stage')).click
|
||||
|
||||
fill_in_custom_label_stage_fields
|
||||
end
|
||||
|
||||
def save_value_stream(custom_value_stream_name)
|
||||
fill_in 'create-value-stream-name', with: custom_value_stream_name
|
||||
|
||||
|
|
Loading…
Reference in New Issue