Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-01-15 12:10:21 +00:00
parent 7cd8614922
commit f58a5001b9
55 changed files with 454 additions and 251 deletions

View File

@ -1,31 +1,39 @@
---
# Base Markdownlint configuration
# Extended Markdownlint configuration in doc/.markdownlint/
# See https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md for explanations of each rule
# First, set the default
default: true
first-header-h1: true
header-style:
style: "atx"
ul-style:
style: "dash"
no-trailing-spaces: false
line-length: false
no-duplicate-header:
allow_different_nesting: true
no-trailing-punctuation:
punctuation: ".,;:!。,;:!?"
ol-prefix:
style: "one"
no-inline-html: false
hr-style:
style: "---"
no-emphasis-as-heading: false
first-line-h1: false
code-block-style:
# Per-rule settings in alphabetical order
code-block-style: # MD046
style: "fenced"
emphasis-style: false
link-fragments: false
reference-links-images: false
proper-names:
emphasis-style: false # MD049
first-header-h1: true # MD002
first-line-h1: false # MD041
header-style: # MD003
style: "atx"
hr-style: # MD035
style: "---"
line-length: false # MD013
link-fragments: false # MD051
no-duplicate-header: # MD024
allow_different_nesting: true
no-emphasis-as-heading: false # MD036
no-inline-html: false # MD033
no-trailing-punctuation: # MD026
punctuation: ".,;:!。,;:!?"
no-trailing-spaces: false # MD009
ol-prefix: # MD029
style: "one"
reference-links-images: false # MD052
ul-style: # MD004
style: "dash"
# Keep this item last due to length
proper-names: # MD044
code_blocks: false
html_elements: false
names: [
"Akismet",
"Alertmanager",
@ -150,5 +158,3 @@ proper-names:
"YAML",
"YouTrack"
]
code_blocks: false
html_elements: false

View File

@ -492,7 +492,7 @@
{"name":"rails","version":"7.0.8","platform":"ruby","checksum":"8e43af921acf766fb429126f020ec90c3b25809631f8fbdff95c3553828d5867"},
{"name":"rails-controller-testing","version":"1.0.5","platform":"ruby","checksum":"741448db59366073e86fc965ba403f881c636b79a2c39a48d0486f2607182e94"},
{"name":"rails-dom-testing","version":"2.0.3","platform":"ruby","checksum":"b140c4f39f6e609c8113137b9a60dfc2ecb89864e496f87f23a68b3b8f12d8d1"},
{"name":"rails-html-sanitizer","version":"1.5.0","platform":"ruby","checksum":"bf326075e8a968cd882c30b15a4c9100059be3af2356093dc68324ec3bd9ea79"},
{"name":"rails-html-sanitizer","version":"1.6.0","platform":"ruby","checksum":"86e9f19d2e6748890dcc2633c8945ca45baa08a1df9d8c215ce17b3b0afaa4de"},
{"name":"rails-i18n","version":"7.0.3","platform":"ruby","checksum":"e3158e98c5332d129fd5131f171ac575eb30dbb8919b21595382b08850cf2bd3"},
{"name":"railties","version":"7.0.8","platform":"ruby","checksum":"12325c3933efd33f8ead640197dec3b8c27c8d45607dd68b7b925896bf09cc69"},
{"name":"rainbow","version":"3.1.1","platform":"ruby","checksum":"039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a"},

View File

@ -1324,8 +1324,9 @@ GEM
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.5.0)
loofah (~> 2.19, >= 2.19.1)
rails-html-sanitizer (1.6.0)
loofah (~> 2.21)
nokogiri (~> 1.14)
rails-i18n (7.0.3)
i18n (>= 0.7, < 2)
railties (>= 6.0.0, < 8)

View File

