Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
e40f19ef83
commit
11c2b8eff6
|
@ -1 +1 @@
|
|||
1.46.0
|
||||
1.47.0
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')}';
|
||||
|
|
|
@ -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' }
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
450028c90cb92f5ce3f8239eb56364b83ed025839aaf305b7ceb4fda077681b1
|
|
@ -0,0 +1 @@
|
|||
a3f9fcac354cccfdfc42b8f5baab651cb65ca60e4474ce937ab25b552bfe483c
|
|
@ -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;
|
||||
|
|
|
@ -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)**
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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)**
|
||||
|
|
|
@ -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')
|
|
@ -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'",
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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 ""
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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('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();
|
||||
|
||||
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('when enabled', () => {
|
||||
beforeEach(() => {
|
||||
window.gon = { features: { suppressApolloErrorsDuringNavigation: true } };
|
||||
});
|
||||
describe('non-suppression cases', () => {
|
||||
describe('when not navigating away', () => {
|
||||
beforeEach(() => {
|
||||
isNavigatingAway.mockReturnValue(false);
|
||||
});
|
||||
|
||||
it('returns an ApolloLink', () => {
|
||||
expect(getSuppressNetworkErrorsDuringNavigationLink()).toEqual(expect.any(ApolloLink));
|
||||
});
|
||||
|
||||
describe('suppression case', () => {
|
||||
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(),
|
||||
});
|
||||
});
|
||||
|
||||
describe('given a network error', () => {
|
||||
it('does not forward the error', async () => {
|
||||
const spy = jest.fn();
|
||||
it('forwards GraphQL errors', (done) => {
|
||||
createSubscription(makeMockGraphQLErrorLink(), {
|
||||
next({ errors }) {
|
||||
expect(errors).toEqual([{ message: 'foo' }]);
|
||||
},
|
||||
error: () => done.fail('Should not happen'),
|
||||
complete: () => done(),
|
||||
});
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
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('non-suppression cases', () => {
|
||||
describe('when not navigating away', () => {
|
||||
beforeEach(() => {
|
||||
isNavigatingAway.mockReturnValue(false);
|
||||
});
|
||||
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 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 successful requests', (done) => {
|
||||
createSubscription(makeMockSuccessLink(), {
|
||||
next({ data }) {
|
||||
expect(data).toEqual({ foo: { id: 1 } });
|
||||
},
|
||||
error: () => done.fail('Should not happen'),
|
||||
complete: () => done(),
|
||||
});
|
||||
});
|
||||
|
||||
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 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(),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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/"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -104,31 +104,73 @@ RSpec.describe ProjectPolicy do
|
|||
end
|
||||
|
||||
context 'pipeline feature' do
|
||||
let(:project) { private_project }
|
||||
|
||||
before do
|
||||
private_project.add_developer(current_user)
|
||||
end
|
||||
|
||||
describe 'for unconfirmed user' do
|
||||
let(:current_user) { create(:user, confirmed_at: nil) }
|
||||
|
||||
it 'disallows to modify pipelines' do
|
||||
expect_disallowed(:create_pipeline)
|
||||
expect_disallowed(:update_pipeline)
|
||||
expect_disallowed(:create_pipeline_schedule)
|
||||
end
|
||||
end
|
||||
let(:project) { private_project }
|
||||
let(:current_user) { developer }
|
||||
let(:pipeline) { create(:ci_pipeline, project: project) }
|
||||
|
||||
describe 'for confirmed user' do
|
||||
let(:current_user) { developer }
|
||||
|
||||
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) { 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 'destroy permission' do
|
||||
describe 'for developers' do
|
||||
it 'prevents :destroy_pipeline' do
|
||||
expect(current_user.can?(:destroy_pipeline, pipeline)).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
context 'builds feature' do
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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==
|
||||
|
|
Loading…
Reference in New Issue