From 8fd149139d3d64b102f51455180f03adbc80f469 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 10 Sep 2021 12:10:27 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .../javascripts/search/store/actions.js | 2 +- .../clusters/agents/group_authorization.rb | 2 + .../clusters/agents/implicit_authorization.rb | 20 + .../update_package_from_metadata_service.rb | 33 +- .../_import_export_limits.html.haml | 16 +- .../application_settings/network.html.haml | 5 +- app/views/shared/_visibility_level.html.haml | 2 +- .../development/group_authorized_agents.yml | 8 + ...ackages_nuget_new_package_file_updater.yml | 8 - ...y_orchestration_policies_configuration.yml | 2 +- doc/development/integrations/jira_connect.md | 2 +- doc/integration/jira/connect-app.md | 2 +- doc/integration/jira/development_panel.md | 2 +- doc/integration/jira/index.md | 2 +- .../img/import_export_rate_limits_v13_2.png | Bin 18320 -> 0 bytes .../settings/import_export_rate_limits.md | 34 +- .../entities/clusters/agent_authorization.rb | 13 + locale/gitlab.pot | 54 +-- spec/frontend/search/store/actions_spec.js | 8 +- .../clusters/agent_authorization_spec.rb | 17 + .../agents/implicit_authorization_spec.rb | 14 + ...date_package_from_metadata_service_spec.rb | 367 +++++++++--------- .../helpers/cycle_analytics_helpers.rb | 27 ++ 23 files changed, 349 insertions(+), 291 deletions(-) create mode 100644 app/models/clusters/agents/implicit_authorization.rb create mode 100644 config/feature_flags/development/group_authorized_agents.yml delete mode 100644 config/feature_flags/development/packages_nuget_new_package_file_updater.yml delete mode 100644 doc/user/admin_area/settings/img/import_export_rate_limits_v13_2.png create mode 100644 lib/api/entities/clusters/agent_authorization.rb create mode 100644 spec/lib/api/entities/clusters/agent_authorization_spec.rb create mode 100644 spec/models/clusters/agents/implicit_authorization_spec.rb diff --git a/app/assets/javascripts/search/store/actions.js b/app/assets/javascripts/search/store/actions.js index ee5e778f63d..be64a9278e3 100644 --- a/app/assets/javascripts/search/store/actions.js +++ b/app/assets/javascripts/search/store/actions.js @@ -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(); }); } diff --git a/app/models/clusters/agents/group_authorization.rb b/app/models/clusters/agents/group_authorization.rb index 96a9997be75..74c0cec3b7e 100644 --- a/app/models/clusters/agents/group_authorization.rb +++ b/app/models/clusters/agents/group_authorization.rb @@ -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 diff --git a/app/models/clusters/agents/implicit_authorization.rb b/app/models/clusters/agents/implicit_authorization.rb new file mode 100644 index 00000000000..967cc686045 --- /dev/null +++ b/app/models/clusters/agents/implicit_authorization.rb @@ -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 diff --git a/app/services/packages/nuget/update_package_from_metadata_service.rb b/app/services/packages/nuget/update_package_from_metadata_service.rb index 6ffe4f097f4..d1e47ad00a1 100644 --- a/app/services/packages/nuget/update_package_from_metadata_service.rb +++ b/app/services/packages/nuget/update_package_from_metadata_service.rb @@ -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? diff --git a/app/views/admin/application_settings/_import_export_limits.html.haml b/app/views/admin/application_settings/_import_export_limits.html.haml index 6a49f884a80..bc4a1577f90 100644 --- a/app/views/admin/application_settings/_import_export_limits.html.haml +++ b/app/views/admin/application_settings/_import_export_limits.html.haml @@ -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: ''.html_safe, code_close: ''.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' } diff --git a/app/views/admin/application_settings/network.html.haml b/app/views/admin/application_settings/network.html.haml index 1bb8a278f2b..238e5c8b299 100644 --- a/app/views/admin/application_settings/network.html.haml +++ b/app/views/admin/application_settings/network.html.haml @@ -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' diff --git a/app/views/shared/_visibility_level.html.haml b/app/views/shared/_visibility_level.html.haml index 84ce40e240c..3e30dcaf35a 100644 --- a/app/views/shared/_visibility_level.html.haml +++ b/app/views/shared/_visibility_level.html.haml @@ -7,7 +7,7 @@ = _('Who can see this group?') - visibility_docs_path = help_page_path('public_access/public_access') - docs_link_start = ''.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: ''.html_safe } + = _('%{docs_link_start}Learn about visibility levels.%{docs_link_end}').html_safe % { docs_link_start: docs_link_start, docs_link_end: ''.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 diff --git a/config/feature_flags/development/group_authorized_agents.yml b/config/feature_flags/development/group_authorized_agents.yml new file mode 100644 index 00000000000..e1c4620994d --- /dev/null +++ b/config/feature_flags/development/group_authorized_agents.yml @@ -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 diff --git a/config/feature_flags/development/packages_nuget_new_package_file_updater.yml b/config/feature_flags/development/packages_nuget_new_package_file_updater.yml deleted file mode 100644 index b1f8a79da9a..00000000000 --- a/config/feature_flags/development/packages_nuget_new_package_file_updater.yml +++ /dev/null @@ -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 diff --git a/config/feature_flags/development/security_orchestration_policies_configuration.yml b/config/feature_flags/development/security_orchestration_policies_configuration.yml index ae64339607e..2570743c101 100644 --- a/config/feature_flags/development/security_orchestration_policies_configuration.yml +++ b/config/feature_flags/development/security_orchestration_policies_configuration.yml @@ -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 diff --git a/doc/development/integrations/jira_connect.md b/doc/development/integrations/jira_connect.md index 9772f7504cf..ca3dc3660ee 100644 --- a/doc/development/integrations/jira_connect.md +++ b/doc/development/integrations/jira_connect.md @@ -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._ diff --git a/doc/integration/jira/connect-app.md b/doc/integration/jira/connect-app.md index 42ec2456c2d..7d32c080fff 100644 --- a/doc/integration/jira/connect-app.md +++ b/doc/integration/jira/connect-app.md @@ -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)** diff --git a/doc/integration/jira/development_panel.md b/doc/integration/jira/development_panel.md index c8ea224f18e..6bae672db71 100644 --- a/doc/integration/jira/development_panel.md +++ b/doc/integration/jira/development_panel.md @@ -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 diff --git a/doc/integration/jira/index.md b/doc/integration/jira/index.md index 4ad9ab9f637..74dec70517c 100644 --- a/doc/integration/jira/index.md +++ b/doc/integration/jira/index.md @@ -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). diff --git a/doc/user/admin_area/settings/img/import_export_rate_limits_v13_2.png b/doc/user/admin_area/settings/img/import_export_rate_limits_v13_2.png deleted file mode 100644 index 76015ce0ee3459dea16972025ec068b451b69770..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18320 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 [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`. diff --git a/lib/api/entities/clusters/agent_authorization.rb b/lib/api/entities/clusters/agent_authorization.rb new file mode 100644 index 00000000000..6c533fff105 --- /dev/null +++ b/lib/api/entities/clusters/agent_authorization.rb @@ -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 diff --git a/locale/gitlab.pot b/locale/gitlab.pot index c5f2a7b6846..21e8d2fc0b9 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -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 "" diff --git a/spec/frontend/search/store/actions_spec.js b/spec/frontend/search/store/actions_spec.js index 9f8c83f2873..b50248bb295 100644 --- a/spec/frontend/search/store/actions_spec.js +++ b/spec/frontend/search/store/actions_spec.js @@ -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), + ); }); }); }); diff --git a/spec/lib/api/entities/clusters/agent_authorization_spec.rb b/spec/lib/api/entities/clusters/agent_authorization_spec.rb new file mode 100644 index 00000000000..101a8af4ac4 --- /dev/null +++ b/spec/lib/api/entities/clusters/agent_authorization_spec.rb @@ -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 diff --git a/spec/models/clusters/agents/implicit_authorization_spec.rb b/spec/models/clusters/agents/implicit_authorization_spec.rb new file mode 100644 index 00000000000..69aa55a350e --- /dev/null +++ b/spec/models/clusters/agents/implicit_authorization_spec.rb @@ -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 diff --git a/spec/services/packages/nuget/update_package_from_metadata_service_spec.rb b/spec/services/packages/nuget/update_package_from_metadata_service_spec.rb index 66ff6a8d03f..d682ee12ed5 100644 --- a/spec/services/packages/nuget/update_package_from_metadata_service_spec.rb +++ b/spec/services/packages/nuget/update_package_from_metadata_service_spec.rb @@ -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 diff --git a/spec/support/helpers/cycle_analytics_helpers.rb b/spec/support/helpers/cycle_analytics_helpers.rb index e48c8125d84..ae0f48fbe47 100644 --- a/spec/support/helpers/cycle_analytics_helpers.rb +++ b/spec/support/helpers/cycle_analytics_helpers.rb @@ -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