@ -1,5 +1,5 @@
<script>
import { GlTabs, GlTab, GlSearchBoxByType, GlSorting, GlSortingItem } from '@gitlab/ui';
import { GlTabs, GlTab, GlSearchBoxByType, GlSorting } from '@gitlab/ui';
import { isString, debounce } from 'lodash';
import { __ } from '~/locale';
import { DEBOUNCE_DELAY } from '~/vue_shared/components/filtered_search_bar/constants';
@ -30,7 +30,6 @@ export default {
GroupsApp,
GlSearchBoxByType,
GlSorting,
GlSortingItem,
SubgroupsAndProjectsEmptyState,
SharedProjectsEmptyState,
ArchivedProjectsEmptyState,
@ -84,6 +83,9 @@ export default {
sortQueryStringValue() {
return this.isAscending ? this.sort.asc : this.sort.desc;
},
activeTabSortOptions() {
return this.activeTab.sortingItems.map(({ label }) => ({ value: label, text: label }));
},
},
mounted() {
this.search = this.$route.query?.filter || '';
@ -178,12 +180,14 @@ export default {
this.handleSearchOrSortChange();
},
handleSortingItemClick(sortingItem) {
if (sortingItem === this.sort) {
handleSortingItemClick(value) {
const selectedSortingItem = this.activeTab.sortingItems.find((item) => item.label === value);
if (selectedSortingItem === this.sort) {
return;
}
this.sort = sortingItem;
this.sort = selectedSortingItem;
this.handleSearchOrSortChange();
},
@ -239,16 +243,11 @@ export default {
data-testid="group_sort_by_dropdown"
:text="sort.label"
:is-ascending="isAscending"
:sort-options="activeTabSortOptions"
:sort-by="sort.label"
@sortByChange="handleSortingItemClick"
@sortDirectionChange="handleSortDirectionChange"
>
<gl-sorting-item
v-for="sortingItem in activeTab.sortingItems"
:key="sortingItem.label"
:active="sortingItem === sort"
@click="handleSortingItemClick(sortingItem)"
>{{ sortingItem.label }}</gl-sorting-item
>
</gl-sorting>
/>
</div>
</div>
</li>

View File

@ -16,7 +16,7 @@ new SigninTabsMemoizer(); // eslint-disable-line no-new
new NoEmojiValidator(); // eslint-disable-line no-new
new OAuthRememberMe({
container: $('.omniauth-container'),
container: $('.js-oauth-login'),
}).bindEvents();
// Save the URL fragment from the current window location. This will be present if the user was

View File

@ -20,8 +20,8 @@ export default class OAuthRememberMe {
toggleRememberMe(event) {
const rememberMe = $(event.target).is(':checked');
$('.js-oauth-login', this.container).each((i, element) => {
const $form = $(element).parent('form');
$('.js-oauth-login form', this.container).each((_, form) => {
const $form = $(form);
const href = $form.attr('action');
if (rememberMe) {

View File

@ -12,7 +12,7 @@ export default function preserveUrlFragment(fragment = '') {
// Append the fragment to all sign-in/sign-up form actions so it is preserved when the user is
// eventually redirected back to the originally requested URL.
const forms = document.querySelectorAll('#signin-container .tab-content form');
const forms = document.querySelectorAll('.js-non-oauth-login form');
Array.prototype.forEach.call(forms, (form) => {
const actionWithFragment = setUrlFragment(form.getAttribute('action'), `#${normalFragment}`);
form.setAttribute('action', actionWithFragment);
@ -20,7 +20,7 @@ export default function preserveUrlFragment(fragment = '') {
// Append a redirect_fragment query param to all oauth provider links. The redirect_fragment
// query param will be available in the omniauth callback upon successful authentication
const oauthForms = document.querySelectorAll('#signin-container .omniauth-container form');
const oauthForms = document.querySelectorAll('.js-oauth-login form');
Array.prototype.forEach.call(oauthForms, (oauthForm) => {
const newHref = mergeUrlParams(
{ redirect_fragment: normalFragment },

View File

@ -110,6 +110,7 @@ export default {
:no-results-text="$options.translations.noResultsText"
:selected="tzValue"
block
fluid-width
searchable
@search="setSearchTerm"
@select="selectTimezone"

View File

@ -450,6 +450,7 @@ module ApplicationSettingsHelper
:issues_create_limit,
:notes_create_limit,
:notes_create_limit_allowlist_raw,
:members_delete_limit,
:raw_blob_request_limit,
:project_import_limit,
:project_export_limit,

View File

@ -33,6 +33,19 @@ module TimeZoneHelper
end
end
# The identifiers in `timezone_data` are not unique. Some cities (e.g. London and Edinburgh) have
# the same `identifier` value (e.g. "Europe/London").
# This method merges such entries into one, joining the city names.
# This unique list is better suited for selectboxes etc.
def timezone_data_with_unique_identifiers(format: :short)
timezone_data(format: format)
.group_by { |entry| entry[:identifier] }
.map do |_identifier, entries|
names = entries.map { |entry| entry[:name] }.sort.join(', ') # rubocop:disable Rails/Pluck -- Not a ActiveRecord object
entries.first.merge({ name: names })
end
end
def local_timezone_instance(timezone)
return Time.zone if timezone.blank?

View File

@ -579,6 +579,7 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
:max_import_size,
:max_pages_custom_domains_per_project,
:max_terraform_state_size_bytes,
:members_delete_limit,
:notes_create_limit,
:package_registry_cleanup_policies_worker_capacity,
:packages_cleanup_package_file_worker_capacity,
@ -594,6 +595,11 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
:users_get_by_id_limit
end
jsonb_accessor :rate_limits,
members_delete_limit: [:integer, { default: 60 }]
validates :rate_limits, json_schema: { filename: "application_setting_rate_limits" }
validates :search_rate_limit_allowlist,
length: { maximum: 100, message: N_('is too long (maximum is 100 entries)') },
allow_nil: false

View File

@ -137,6 +137,7 @@ module ApplicationSettingImplementation
mirror_available: true,
notes_create_limit: 300,
notes_create_limit_allowlist: [],
members_delete_limit: 60,
notify_on_unknown_sign_in: true,
outbound_local_requests_whitelist: [],
password_authentication_enabled_for_git: true,

View File

@ -6,7 +6,7 @@ module Integrations
section: SECTION_TYPE_CONNECTION,
type: :password,
title: -> { s_('DiffblueCover|License key') },
description: -> { s_('DiffblueCover|Diffblue Cover license key') },
description: -> { s_('DiffblueCover|Diffblue Cover license key.') },
non_empty_password_title: -> { s_('DiffblueCover|License key') },
non_empty_password_help: -> {
s_(
@ -21,7 +21,7 @@ module Integrations
format(
s_(
'DiffblueCover|Enter your Diffblue Cover license key or ' \
'visit %{diffblue_link} to obtain a free trial license.'
'go to %{diffblue_link} to obtain a free trial license.'
),
diffblue_link: diffblue_link
)
@ -30,7 +30,7 @@ module Integrations
field :diffblue_access_token_name,
section: SECTION_TYPE_CONFIGURATION,
title: -> { s_('DiffblueCover|Name') },
description: -> { s_('DiffblueCover|Access token name used by Diffblue Cover in pipelines') },
description: -> { s_('DiffblueCover|Access token name used by Diffblue Cover in pipelines.') },
required: true,
placeholder: -> { s_('DiffblueCover|My token name') }
@ -38,7 +38,7 @@ module Integrations
section: SECTION_TYPE_CONFIGURATION,
type: :password,
title: -> { s_('DiffblueCover|Secret') },
description: -> { s_('DiffblueCover|Access token secret used by Diffblue Cover in pipelines') },
description: -> { s_('DiffblueCover|Access token secret used by Diffblue Cover in pipelines.') },
non_empty_password_title: -> { s_('DiffblueCover|Secret') },
non_empty_password_help: -> { s_('DiffblueCover|Leave blank to use your current secret value.') },
required: true,
@ -82,8 +82,8 @@ module Integrations
title: s_('DiffblueCover|Integration details'),
description:
s_(
'DiffblueCover|Diffblue Cover is a reinforcement learning AI platform that automatically ' \
'writes comprehensive, human-like Java unit tests. Integrate the power of Diffblue ' \
'DiffblueCover|Diffblue Cover is a generative AI platform that automatically ' \
'writes comprehensive, human-like Java unit tests. Integrate Diffblue ' \
'Cover into your CI/CD workflow for fully autonomous operation.'
)
},
@ -91,9 +91,9 @@ module Integrations
type: SECTION_TYPE_CONFIGURATION,
title: s_('DiffblueCover|Access token'),
description:
'A GitLab access token is required in allow Diffblue Cover to access your project. ' \
'Use a GitLab access token with a <code>Developer</code> role, plus ' \
'<code>api</code> and <code>write_repository</code> scopes.'
'You must have a GitLab access token for Diffblue Cover to access your project. ' \
'Use a GitLab access token with at least the Developer role and ' \
'the <code>api</code> and <code>write_repository</code> permissions.'
}
]
end

View File

@ -0,0 +1,13 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Application rate limits",
"type": "object",
"additionalProperties": false,
"properties": {
"members_delete_limit": {
"type": "integer",
"minimum": 0,
"description": "Number of project or group members a user can delete per minute."
}
}
}

View File

@ -0,0 +1,21 @@
%section.settings.as-members-api-limits.no-animate#js-members-api-limits-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
= _('Members API rate limit')
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
= expanded_by_default? ? _('Collapse') : _('Expand')
%p.gl-text-secondary
= _('Limit the number of project or group members a user can delete per minute through API requests.')
= link_to _('Learn more.'), help_page_path('administration/settings/rate_limit_on_members_api'), target: '_blank', rel: 'noopener noreferrer'
.settings-content
= gitlab_ui_form_for @application_setting, url: network_admin_application_settings_path(anchor: 'js-members-api-limits-settings'), html: { class: 'fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
= f.label :members_delete_limit, _('Maximum requests per minute per group / project'), class: 'label-bold'
= f.number_field :members_delete_limit, min: 0, class: 'form-control gl-form-input'
.form-text.gl-text-gray-600
= _("Set to 0 to disable the limit.")
= f.submit _('Save changes'), pajamas_button: true

View File

@ -151,6 +151,8 @@
= render 'projects_api_limits'
= render 'members_api_limits'
%section.settings.as-import-export-limits.no-animate#js-import-export-limits-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only

View File

@ -4,7 +4,7 @@
.row.gl-mt-5.justify-content-center
.col-md-5
.login-page
#signin-container.borderless
.borderless
- if any_form_based_providers_enabled?
= render 'devise/shared/tabs_ldap', show_password_form: allow_admin_mode_password_authentication_for_web?, render_signup_link: false
.tab-content

View File

@ -4,7 +4,7 @@
.row.justify-content-center
.col-md-5
.login-page
#signin-container.borderless
.borderless
.login-box.gl-p-5
.login-body
- if current_user.two_factor_enabled?

View File

@ -9,26 +9,23 @@
= render_if_exists "layouts/google_tag_manager_body"
#signin-container
.js-non-oauth-login
- if any_form_based_providers_enabled?
= render 'devise/shared/tabs_ldap', render_signup_link: false
.tab-content
- if password_authentication_enabled_for_web? || ldap_sign_in_enabled? || crowd_enabled?
= render 'devise/shared/signin_box'
-# Show a message if none of the mechanisms above are enabled
- if !password_authentication_enabled_for_web? && !ldap_sign_in_enabled? && !(omniauth_enabled? && devise_mapping.omniauthable?)
%div
= _('No authentication methods configured.')
- if Gitlab::CurrentSettings.current_application_settings.terms
%p.gl-px-5
= html_escape(s_("SignUp|By signing in you accept the %{link_start}Terms of Use and acknowledge the Privacy Statement and Cookie Policy%{link_end}.")) % { link_start: "<a href='#{terms_path}' target='_blank' rel='noreferrer noopener'>".html_safe,
link_end: '</a>'.html_safe }
- if allow_signup?
%p.gl-mt-3.gl-text-center
= _("Don't have an account yet?")
= link_to _("Register now"), new_registration_path(:user, invite_email: @invite_email), data: { testid: 'register-link' }
- if omniauth_enabled? && devise_mapping.omniauthable? && button_based_providers_enabled?
= render 'devise/shared/omniauth_box'
-# Show a message if none of the mechanisms above are enabled
- if !password_authentication_enabled_for_web? && !ldap_sign_in_enabled? && !(omniauth_enabled? && devise_mapping.omniauthable?)
%div
= _('No authentication methods configured.')
- if Gitlab::CurrentSettings.current_application_settings.terms
%p.gl-px-5
= html_escape(s_("SignUp|By signing in you accept the %{link_start}Terms of Use and acknowledge the Privacy Statement and Cookie Policy%{link_end}.")) % { link_start: "<a href='#{terms_path}' target='_blank' rel='noreferrer noopener'>".html_safe,
link_end: '</a>'.html_safe }
- if allow_signup?
%p.gl-mt-3.gl-text-center
= _("Don't have an account yet?")
= link_to _("Register now"), new_registration_path(:user, invite_email: @invite_email), data: { testid: 'register-link' }
- if omniauth_enabled? && devise_mapping.omniauthable? && button_based_providers_enabled?
= render 'devise/shared/omniauth_box'

View File

@ -4,12 +4,11 @@
.omniauth-divider.gl-display-flex.gl-align-items-center
= _("or sign in with")
.gl-mt-5.gl-px-5.omniauth-container.gl-text-center.gl-display-flex.gl-flex-direction-column.gl-gap-3
.gl-mt-5.gl-px-5.gl-text-center.gl-display-flex.gl-flex-direction-column.gl-gap-3.js-oauth-login
- enabled_button_based_providers.each do |provider|
= render 'devise/shared/omniauth_provider_button',
href: omniauth_authorize_path(:user, provider),
provider: provider,
classes: 'js-oauth-login',
data: { testid: test_id_for_provider(provider) },
id: "oauth-login-#{provider}"
- if render_remember_me

View File

@ -1,4 +1,4 @@
- button_options = { class: classes, data: data, id: id }
- button_options = { class: local_assigns.fetch(:classes, nil) || nil, data: data, id: id }
= render Pajamas::ButtonComponent.new(href: href, method: :post, form: true, block: true, button_options: button_options) do
- if provider_has_icon?(provider)

View File

@ -66,7 +66,7 @@
%h4.gl-my-0= s_("Profiles|Time settings")
%p.gl-text-secondary= s_("Profiles|Set your local time zone.")
= f.label :user_timezone, _("Time zone")
.js-timezone-dropdown{ data: { timezone_data: timezone_data.to_json, initial_value: @user.timezone, name: 'user[timezone]' } }
.js-timezone-dropdown{ data: { timezone_data: timezone_data_with_unique_identifiers.to_json, initial_value: @user.timezone, name: 'user[timezone]' } }
.settings-section.js-search-settings-section.gl-border-t.gl-pt-6
.settings-sticky-header

View File

@ -3,13 +3,13 @@
#
- title: "Atlassian Crowd OmniAuth provider" # (required) The name of the feature to be deprecated
announcement_milestone: "15.3" # (required) The milestone when this feature was first announced as deprecated.
removal_milestone: "17.0" # (required) The milestone when this feature is planned to be removed
removal_milestone: "18.0" # (required) The milestone when this feature is planned to be removed
breaking_change: true # (required) If this deprecation is a breaking change, set this value to true
reporter: hsutor # (required) GitLab username of the person reporting the deprecation
stage: Manage # (required) String value of the stage that the feature was created in. e.g., Growth
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/369117 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
The `omniauth_crowd` gem that provides GitLab with the Atlassian Crowd OmniAuth provider will be removed in our
next major release, GitLab 16.0. This gem sees very little use and its
next major release, GitLab 18.0. This gem sees very little use and its
[lack of compatibility](https://github.com/robdimarco/omniauth_crowd/issues/37) with OmniAuth 2.0 is
[blocking our upgrade](https://gitlab.com/gitlab-org/gitlab/-/issues/30073).

View File

@ -4,7 +4,16 @@ classes:
- Clusters::Agents::Authorizations::CiAccess::ProjectAuthorization
feature_categories:
- deployment_management
description: Configuration for a project that is authorized to use a particular cluster agent
description: Configuration for a project that is authorized to use a particular cluster
agent
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67295
milestone: '14.3'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
sharding_key:
project_id: projects

View File

@ -7,4 +7,12 @@ feature_categories:
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44098
milestone: '13.5'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
sharding_key:
namespace_id: namespaces

View File

@ -7,4 +7,12 @@ feature_categories:
description: Stores project's external status checks
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62186
milestone: '14.0'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
sharding_key:
project_id: projects

View File

@ -7,4 +7,12 @@ feature_categories:
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28182
milestone: '13.0'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
sharding_key:
project_id: projects

View File

@ -1,10 +1,12 @@
---
table_name: project_compliance_standards_adherence
classes:
- Projects::ComplianceStandards::Adherence
- Projects::ComplianceStandards::Adherence
feature_categories:
- compliance_management
description: Stores the details about projects and their adherence to compliance standards
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/122293
milestone: '16.1'
gitlab_schema: gitlab_main_cell
sharding_key:
project_id: projects

View File

@ -0,0 +1,10 @@
# frozen_string_literal: true
class AddRateLimitsToApplicationSettings < Gitlab::Database::Migration[2.2]
milestone '16.9'
enable_lock_retries!
def change
add_column :application_settings, :rate_limits, :jsonb, default: {}, null: false
end
end

View File

@ -0,0 +1 @@
9c9eb37365dae73fb68000d18675a280e063711eaed8f96f64724bff20326957

View File

@ -12633,6 +12633,7 @@ CREATE TABLE application_settings (
lock_toggle_security_policy_custom_ci boolean DEFAULT false NOT NULL,
toggle_security_policies_policy_scope boolean DEFAULT false NOT NULL,
lock_toggle_security_policies_policy_scope boolean DEFAULT false NOT NULL,
rate_limits jsonb DEFAULT '{}'::jsonb NOT NULL,
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)),
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),

View File

@ -0,0 +1,33 @@
---
stage: Data Stores
group: Tenant Scale
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Rate limit on Members API **(FREE SELF)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/140633) in GitLab 16.9.
You can configure the rate limit per group (or project) per user to the
[delete members API](../../api/members.md#remove-a-member-from-a-group-or-project).
To change the rate limit:
1. On the left sidebar, at the bottom, select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **Members API rate limit**.
1. In the **Maximum requests per minute per group / project** text box, enter the new value.
1. Select **Save changes**.
The rate limit:
- Applies per group or project per user.
- Can be set to 0 to disable rate limiting.
The default value of the rate limit is `60`.
Requests over the rate limit are logged into the `auth.log` file.
For example, if you set a limit of 60, requests sent to the
[delete members API](../../api/members.md#remove-a-member-from-a-group-or-project) exceeding a rate of 300 per minute
are blocked. Access to the endpoint is allowed after one minute.

View File

@ -462,6 +462,40 @@ Get the Datadog integration settings for a project.
GET /projects/:id/integrations/datadog
```
## Diffblue Cover
### Set up Diffblue Cover
Set up the Diffblue Cover integration for a project.
```plaintext
PUT /projects/:id/integrations/diffblue-cover
```
Parameters:
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `diffblue_license_key` | string | true | Diffblue Cover license key. |
| `diffblue_access_token_name` | string | true | Access token name used by Diffblue Cover in pipelines. |
| `diffblue_access_token_secret` | string | true | Access token secret used by Diffblue Cover in pipelines. |
### Disable Diffblue Cover
Disable the Diffblue Cover integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/diffblue-cover
```
### Get Diffblue Cover settings
Get the Diffblue Cover integration settings for a project.
```plaintext
GET /projects/:id/integrations/diffblue-cover
```
## Discord Notifications
### Set up Discord Notifications

View File

@ -42,7 +42,7 @@ repositories that depend on the object pool.
The danger lies in `git prune`, and `git gc` calls `git prune`. The
problem is that `git prune`, when running in a pool repository, cannot
reliable decide if an object is no longer needed.
reliably decide if an object is no longer needed.
### Git alternates in GitLab: pool repositories
@ -51,7 +51,7 @@ which are hidden from the user. We then use Git
alternates to let a collection of project repositories borrow from a
single pool repository. We call such a collection of project
repositories a pool. Pools form star-shaped networks of repositories
that borrow from a single pool, which resemble (but not be
that borrow from a single pool, which resemble (but are not
identical to) the fork networks that get formed when users fork
projects.

View File

@ -52,6 +52,23 @@ For deprecation reviewers (Technical Writers only):
<div class="deprecation breaking-change" data-milestone="18.0">
### Atlassian Crowd OmniAuth provider
<div class="deprecation-notes">
- Announced in GitLab <span class="milestone">15.3</span>
- Removal in GitLab <span class="milestone">18.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/369117).
</div>
The `omniauth_crowd` gem that provides GitLab with the Atlassian Crowd OmniAuth provider will be removed in our
next major release, GitLab 18.0. This gem sees very little use and its
[lack of compatibility](https://github.com/robdimarco/omniauth_crowd/issues/37) with OmniAuth 2.0 is
[blocking our upgrade](https://gitlab.com/gitlab-org/gitlab/-/issues/30073).
</div>
<div class="deprecation breaking-change" data-milestone="18.0">
### GitLab Runner registration token in Runner Operator
<div class="deprecation-notes">
@ -194,23 +211,6 @@ From GitLab 18.0 and later, the methods to register runners introduced by the ne
<div class="deprecation breaking-change" data-milestone="17.0">
### Atlassian Crowd OmniAuth provider
<div class="deprecation-notes">
- Announced in GitLab <span class="milestone">15.3</span>
- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/369117).
</div>
The `omniauth_crowd` gem that provides GitLab with the Atlassian Crowd OmniAuth provider will be removed in our
next major release, GitLab 16.0. This gem sees very little use and its
[lack of compatibility](https://github.com/robdimarco/omniauth_crowd/issues/37) with OmniAuth 2.0 is
[blocking our upgrade](https://gitlab.com/gitlab-org/gitlab/-/issues/30073).
</div>
<div class="deprecation breaking-change" data-milestone="17.0">
### Auto DevOps support for Herokuish is deprecated
<div class="deprecation-notes">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

View File

@ -1,94 +1,11 @@
---
stage: Plan
group: Optimize
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
redirect_to: '../../project/insights/index.md'
remove_date: '2024-04-20'
---
# Insights for groups **(ULTIMATE ALL)**
This document was moved to [another location](../../project/insights/index.md).
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/725) in GitLab 12.0.
Configure insights to explore data about you group's activity, such as
triage hygiene, issues created or closed in a given period, and average time for merge
requests to be merged.
You can also create custom insights reports that are relevant for your group.
## View group insights
Prerequisites:
- You must have [permission](../../permissions.md#group-members-permissions) to view the group.
- You must have access to a project to view information about its merge requests and issues,
and permission to view them if they are confidential.
To access your group's insights:
1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Analyze > Insights**.
## Interact with insights charts
You can interact with the insights charts to view details about your group's activity.
![Insights example stacked bar chart](img/insights_example_stacked_bar_chart_v15_4.png)
### Display different reports
To display one of the available reports on the insights page, from the **Select report** dropdown list,
select the report you want to display.
### View bar chart annotations
To view annotations, hover over each bar in the chart.
### Zoom in on chart
Insights display data from the last 90 days. You can zoom in to display data only from a subset of the 90-day range.
To do this, select the pause icons (**{status-paused}**) and slide them along the horizontal axis:
- To change the start date, slide the left pause icon to the left or right.
- To change the end date, slide the right pause icon to the left or right.
### Exclude dimensions from charts
By default, insights display all available dimensions on the chart.
To exclude a dimension, from the legend below the chart, select the name of the dimension.
### Drill down on charts
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/372215/) in GitLab 16.7.
You can drill down into the data of the **Bugs created per month by priority** and **Bugs created per month by severity** charts from the [default configuration file](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/fixtures/insights/default.yml).
To view a drill-down report of the data for a specific priority or severity in a month:
- On the chart, select the bar stack you want to drill down on.
## Configure group insights
GitLab reads insights from the
[default configuration file](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/fixtures/insights/default.yml).
To configure group insights:
1. Create a new file [`.gitlab/insights.yml`](../../project/insights/index.md#configure-project-insights)
in a project that belongs to your group.
1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Analytics** and find the **Insights** section.
1. Select the project that contains your `.gitlab/insights.yml` configuration file.
1. Select **Save changes**.
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
one might have when setting this up, or when something is changed, or on upgrading, it's
important to describe those, too. Think of things that may go wrong and include them here.
This is important to minimize requests for support, and to avoid doc comments with
questions that you know someone might ask.
Each scenario can be a third-level heading, for example `### Getting error message X`.
If you have none to add when creating a doc, leave this section in place
but commented out to help encourage others to add to it in the future. -->
<!-- This redirect file can be deleted after <YYYY-MM-DD>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -4,27 +4,28 @@ group: Optimize
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Insights for projects **(ULTIMATE ALL)**
# Insights **(ULTIMATE ALL)**
Configure project insights to explore data such as:
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/725) in GitLab 12.0.
Configure insights for your projects and groups to explore data such as:
- Issues created and closed during a specified period.
- Average time for merge requests to be merged.
- Triage hygiene.
Insights are also available for [groups](../../group/insights/index.md).
You can also create custom Insights reports that are relevant for your group.
## View project insights
Prerequisites:
- You must have:
- Access to a project to view information about its merge requests and issues.
- Permission to view confidential merge requests and issues in the project.
- For project insights, you must have access to the project and permission to view information about its merge requests and issues.
- For group insights, you must have permission to view the group.
To view project insights:
To view insights for a project or group:
1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Analyze > Insights**.
1. To view a report, select the **Select report** dropdown list.
@ -35,23 +36,61 @@ You can direct users to a specific report in Insights by using the deep-linked U
To create a deep link, append the report key to the end of the Insights report URL.
For example, a GitLab report with the key `bugsCharts` has the deep link URL `https://gitlab.com/gitlab-org/gitlab/insights/#/bugsCharts`.
## Interact with Insights charts
You can interact with the insights charts to view details about your group's activity.
### Display different reports
To display one of the available reports on the insights page, from the **Select report** dropdown list,
select the report you want to display.
### View bar chart annotations
To view annotations, hover over each bar in the chart.
### Zoom in on chart
Insights display data from the last 90 days. You can zoom in to display data only from a subset of the 90-day range.
To do this, select the pause icons (**{status-paused}**) and slide them along the horizontal axis:
- To change the start date, slide the left pause icon to the left or right.
- To change the end date, slide the right pause icon to the left or right.
### Exclude dimensions from charts
By default, insights display all available dimensions on the chart.
To exclude a dimension, from the legend below the chart, select the name of the dimension.
### Drill down on charts
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/372215/) in GitLab 16.7.
You can drill down into the data of the **Bugs created per month by priority** and **Bugs created per month by severity** charts from the [default configuration file](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/fixtures/insights/default.yml).
To view a drill-down report of the data for a specific priority or severity in a month:
- On the chart, select the bar stack you want to drill down on.
## Configure project insights
Prerequisites:
- Depending on your project configuration, you must have at least the Developer role.
Project insights are configured with the [`.gitlab/insights.yml`](#insights-configuration-file) file in the project. If a project doesn't have a configuration file, it uses the [group configuration](../../group/insights/index.md#configure-group-insights).
Project insights are configured with the [`.gitlab/insights.yml`](#insights-configuration-file) file in the project. If a project doesn't have a configuration file, it uses the [group configuration](#configure-group-insights).
The `.gitlab/insights.yml` file is a YAML file where you define:
- The structure and order of charts in a report.
- The style of charts displayed in the report of your project or group.
To configure project insights, either:
To configure project insights, create a file `.gitlab/insights.yml` either:
- Create a `.gitlab/insights.yml` file locally in the root directory of your project, and push your changes.
- Create a `.gitlab/insights.yml` file in the UI:
- Locally, in the root directory of your project, and push your changes.
- From the UI:
1. On the left sidebar, select **Search or go to** and find your project.
1. Above the file list, select the branch you want to commit to, select the plus icon, then select **New file**.
1. In the **File name** text box, enter `.gitlab/insights.yml`.
@ -59,7 +98,21 @@ To configure project insights, either:
1. Select **Commit changes**.
After you create the configuration file, you can also
[use it for the project's group](../../group/insights/index.md#configure-group-insights).
use it for the project's group.
## Configure group insights
GitLab reads insights from the
[default configuration file](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/fixtures/insights/default.yml).
To configure group insights:
1. In a project that belongs to your group, [create a `.gitlab/insights.yml` file](#configure-project-insights).
1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Analytics** and find the **Insights** section.
1. Select the project that contains your `.gitlab/insights.yml` configuration file.
1. Select **Save changes**.
## Insights configuration file
@ -403,7 +456,7 @@ Use `query.environment_tiers` to define an array of environments to include the
Use `projects` to limit where issuables are queried from:
- If `.gitlab/insights.yml` is used for a [group's insights](../../group/insights/index.md#configure-group-insights), use `projects` to define the projects from which to query issuables. By default, all projects under the group are used.
- If `.gitlab/insights.yml` is used for a group's insights, use `projects` to define the projects from which to query issuables. By default, all projects under the group are used.
- If `.gitlab/insights.yml` is used for a project's insights, specifying other projects does not yield results. By default, the project is used.
#### `projects.only`

View File

@ -176,7 +176,7 @@ module API
source = find_source(source_type, params[:id])
member = source_members(source).find_by!(user_id: params[:user_id])
check_rate_limit!(:member_delete, scope: [source, current_user])
check_rate_limit!(:members_delete, scope: [source, current_user])
destroy_conditionally!(member) do
::Members::DestroyService.new(current_user).execute(member, skip_subresources: params[:skip_subresources], unassign_issuables: params[:unassign_issuables])

View File

@ -30,7 +30,7 @@ module Gitlab
group_download_export: { threshold: -> { application_settings.group_download_export_limit }, interval: 1.minute },
group_import: { threshold: -> { application_settings.group_import_limit }, interval: 1.minute },
group_testing_hook: { threshold: 5, interval: 1.minute },
member_delete: { threshold: 60, interval: 1.minute },
members_delete: { threshold: -> { application_settings.members_delete_limit }, interval: 1.minute },
profile_add_new_email: { threshold: 5, interval: 1.minute },
web_hook_calls: { interval: 1.minute },
web_hook_calls_mid: { interval: 1.minute },

View File

@ -16658,6 +16658,9 @@ msgstr ""
msgid "Dependencies|Export as JSON"
msgstr ""
msgid "Dependencies|Filtering unavailable"
msgstr ""
msgid "Dependencies|Job failed to generate the dependency list"
msgstr ""
@ -16682,6 +16685,9 @@ msgstr ""
msgid "Dependencies|Projects"
msgstr ""
msgid "Dependencies|Search or filter dependencies..."
msgstr ""
msgid "Dependencies|Software Bill of Materials (SBOM) based on the %{linkStart}latest successful%{linkEnd} scan"
msgstr ""
@ -16706,6 +16712,9 @@ msgstr ""
msgid "Dependencies|There was an error fetching the projects for this group. Please try again later."
msgstr ""
msgid "Dependencies|This group exceeds the maximum number of 600 sub-groups. We cannot accurately filter or search the dependency list above this maximum. To view or filter a subset of this information, go to a subgroup's dependency list."
msgstr ""
msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
msgstr ""
@ -17733,22 +17742,22 @@ msgstr ""
msgid "DiffblueCover|Access token"
msgstr ""
msgid "DiffblueCover|Access token name used by Diffblue Cover in pipelines"
msgid "DiffblueCover|Access token name used by Diffblue Cover in pipelines."
msgstr ""
msgid "DiffblueCover|Access token secret used by Diffblue Cover in pipelines"
msgid "DiffblueCover|Access token secret used by Diffblue Cover in pipelines."
msgstr ""
msgid "DiffblueCover|Automatically write comprehensive, human-like Java unit tests."
msgstr ""
msgid "DiffblueCover|Diffblue Cover is a reinforcement learning AI platform that automatically writes comprehensive, human-like Java unit tests. Integrate the power of Diffblue Cover into your CI/CD workflow for fully autonomous operation."
msgid "DiffblueCover|Diffblue Cover is a generative AI platform that automatically writes comprehensive, human-like Java unit tests. Integrate Diffblue Cover into your CI/CD workflow for fully autonomous operation."
msgstr ""
msgid "DiffblueCover|Diffblue Cover license key"
msgid "DiffblueCover|Diffblue Cover license key."
msgstr ""
msgid "DiffblueCover|Enter your Diffblue Cover license key or visit %{diffblue_link} to obtain a free trial license."
msgid "DiffblueCover|Enter your Diffblue Cover license key or go to %{diffblue_link} to obtain a free trial license."
msgstr ""
msgid "DiffblueCover|Integration details"
@ -29013,6 +29022,9 @@ msgstr ""
msgid "Limit the number of pipeline creation requests per minute. This limit includes pipelines created through the UI, the API, and by background processing."
msgstr ""
msgid "Limit the number of project or group members a user can delete per minute through API requests."
msgstr ""
msgid "Limit the size of Sidekiq jobs stored in Redis."
msgstr ""
@ -29882,6 +29894,9 @@ msgstr ""
msgid "Maximum requests per minute"
msgstr ""
msgid "Maximum requests per minute per group / project"
msgstr ""
msgid "Maximum running slices"
msgstr ""
@ -30071,6 +30086,9 @@ msgstr ""
msgid "Members"
msgstr ""
msgid "Members API rate limit"
msgstr ""
msgid "Members can be added by project %{i_open}Maintainers%{i_close} or %{i_open}Owners%{i_close}"
msgstr ""
@ -43389,9 +43407,6 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
msgid "Search or filter dependencies..."
msgstr ""
msgid "Search or filter results…"
msgstr ""

View File

@ -81,6 +81,7 @@ RSpec.describe 'Group show page', feature_category: :groups_and_projects do
expect(find('.group-row:nth-child(1) .namespace-title > a')).to have_content(project2.title)
expect(find('.group-row:nth-child(2) .namespace-title > a')).to have_content(project1.title)
expect(find('.group-row:nth-child(3) .namespace-title > a')).to have_content(project3.title)
expect(page).to have_selector('button[data-testid="base-dropdown-toggle"]', text: 'Stars')
end
end
end

View File

@ -10,6 +10,10 @@ RSpec.describe 'User sorts projects and order persists', feature_category: :grou
let_it_be(:group_member) { create(:group_member, :maintainer, user: user, group: group) }
let_it_be(:project) { create(:project, :public, group: group) }
def find_dropdown_toggle
find('button[data-testid=base-dropdown-toggle]')
end
shared_examples_for "sort order persists across all views" do |project_paths_label, group_paths_label|
it "is set on the dashboard_projects_path" do
visit(dashboard_projects_path)
@ -27,7 +31,7 @@ RSpec.describe 'User sorts projects and order persists', feature_category: :grou
visit(group_canonical_path(group))
within '[data-testid=group_sort_by_dropdown]' do
expect(find('.gl-dropdown-toggle')).to have_content(group_paths_label)
expect(find_dropdown_toggle).to have_content(group_paths_label)
end
end
@ -35,7 +39,7 @@ RSpec.describe 'User sorts projects and order persists', feature_category: :grou
visit(details_group_path(group))
within '[data-testid=group_sort_by_dropdown]' do
expect(find('.gl-dropdown-toggle')).to have_content(group_paths_label)
expect(find_dropdown_toggle).to have_content(group_paths_label)
end
end
end
@ -67,8 +71,8 @@ RSpec.describe 'User sorts projects and order persists', feature_category: :grou
sign_in(user)
visit(group_canonical_path(group))
within '[data-testid=group_sort_by_dropdown]' do
find('button.gl-dropdown-toggle').click
first(:button, 'Created').click
find_dropdown_toggle.click
find('li', text: 'Created').click
wait_for_requests
end
end
@ -81,8 +85,8 @@ RSpec.describe 'User sorts projects and order persists', feature_category: :grou
sign_in(user)
visit(details_group_path(group))
within '[data-testid=group_sort_by_dropdown]' do
find('button.gl-dropdown-toggle').click
first(:button, 'Updated').click
find_dropdown_toggle.click
find('li', text: 'Updated').click
wait_for_requests
end
end

View File

@ -1,20 +1,20 @@
<div id="oauth-container">
<div class="js-oauth-login">
<input id="remember_me_omniauth" type="checkbox" />
<form method="post" action="http://example.com/">
<button class="js-oauth-login twitter" type="submit">
<button class="twitter" type="submit">
<span>Twitter</span>
</button>
</form>
<form method="post" action="http://example.com/">
<button class="js-oauth-login github" type="submit">
<button class="github" type="submit">
<span>GitHub</span>
</button>
</form>
<form method="post" action="http://example.com/?redirect_fragment=L1">
<button class="js-oauth-login facebook" type="submit">
<button class="facebook" type="submit">
<span>Facebook</span>
</button>
</form>

View File

@ -1,4 +1,4 @@
import { GlSorting, GlSortingItem, GlTab } from '@gitlab/ui';
import { GlSorting, GlTab } from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
import AxiosMockAdapter from 'axios-mock-adapter';
import { mountExtended } from 'helpers/vue_test_utils_helper';
@ -17,6 +17,7 @@ import {
ACTIVE_TAB_SUBGROUPS_AND_PROJECTS,
ACTIVE_TAB_SHARED,
ACTIVE_TAB_ARCHIVED,
OVERVIEW_TABS_SORTING_ITEMS,
SORTING_ITEM_NAME,
SORTING_ITEM_UPDATED,
SORTING_ITEM_STARS,
@ -74,6 +75,7 @@ describe('OverviewTabs', () => {
const findTab = (name) => wrapper.findByRole('tab', { name });
const findSelectedTab = () => wrapper.findByRole('tab', { selected: true });
const findSearchInput = () => wrapper.findByPlaceholderText(OverviewTabs.i18n.searchPlaceholder);
const findGlSorting = () => wrapper.findComponent(GlSorting);
beforeEach(() => {
axiosMock = new AxiosMockAdapter(axios);
@ -301,7 +303,7 @@ describe('OverviewTabs', () => {
describe('when sort is changed', () => {
beforeEach(async () => {
await setup();
wrapper.findAllComponents(GlSortingItem).at(2).vm.$emit('click');
findGlSorting().vm.$emit('sortByChange', SORTING_ITEM_UPDATED.label);
await nextTick();
});
@ -403,12 +405,15 @@ describe('OverviewTabs', () => {
});
it('sets sort dropdown', () => {
expect(wrapper.findComponent(GlSorting).props()).toMatchObject({
const expectedSortOptions = OVERVIEW_TABS_SORTING_ITEMS.map(({ label }) => {
return { value: label, text: label };
});
expect(findGlSorting().props()).toMatchObject({
text: SORTING_ITEM_UPDATED.label,
isAscending: false,
sortBy: SORTING_ITEM_UPDATED.label,
sortOptions: expectedSortOptions,
});
expect(wrapper.findAllComponents(GlSortingItem).at(2).vm.$attrs.active).toBe(true);
});
});
});

View File

@ -5,13 +5,13 @@ import OAuthRememberMe from '~/pages/sessions/new/oauth_remember_me';
describe('OAuthRememberMe', () => {
const findFormAction = (selector) => {
return $(`#oauth-container .js-oauth-login${selector}`).parent('form').attr('action');
return $(`.js-oauth-login ${selector}`).parent('form').attr('action');
};
beforeEach(() => {
setHTMLFixture(htmlOauthRememberMe);
new OAuthRememberMe({ container: $('#oauth-container') }).bindEvents();
new OAuthRememberMe({ container: $('.js-oauth-login') }).bindEvents();
});
afterEach(() => {
@ -19,7 +19,7 @@ describe('OAuthRememberMe', () => {
});
it('adds and removes the "remember_me" query parameter from all OAuth login buttons', () => {
$('#oauth-container #remember_me_omniauth').click();
$('.js-oauth-login #remember_me_omniauth').click();
expect(findFormAction('.twitter')).toBe('http://example.com/?remember_me=1');
expect(findFormAction('.github')).toBe('http://example.com/?remember_me=1');
@ -27,7 +27,7 @@ describe('OAuthRememberMe', () => {
'http://example.com/?redirect_fragment=L1&remember_me=1',
);
$('#oauth-container #remember_me_omniauth').click();
$('.js-oauth-login #remember_me_omniauth').click();
expect(findFormAction('.twitter')).toBe('http://example.com/');
expect(findFormAction('.github')).toBe('http://example.com/');

View File

@ -5,7 +5,7 @@ import preserveUrlFragment from '~/pages/sessions/new/preserve_url_fragment';
describe('preserve_url_fragment', () => {
const findFormAction = (selector) => {
return $(`.omniauth-container ${selector}`).parent('form').attr('action');
return $(`.js-oauth-login ${selector}`).parent('form').attr('action');
};
beforeEach(() => {
@ -44,9 +44,7 @@ describe('preserve_url_fragment', () => {
});
it('when "remember-me" is present', () => {
$('.js-oauth-login')
.parent('form')
.attr('action', (i, href) => `${href}?remember_me=1`);
$('.js-oauth-login form').attr('action', (i, href) => `${href}?remember_me=1`);
preserveUrlFragment('#L65');

View File

@ -65,6 +65,7 @@ RSpec.describe ApplicationSettingsHelper do
project_download_export_limit project_export_limit project_import_limit
raw_blob_request_limit group_export_limit group_download_export_limit
group_import_limit users_get_by_id_limit search_rate_limit search_rate_limit_unauthenticated
members_delete_limit
])
end

View File

@ -461,7 +461,7 @@ RSpec.describe MarkupHelper, feature_category: :team_planning do
it 'displays the first line of a code block' do
object = create_object("```\nCode block\nwith two lines\n```")
expected = %r{<pre.+><code><span class="line">Code block\.\.\.</span></code></pre>}
expected = %r{<pre.+><code><span class="line" lang="plaintext">Code block\.\.\.</span></code></pre>}
expect(helper.first_line_in_markdown(object, attribute, 100, is_todo: true, project: project)).to match(expected)
end
@ -476,8 +476,8 @@ RSpec.describe MarkupHelper, feature_category: :team_planning do
it 'preserves code color scheme' do
object = create_object("```ruby\ndef test\n 'hello world'\nend\n```")
expected = "\n<pre class=\"code highlight js-syntax-highlight language-ruby\">" \
"<code><span class=\"line\"><span class=\"k\">def</span> <span class=\"nf\">test</span>...</span>" \
expected = "\n<pre class=\"code highlight js-syntax-highlight language-ruby\" lang=\"ruby\">" \
"<code><span class=\"line\" lang=\"ruby\"><span class=\"k\">def</span> <span class=\"nf\">test</span>...</span>" \
"</code></pre>\n"
expect(helper.first_line_in_markdown(object, attribute, 150, is_todo: true, project: project)).to eq(expected)

View File

@ -93,6 +93,29 @@ RSpec.describe TimeZoneHelper, :aggregate_failures do
end
end
describe '#timezone_data_with_unique_identifiers' do
subject { helper.timezone_data_with_unique_identifiers }
before do
allow(helper).to receive(:timezone_data).and_return([
{ identifier: 'Europe/London', name: 'London' },
{ identifier: 'Europe/London', name: 'Edinburgh' },
{ identifier: 'Europe/Berlin', name: 'Berlin' },
{ identifier: 'Europe/London', name: 'Hogwarts' }
])
end
let(:expected) do
[
{ identifier: 'Europe/London', name: 'Edinburgh, Hogwarts, London' },
{ identifier: 'Europe/Berlin', name: 'Berlin' }
]
end
it { is_expected.to eq(expected) }
end
describe '#local_time' do
let_it_be(:timezone) { 'America/Los_Angeles' }

View File

@ -28,6 +28,7 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
it { expect(setting.decompress_archive_file_timeout).to eq(210) }
it { expect(setting.bulk_import_concurrent_pipeline_batch_limit).to eq(25) }
it { expect(setting.allow_project_creation_for_guest_and_below).to eq(true) }
it { expect(setting.members_delete_limit).to eq(60) }
end
describe 'validations' do
@ -58,6 +59,8 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
}
end
it { expect(described_class).to validate_jsonb_schema(['application_setting_rate_limits']) }
it { is_expected.to allow_value(nil).for(:home_page_url) }
it { is_expected.to allow_value(http).for(:home_page_url) }
it { is_expected.to allow_value(https).for(:home_page_url) }
@ -225,6 +228,8 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
max_import_size
max_pages_custom_domains_per_project
max_terraform_state_size_bytes
members_delete_limit
notes_create_limit
package_registry_cleanup_policies_worker_capacity
packages_cleanup_package_file_worker_capacity
pipeline_limit_per_project_user_sha
@ -237,7 +242,6 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
sidekiq_job_limiter_limit_bytes
terminal_max_session_time
users_get_by_id_limit
notes_create_limit
]
end

View File

@ -717,7 +717,7 @@ RSpec.describe API::Members, feature_category: :groups_and_projects do
end.to change { source.members.count }.by(-1)
end
it_behaves_like 'rate limited endpoint', rate_limit_key: :member_delete do
it_behaves_like 'rate limited endpoint', rate_limit_key: :members_delete do
let(:current_user) { maintainer }
let(:another_member) { create(:user) }

View File

@ -110,7 +110,7 @@ module LoginHelpers
def login_via(provider, user, uid, remember_me: false, additional_info: {})
mock_auth_hash(provider, uid, user.email, additional_info: additional_info)
visit new_user_session_path
expect(page).to have_css('.omniauth-container')
expect(page).to have_css('.js-oauth-login')
check 'remember_me_omniauth' if remember_me

View File

@ -18,4 +18,12 @@ RSpec.describe 'admin/application_settings/network.html.haml', feature_category:
expect(rendered).to have_field('application_setting_projects_api_rate_limit_unauthenticated')
end
end
context 'for Members API rate limit' do
it 'renders the `members_delete_limit` field' do
render
expect(rendered).to have_field('application_setting_members_delete_limit')
end
end
end

View File

@ -45,7 +45,7 @@ RSpec.describe 'admin/sessions/new.html.haml' do
expect(rendered).not_to have_content _('No authentication methods configured.')
expect(rendered).to have_css('.omniauth-divider')
expect(rendered).to have_content(_('or sign in with'))
expect(rendered).to have_css('.omniauth-container')
expect(rendered).to have_css('.js-oauth-login')
end
end