Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-11-11 21:14:04 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-11-11 21:14:04 +0300
commit11c2b8eff6ca5360fb0f732b23b764d2a0b81be5 (patch)
tree7f92622462127ff24023283133f81d9c4b2f6842
parente40f19ef830c5863089bc6a7a73e6695efa60a13 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--GITLAB_PAGES_VERSION2
-rw-r--r--app/assets/javascripts/lib/apollo/suppress_network_errors_during_navigation_link.js4
-rw-r--r--app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue1
-rw-r--r--app/assets/stylesheets/pages/deploy_keys.scss9
-rw-r--r--app/experiments/change_continuous_onboarding_link_urls_experiment.rb9
-rw-r--r--app/helpers/learn_gitlab_helper.rb1
-rw-r--r--app/policies/project_policy.rb11
-rw-r--r--app/views/admin/deploy_keys/index.html.haml55
-rw-r--r--app/views/explore/groups/_nav.html.haml6
-rw-r--r--app/views/explore/projects/_nav.html.haml14
-rw-r--r--app/views/projects/blob/edit.html.haml10
-rw-r--r--app/views/projects/merge_requests/_widget.html.haml4
-rw-r--r--app/views/search/_category.html.haml2
-rw-r--r--app/views/shared/_md_preview.html.haml2
-rw-r--r--config/feature_flags/development/suppress_apollo_errors_during_navigation.yml8
-rw-r--r--db/post_migrate/20211102103127_add_temp_index_to_vulnerability_occurrences.rb15
-rw-r--r--db/post_migrate/20211102114802_update_vulnerability_occurrences_location.rb22
-rw-r--r--db/schema_migrations/202111021031271
-rw-r--r--db/schema_migrations/202111021148021
-rw-r--r--db/structure.sql2
-rw-r--r--doc/development/service_ping/index.md32
-rw-r--r--doc/operations/incident_management/integrations.md4
-rw-r--r--doc/user/infrastructure/index.md2
-rw-r--r--doc/user/project/merge_requests/approvals/index.md2
-rw-r--r--lib/gitlab/background_migration/update_vulnerability_occurrences_location.rb14
-rw-r--r--lib/gitlab/content_security_policy/config_loader.rb4
-rw-r--r--lib/gitlab/content_security_policy/directives.rb21
-rw-r--r--lib/gitlab/gon_helper.rb1
-rw-r--r--locale/gitlab.pot24
-rw-r--r--package.json2
-rw-r--r--qa/qa/resource/project.rb13
-rw-r--r--qa/qa/specs/features/api/1_manage/bulk_import_project_spec.rb3
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb2
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb2
-rw-r--r--spec/experiments/change_continuous_onboarding_link_urls_experiment_spec.rb53
-rw-r--r--spec/features/admin/admin_deploy_keys_spec.rb10
-rw-r--r--spec/frontend/lib/apollo/suppress_network_errors_during_navigation_link_spec.js150
-rw-r--r--spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_spec.js.snap7
-rw-r--r--spec/lib/gitlab/content_security_policy/config_loader_spec.rb8
-rw-r--r--spec/lib/gitlab/database/partitioning_spec.rb33
-rw-r--r--spec/lib/gitlab/email/handler/service_desk_handler_spec.rb24
-rw-r--r--spec/policies/project_policy_spec.rb62
-rw-r--r--spec/services/issues/create_service_spec.rb24
-rw-r--r--spec/services/projects/destroy_service_spec.rb8
-rw-r--r--yarn.lock2
45 files changed, 442 insertions, 244 deletions
diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION
index 0a3db35b241..21998d3c2d9 100644
--- a/GITLAB_PAGES_VERSION
+++ b/GITLAB_PAGES_VERSION
@@ -1 +1 @@
-1.46.0
+1.47.0
diff --git a/app/assets/javascripts/lib/apollo/suppress_network_errors_during_navigation_link.js b/app/assets/javascripts/lib/apollo/suppress_network_errors_during_navigation_link.js
index ad92bd4de42..9b7901685b6 100644
--- a/app/assets/javascripts/lib/apollo/suppress_network_errors_during_navigation_link.js
+++ b/app/assets/javascripts/lib/apollo/suppress_network_errors_during_navigation_link.js
@@ -9,10 +9,6 @@ import { isNavigatingAway } from '~/lib/utils/is_navigating_away';
* @returns {ApolloLink|null}
*/
export const getSuppressNetworkErrorsDuringNavigationLink = () => {
- if (!gon.features?.suppressApolloErrorsDuringNavigation) {
- return null;
- }
-
return onError(({ networkError }) => {
if (networkError && isNavigatingAway()) {
// Return an observable that will never notify any subscribers with any
diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue
index 69fb5878f5c..0995947f3e7 100644
--- a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue
+++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue
@@ -40,6 +40,7 @@ export default {
data-track-action="click_link"
:data-track-label="$options.i18n.ACTION_LABELS[action].title"
data-track-property="Growth::Conversion::Experiment::LearnGitLab"
+ data-track-experiment="change_continuous_onboarding_link_urls"
>
{{ $options.i18n.ACTION_LABELS[action].title }}
</gl-link>
diff --git a/app/assets/stylesheets/pages/deploy_keys.scss b/app/assets/stylesheets/pages/deploy_keys.scss
index 2fafe052106..997e42a8fd5 100644
--- a/app/assets/stylesheets/pages/deploy_keys.scss
+++ b/app/assets/stylesheets/pages/deploy_keys.scss
@@ -1,12 +1,3 @@
-.deploy-keys-list {
- width: 100%;
- overflow: auto;
-
- table {
- border: 1px solid $table-border-color;
- }
-}
-
.deploy-keys-title {
padding-bottom: 2px;
line-height: 2;
diff --git a/app/experiments/change_continuous_onboarding_link_urls_experiment.rb b/app/experiments/change_continuous_onboarding_link_urls_experiment.rb
new file mode 100644
index 00000000000..680cb8eadd8
--- /dev/null
+++ b/app/experiments/change_continuous_onboarding_link_urls_experiment.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class ChangeContinuousOnboardingLinkUrlsExperiment < ApplicationExperiment # rubocop:disable Gitlab/NamespacedClass
+ attr_writer :namespace
+
+ def track(action, **event_args)
+ super(action, **event_args.merge(namespace: @namespace))
+ end
+end
diff --git a/app/helpers/learn_gitlab_helper.rb b/app/helpers/learn_gitlab_helper.rb
index 4f69d1bba0e..a7c77bcad67 100644
--- a/app/helpers/learn_gitlab_helper.rb
+++ b/app/helpers/learn_gitlab_helper.rb
@@ -13,6 +13,7 @@ module LearnGitlabHelper
urls_to_use = nil
experiment(:change_continuous_onboarding_link_urls) do |e|
+ e.namespace = project.namespace
e.use { urls_to_use = action_urls }
e.try { urls_to_use = new_action_urls(project) }
end
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index c2d1447bf8b..d81db357162 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -47,6 +47,9 @@ class ProjectPolicy < BasePolicy
desc "Project is archived"
condition(:archived, scope: :subject, score: 0) { project.archived? }
+ desc "Project is in the process of being deleted"
+ condition(:pending_delete) { project.pending_delete? }
+
condition(:default_issues_tracker, scope: :subject) { project.default_issues_tracker? }
desc "Container registry is disabled"
@@ -457,7 +460,13 @@ class ProjectPolicy < BasePolicy
prevent(*readonly_abilities)
readonly_features.each do |feature|
- prevent(*create_update_admin_destroy(feature))
+ prevent(*create_update_admin(feature))
+ end
+ end
+
+ rule { archived & ~pending_delete }.policy do
+ readonly_features.each do |feature|
+ prevent(:"destroy_#{feature}")
end
end
diff --git a/app/views/admin/deploy_keys/index.html.haml b/app/views/admin/deploy_keys/index.html.haml
index 1cbb5296f8d..ba4abdc02e4 100644
--- a/app/views/admin/deploy_keys/index.html.haml
+++ b/app/views/admin/deploy_keys/index.html.haml
@@ -7,31 +7,38 @@
%h3.page-title.deploy-keys-title
= _('Public deploy keys (%{deploy_keys_count})') % { deploy_keys_count: @deploy_keys.load.size }
= link_to _('New deploy key'), new_admin_deploy_key_path, class: 'float-right btn gl-button btn-confirm btn-md gl-button'
- .table-holder.deploy-keys-list
- %table.table
- %thead
+ %table.table.b-table.gl-table.b-table-stacked-lg{ data: { testid: 'deploy-keys-list' } }
+ %thead
+ %tr
+ %th= _('Title')
+ %th= _('Fingerprint')
+ %th= _('Projects with write access')
+ %th= _('Created')
+ %th.gl-lg-w-1px.gl-white-space-nowrap
+ %span.gl-sr-only
+ = _('Actions')
+ %tbody
+ - @deploy_keys.each do |deploy_key|
%tr
- %th.col-sm-2= _('Title')
- %th.col-sm-4= _('Fingerprint')
- %th.col-sm-2= _('Projects with write access')
- %th.col-sm-2= _('Added at')
- %th.col-sm-2
- %tbody
- - @deploy_keys.each do |deploy_key|
- %tr
- %td
- %strong= deploy_key.title
- %td
- %code.key-fingerprint= deploy_key.fingerprint
- %td
+ %td{ data: { label: _('Title') } }
+ %div
+ = deploy_key.title
+ %td{ data: { label: _('Fingerprint') } }
+ %div
+ %code= deploy_key.fingerprint
+ %td{ data: { label: _('Projects with write access') } }
+ %div
- deploy_key.projects_with_write_access.each do |project|
- = link_to project.full_name, admin_project_path(project), class: 'label deploy-project-label'
- %td
- %span.cgray
- = _('added %{created_at_timeago}').html_safe % { created_at_timeago: time_ago_with_tooltip(deploy_key.created_at) }
- %td
- .float-right
- = link_to _('Edit'), edit_admin_deploy_key_path(deploy_key), class: 'btn gl-button btn-sm'
- = link_to _('Remove'), admin_deploy_key_path(deploy_key), data: { confirm: _('Are you sure?') }, method: :delete, class: 'gl-button btn btn-sm btn-danger delete-key'
+ = link_to project.full_name, admin_project_path(project), class: 'gl-display-block'
+ %td{ data: { label: _('Created') } }
+ %div
+ = time_ago_with_tooltip(deploy_key.created_at)
+ %td.gl-lg-w-1px.gl-white-space-nowrap{ data: { label: _('Actions') } }
+ %div
+ = link_to edit_admin_deploy_key_path(deploy_key), class: 'btn btn-default btn-md gl-button btn-icon gl-mr-3', aria: { label: _('Edit deploy key') } do
+ = sprite_icon('pencil', css_class: 'gl-button-icon')
+ = link_to admin_deploy_key_path(deploy_key), data: { confirm: _('Are you sure?') }, method: :delete, class: 'btn btn-danger btn-md gl-button btn-icon', aria: { label: _('Remove deploy key') } do
+ = sprite_icon('remove', css_class: 'gl-button-icon')
+
- else
= render 'shared/empty_states/deploy_keys'
diff --git a/app/views/explore/groups/_nav.html.haml b/app/views/explore/groups/_nav.html.haml
index c337149a2f3..3c9c4e9f76b 100644
--- a/app/views/explore/groups/_nav.html.haml
+++ b/app/views/explore/groups/_nav.html.haml
@@ -1,8 +1,6 @@
.top-area
- %ul.nav-links.nav.nav-tabs
- = nav_link(page: explore_groups_path) do
- = link_to explore_groups_path do
- = _("Explore Groups")
+ = gl_tabs_nav({ class: 'gl-display-flex gl-flex-grow-1 gl-border-none'}) do
+ = gl_tab_link_to _("Explore Groups"), explore_groups_path
.nav-controls
= render 'shared/groups/search_form'
= render 'shared/groups/dropdown'
diff --git a/app/views/explore/projects/_nav.html.haml b/app/views/explore/projects/_nav.html.haml
index 65b7d055843..9d7a6f1ccfb 100644
--- a/app/views/explore/projects/_nav.html.haml
+++ b/app/views/explore/projects/_nav.html.haml
@@ -1,14 +1,8 @@
.top-area
- %ul.nav-links.nav.nav-tabs
- = nav_link(page: [explore_projects_path, explore_root_path]) do
- = link_to explore_projects_path do
- = _('All')
- = nav_link(page: starred_explore_projects_path) do
- = link_to starred_explore_projects_path do
- = _('Most stars')
- = nav_link(page: trending_explore_projects_path) do
- = link_to trending_explore_projects_path do
- = _('Trending')
+ = gl_tabs_nav({ class: 'gl-display-flex gl-flex-grow-1 gl-border-none'}) do
+ = gl_tab_link_to _('All'), explore_projects_path, { item_active: current_page?(explore_projects_path) || current_page?(explore_root_path) }
+ = gl_tab_link_to _('Most stars'), starred_explore_projects_path
+ = gl_tab_link_to _('Trending'), trending_explore_projects_path
.nav-controls
- unless current_user
diff --git a/app/views/projects/blob/edit.html.haml b/app/views/projects/blob/edit.html.haml
index ecbef9a11a7..8378ce2c7e5 100644
--- a/app/views/projects/blob/edit.html.haml
+++ b/app/views/projects/blob/edit.html.haml
@@ -16,14 +16,10 @@
%h3.page-title.blob-edit-page-title
Edit file
.file-editor
- %ul.nav-links.no-bottom.js-edit-mode.nav.nav-tabs
- %li.active
- = link_to '#editor' do
- Write
+ = gl_tabs_nav({ class: 'js-edit-mode nav-links gl-border-0'}) do
+ = gl_tab_link_to _('Write'), '#editor', { tab_class: 'active' }
- %li
- = link_to '#preview', 'data-preview-url' => project_preview_blob_path(@project, @id) do
- = editing_preview_title(@blob.name)
+ = gl_tab_link_to editing_preview_title(@blob.name), '#preview', { data: { 'preview-url': project_preview_blob_path(@project, @id) } }
= form_tag(project_update_blob_path(@project, @id), method: :put, class: 'js-quick-submit js-requires-input js-edit-blob-form', data: blob_editor_paths(@project)) do
= render 'projects/blob/editor', ref: @ref, path: @path, blob_data: @blob.data
diff --git a/app/views/projects/merge_requests/_widget.html.haml b/app/views/projects/merge_requests/_widget.html.haml
index 459742c3b81..0c8af873095 100644
--- a/app/views/projects/merge_requests/_widget.html.haml
+++ b/app/views/projects/merge_requests/_widget.html.haml
@@ -14,8 +14,8 @@
window.gl.mrWidgetData.pipeline_must_succeed_docs_path = '#{help_page_path('user/project/merge_requests/merge_when_pipeline_succeeds.md', anchor: 'only-allow-merge-requests-to-be-merged-if-the-pipeline-succeeds')}';
window.gl.mrWidgetData.security_approvals_help_page_path = '#{help_page_path('user/application_security/index.md', anchor: 'security-approvals-in-merge-requests')}';
window.gl.mrWidgetData.license_compliance_docs_path = '#{help_page_path('user/compliance/license_compliance/index.md', anchor: 'policies')}';
- window.gl.mrWidgetData.eligible_approvers_docs_path = '#{help_page_path('user/project/merge_requests/merge_request_approvals', anchor: 'eligible-approvers')}';
- window.gl.mrWidgetData.approvals_help_path = '#{help_page_path("user/project/merge_requests/merge_request_approvals")}';
+ window.gl.mrWidgetData.eligible_approvers_docs_path = '#{help_page_path('user/project/merge_requests/approvals/rules.md', anchor: 'eligible-approvers')}';
+ window.gl.mrWidgetData.approvals_help_path = '#{help_page_path("user/project/merge_requests/approvals/index.md")}';
window.gl.mrWidgetData.pipelines_empty_svg_path = '#{image_path('illustrations/pipelines_empty.svg')}';
window.gl.mrWidgetData.codequality_help_path = '#{help_page_path("user/project/merge_requests/code_quality", anchor: "code-quality-reports")}';
window.gl.mrWidgetData.false_positive_doc_url = '#{help_page_path('user/application_security/vulnerabilities/index')}';
diff --git a/app/views/search/_category.html.haml b/app/views/search/_category.html.haml
index ca6f2369bd8..54aa9aad8a5 100644
--- a/app/views/search/_category.html.haml
+++ b/app/views/search/_category.html.haml
@@ -5,7 +5,7 @@
.scrolling-tabs-container.inner-page-scroll-tabs.is-smaller
.fade-left= sprite_icon('chevron-lg-left', size: 12)
.fade-right= sprite_icon('chevron-lg-right', size: 12)
- %ul.nav-links.search-filter.scrolling-tabs.nav.nav-tabs
+ = gl_tabs_nav({ class: 'search-filter scrolling-tabs nav-links'}) do
- if @project
- if project_search_tabs?(:blobs)
= search_filter_link 'blobs', _("Code"), data: { qa_selector: 'code_tab' }
diff --git a/app/views/shared/_md_preview.html.haml b/app/views/shared/_md_preview.html.haml
index 0976defea1b..a49a0667d84 100644
--- a/app/views/shared/_md_preview.html.haml
+++ b/app/views/shared/_md_preview.html.haml
@@ -9,7 +9,7 @@
.md-area.position-relative
.md-header
- %ul.nav.nav-tabs.nav-links.clearfix
+ = gl_tabs_nav({ class: 'clearfix nav-links'}) do
%li.md-header-tab.active
%button.js-md-write-button
= _("Write")
diff --git a/config/feature_flags/development/suppress_apollo_errors_during_navigation.yml b/config/feature_flags/development/suppress_apollo_errors_during_navigation.yml
deleted file mode 100644
index 21548fa4dbb..00000000000
--- a/config/feature_flags/development/suppress_apollo_errors_during_navigation.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: suppress_apollo_errors_during_navigation
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72031
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/342745
-milestone: '14.4'
-type: development
-group: group::foundations
-default_enabled: false
diff --git a/db/post_migrate/20211102103127_add_temp_index_to_vulnerability_occurrences.rb b/db/post_migrate/20211102103127_add_temp_index_to_vulnerability_occurrences.rb
new file mode 100644
index 00000000000..4aee79950dc
--- /dev/null
+++ b/db/post_migrate/20211102103127_add_temp_index_to_vulnerability_occurrences.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddTempIndexToVulnerabilityOccurrences < Gitlab::Database::Migration[1.0]
+ INDEX_NAME = 'vulnerability_occurrences_location_temp_index'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :vulnerability_occurrences, :id, where: 'location IS NULL', name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :vulnerability_occurrences, name: INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20211102114802_update_vulnerability_occurrences_location.rb b/db/post_migrate/20211102114802_update_vulnerability_occurrences_location.rb
new file mode 100644
index 00000000000..20618b78391
--- /dev/null
+++ b/db/post_migrate/20211102114802_update_vulnerability_occurrences_location.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class UpdateVulnerabilityOccurrencesLocation < Gitlab::Database::Migration[1.0]
+ BATCH_SIZE = 20_000
+ DELAY_INTERVAL = 3.minutes
+ MIGRATION_NAME = 'UpdateVulnerabilityOccurrencesLocation'
+
+ disable_ddl_transaction!
+
+ def up
+ relation = Gitlab::BackgroundMigration::UpdateVulnerabilityOccurrencesLocation::Occurrence.where(location: nil)
+ queue_background_migration_jobs_by_range_at_intervals(relation,
+ MIGRATION_NAME,
+ DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ track_jobs: true)
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/schema_migrations/20211102103127 b/db/schema_migrations/20211102103127
new file mode 100644
index 00000000000..2ce33ad085a
--- /dev/null
+++ b/db/schema_migrations/20211102103127
@@ -0,0 +1 @@
+450028c90cb92f5ce3f8239eb56364b83ed025839aaf305b7ceb4fda077681b1 \ No newline at end of file
diff --git a/db/schema_migrations/20211102114802 b/db/schema_migrations/20211102114802
new file mode 100644
index 00000000000..35d3a25f3cb
--- /dev/null
+++ b/db/schema_migrations/20211102114802
@@ -0,0 +1 @@
+a3f9fcac354cccfdfc42b8f5baab651cb65ca60e4474ce937ab25b552bfe483c \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index c2bf310d3c6..f1c6725d927 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -27795,6 +27795,8 @@ CREATE UNIQUE INDEX vulnerability_feedback_unique_idx ON vulnerability_feedback
CREATE UNIQUE INDEX vulnerability_occurrence_pipelines_on_unique_keys ON vulnerability_occurrence_pipelines USING btree (occurrence_id, pipeline_id);
+CREATE INDEX vulnerability_occurrences_location_temp_index ON vulnerability_occurrences USING btree (id) WHERE (location IS NULL);
+
CREATE UNIQUE INDEX work_item_types_namespace_id_and_name_unique ON work_item_types USING btree (namespace_id, btrim(lower(name)));
ALTER INDEX analytics_cycle_analytics_issue_stage_events_pkey ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_00_pkey;
diff --git a/doc/development/service_ping/index.md b/doc/development/service_ping/index.md
index 152eec87d5d..6007468db3f 100644
--- a/doc/development/service_ping/index.md
+++ b/doc/development/service_ping/index.md
@@ -51,7 +51,7 @@ We use the following terminology to describe the Service Ping components:
metric has a corresponding [metric definition](metrics_dictionary.md#metrics-definition-and-validation)
in a YAML file.
- **MAU**: monthly active users.
-- **WAU**: weekly active users.
+- **WAU**: weekly active users.
### Why should we enable Service Ping?
@@ -64,29 +64,43 @@ We use the following terminology to describe the Service Ping components:
- Service Ping is enabled by default. To disable it, see [Disable Service Ping](#disable-service-ping).
- When Service Ping is enabled, you have the option to participate in our [Registration Features Program](#registration-features-program) and receive free paid features.
-#### Registration Features Program
+### Limitations
+
+- Service Ping does not track frontend events things like page views, link clicks, or user sessions.
+- Service Ping focuses only on aggregated backend events.
+
+Because of these limitations we recommend you:
+
+- Instrument your products with Snowplow for more detailed analytics on GitLab.com.
+- Use Service Ping to track aggregated backend events on self-managed instances.
+
+### Registration Features Program
> Introduced in GitLab 14.1.
-Starting with GitLab version 14.1, free self-managed users running [GitLab EE](../ee_features.md) can receive paid features by registering with GitLab and sending us activity data via [Service Ping](#what-is-service-ping). Features introduced here do not remove the feature from its paid tier. Users can continue to access the features in a paid tier without sharing usage data.
+In GitLab versions 14.1 and later, free self-managed users running [GitLab EE](../ee_features.md) can receive paid features by registering with GitLab and sending us activity data through [Service Ping](#what-is-service-ping). Features introduced here do not remove the feature from its paid tier. Users can continue to access the features in a paid tier without sharing usage data.
-##### Features available in 14.1 and later
+#### Features available in 14.1 and later
1. [Email from GitLab](../../tools/email.md).
-##### Features available in 14.4 and later
+#### Features available in 14.4 and later
1. [Repository size limit](../../user/admin_area/settings/account_and_limit_settings.md#repository-size-limit).
-
1. [Restrict group access by IP address](../../user/group/index.md#restrict-group-access-by-ip-address).
NOTE:
Registration is not yet required for participation, but will be added in a future milestone.
-### Limitations
+#### Enable Registration Features
-- Service Ping does not track frontend events things like page views, link clicks, or user sessions, and only focuses on aggregated backend events.
-- Because of these limitations we recommend instrumenting your products with Snowplow for more detailed analytics on GitLab.com and use Service Ping to track aggregated backend events on self-managed.
+1. Sign in as a user with the [Administrator](../../user/permissions.md) role.
+1. On the top bar, select **Menu > Admin**.
+1. On the left sidebar, select **Settings > Metrics and profiling**.
+1. Expand the **Usage statistics** section.
+1. If not enabled, select the **Enable Service Ping** checkbox.
+1. Select the **Enable Registration Features** checkbox.
+1. Select **Save changes**.
## View the Service Ping payload **(FREE SELF)**
diff --git a/doc/operations/incident_management/integrations.md b/doc/operations/incident_management/integrations.md
index 3e498454c55..92f5a50b1c3 100644
--- a/doc/operations/incident_management/integrations.md
+++ b/doc/operations/incident_management/integrations.md
@@ -196,7 +196,9 @@ WARNING:
Using your authorization key in the URL is insecure, as it's visible in server logs. We recommend
using one of the above header options if your tooling supports it.
-## Response Body
+## Response body
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/342730) in GitLab 14.5.
The JSON response body contains a list of any alerts created within the request:
diff --git a/doc/user/infrastructure/index.md b/doc/user/infrastructure/index.md
index 3dcce47105b..3bb518596cc 100644
--- a/doc/user/infrastructure/index.md
+++ b/doc/user/infrastructure/index.md
@@ -31,7 +31,7 @@ Learn more about how GitLab can help you run [Infrastructure as Code](iac/index.
The GitLab integration with Kubernetes helps you to install, configure, manage, deploy, and troubleshoot
cluster applications. With the GitLab Kubernetes Agent, you can connect clusters behind a firewall,
-have real-time access to API endpoints, perform pull-beased or push-based deployments for production
+have real-time access to API endpoints, perform pull-based or push-based deployments for production
and non-production environments, and much more.
Learn more about the [GitLab Kubernetes Agent](../clusters/agent/index.md).
diff --git a/doc/user/project/merge_requests/approvals/index.md b/doc/user/project/merge_requests/approvals/index.md
index aff55419a88..d873f715557 100644
--- a/doc/user/project/merge_requests/approvals/index.md
+++ b/doc/user/project/merge_requests/approvals/index.md
@@ -3,7 +3,7 @@ stage: Create
group: Source Code
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"
type: reference, concepts
-disqus_identifier: 'https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html'
+disqus_identifier: 'https://docs.gitlab.com/ee/user/project/merge_requests/approvals/index.html'
---
# Merge request approvals **(FREE)**
diff --git a/lib/gitlab/background_migration/update_vulnerability_occurrences_location.rb b/lib/gitlab/background_migration/update_vulnerability_occurrences_location.rb
new file mode 100644
index 00000000000..458e0537f1c
--- /dev/null
+++ b/lib/gitlab/background_migration/update_vulnerability_occurrences_location.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # rubocop: disable Style/Documentation
+ class UpdateVulnerabilityOccurrencesLocation
+ def perform(start_id, stop_id)
+ end
+ end
+ # rubocop: enable Style/Documentation
+ end
+end
+
+Gitlab::BackgroundMigration::UpdateVulnerabilityOccurrencesLocation.prepend_mod_with('Gitlab::BackgroundMigration::UpdateVulnerabilityOccurrencesLocation')
diff --git a/lib/gitlab/content_security_policy/config_loader.rb b/lib/gitlab/content_security_policy/config_loader.rb
index b55eb4f1263..bdae59e7e3c 100644
--- a/lib/gitlab/content_security_policy/config_loader.rb
+++ b/lib/gitlab/content_security_policy/config_loader.rb
@@ -19,11 +19,11 @@ module Gitlab
'font_src' => "'self'",
'form_action' => "'self' https: http:",
'frame_ancestors' => "'self'",
- 'frame_src' => "https://www.google.com/recaptcha/ https://www.recaptcha.net/ https://content.googleapis.com https://content-compute.googleapis.com https://content-cloudbilling.googleapis.com https://content-cloudresourcemanager.googleapis.com",
+ 'frame_src' => ContentSecurityPolicy::Directives.frame_src,
'img_src' => "'self' data: blob: http: https:",
'manifest_src' => "'self'",
'media_src' => "'self'",
- 'script_src' => "'strict-dynamic' 'self' 'unsafe-inline' 'unsafe-eval' https://www.google.com/recaptcha/ https://www.recaptcha.net https://apis.google.com",
+ 'script_src' => ContentSecurityPolicy::Directives.script_src,
'style_src' => "'self' 'unsafe-inline'",
'worker_src' => "#{Gitlab::Utils.append_path(Gitlab.config.gitlab.url, 'assets/')} blob: data:",
'object_src' => "'none'",
diff --git a/lib/gitlab/content_security_policy/directives.rb b/lib/gitlab/content_security_policy/directives.rb
new file mode 100644
index 00000000000..30f3c16247d
--- /dev/null
+++ b/lib/gitlab/content_security_policy/directives.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+# This module is used to return various SaaS related
+# ContentSecurityPolicy Directives src which may be
+# overridden in other variants of GitLab
+
+module Gitlab
+ module ContentSecurityPolicy
+ module Directives
+ def self.frame_src
+ "https://www.google.com/recaptcha/ https://www.recaptcha.net/ https://content.googleapis.com https://content-compute.googleapis.com https://content-cloudbilling.googleapis.com https://content-cloudresourcemanager.googleapis.com"
+ end
+
+ def self.script_src
+ "'strict-dynamic' 'self' 'unsafe-inline' 'unsafe-eval' https://www.google.com/recaptcha/ https://www.recaptcha.net https://apis.google.com"
+ end
+ end
+ end
+end
+
+Gitlab::ContentSecurityPolicy::Directives.prepend_mod
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index 027551df15d..9ad902efb3a 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -56,7 +56,6 @@ module Gitlab
push_frontend_feature_flag(:security_auto_fix, default_enabled: false)
push_frontend_feature_flag(:improved_emoji_picker, default_enabled: :yaml)
push_frontend_feature_flag(:new_header_search, default_enabled: :yaml)
- push_frontend_feature_flag(:suppress_apollo_errors_during_navigation, current_user, default_enabled: :yaml)
push_frontend_feature_flag(:configure_iac_scanning_via_mr, current_user, default_enabled: :yaml)
push_frontend_feature_flag(:bootstrap_confirmation_modals, default_enabled: :yaml)
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 9fa1f64f025..f9fcc07c367 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2166,9 +2166,6 @@ msgstr ""
msgid "Added an issue to an epic."
msgstr ""
-msgid "Added at"
-msgstr ""
-
msgid "Added for this merge request"
msgstr ""
@@ -12465,6 +12462,9 @@ msgstr ""
msgid "Edit deploy freeze"
msgstr ""
+msgid "Edit deploy key"
+msgstr ""
+
msgid "Edit description"
msgstr ""
@@ -13927,9 +13927,6 @@ msgstr ""
msgid "Exceptions"
msgstr ""
-msgid "Excess storage"
-msgstr ""
-
msgid "Excluding merge commits. Limited to %{limit} commits."
msgstr ""
@@ -37263,18 +37260,6 @@ msgstr ""
msgid "UsageQuota|This namespace has no projects which use shared runners"
msgstr ""
-msgid "UsageQuota|This project is at risk of being locked because purchased storage is running low."
-msgstr ""
-
-msgid "UsageQuota|This project is locked because it is using %{actualRepositorySizeLimit} of free storage and there is no purchased storage available."
-msgstr ""
-
-msgid "UsageQuota|This project is locked because it used %{actualRepositorySizeLimit} of free storage and all the purchased storage."
-msgstr ""
-
-msgid "UsageQuota|This project is near the free %{actualRepositorySizeLimit} limit and at risk of being locked."
-msgstr ""
-
msgid "UsageQuota|Total excess storage used"
msgstr ""
@@ -40188,9 +40173,6 @@ msgstr ""
msgid "added"
msgstr ""
-msgid "added %{created_at_timeago}"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
diff --git a/package.json b/package.json
index a51f3d180c5..b6f7725d068 100644
--- a/package.json
+++ b/package.json
@@ -205,7 +205,7 @@
"@babel/plugin-transform-modules-commonjs": "^7.10.1",
"@gitlab/eslint-plugin": "10.0.0",
"@gitlab/stylelint-config": "2.6.0",
- "@graphql-eslint/eslint-plugin": "^2.3.0",
+ "@graphql-eslint/eslint-plugin": "2.3.0",
"@testing-library/dom": "^7.16.2",
"@vue/test-utils": "1.2.0",
"acorn": "^6.3.0",
diff --git a/qa/qa/resource/project.rb b/qa/qa/resource/project.rb
index 43f2039fd78..864f3a14c3d 100644
--- a/qa/qa/resource/project.rb
+++ b/qa/qa/resource/project.rb
@@ -217,6 +217,10 @@ module QA
"#{api_get_path}/wikis"
end
+ def api_push_rules_path
+ "#{api_get_path}/push_rule"
+ end
+
def api_post_body
post_body = {
name: name,
@@ -361,6 +365,15 @@ module QA
parse_body(response)
end
+ def push_rules
+ response = get(request_url(api_push_rules_path))
+ parse_body(response)
+ end
+
+ def add_push_rules(rules)
+ api_post_to(api_push_rules_path, rules)
+ end
+
# Object comparison
#
# @param [QA::Resource::Project] other
diff --git a/qa/qa/specs/features/api/1_manage/bulk_import_project_spec.rb b/qa/qa/specs/features/api/1_manage/bulk_import_project_spec.rb
index 2bf9a7e62bf..7d0bb92f13a 100644
--- a/qa/qa/specs/features/api/1_manage/bulk_import_project_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/bulk_import_project_spec.rb
@@ -33,6 +33,7 @@ module QA
Resource::Project.fabricate_via_api! do |project|
project.api_client = api_client
project.group = source_group
+ project.initialize_with_readme = true
end
end
@@ -60,7 +61,7 @@ module QA
sandbox.add_member(user, Resource::Members::AccessLevel::MAINTAINER)
- source_project # fabricate source group and project
+ source_project.tap { |project| project.add_push_rules(member_check: true) } # fabricate source group and project
end
after do
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb
index f4b306d6830..f269cac4492 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb
@@ -128,7 +128,7 @@ module QA
end
end
- it "push and pull a npm package via CI using a #{params[:token_name]}" do
+ it "push and pull a npm package via CI using a #{params[:token_name]}", quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/344537', type: :investigating } do
Resource::Repository::Commit.fabricate_via_api! do |commit|
commit.project = project
commit.commit_message = 'Add .gitlab-ci.yml'
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 382ce0feda0..0f1c6ae4c70 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -1408,7 +1408,7 @@ RSpec.describe Projects::IssuesController do
end
end
- context 'when the endpoint receives requests above the limit' do
+ context 'when the endpoint receives requests above the limit', :freeze_time, :clean_gitlab_redis_rate_limiting do
before do
stub_application_setting(issues_create_limit: 5)
end
diff --git a/spec/experiments/change_continuous_onboarding_link_urls_experiment_spec.rb b/spec/experiments/change_continuous_onboarding_link_urls_experiment_spec.rb
new file mode 100644
index 00000000000..815aaf7c397
--- /dev/null
+++ b/spec/experiments/change_continuous_onboarding_link_urls_experiment_spec.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ChangeContinuousOnboardingLinkUrlsExperiment, :snowplow do
+ before do
+ stub_experiments(change_continuous_onboarding_link_urls: 'control')
+ end
+
+ describe '#track' do
+ context 'when no namespace has been set' do
+ it 'tracks the action as normal' do
+ subject.track(:some_action)
+
+ expect_snowplow_event(
+ category: subject.name,
+ action: 'some_action',
+ namespace: nil,
+ context: [
+ {
+ schema: 'iglu:com.gitlab/gitlab_experiment/jsonschema/1-0-0',
+ data: an_instance_of(Hash)
+ }
+ ]
+ )
+ end
+ end
+
+ context 'when a namespace has been set' do
+ let_it_be(:namespace) { create(:namespace) }
+
+ before do
+ subject.namespace = namespace
+ end
+
+ it 'tracks the action and merges the namespace into the event args' do
+ subject.track(:some_action)
+
+ expect_snowplow_event(
+ category: subject.name,
+ action: 'some_action',
+ namespace: namespace,
+ context: [
+ {
+ schema: 'iglu:com.gitlab/gitlab_experiment/jsonschema/1-0-0',
+ data: an_instance_of(Hash)
+ }
+ ]
+ )
+ end
+ end
+ end
+end
diff --git a/spec/features/admin/admin_deploy_keys_spec.rb b/spec/features/admin/admin_deploy_keys_spec.rb
index fd74a13deff..53caf0fac33 100644
--- a/spec/features/admin/admin_deploy_keys_spec.rb
+++ b/spec/features/admin/admin_deploy_keys_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe 'admin deploy keys' do
it 'show all public deploy keys' do
visit admin_deploy_keys_path
- page.within(find('.deploy-keys-list', match: :first)) do
+ page.within(find('[data-testid="deploy-keys-list"]', match: :first)) do
expect(page).to have_content(deploy_key.title)
expect(page).to have_content(another_deploy_key.title)
end
@@ -28,7 +28,7 @@ RSpec.describe 'admin deploy keys' do
visit admin_deploy_keys_path
- page.within(find('.deploy-keys-list', match: :first)) do
+ page.within(find('[data-testid="deploy-keys-list"]', match: :first)) do
expect(page).to have_content(write_key.project.full_name)
end
end
@@ -48,7 +48,7 @@ RSpec.describe 'admin deploy keys' do
expect(current_path).to eq admin_deploy_keys_path
- page.within(find('.deploy-keys-list', match: :first)) do
+ page.within(find('[data-testid="deploy-keys-list"]', match: :first)) do
expect(page).to have_content('laptop')
end
end
@@ -66,7 +66,7 @@ RSpec.describe 'admin deploy keys' do
expect(current_path).to eq admin_deploy_keys_path
- page.within(find('.deploy-keys-list', match: :first)) do
+ page.within(find('[data-testid="deploy-keys-list"]', match: :first)) do
expect(page).to have_content('new-title')
end
end
@@ -81,7 +81,7 @@ RSpec.describe 'admin deploy keys' do
find('tr', text: deploy_key.title).click_link('Remove')
expect(current_path).to eq admin_deploy_keys_path
- page.within(find('.deploy-keys-list', match: :first)) do
+ page.within(find('[data-testid="deploy-keys-list"]', match: :first)) do
expect(page).not_to have_content(deploy_key.title)
end
end
diff --git a/spec/frontend/lib/apollo/suppress_network_errors_during_navigation_link_spec.js b/spec/frontend/lib/apollo/suppress_network_errors_during_navigation_link_spec.js
index 852106db44e..7b604724977 100644
--- a/spec/frontend/lib/apollo/suppress_network_errors_during_navigation_link_spec.js
+++ b/spec/frontend/lib/apollo/suppress_network_errors_during_navigation_link_spec.js
@@ -47,107 +47,95 @@ describe('getSuppressNetworkErrorsDuringNavigationLink', () => {
subscription = link.request(mockOperation).subscribe(observer);
};
- describe('when disabled', () => {
- it('returns null', () => {
- expect(getSuppressNetworkErrorsDuringNavigationLink()).toBe(null);
- });
+ it('returns an ApolloLink', () => {
+ expect(getSuppressNetworkErrorsDuringNavigationLink()).toEqual(expect.any(ApolloLink));
});
- describe('when enabled', () => {
- beforeEach(() => {
- window.gon = { features: { suppressApolloErrorsDuringNavigation: true } };
- });
-
- it('returns an ApolloLink', () => {
- expect(getSuppressNetworkErrorsDuringNavigationLink()).toEqual(expect.any(ApolloLink));
- });
-
- describe('suppression case', () => {
- describe('when navigating away', () => {
- beforeEach(() => {
- isNavigatingAway.mockReturnValue(true);
- });
-
- describe('given a network error', () => {
- it('does not forward the error', async () => {
- const spy = jest.fn();
+ describe('suppression case', () => {
+ describe('when navigating away', () => {
+ beforeEach(() => {
+ isNavigatingAway.mockReturnValue(true);
+ });
- createSubscription(makeMockNetworkErrorLink(), {
- next: spy,
- error: spy,
- complete: spy,
- });
+ describe('given a network error', () => {
+ it('does not forward the error', async () => {
+ const spy = jest.fn();
- // It's hard to test for something _not_ happening. The best we can
- // do is wait a bit to make sure nothing happens.
- await waitForPromises();
- expect(spy).not.toHaveBeenCalled();
+ createSubscription(makeMockNetworkErrorLink(), {
+ next: spy,
+ error: spy,
+ complete: spy,
});
+
+ // It's hard to test for something _not_ happening. The best we can
+ // do is wait a bit to make sure nothing happens.
+ await waitForPromises();
+ expect(spy).not.toHaveBeenCalled();
});
});
});
+ });
- describe('non-suppression cases', () => {
- describe('when not navigating away', () => {
- beforeEach(() => {
- isNavigatingAway.mockReturnValue(false);
- });
+ describe('non-suppression cases', () => {
+ describe('when not navigating away', () => {
+ beforeEach(() => {
+ isNavigatingAway.mockReturnValue(false);
+ });
- it('forwards successful requests', (done) => {
- createSubscription(makeMockSuccessLink(), {
- next({ data }) {
- expect(data).toEqual({ foo: { id: 1 } });
- },
- error: () => done.fail('Should not happen'),
- complete: () => done(),
- });
+ it('forwards successful requests', (done) => {
+ createSubscription(makeMockSuccessLink(), {
+ next({ data }) {
+ expect(data).toEqual({ foo: { id: 1 } });
+ },
+ error: () => done.fail('Should not happen'),
+ complete: () => done(),
});
+ });
- it('forwards GraphQL errors', (done) => {
- createSubscription(makeMockGraphQLErrorLink(), {
- next({ errors }) {
- expect(errors).toEqual([{ message: 'foo' }]);
- },
- error: () => done.fail('Should not happen'),
- complete: () => done(),
- });
+ it('forwards GraphQL errors', (done) => {
+ createSubscription(makeMockGraphQLErrorLink(), {
+ next({ errors }) {
+ expect(errors).toEqual([{ message: 'foo' }]);
+ },
+ error: () => done.fail('Should not happen'),
+ complete: () => done(),
});
+ });
- it('forwards network errors', (done) => {
- createSubscription(makeMockNetworkErrorLink(), {
- next: () => done.fail('Should not happen'),
- error: (error) => {
- expect(error.message).toBe('NetworkError');
- done();
- },
- complete: () => done.fail('Should not happen'),
- });
+ it('forwards network errors', (done) => {
+ createSubscription(makeMockNetworkErrorLink(), {
+ next: () => done.fail('Should not happen'),
+ error: (error) => {
+ expect(error.message).toBe('NetworkError');
+ done();
+ },
+ complete: () => done.fail('Should not happen'),
});
});
+ });
- describe('when navigating away', () => {
- beforeEach(() => {
- isNavigatingAway.mockReturnValue(true);
- });
+ describe('when navigating away', () => {
+ beforeEach(() => {
+ isNavigatingAway.mockReturnValue(true);
+ });
- it('forwards successful requests', (done) => {
- createSubscription(makeMockSuccessLink(), {
- next({ data }) {
- expect(data).toEqual({ foo: { id: 1 } });
- },
- error: () => done.fail('Should not happen'),
- complete: () => done(),
- });
+ it('forwards successful requests', (done) => {
+ createSubscription(makeMockSuccessLink(), {
+ next({ data }) {
+ expect(data).toEqual({ foo: { id: 1 } });
+ },
+ error: () => done.fail('Should not happen'),
+ complete: () => done(),
});
+ });
- it('forwards GraphQL errors', (done) => {
- createSubscription(makeMockGraphQLErrorLink(), {
- next({ errors }) {
- expect(errors).toEqual([{ message: 'foo' }]);
- },
- error: () => done.fail('Should not happen'),
- complete: () => done(),
- });
+ it('forwards GraphQL errors', (done) => {
+ createSubscription(makeMockGraphQLErrorLink(), {
+ next({ errors }) {
+ expect(errors).toEqual([{ message: 'foo' }]);
+ },
+ error: () => done.fail('Should not happen'),
+ complete: () => done(),
});
});
});
diff --git a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_spec.js.snap b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_spec.js.snap
index 3aa0e99a858..3e371a8765f 100644
--- a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_spec.js.snap
+++ b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_spec.js.snap
@@ -135,6 +135,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<a
class="gl-link"
data-track-action="click_link"
+ data-track-experiment="change_continuous_onboarding_link_urls"
data-track-label="Set up CI/CD"
data-track-property="Growth::Conversion::Experiment::LearnGitLab"
href="http://example.com/"
@@ -156,6 +157,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<a
class="gl-link"
data-track-action="click_link"
+ data-track-experiment="change_continuous_onboarding_link_urls"
data-track-label="Start a free Ultimate trial"
data-track-property="Growth::Conversion::Experiment::LearnGitLab"
href="http://example.com/"
@@ -177,6 +179,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<a
class="gl-link"
data-track-action="click_link"
+ data-track-experiment="change_continuous_onboarding_link_urls"
data-track-label="Add code owners"
data-track-property="Growth::Conversion::Experiment::LearnGitLab"
href="http://example.com/"
@@ -205,6 +208,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<a
class="gl-link"
data-track-action="click_link"
+ data-track-experiment="change_continuous_onboarding_link_urls"
data-track-label="Add merge request approval"
data-track-property="Growth::Conversion::Experiment::LearnGitLab"
href="http://example.com/"
@@ -269,6 +273,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<a
class="gl-link"
data-track-action="click_link"
+ data-track-experiment="change_continuous_onboarding_link_urls"
data-track-label="Create an issue"
data-track-property="Growth::Conversion::Experiment::LearnGitLab"
href="http://example.com/"
@@ -290,6 +295,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<a
class="gl-link"
data-track-action="click_link"
+ data-track-experiment="change_continuous_onboarding_link_urls"
data-track-label="Submit a merge request"
data-track-property="Growth::Conversion::Experiment::LearnGitLab"
href="http://example.com/"
@@ -347,6 +353,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<a
class="gl-link"
data-track-action="click_link"
+ data-track-experiment="change_continuous_onboarding_link_urls"
data-track-label="Run a Security scan using CI/CD"
data-track-property="Growth::Conversion::Experiment::LearnGitLab"
href="http://example.com/"
diff --git a/spec/lib/gitlab/content_security_policy/config_loader_spec.rb b/spec/lib/gitlab/content_security_policy/config_loader_spec.rb
index 5892bae5c0b..c0476d38380 100644
--- a/spec/lib/gitlab/content_security_policy/config_loader_spec.rb
+++ b/spec/lib/gitlab/content_security_policy/config_loader_spec.rb
@@ -81,11 +81,11 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do
end
it 'adds CDN host to CSP' do
- expect(directives['script_src']).to eq("'strict-dynamic' 'self' 'unsafe-inline' 'unsafe-eval' https://www.google.com/recaptcha/ https://www.recaptcha.net https://apis.google.com https://cdn.example.com")
+ expect(directives['script_src']).to eq(::Gitlab::ContentSecurityPolicy::Directives.script_src + " https://cdn.example.com")
expect(directives['style_src']).to eq("'self' 'unsafe-inline' https://cdn.example.com")
expect(directives['font_src']).to eq("'self' https://cdn.example.com")
expect(directives['worker_src']).to eq('http://localhost/assets/ blob: data: https://cdn.example.com')
- expect(directives['frame_src']).to eq("https://www.google.com/recaptcha/ https://www.recaptcha.net/ https://content.googleapis.com https://content-compute.googleapis.com https://content-cloudbilling.googleapis.com https://content-cloudresourcemanager.googleapis.com https://cdn.example.com http://localhost/admin/sidekiq http://localhost/admin/sidekiq/ http://localhost/-/speedscope/index.html")
+ expect(directives['frame_src']).to eq(::Gitlab::ContentSecurityPolicy::Directives.frame_src + " https://cdn.example.com http://localhost/admin/sidekiq http://localhost/admin/sidekiq/ http://localhost/-/speedscope/index.html")
end
end
@@ -113,7 +113,7 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do
end
it 'does not add CUSTOMER_PORTAL_URL to CSP' do
- expect(directives['frame_src']).to eq("https://www.google.com/recaptcha/ https://www.recaptcha.net/ https://content.googleapis.com https://content-compute.googleapis.com https://content-cloudbilling.googleapis.com https://content-cloudresourcemanager.googleapis.com http://localhost/admin/sidekiq http://localhost/admin/sidekiq/ http://localhost/-/speedscope/index.html")
+ expect(directives['frame_src']).to eq(::Gitlab::ContentSecurityPolicy::Directives.frame_src + " http://localhost/admin/sidekiq http://localhost/admin/sidekiq/ http://localhost/-/speedscope/index.html")
end
end
@@ -123,7 +123,7 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do
end
it 'adds CUSTOMER_PORTAL_URL to CSP' do
- expect(directives['frame_src']).to eq("https://www.google.com/recaptcha/ https://www.recaptcha.net/ https://content.googleapis.com https://content-compute.googleapis.com https://content-cloudbilling.googleapis.com https://content-cloudresourcemanager.googleapis.com http://localhost/rails/letter_opener/ https://customers.example.com http://localhost/admin/sidekiq http://localhost/admin/sidekiq/ http://localhost/-/speedscope/index.html")
+ expect(directives['frame_src']).to eq(::Gitlab::ContentSecurityPolicy::Directives.frame_src + " http://localhost/rails/letter_opener/ https://customers.example.com http://localhost/admin/sidekiq http://localhost/admin/sidekiq/ http://localhost/-/speedscope/index.html")
end
end
end
diff --git a/spec/lib/gitlab/database/partitioning_spec.rb b/spec/lib/gitlab/database/partitioning_spec.rb
index 7855e0aabf9..154cc2b7972 100644
--- a/spec/lib/gitlab/database/partitioning_spec.rb
+++ b/spec/lib/gitlab/database/partitioning_spec.rb
@@ -30,6 +30,39 @@ RSpec.describe Gitlab::Database::Partitioning do
end
end
+ describe '.sync_partitions_ignore_db_error' do
+ it 'calls sync_partitions' do
+ expect(described_class).to receive(:sync_partitions)
+
+ described_class.sync_partitions_ignore_db_error
+ end
+
+ [ActiveRecord::ActiveRecordError, PG::Error].each do |error|
+ context "when #{error} is raised" do
+ before do
+ expect(described_class).to receive(:sync_partitions)
+ .and_raise(error)
+ end
+
+ it 'ignores it' do
+ described_class.sync_partitions_ignore_db_error
+ end
+ end
+ end
+
+ context 'when DISABLE_POSTGRES_PARTITION_CREATION_ON_STARTUP is set' do
+ before do
+ stub_env('DISABLE_POSTGRES_PARTITION_CREATION_ON_STARTUP', '1')
+ end
+
+ it 'does not call sync_partitions' do
+ expect(described_class).to receive(:sync_partitions).never
+
+ described_class.sync_partitions_ignore_db_error
+ end
+ end
+ end
+
describe '.sync_partitions' do
let(:table_names) { %w[partitioning_test1 partitioning_test2] }
let(:models) do
diff --git a/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb b/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
index 942ac67c39d..93b3566b709 100644
--- a/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
@@ -259,7 +259,7 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler do
end
end
- context 'when rate limiting is in effect', :clean_gitlab_redis_cache do
+ context 'when rate limiting is in effect', :freeze_time, :clean_gitlab_redis_rate_limiting do
let(:receiver) { Gitlab::Email::Receiver.new(email_raw) }
subject { 2.times { receiver.execute } }
@@ -271,18 +271,14 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler do
context 'when too many requests are sent by one user' do
it 'raises an error' do
- freeze_time do
- expect { subject }.to raise_error(RateLimitedService::RateLimitedError)
- end
+ expect { subject }.to raise_error(RateLimitedService::RateLimitedError)
end
it 'creates 1 issue' do
- freeze_time do
- expect do
- subject
- rescue RateLimitedService::RateLimitedError
- end.to change { Issue.count }.by(1)
- end
+ expect do
+ subject
+ rescue RateLimitedService::RateLimitedError
+ end.to change { Issue.count }.by(1)
end
context 'when requests are sent by different users' do
@@ -295,9 +291,7 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler do
end
it 'creates 2 issues' do
- freeze_time do
- expect { subject }.to change { Issue.count }.by(2)
- end
+ expect { subject }.to change { Issue.count }.by(2)
end
end
end
@@ -308,9 +302,7 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler do
end
it 'creates 2 issues' do
- freeze_time do
- expect { subject }.to change { Issue.count }.by(2)
- end
+ expect { subject }.to change { Issue.count }.by(2)
end
end
end
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index 67d7e49f8db..2953c198af6 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -104,29 +104,71 @@ RSpec.describe ProjectPolicy do
end
context 'pipeline feature' do
- let(:project) { private_project }
+ let(:project) { private_project }
+ let(:current_user) { developer }
+ let(:pipeline) { create(:ci_pipeline, project: project) }
- before do
- private_project.add_developer(current_user)
+ describe 'for confirmed user' do
+ it 'allows modify pipelines' do
+ expect_allowed(:create_pipeline)
+ expect_allowed(:update_pipeline)
+ expect_allowed(:create_pipeline_schedule)
+ end
end
describe 'for unconfirmed user' do
- let(:current_user) { create(:user, confirmed_at: nil) }
+ let(:current_user) { project.owner.tap { |u| u.update!(confirmed_at: nil) } }
it 'disallows to modify pipelines' do
expect_disallowed(:create_pipeline)
expect_disallowed(:update_pipeline)
+ expect_disallowed(:destroy_pipeline)
expect_disallowed(:create_pipeline_schedule)
end
end
- describe 'for confirmed user' do
- let(:current_user) { developer }
+ describe 'destroy permission' do
+ describe 'for developers' do
+ it 'prevents :destroy_pipeline' do
+ expect(current_user.can?(:destroy_pipeline, pipeline)).to be_falsey
+ end
+ end
- it 'allows modify pipelines' do
- expect_allowed(:create_pipeline)
- expect_allowed(:update_pipeline)
- expect_allowed(:create_pipeline_schedule)
+ describe 'for maintainers' do
+ let(:current_user) { maintainer }
+
+ it 'prevents :destroy_pipeline' do
+ project.add_maintainer(maintainer)
+ expect(current_user.can?(:destroy_pipeline, pipeline)).to be_falsey
+ end
+ end
+
+ describe 'for project owner' do
+ let(:current_user) { project.owner }
+
+ it 'allows :destroy_pipeline' do
+ expect(current_user.can?(:destroy_pipeline, pipeline)).to be_truthy
+ end
+
+ context 'on archived projects' do
+ before do
+ project.update!(archived: true)
+ end
+
+ it 'prevents :destroy_pipeline' do
+ expect(current_user.can?(:destroy_pipeline, pipeline)).to be_falsey
+ end
+ end
+
+ context 'on archived pending_delete projects' do
+ before do
+ project.update!(archived: true, pending_delete: true)
+ end
+
+ it 'allows :destroy_pipeline' do
+ expect(current_user.can?(:destroy_pipeline, pipeline)).to be_truthy
+ end
+ end
end
end
end
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index 3ea447b2384..57fcdf84163 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -302,7 +302,7 @@ RSpec.describe Issues::CreateService do
described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params).execute
end
- context 'when rate limiting is in effect', :clean_gitlab_redis_cache do
+ context 'when rate limiting is in effect', :freeze_time, :clean_gitlab_redis_rate_limiting do
let(:user) { create(:user) }
before do
@@ -316,20 +316,16 @@ RSpec.describe Issues::CreateService do
context 'when too many requests are sent by one user' do
it 'raises an error' do
- freeze_time do
- expect do
- subject
- end.to raise_error(RateLimitedService::RateLimitedError)
- end
+ expect do
+ subject
+ end.to raise_error(RateLimitedService::RateLimitedError)
end
it 'creates 1 issue' do
- freeze_time do
- expect do
- subject
- rescue RateLimitedService::RateLimitedError
- end.to change { Issue.count }.by(1)
- end
+ expect do
+ subject
+ rescue RateLimitedService::RateLimitedError
+ end.to change { Issue.count }.by(1)
end
end
@@ -339,9 +335,7 @@ RSpec.describe Issues::CreateService do
end
it 'creates 2 issues' do
- freeze_time do
- expect { subject }.to change { Issue.count }.by(2)
- end
+ expect { subject }.to change { Issue.count }.by(2)
end
end
end
diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb
index 9bdd9800fcc..ac84614121a 100644
--- a/spec/services/projects/destroy_service_spec.rb
+++ b/spec/services/projects/destroy_service_spec.rb
@@ -331,6 +331,14 @@ RSpec.describe Projects::DestroyService, :aggregate_failures do
end
end
end
+
+ context 'for an archived project' do
+ before do
+ project.update!(archived: true)
+ end
+
+ it_behaves_like 'deleting the project with pipeline and build'
+ end
end
describe 'container registry' do
diff --git a/yarn.lock b/yarn.lock
index 7a861505d2c..a286b762a50 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -946,7 +946,7 @@
resolved "https://registry.yarnpkg.com/@gitlab/visual-review-tools/-/visual-review-tools-1.6.1.tgz#0d8f3ff9f51b05f7c80b9a107727703d48997e4e"
integrity sha512-vY8K1igwZFoEOmU0h4E7XTLlilsQ4ylPr27O01UsSe6ZTKi6oEMREsRAEpNIUgRlxUARCsf+Opp4pgSFzFkFcw==
-"@graphql-eslint/eslint-plugin@^2.3.0":
+"@graphql-eslint/eslint-plugin@2.3.0":
version "2.3.0"
resolved "https://registry.yarnpkg.com/@graphql-eslint/eslint-plugin/-/eslint-plugin-2.3.0.tgz#4e500466fa56b64680c67d7639f1bdf11d890f8a"
integrity sha512-YYTBKhadvdTO6myWFm3O8A8dP/ca5NsyB2FKYoHGUIToEl25xAMuj2yzvhIjIBwA/yhlLRPe9+EIQ+8f0kjBDg==