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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.rubocop_todo/rspec/useless_dynamic_definition.yml1
-rw-r--r--app/assets/javascripts/badges/components/badge.vue2
-rw-r--r--app/assets/javascripts/badges/components/badge_list.vue4
-rw-r--r--app/assets/javascripts/batch_comments/components/submit_dropdown.vue3
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/components/ci_environments_dropdown.vue31
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/components/ci_variable_drawer.vue1
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/components/ci_variable_modal.vue15
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/components/ci_variable_settings.vue5
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/components/ci_variable_shared.vue1
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/utils.js23
-rw-r--r--app/assets/javascripts/content_editor/extensions/selection.js12
-rw-r--r--app/assets/javascripts/content_editor/services/serialization_helpers.js9
-rw-r--r--app/assets/javascripts/design_management/components/design_description/description_form.vue3
-rw-r--r--app/assets/javascripts/invite_members/components/invite_groups_modal.vue2
-rw-r--r--app/assets/javascripts/invite_members/components/invite_modal_base.vue1
-rw-r--r--app/assets/javascripts/issues/show/components/app.vue5
-rw-r--r--app/assets/javascripts/issues/show/components/description.vue8
-rw-r--r--app/assets/javascripts/issues/show/components/fields/description.vue4
-rw-r--r--app/assets/javascripts/issues/show/components/form.vue15
-rw-r--r--app/assets/javascripts/issues/show/index.js4
-rw-r--r--app/assets/javascripts/members/components/members_tabs.vue2
-rw-r--r--app/assets/javascripts/notes/components/comment_form.vue4
-rw-r--r--app/assets/javascripts/notes/components/note_form.vue7
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js1
-rw-r--r--app/controllers/admin/topics_controller.rb4
-rw-r--r--app/controllers/groups/milestones_controller.rb4
-rw-r--r--app/controllers/projects/issues_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests/application_controller.rb5
-rw-r--r--app/controllers/projects/merge_requests_controller.rb2
-rw-r--r--app/controllers/projects/milestones_controller.rb4
-rw-r--r--app/events/merge_requests/unblocked_state_event.rb19
-rw-r--r--app/models/bulk_imports/entity.rb6
-rw-r--r--app/models/group.rb4
-rw-r--r--app/models/integrations/discord.rb2
-rw-r--r--app/models/merge_request.rb12
-rw-r--r--app/models/project.rb4
-rw-r--r--app/serializers/merge_request_noteable_entity.rb4
-rw-r--r--app/services/auto_merge/base_service.rb7
-rw-r--r--app/views/dashboard/projects/_zero_authorized_projects.html.haml2
-rw-r--r--app/views/layouts/component_preview.html.haml6
-rw-r--r--app/workers/bulk_imports/export_request_worker.rb2
-rw-r--r--app/workers/bulk_imports/finish_batched_pipeline_worker.rb2
-rw-r--r--app/workers/bulk_imports/pipeline_batch_worker.rb6
-rw-r--r--config/application.rb2
-rw-r--r--config/feature_flags/development/bulk_imports_batched_import_export.yml (renamed from config/feature_flags/development/content_editor_on_issues.yml)12
-rw-r--r--doc/administration/geo/replication/troubleshooting.md83
-rw-r--r--doc/administration/job_artifacts.md4
-rw-r--r--doc/administration/raketasks/maintenance.md12
-rw-r--r--doc/api/graphql/reference/index.md4
-rw-r--r--doc/api/integrations.md2
-rw-r--r--doc/ci/components/index.md7
-rw-r--r--doc/development/ai_features/index.md11
-rw-r--r--doc/user/project/issues/design_management.md10
-rw-r--r--doc/user/project/merge_requests/reviews/suggestions.md5
-rw-r--r--doc/user/rich_text_editor.md10
-rw-r--r--lib/api/ml/mlflow/runs.rb2
-rw-r--r--lib/gitlab/auth/ldap/auth_hash.rb8
-rw-r--r--lib/gitlab/auth/o_auth/auth_hash.rb5
-rw-r--r--locale/gitlab.pot9
-rw-r--r--qa/qa/page/component/badges.rb14
-rw-r--r--qa/qa/page/component/members/invite_members_modal.rb6
-rw-r--r--qa/qa/page/component/members/members_table.rb6
-rw-r--r--qa/qa/page/dashboard/welcome.rb4
-rw-r--r--qa/qa/page/search/results.rb2
-rw-r--r--spec/features/merge_request/user_views_open_merge_request_spec.rb12
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_environments_dropdown_spec.js79
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_variable_modal_spec.js41
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_variable_settings_spec.js2
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js2
-rw-r--r--spec/frontend/ci/ci_variable_list/mocks.js3
-rw-r--r--spec/frontend/ci/ci_variable_list/utils_spec.js53
-rw-r--r--spec/frontend/content_editor/services/markdown_serializer_spec.js8
-rw-r--r--spec/frontend/design_management/components/design_description/description_form_spec.js8
-rw-r--r--spec/frontend/issues/show/components/description_spec.js4
-rw-r--r--spec/frontend/issues/show/components/fields/description_spec.js17
-rw-r--r--spec/frontend/notes/components/comment_form_spec.js11
-rw-r--r--spec/frontend/notes/components/note_form_spec.js10
-rw-r--r--spec/lib/gitlab/auth/o_auth/auth_hash_spec.rb16
-rw-r--r--spec/models/bulk_imports/entity_spec.rb4
-rw-r--r--spec/models/group_spec.rb7
-rw-r--r--spec/models/integrations/discord_spec.rb2
-rw-r--r--spec/models/project_spec.rb10
-rw-r--r--spec/requests/api/ml/mlflow/runs_spec.rb6
-rw-r--r--spec/services/auto_merge/base_service_spec.rb22
-rw-r--r--spec/support/shared_examples/models/chat_integration_shared_examples.rb18
-rw-r--r--spec/workers/bulk_imports/export_request_worker_spec.rb14
-rw-r--r--spec/workers/bulk_imports/finish_batched_pipeline_worker_spec.rb12
-rw-r--r--spec/workers/bulk_imports/pipeline_batch_worker_spec.rb1
88 files changed, 327 insertions, 513 deletions
diff --git a/.rubocop_todo/rspec/useless_dynamic_definition.yml b/.rubocop_todo/rspec/useless_dynamic_definition.yml
index 94a53324dee..75bea5601ae 100644
--- a/.rubocop_todo/rspec/useless_dynamic_definition.yml
+++ b/.rubocop_todo/rspec/useless_dynamic_definition.yml
@@ -5,7 +5,6 @@ RSpec/UselessDynamicDefinition:
- 'ee/spec/factories/ci/job_artifacts.rb'
- 'ee/spec/factories/ci/pipelines.rb'
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/count_security_scans_metric_spec.rb'
- - 'ee/spec/support/shared_examples/lib/gitlab/elastic/search_results_shared_examples.rb'
- 'spec/models/ci/resource_group_spec.rb'
- 'spec/services/packages/nuget/update_package_from_metadata_service_spec.rb'
- 'spec/support/helpers/cycle_analytics_helpers/test_generation.rb'
diff --git a/app/assets/javascripts/badges/components/badge.vue b/app/assets/javascripts/badges/components/badge.vue
index 31531c90b94..1cd5854740e 100644
--- a/app/assets/javascripts/badges/components/badge.vue
+++ b/app/assets/javascripts/badges/components/badge.vue
@@ -80,7 +80,7 @@ export default {
:href="linkUrl"
target="_blank"
rel="noopener noreferrer"
- data-qa-selector="badge_image_link"
+ data-testid="badge-image-link"
:data-qa-link-url="linkUrl"
>
<img
diff --git a/app/assets/javascripts/badges/components/badge_list.vue b/app/assets/javascripts/badges/components/badge_list.vue
index b69890572eb..12c9662b30d 100644
--- a/app/assets/javascripts/badges/components/badge_list.vue
+++ b/app/assets/javascripts/badges/components/badge_list.vue
@@ -100,7 +100,7 @@ export default {
<template>
<div>
<gl-loading-icon v-show="isLoading" size="md" />
- <div data-qa-selector="badge_list_content">
+ <div data-testid="badge-list-content">
<gl-table
:empty-text="emptyMessage"
:fields="fields"
@@ -109,7 +109,7 @@ export default {
:current-page="currentPage"
stacked="md"
show-empty
- data-qa-selector="badge_list"
+ data-testid="badge-list"
>
<template #cell(name)="{ item }">
<label class="label-bold str-truncated mb-0">{{ item.name }}</label>
diff --git a/app/assets/javascripts/batch_comments/components/submit_dropdown.vue b/app/assets/javascripts/batch_comments/components/submit_dropdown.vue
index f82983a79a7..fac45f32464 100644
--- a/app/assets/javascripts/batch_comments/components/submit_dropdown.vue
+++ b/app/assets/javascripts/batch_comments/components/submit_dropdown.vue
@@ -6,7 +6,6 @@ import { __ } from '~/locale';
import { createAlert } from '~/alert';
import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
import { scrollToElement } from '~/lib/utils/common_utils';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { CLEAR_AUTOSAVE_ENTRY_EVENT } from '~/vue_shared/constants';
import markdownEditorEventHub from '~/vue_shared/components/markdown/eventhub';
import { trackSavedUsingEditor } from '~/vue_shared/components/markdown/tracking';
@@ -23,7 +22,6 @@ export default {
SummarizeMyReview: () =>
import('ee_component/batch_comments/components/summarize_my_review.vue'),
},
- mixins: [glFeatureFlagsMixin()],
inject: {
canSummarize: { default: false },
},
@@ -151,7 +149,6 @@ export default {
<markdown-editor
ref="markdownEditor"
v-model="noteData.note"
- :enable-content-editor="Boolean(glFeatures.contentEditorOnIssues)"
class="js-no-autosize"
:is-submitting="isSubmitting"
:render-markdown-path="getNoteableData.preview_note_path"
diff --git a/app/assets/javascripts/ci/ci_variable_list/components/ci_environments_dropdown.vue b/app/assets/javascripts/ci/ci_variable_list/components/ci_environments_dropdown.vue
index abd272ee24b..77af643cbb3 100644
--- a/app/assets/javascripts/ci/ci_variable_list/components/ci_environments_dropdown.vue
+++ b/app/assets/javascripts/ci/ci_variable_list/components/ci_environments_dropdown.vue
@@ -24,10 +24,6 @@ export default {
type: Array,
required: true,
},
- hasEnvScopeQuery: {
- type: Boolean,
- required: true,
- },
selectedEnvironmentScope: {
type: String,
required: false,
@@ -46,26 +42,17 @@ export default {
composedCreateButtonLabel() {
return sprintf(__('Create wildcard: %{searchTerm}'), { searchTerm: this.searchTerm });
},
- filteredEnvironments() {
- const lowerCasedSearchTerm = this.searchTerm.toLowerCase();
- return this.environments.filter((environment) => {
- return environment.toLowerCase().includes(lowerCasedSearchTerm);
- });
- },
isDropdownLoading() {
- return this.areEnvironmentsLoading && this.hasEnvScopeQuery && !this.isDropdownShown;
+ return this.areEnvironmentsLoading && !this.isDropdownShown;
},
isDropdownSearching() {
- return this.areEnvironmentsLoading && this.hasEnvScopeQuery && this.isDropdownShown;
+ return this.areEnvironmentsLoading && this.isDropdownShown;
},
searchedEnvironments() {
- // If hasEnvScopeQuery (applies only to projects for now), search query will be fired so this
- // component will already receive filtered environments during the refetch.
- // Otherwise (applies to groups), search the existing list of environments in the frontend
- let filtered = this.hasEnvScopeQuery ? this.environments : this.filteredEnvironments;
+ let filtered = this.environments;
// If there is no search term, make sure to include *
- if (this.hasEnvScopeQuery && !this.searchTerm) {
+ if (!this.searchTerm) {
filtered = uniq([...filtered, '*']);
}
@@ -85,9 +72,7 @@ export default {
);
},
shouldRenderDivider() {
- return (
- (this.hasEnvScopeQuery || this.shouldRenderCreateButton) && !this.areEnvironmentsLoading
- );
+ return !this.areEnvironmentsLoading;
},
environmentScopeLabel() {
return convertEnvironmentScope(this.selectedEnvironmentScope);
@@ -97,9 +82,7 @@ export default {
debouncedSearch: debounce(function debouncedSearch(searchTerm) {
const newSearchTerm = searchTerm.trim();
this.searchTerm = newSearchTerm;
- if (this.hasEnvScopeQuery) {
- this.$emit('search-environment-scope', newSearchTerm);
- }
+ this.$emit('search-environment-scope', newSearchTerm);
}, 500),
selectEnvironment(selected) {
this.$emit('select-environment', selected);
@@ -137,7 +120,7 @@ export default {
>
<template #footer>
<gl-dropdown-divider v-if="shouldRenderDivider" />
- <div v-if="hasEnvScopeQuery" data-testid="max-envs-notice">
+ <div data-testid="max-envs-notice">
<gl-dropdown-item class="gl-list-style-none" disabled>
<gl-sprintf :message="$options.i18n.maxEnvsNote" class="gl-font-sm">
<template #limit>
diff --git a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_drawer.vue b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_drawer.vue
index 14410d8b344..5b2984e5249 100644
--- a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_drawer.vue
+++ b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_drawer.vue
@@ -311,7 +311,6 @@ export default {
<ci-environments-dropdown
v-if="areScopedVariablesAvailable"
class="gl-mb-5"
- has-env-scope-query
:are-environments-loading="areEnvironmentsLoading"
:environments="environments"
:selected-environment-scope="variable.environmentScope"
diff --git a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_modal.vue b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_modal.vue
index 2d135056073..cc664d76267 100644
--- a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_modal.vue
+++ b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_modal.vue
@@ -38,7 +38,6 @@ import {
VARIABLE_ACTIONS,
variableOptions,
} from '../constants';
-import { createJoinedEnvironments } from '../utils';
import CiEnvironmentsDropdown from './ci_environments_dropdown.vue';
import { awsTokens, awsTokenList } from './ci_variable_autocomplete_tokens';
@@ -90,10 +89,6 @@ export default {
required: false,
default: false,
},
- hasEnvScopeQuery: {
- type: Boolean,
- required: true,
- },
mode: {
type: String,
required: true,
@@ -147,13 +142,6 @@ export default {
isTipVisible() {
return !this.isTipDismissed && AWS_TOKEN_CONSTANTS.includes(this.variable.key);
},
- environmentsList() {
- if (this.hasEnvScopeQuery) {
- return this.environments;
- }
-
- return createJoinedEnvironments(this.variables, this.environments, this.newEnvironments);
- },
maskedFeedback() {
return this.displayMaskedError
? __('This variable value does not meet the masking requirements.')
@@ -404,9 +392,8 @@ export default {
<ci-environments-dropdown
v-if="areScopedVariablesAvailable"
:are-environments-loading="areEnvironmentsLoading"
- :has-env-scope-query="hasEnvScopeQuery"
:selected-environment-scope="variable.environmentScope"
- :environments="environmentsList"
+ :environments="environments"
@select-environment="setEnvironmentScope"
@search-environment-scope="$emit('search-environment-scope', $event)"
/>
diff --git a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_settings.vue b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_settings.vue
index 482f6da5617..2d25a4be9e7 100644
--- a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_settings.vue
+++ b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_settings.vue
@@ -37,10 +37,6 @@ export default {
required: false,
default: false,
},
- hasEnvScopeQuery: {
- type: Boolean,
- required: true,
- },
isLoading: {
type: Boolean,
required: false,
@@ -125,7 +121,6 @@ export default {
:are-environments-loading="areEnvironmentsLoading"
:are-scoped-variables-available="areScopedVariablesAvailable"
:environments="environments"
- :has-env-scope-query="hasEnvScopeQuery"
:hide-environment-scope="hideEnvironmentScope"
:variables="variables"
:mode="mode"
diff --git a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_shared.vue b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_shared.vue
index 3d5ed327dc7..ebc0db6fad1 100644
--- a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_shared.vue
+++ b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_shared.vue
@@ -285,7 +285,6 @@ export default {
:are-scoped-variables-available="areScopedVariablesAvailable"
:entity="entity"
:environments="environments"
- :has-env-scope-query="hasEnvScopeQuery"
:hide-environment-scope="hideEnvironmentScope"
:is-loading="isLoading"
:max-variable-limit="maxVariableLimit"
diff --git a/app/assets/javascripts/ci/ci_variable_list/utils.js b/app/assets/javascripts/ci/ci_variable_list/utils.js
index 1faa97a5f73..a7e020206ea 100644
--- a/app/assets/javascripts/ci/ci_variable_list/utils.js
+++ b/app/assets/javascripts/ci/ci_variable_list/utils.js
@@ -1,29 +1,6 @@
-import { uniq } from 'lodash';
import { allEnvironments } from './constants';
/**
- * This function takes a list of variable, environments and
- * new environments added through the scope dropdown
- * and create a new Array that concatenate the environment list
- * with the environment scopes find in the variable list. This is
- * useful for variable settings so that we can render a list of all
- * environment scopes available based on the list of envs, the ones the user
- * added explictly and what is found under each variable.
- * @param {Array} variables
- * @param {Array} environments
- * @returns {Array} - Array of environments
- */
-
-export const createJoinedEnvironments = (
- variables = [],
- environments = [],
- newEnvironments = [],
-) => {
- const scopesFromVariables = variables.map((variable) => variable.environmentScope);
- return uniq([...environments, ...newEnvironments, ...scopesFromVariables]).sort();
-};
-
-/**
* This function job is to convert the * wildcard to text when applicable
* in the UI. It uses a constants to compare the incoming value to that
* of the * and then apply the corresponding label if applicable. If there
diff --git a/app/assets/javascripts/content_editor/extensions/selection.js b/app/assets/javascripts/content_editor/extensions/selection.js
index 2e0bb29e5a1..0c24207b395 100644
--- a/app/assets/javascripts/content_editor/extensions/selection.js
+++ b/app/assets/javascripts/content_editor/extensions/selection.js
@@ -6,12 +6,22 @@ export default Extension.create({
name: 'selection',
addProseMirrorPlugins() {
+ let contextMenuVisible = false;
+
return [
new Plugin({
key: new PluginKey('selection'),
props: {
+ handleDOMEvents: {
+ contextmenu() {
+ contextMenuVisible = true;
+ setTimeout(() => {
+ contextMenuVisible = false;
+ });
+ },
+ },
decorations(state) {
- if (state.selection.empty) return null;
+ if (state.selection.empty || contextMenuVisible) return null;
return DecorationSet.create(state.doc, [
Decoration.inline(state.selection.from, state.selection.to, {
diff --git a/app/assets/javascripts/content_editor/services/serialization_helpers.js b/app/assets/javascripts/content_editor/services/serialization_helpers.js
index 17e650644b3..0897232cf89 100644
--- a/app/assets/javascripts/content_editor/services/serialization_helpers.js
+++ b/app/assets/javascripts/content_editor/services/serialization_helpers.js
@@ -561,7 +561,14 @@ const linkType = (sourceMarkdown) => {
return LINK_HTML;
};
-const normalizeUrl = (url) => decodeURIComponent(removeLastSlashInUrlPath(removeUrlProtocol(url)));
+const normalizeUrl = (url) => {
+ const processedUrl = removeLastSlashInUrlPath(removeUrlProtocol(url));
+ try {
+ return decodeURIComponent(processedUrl);
+ } catch {
+ return processedUrl;
+ }
+};
/**
* Validates that the provided URL is a valid GFM autolink
diff --git a/app/assets/javascripts/design_management/components/design_description/description_form.vue b/app/assets/javascripts/design_management/components/design_description/description_form.vue
index 413442074f0..6be643e88dc 100644
--- a/app/assets/javascripts/design_management/components/design_description/description_form.vue
+++ b/app/assets/javascripts/design_management/components/design_description/description_form.vue
@@ -4,7 +4,6 @@ import SafeHtml from '~/vue_shared/directives/safe_html';
import { __, s__ } from '~/locale';
import { helpPagePath } from '~/helpers/help_page_helper';
import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
-import glFeaturesFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { renderGFM } from '~/behaviors/markdown/render_gfm';
import { toggleMarkCheckboxes } from '~/behaviors/markdown/utils';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
@@ -36,7 +35,6 @@ export default {
placeholder: s__('DesignManagement|Write a comment or drag your files here…'),
'aria-label': s__('DesignManagement|Design description'),
},
- mixins: [glFeaturesFlagMixin()],
markdownDocsPath: helpPagePath('user/markdown'),
quickActionsDocsPath: helpPagePath('user/project/quick_actions'),
props: {
@@ -174,7 +172,6 @@ export default {
:render-markdown-path="markdownPreviewPath"
:markdown-docs-path="$options.markdownDocsPath"
:form-field-props="$options.formFieldProps"
- :enable-content-editor="Boolean(glFeatures.contentEditorOnIssues)"
:quick-actions-docs-path="$options.quickActionsDocsPath"
:autosave-key="autosaveKey"
enable-autocomplete
diff --git a/app/assets/javascripts/invite_members/components/invite_groups_modal.vue b/app/assets/javascripts/invite_members/components/invite_groups_modal.vue
index 91dbd86418c..4b492e48095 100644
--- a/app/assets/javascripts/invite_members/components/invite_groups_modal.vue
+++ b/app/assets/javascripts/invite_members/components/invite_groups_modal.vue
@@ -16,7 +16,7 @@ import GroupSelect from './group_select.vue';
import InviteGroupNotification from './invite_group_notification.vue';
export default {
- name: 'InviteMembersModal',
+ name: 'InviteGroupsModal',
components: {
GroupSelect,
InviteModalBase,
diff --git a/app/assets/javascripts/invite_members/components/invite_modal_base.vue b/app/assets/javascripts/invite_members/components/invite_modal_base.vue
index 5a891e23faf..18d22395104 100644
--- a/app/assets/javascripts/invite_members/components/invite_modal_base.vue
+++ b/app/assets/javascripts/invite_members/components/invite_modal_base.vue
@@ -253,7 +253,6 @@ export default {
<gl-modal
ref="modal"
:modal-id="modalId"
- data-qa-selector="invite_members_modal_content"
data-testid="invite-modal"
size="sm"
dialog-class="gl-mx-5"
diff --git a/app/assets/javascripts/issues/show/components/app.vue b/app/assets/javascripts/issues/show/components/app.vue
index d31b56c0277..756585683c8 100644
--- a/app/assets/javascripts/issues/show/components/app.vue
+++ b/app/assets/javascripts/issues/show/components/app.vue
@@ -185,12 +185,12 @@ export default {
default: false,
},
issueId: {
- type: Number,
+ type: String,
required: false,
default: null,
},
issueIid: {
- type: Number,
+ type: String,
required: false,
default: null,
},
@@ -521,7 +521,6 @@ export default {
:project-namespace="projectNamespace"
:can-attach-file="canAttachFile"
:enable-autocomplete="enableAutocomplete"
- :issue-id="issueId"
:issuable-type="issuableType"
@updateForm="setFormState"
/>
diff --git a/app/assets/javascripts/issues/show/components/description.vue b/app/assets/javascripts/issues/show/components/description.vue
index 5735a518a3e..369aa694739 100644
--- a/app/assets/javascripts/issues/show/components/description.vue
+++ b/app/assets/javascripts/issues/show/components/description.vue
@@ -74,12 +74,12 @@ export default {
default: 0,
},
issueId: {
- type: Number,
+ type: String,
required: false,
default: null,
},
issueIid: {
- type: Number,
+ type: String,
required: false,
default: null,
},
@@ -365,7 +365,7 @@ export default {
addHierarchyChild({
cache,
fullPath: this.fullPath,
- iid: String(this.issueIid),
+ iid: this.issueIid,
workItem: workItemCreate.workItem,
}),
});
@@ -400,7 +400,7 @@ export default {
removeHierarchyChild({
cache,
fullPath: this.fullPath,
- iid: String(this.issueIid),
+ iid: this.issueIid,
workItem: { id },
}),
});
diff --git a/app/assets/javascripts/issues/show/components/fields/description.vue b/app/assets/javascripts/issues/show/components/fields/description.vue
index efe1619ed1f..10323b99665 100644
--- a/app/assets/javascripts/issues/show/components/fields/description.vue
+++ b/app/assets/javascripts/issues/show/components/fields/description.vue
@@ -2,7 +2,6 @@
<script>
import { __ } from '~/locale';
import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
-import glFeaturesFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { trackSavedUsingEditor } from '~/vue_shared/components/markdown/tracking';
import { ISSUE_NOTEABLE_TYPE } from '~/notes/constants';
import updateMixin from '../../mixins/update';
@@ -11,7 +10,7 @@ export default {
components: {
MarkdownEditor,
},
- mixins: [updateMixin, glFeaturesFlagMixin()],
+ mixins: [updateMixin],
props: {
value: {
type: String,
@@ -71,7 +70,6 @@ export default {
<label class="sr-only" for="issue-description">{{ __('Description') }}</label>
<markdown-editor
ref="markdownEditor"
- :enable-content-editor="Boolean(glFeatures.contentEditorOnIssues)"
class="gl-mt-3"
:value="value"
:render-markdown-path="markdownPreviewPath"
diff --git a/app/assets/javascripts/issues/show/components/form.vue b/app/assets/javascripts/issues/show/components/form.vue
index 047bdcdcefc..c2248d66860 100644
--- a/app/assets/javascripts/issues/show/components/form.vue
+++ b/app/assets/javascripts/issues/show/components/form.vue
@@ -2,10 +2,7 @@
<script>
import { GlAlert } from '@gitlab/ui';
import { getDraft, updateDraft, getLockVersion, clearDraft } from '~/lib/utils/autosave';
-import { convertToGraphQLId } from '~/graphql_shared/utils';
-import { TYPENAME_ISSUE, TYPENAME_USER } from '~/graphql_shared/constants';
import { TYPE_INCIDENT, TYPE_ISSUE } from '~/issues/constants';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import eventHub from '../event_hub';
import EditActions from './edit_actions.vue';
import DescriptionField from './fields/description.vue';
@@ -24,7 +21,6 @@ export default {
IssuableTypeField,
LockedWarning,
},
- mixins: [glFeatureFlagMixin()],
props: {
endpoint: {
type: String,
@@ -78,11 +74,6 @@ export default {
required: false,
default: '',
},
- issueId: {
- type: Number,
- required: false,
- default: null,
- },
},
data() {
const autosaveKey = [document.location.pathname, document.location.search];
@@ -110,12 +101,6 @@ export default {
showTypeField() {
return [TYPE_INCIDENT, TYPE_ISSUE].includes(this.issuableType);
},
- resourceId() {
- return this.issueId && convertToGraphQLId(TYPENAME_ISSUE, this.issueId);
- },
- userId() {
- return convertToGraphQLId(TYPENAME_USER, gon.current_user_id);
- },
},
watch: {
formData: {
diff --git a/app/assets/javascripts/issues/show/index.js b/app/assets/javascripts/issues/show/index.js
index b94f88f690e..cd5c6f4825a 100644
--- a/app/assets/javascripts/issues/show/index.js
+++ b/app/assets/javascripts/issues/show/index.js
@@ -131,8 +131,8 @@ export function initIssuableApp(store) {
isLocked: this.getNoteableData?.discussion_locked,
issuableStatus: this.getNoteableData?.state,
issuableType: issueType,
- issueId: this.getNoteableData?.id,
- issueIid: this.getNoteableData?.iid,
+ issueId: this.getNoteableData?.id.toString(),
+ issueIid: this.getNoteableData?.iid.toString(),
showTitleBorder: issueType !== TYPE_INCIDENT,
},
});
diff --git a/app/assets/javascripts/members/components/members_tabs.vue b/app/assets/javascripts/members/components/members_tabs.vue
index de5c9eb5a55..449ad20e7ab 100644
--- a/app/assets/javascripts/members/components/members_tabs.vue
+++ b/app/assets/javascripts/members/components/members_tabs.vue
@@ -22,7 +22,7 @@ export const TABS = [
{
namespace: MEMBER_TYPES.group,
title: __('Groups'),
- attrs: { 'data-qa-selector': 'groups_list_tab' },
+ attrs: { 'data-testid': 'groups-list-tab' },
queryParamValue: TAB_QUERY_PARAM_VALUES.group,
},
{
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index 142f07973f2..329d6cfec00 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -16,7 +16,6 @@ import { sprintf } from '~/locale';
import { badgeState } from '~/merge_requests/components/merge_request_header.vue';
import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { trackSavedUsingEditor } from '~/vue_shared/components/markdown/tracking';
import * as constants from '../constants';
@@ -49,7 +48,7 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
- mixins: [glFeatureFlagsMixin(), issuableStateMixin],
+ mixins: [issuableStateMixin],
props: {
noteableType: {
type: String,
@@ -361,7 +360,6 @@ export default {
>
<markdown-editor
ref="markdownEditor"
- :enable-content-editor="Boolean(glFeatures.contentEditorOnIssues)"
:value="note"
:render-markdown-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath"
diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue
index 8073428c108..f8a0db93e37 100644
--- a/app/assets/javascripts/notes/components/note_form.vue
+++ b/app/assets/javascripts/notes/components/note_form.vue
@@ -5,7 +5,6 @@ import { mapGetters, mapActions, mapState } from 'vuex';
import { mergeUrlParams } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
-import glFeaturesFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { trackSavedUsingEditor } from '~/vue_shared/components/markdown/tracking';
import eventHub from '../event_hub';
import issuableStateMixin from '../mixins/issuable_state';
@@ -24,7 +23,7 @@ export default {
GlLink,
GlFormCheckbox,
},
- mixins: [issuableStateMixin, resolvable, glFeaturesFlagMixin()],
+ mixins: [issuableStateMixin, resolvable],
props: {
noteBody: {
type: String,
@@ -224,9 +223,6 @@ export default {
placeholder: { link: ['startTag', 'endTag'] },
};
},
- enableContentEditor() {
- return Boolean(this.glFeatures.contentEditorOnIssues);
- },
codeSuggestionsConfig() {
return {
canSuggest: this.canSuggest,
@@ -361,7 +357,6 @@ export default {
<comment-field-layout :noteable-data="getNoteableData" :is-internal-note="isInternalNote">
<markdown-editor
ref="markdownEditor"
- :enable-content-editor="enableContentEditor"
:value="updatedNoteBody"
:render-markdown-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath"
diff --git a/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js b/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js
index 6c2f084591e..f7fb1339bbc 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js
+++ b/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js
@@ -105,7 +105,6 @@ export function mountMarkdownEditor(options = {}) {
return h(MarkdownEditor, {
props: {
setFacade,
- enableContentEditor: Boolean(gon.features?.contentEditorOnIssues),
value: formFieldValue,
renderMarkdownPath,
markdownDocsPath,
diff --git a/app/controllers/admin/topics_controller.rb b/app/controllers/admin/topics_controller.rb
index c4de600dd1d..40cad2d26f4 100644
--- a/app/controllers/admin/topics_controller.rb
+++ b/app/controllers/admin/topics_controller.rb
@@ -8,10 +8,6 @@ class Admin::TopicsController < Admin::ApplicationController
feature_category :groups_and_projects
- before_action do
- push_frontend_feature_flag(:content_editor_on_issues, current_user)
- end
-
def index
@topics = Projects::TopicsFinder.new(params: params.permit(:search)).execute.page(params[:page]).without_count
end
diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb
index cbed75019f2..5f6b55ea928 100644
--- a/app/controllers/groups/milestones_controller.rb
+++ b/app/controllers/groups/milestones_controller.rb
@@ -9,10 +9,6 @@ class Groups::MilestonesController < Groups::ApplicationController
feature_category :team_planning
urgency :low
- before_action do
- push_frontend_feature_flag(:content_editor_on_issues, group)
- end
-
def index
respond_to do |format|
format.html do
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index fc7865c949d..ac9726112c2 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -45,8 +45,6 @@ class Projects::IssuesController < Projects::ApplicationController
before_action do
push_frontend_feature_flag(:preserve_unchanged_markdown, project)
- push_frontend_feature_flag(:content_editor_on_issues, project&.group)
- push_force_frontend_feature_flag(:content_editor_on_issues, project&.content_editor_on_issues_feature_flag_enabled?)
push_frontend_feature_flag(:service_desk_new_note_email_native_attachments, project)
push_frontend_feature_flag(:saved_replies, current_user)
push_frontend_feature_flag(:issues_grid_view)
diff --git a/app/controllers/projects/merge_requests/application_controller.rb b/app/controllers/projects/merge_requests/application_controller.rb
index 81ff6c215f9..1af0ce3c35e 100644
--- a/app/controllers/projects/merge_requests/application_controller.rb
+++ b/app/controllers/projects/merge_requests/application_controller.rb
@@ -7,11 +7,6 @@ class Projects::MergeRequests::ApplicationController < Projects::ApplicationCont
feature_category :code_review_workflow
- before_action do
- push_frontend_feature_flag(:content_editor_on_issues, project&.group)
- push_force_frontend_feature_flag(:content_editor_on_issues, project&.content_editor_on_issues_feature_flag_enabled?)
- end
-
private
# Normally the methods with `check_(\w+)_available!` pattern are
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 858fddb313f..d57cb0a5926 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -36,8 +36,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
end
before_action only: [:show, :diffs] do
- push_frontend_feature_flag(:content_editor_on_issues, project&.group)
- push_force_frontend_feature_flag(:content_editor_on_issues, project&.content_editor_on_issues_feature_flag_enabled?)
push_frontend_feature_flag(:core_security_mr_widget_counts, project)
push_frontend_feature_flag(:issue_assignees_widget, @project)
push_frontend_feature_flag(:moved_mr_sidebar, project)
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index 1f4e5b54500..35b65dbce7e 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -24,10 +24,6 @@ class Projects::MilestonesController < Projects::ApplicationController
feature_category :team_planning
urgency :low
- before_action do
- push_frontend_feature_flag(:content_editor_on_issues, @project)
- end
-
def index
@sort = params[:sort] || 'due_date_asc'
@milestones = milestones.sort_by_attribute(@sort)
diff --git a/app/events/merge_requests/unblocked_state_event.rb b/app/events/merge_requests/unblocked_state_event.rb
new file mode 100644
index 00000000000..2cf79059cf7
--- /dev/null
+++ b/app/events/merge_requests/unblocked_state_event.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module MergeRequests
+ class UnblockedStateEvent < Gitlab::EventStore::Event
+ def schema
+ {
+ 'type' => 'object',
+ 'required' => %w[
+ current_user_id
+ merge_request_id
+ ],
+ 'properties' => {
+ 'current_user_id' => { 'type' => 'integer' },
+ 'merge_request_id' => { 'type' => 'integer' }
+ }
+ }
+ end
+ end
+end
diff --git a/app/models/bulk_imports/entity.rb b/app/models/bulk_imports/entity.rb
index da620c85676..437118c36e8 100644
--- a/app/models/bulk_imports/entity.rb
+++ b/app/models/bulk_imports/entity.rb
@@ -144,9 +144,9 @@ class BulkImports::Entity < ApplicationRecord
File.join(base_resource_path, 'export_relations')
end
- def export_relations_url_path
- if bulk_import.supports_batched_export?
- Gitlab::Utils.add_url_parameters(export_relations_url_path_base, batched: true)
+ def export_relations_url_path(batched: false)
+ if batched && bulk_import.supports_batched_export?
+ Gitlab::Utils.add_url_parameters(export_relations_url_path_base, batched: batched)
else
export_relations_url_path_base
end
diff --git a/app/models/group.rb b/app/models/group.rb
index f3a501cfb04..587451ac195 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -885,10 +885,6 @@ class Group < Namespace
].compact.min
end
- def content_editor_on_issues_feature_flag_enabled?
- feature_flag_enabled_for_self_or_ancestor?(:content_editor_on_issues)
- end
-
def work_items_feature_flag_enabled?
feature_flag_enabled_for_self_or_ancestor?(:work_items)
end
diff --git a/app/models/integrations/discord.rb b/app/models/integrations/discord.rb
index 6aca9fc9921..7917d17eb62 100644
--- a/app/models/integrations/discord.rb
+++ b/app/models/integrations/discord.rb
@@ -43,7 +43,7 @@ module Integrations
end
def self.supported_events
- %w[push issue confidential_issue merge_request note confidential_note tag_push pipeline wiki_page]
+ %w[push issue confidential_issue merge_request note confidential_note tag_push pipeline wiki_page deployment]
end
def configurable_channels?
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 72b0632f9fd..9ac9f94310d 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -1237,13 +1237,14 @@ class MergeRequest < ApplicationRecord
def mergeable?(
skip_ci_check: false, skip_discussions_check: false, skip_approved_check: false, check_mergeability_retry_lease: false,
- skip_draft_check: false, skip_rebase_check: false)
+ skip_draft_check: false, skip_rebase_check: false, skip_blocked_check: false)
return false unless mergeable_state?(
skip_ci_check: skip_ci_check,
- skip_draft_check: skip_draft_check,
skip_discussions_check: skip_discussions_check,
- skip_approved_check: skip_approved_check
+ skip_draft_check: skip_draft_check,
+ skip_approved_check: skip_approved_check,
+ skip_blocked_check: skip_blocked_check
)
check_mergeability(sync_retry_lease: check_mergeability_retry_lease)
@@ -1276,14 +1277,15 @@ class MergeRequest < ApplicationRecord
def mergeable_state?(
skip_ci_check: false, skip_discussions_check: false, skip_approved_check: false,
- skip_draft_check: false)
+ skip_draft_check: false, skip_blocked_check: false)
additional_checks = execute_merge_checks(
mergeable_state_checks,
params: {
skip_ci_check: skip_ci_check,
skip_discussions_check: skip_discussions_check,
skip_approved_check: skip_approved_check,
- skip_draft_check: skip_draft_check
+ skip_draft_check: skip_draft_check,
+ skip_blocked_check: skip_blocked_check
}
)
additional_checks.success?
diff --git a/app/models/project.rb b/app/models/project.rb
index 2e331c391b1..612931e7d40 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -3187,10 +3187,6 @@ class Project < ApplicationRecord
creator.banned? && team.max_member_access(creator.id) == Gitlab::Access::OWNER
end
- def content_editor_on_issues_feature_flag_enabled?
- group&.content_editor_on_issues_feature_flag_enabled? || Feature.enabled?(:content_editor_on_issues, self)
- end
-
def work_items_feature_flag_enabled?
group&.work_items_feature_flag_enabled? || Feature.enabled?(:work_items, self)
end
diff --git a/app/serializers/merge_request_noteable_entity.rb b/app/serializers/merge_request_noteable_entity.rb
index 306bac7daae..aac90c20b53 100644
--- a/app/serializers/merge_request_noteable_entity.rb
+++ b/app/serializers/merge_request_noteable_entity.rb
@@ -15,8 +15,8 @@ class MergeRequestNoteableEntity < IssuableEntity
project_tree_path(merge_request.source_project, merge_request.source_branch)
end
- expose :target_branch_path, if: -> (merge_request) { merge_request.source_project } do |merge_request|
- project_tree_path(merge_request.source_project, merge_request.target_branch)
+ expose :target_branch_path, if: -> (merge_request) { merge_request.target_project } do |merge_request|
+ project_tree_path(merge_request.target_project, merge_request.target_branch)
end
expose :diff_head_sha
diff --git a/app/services/auto_merge/base_service.rb b/app/services/auto_merge/base_service.rb
index caefa9af24a..545e4d9b7dc 100644
--- a/app/services/auto_merge/base_service.rb
+++ b/app/services/auto_merge/base_service.rb
@@ -63,7 +63,7 @@ module AutoMerge
!merge_request.broken? &&
(skip_draft_check(merge_request) || !merge_request.draft?) &&
merge_request.mergeable_discussions_state? &&
- !merge_request.merge_blocked_by_other_mrs? &&
+ (skip_blocked_check(merge_request) || !merge_request.merge_blocked_by_other_mrs?) &&
yield
end
end
@@ -114,5 +114,10 @@ module AutoMerge
def skip_draft_check(merge_request)
false
end
+
+ # Will skip the blocked check or not when checking if strategy is available
+ def skip_blocked_check(merge_request)
+ false
+ end
end
end
diff --git a/app/views/dashboard/projects/_zero_authorized_projects.html.haml b/app/views/dashboard/projects/_zero_authorized_projects.html.haml
index e72762f2ae5..da25dee1e88 100644
--- a/app/views/dashboard/projects/_zero_authorized_projects.html.haml
+++ b/app/views/dashboard/projects/_zero_authorized_projects.html.haml
@@ -1,6 +1,6 @@
.container
.gl-text-center.gl-pt-6.gl-pb-7
- %h2.gl-font-size-h1{ data: { qa_selector: 'welcome_title_content' } }
+ %h2.gl-font-size-h1{ data: { testid: 'welcome-title-content' } }
= _('Welcome to GitLab')
%p.gl-m-0
= _('Faster releases. Better code. Less pain.')
diff --git a/app/views/layouts/component_preview.html.haml b/app/views/layouts/component_preview.html.haml
index 8217ac13c52..4ef7ba04868 100644
--- a/app/views/layouts/component_preview.html.haml
+++ b/app/views/layouts/component_preview.html.haml
@@ -5,6 +5,12 @@
- else
= stylesheet_link_tag "application_dark"
= stylesheet_link_tag "application_utilities_dark"
+
+ - if ::Feature.enabled?(:font_display_swap, current_user)
+ = stylesheet_link_tag_defer "fonts_swap"
+ - else
+ = stylesheet_link_tag_defer "fonts_optional"
+
%body
.gl-mt-6{ class: (params[:lookbook][:display][:layout] == "fluid" ? "container-fluid" : "container") }
- if params[:lookbook][:display][:bg_dark]
diff --git a/app/workers/bulk_imports/export_request_worker.rb b/app/workers/bulk_imports/export_request_worker.rb
index 1b2183e96b4..44759916f99 100644
--- a/app/workers/bulk_imports/export_request_worker.rb
+++ b/app/workers/bulk_imports/export_request_worker.rb
@@ -125,7 +125,7 @@ module BulkImports
end
def export_url
- entity.export_relations_url_path
+ entity.export_relations_url_path(batched: Feature.enabled?(:bulk_imports_batched_import_export))
end
end
end
diff --git a/app/workers/bulk_imports/finish_batched_pipeline_worker.rb b/app/workers/bulk_imports/finish_batched_pipeline_worker.rb
index 91365d23dea..b1f3757e058 100644
--- a/app/workers/bulk_imports/finish_batched_pipeline_worker.rb
+++ b/app/workers/bulk_imports/finish_batched_pipeline_worker.rb
@@ -43,7 +43,7 @@ module BulkImports
end
def import_in_progress?
- tracker.batches.any?(&:started?)
+ tracker.batches.any? { |b| b.started? || b.created? }
end
end
end
diff --git a/app/workers/bulk_imports/pipeline_batch_worker.rb b/app/workers/bulk_imports/pipeline_batch_worker.rb
index 634d7ed3c87..6230d517641 100644
--- a/app/workers/bulk_imports/pipeline_batch_worker.rb
+++ b/app/workers/bulk_imports/pipeline_batch_worker.rb
@@ -14,15 +14,16 @@ module BulkImports
def perform(batch_id)
@batch = ::BulkImports::BatchTracker.find(batch_id)
@tracker = @batch.tracker
+ @pending_retry = false
try_obtain_lease { run }
ensure
- ::BulkImports::FinishBatchedPipelineWorker.perform_async(tracker.id)
+ ::BulkImports::FinishBatchedPipelineWorker.perform_async(tracker.id) unless pending_retry
end
private
- attr_reader :batch, :tracker
+ attr_reader :batch, :tracker, :pending_retry
def run
return batch.skip! if tracker.failed? || tracker.finished?
@@ -31,6 +32,7 @@ module BulkImports
tracker.pipeline_class.new(context).run
batch.finish!
rescue BulkImports::RetryPipelineError => e
+ @pending_retry = true
retry_batch(e)
rescue StandardError => e
fail_batch(e)
diff --git a/config/application.rb b/config/application.rb
index ad62648868f..bc4809d0c53 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -430,7 +430,7 @@ module Gitlab
config.middleware.insert_before ActionDispatch::RemoteIp, ::Gitlab::Middleware::HandleIpSpoofAttackError
- config.middleware.insert_after Rails::Rack::Logger, ::Gitlab::Middleware::HandleMalformedStrings
+ config.middleware.insert_after ActionDispatch::ShowExceptions, ::Gitlab::Middleware::HandleMalformedStrings
config.middleware.insert_after ::Gitlab::Middleware::HandleMalformedStrings, ::Gitlab::Middleware::PathTraversalCheck
diff --git a/config/feature_flags/development/content_editor_on_issues.yml b/config/feature_flags/development/bulk_imports_batched_import_export.yml
index 79aaccee828..4afb715b1ee 100644
--- a/config/feature_flags/development/content_editor_on_issues.yml
+++ b/config/feature_flags/development/bulk_imports_batched_import_export.yml
@@ -1,8 +1,8 @@
---
-name: content_editor_on_issues
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98703
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/375172
-milestone: '15.5'
+name: bulk_imports_batched_import_export
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124434
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/406559
+milestone: '16.2'
type: development
-group: group::knowledge
-default_enabled: true
+group: group::import and integrate
+default_enabled: false
diff --git a/doc/administration/geo/replication/troubleshooting.md b/doc/administration/geo/replication/troubleshooting.md
index e2f88f3dfb8..3c2d43d196a 100644
--- a/doc/administration/geo/replication/troubleshooting.md
+++ b/doc/administration/geo/replication/troubleshooting.md
@@ -503,6 +503,46 @@ This check is also required when using a mixture of GitLab deployments. The loca
## Fixing PostgreSQL database replication errors
+The following sections outline troubleshooting steps for fixing replication error messages (indicated by `Database replication working? ... no` in the
+[`geo:check` output](#health-check-rake-task).
+The instructions present here mostly assume a single-node Geo Linux package deployment, and might need to be adapted to different environments.
+
+### Removing an inactive replication slot
+
+Replication slots are marked as 'inactive' when the replication client (a secondary site) connected to the slot disconnects.
+Inactive replication slots cause WAL files to be retained, because they are sent to the client when it reconnects and the slot becomes active once more.
+If the secondary site is not able to reconnect, use the following steps to remove its corresponding inactive replication slot:
+
+1. [Start a PostgreSQL console session](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-postgresql-database) on the Geo primary site's database node:
+
+ ```shell
+ sudo gitlab-psql -d gitlabhq_production
+ ```
+
+ NOTE:
+ Using `gitlab-rails dbconsole` does not work, because managing replication slots requires superuser permissions.
+
+1. View the replication slots and remove them if they are inactive:
+
+ ```sql
+ SELECT * FROM pg_replication_slots;
+ ```
+
+ Slots where `active` is `f` are inactive.
+
+ - When this slot should be active, because you have a **secondary** site configured using that slot,
+ look for the [PostgreSQL logs](../../logs/index.md#postgresql-logs) for the **secondary** site,
+ to view why the replication is not running.
+ - If you are no longer using the slot (for example, you no longer have Geo enabled), or the secondary site is no longer able to reconnect,
+ you should remove it using the PostgreSQL console session:
+
+ ```sql
+ SELECT pg_drop_replication_slot('<name_of_inactive_slot>');
+ ```
+
+1. Follow either the steps [to remove that Geo site](remove_geo_site.md) if it's no longer required,
+ or [re-initiate the replication process](../setup/database.md#step-3-initiate-the-replication-process), which recreates the replication slot correctly.
+
### Message: `WARNING: oldest xmin is far in the past` and `pg_wal` size growing
If a replication slot is inactive,
@@ -517,18 +557,7 @@ HINT: Close open transactions soon to avoid wraparound problems.
You might also need to commit or roll back old prepared transactions, or drop stale replication slots.
```
-To fix this:
-
-1. [Connect to the primary database](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database).
-
-1. Run `SELECT * FROM pg_replication_slots;`.
- Note the `slot_name` that reports `active` as `f` (false).
-
-1. Follow [the steps to remove that Geo site](remove_geo_site.md).
-
-The following sections outline troubleshooting steps for fixing replication
-error messages (indicated by `Database replication working? ... no` in the
-[`geo:check` output](#health-check-rake-task).
+To fix this, you should [remove the inactive replication slot](#removing-an-inactive-replication-slot) and re-initiate the replication.
### Message: `ERROR: replication slots can only be used if max_replication_slots > 0`?
@@ -568,35 +597,9 @@ the default 30 minutes. Adjust as required for your installation.
### Message: "PANIC: could not write to file `pg_xlog/xlogtemp.123`: No space left on device"
Determine if you have any unused replication slots in the **primary** database. This can cause large amounts of
-log data to build up in `pg_xlog`. Removing the unused slots can reduce the amount of space used in the `pg_xlog`.
-
-1. Start a PostgreSQL console session:
+log data to build up in `pg_xlog`.
- ```shell
- sudo gitlab-psql
- ```
-
- NOTE:
- Using `gitlab-rails dbconsole` does not work, because managing replication slots requires superuser permissions.
-
-1. View your replication slots:
-
- ```sql
- SELECT * FROM pg_replication_slots;
- ```
-
-Slots where `active` is `f` are not active.
-
-- When this slot should be active, because you have a **secondary** site configured using that slot,
- sign in on the web interface for the **secondary** site and check the [PostgreSQL logs](../../logs/index.md#postgresql-logs)
- to view why the replication is not running.
-
-- If you are no longer using the slot (for example, you no longer have Geo enabled), you can remove it with in the
- PostgreSQL console session:
-
- ```sql
- SELECT pg_drop_replication_slot('<name_of_extra_slot>');
- ```
+[Removing the inactive slots](#removing-an-inactive-replication-slot) can reduce the amount of space used in the `pg_xlog`.
### Message: "ERROR: canceling statement due to conflict with recovery"
diff --git a/doc/administration/job_artifacts.md b/doc/administration/job_artifacts.md
index b3778e89b19..442e9638d86 100644
--- a/doc/administration/job_artifacts.md
+++ b/doc/administration/job_artifacts.md
@@ -284,10 +284,10 @@ If [`artifacts:expire_in`](../ci/yaml/index.md#artifactsexpire_in) is used to se
an expiry for the artifacts, they are marked for deletion right after that date passes.
Otherwise, they expire per the [default artifacts expiration setting](../administration/settings/continuous_integration.md).
-Artifacts are cleaned up by the `expire_build_artifacts_worker` cron job which Sidekiq
+Artifacts are deleted by the `expire_build_artifacts_worker` cron job which Sidekiq
runs every 7 minutes (`*/7 * * * *` in [Cron](../topics/cron/index.md) syntax).
-To change the default schedule on which the artifacts are expired:
+To change the default schedule on which expired artifacts are deleted:
::Tabs
diff --git a/doc/administration/raketasks/maintenance.md b/doc/administration/raketasks/maintenance.md
index cdb70ca715b..724dcc2046a 100644
--- a/doc/administration/raketasks/maintenance.md
+++ b/doc/administration/raketasks/maintenance.md
@@ -454,3 +454,15 @@ main: == [advisory_lock_connection] object_id: 173580, pg_backend_pid: 5532
```
The messages returned are informational and can be ignored.
+
+### PostgreSQL socket errors when executing the `gitlab:env:info` Rake task
+
+After running `sudo gitlab-rake gitlab:env:info` on Gitaly or other non-Rails nodes , you might see the following error:
+
+```plaintext
+PG::ConnectionBad: could not connect to server: No such file or directory
+Is the server running locally and accepting
+connections on Unix domain socket "/var/opt/gitlab/postgresql/.s.PGSQL.5432"?
+```
+
+This is because, in a multi-node environment, the `gitlab:env:info` Rake task should only be executed on the nodes running **GitLab Rails**.
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 7ab3415f756..6858d8f0b84 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -1425,6 +1425,7 @@ Input type: `AuditEventsStreamingHeadersCreateInput`
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="mutationauditeventsstreamingheaderscreateactive"></a>`active` | [`Boolean`](#boolean) | Boolean option determining whether header is active or not. |
| <a id="mutationauditeventsstreamingheaderscreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationauditeventsstreamingheaderscreatedestinationid"></a>`destinationId` | [`AuditEventsExternalAuditEventDestinationID!`](#auditeventsexternalauditeventdestinationid) | Destination to associate header with. |
| <a id="mutationauditeventsstreamingheaderscreatekey"></a>`key` | [`String!`](#string) | Header key. |
@@ -1486,6 +1487,7 @@ Input type: `AuditEventsStreamingInstanceHeadersCreateInput`
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="mutationauditeventsstreaminginstanceheaderscreateactive"></a>`active` | [`Boolean`](#boolean) | Boolean option determining whether header is active or not. |
| <a id="mutationauditeventsstreaminginstanceheaderscreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationauditeventsstreaminginstanceheaderscreatedestinationid"></a>`destinationId` | [`AuditEventsInstanceExternalAuditEventDestinationID!`](#auditeventsinstanceexternalauditeventdestinationid) | Instance level external destination to associate header with. |
| <a id="mutationauditeventsstreaminginstanceheaderscreatekey"></a>`key` | [`String!`](#string) | Header key. |
@@ -24730,7 +24732,7 @@ Represents the scan result policy.
| <a id="scanresultpolicydescription"></a>`description` | [`String!`](#string) | Description of the policy. |
| <a id="scanresultpolicyeditpath"></a>`editPath` | [`String!`](#string) | URL of policy edit page. |
| <a id="scanresultpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
-| <a id="scanresultpolicygroupapprovers"></a>`groupApprovers` | [`[Group!]`](#group) | Approvers of the group type. |
+| <a id="scanresultpolicygroupapprovers"></a>`groupApprovers` **{warning-solid}** | [`[Group!]`](#group) | **Deprecated** in 16.5. Use `allGroupApprovers`. |
| <a id="scanresultpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
| <a id="scanresultpolicyroleapprovers"></a>`roleApprovers` | [`[MemberAccessLevelName!]`](#memberaccesslevelname) | Approvers of the role type. Users belonging to these role(s) alone will be approvers. |
| <a id="scanresultpolicysource"></a>`source` | [`SecurityPolicySource!`](#securitypolicysource) | Source of the policy. Its fields depend on the source type. |
diff --git a/doc/api/integrations.md b/doc/api/integrations.md
index 202513482ef..47ab7ab805c 100644
--- a/doc/api/integrations.md
+++ b/doc/api/integrations.md
@@ -483,6 +483,8 @@ Parameters:
| `confidential_issue_channel` | string | false | The webhook override to receive notifications for confidential issue events. |
| `confidential_note_events` | boolean | false | Enable notifications for confidential note events. |
| `confidential_note_channel` | string | false | The webhook override to receive notifications for confidential note events. |
+| `deployment_events` | boolean | false | Enable notifications for deployment events. |
+| `deployment_channel` | string | false | The webhook override to receive notifications for deployment events. |
| `issues_events` | boolean | false | Enable notifications for issue events. |
| `issue_channel` | string | false | The webhook override to receive notifications for issue events. |
| `merge_requests_events` | boolean | false | Enable notifications for merge request events. |
diff --git a/doc/ci/components/index.md b/doc/ci/components/index.md
index e0379bf783d..aeee871612f 100644
--- a/doc/ci/components/index.md
+++ b/doc/ci/components/index.md
@@ -34,7 +34,8 @@ If a component requires different versioning from other components, the componen
To create a components repository, you must:
1. [Create a new project](../../user/project/index.md#create-a-blank-project) with a `README.md` file.
-1. Create a `template.yml` file inside the project's root directory that contains the configuration you want to provide as a component.
+1. Create either a single file or a templates directory according to the [directory structure](#directory-structure).
+
For example:
```yaml
@@ -106,8 +107,8 @@ For example, the following component could be referenced with `gitlab.com/my-use
#### Component configurations saved in any directory (deprecated)
-NOTE:
-Saving component configurations through this directory structure is [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/415855).
+WARNING:
+Saving component configurations through this directory structure is [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/415855) and should be avoided.
Components configurations can be saved through the following directory structure, containing:
diff --git a/doc/development/ai_features/index.md b/doc/development/ai_features/index.md
index 723a7716327..4401a7e3fb1 100644
--- a/doc/development/ai_features/index.md
+++ b/doc/development/ai_features/index.md
@@ -61,6 +61,7 @@ Use [this snippet](https://gitlab.com/gitlab-org/gitlab/-/snippets/2554994) for
Feature.enable(:openai_experimentation)
```
+1. Ensure you have followed [the process to obtain an EE license](https://about.gitlab.com/handbook/developer-onboarding/#working-on-gitlab-ee-developer-licenses) for your local instance
1. Simulate the GDK to [simulate SaaS](../ee_features.md#simulate-a-saas-instance) and ensure the group you want to test has an Ultimate license
1. Enable `Experimental features` and `Third-party AI services`
1. Go to the group with the Ultimate license
@@ -101,24 +102,18 @@ To populate the embedding database for GitLab chat:
In order to obtain a GCP service key for local development, please follow the steps below:
- Create a sandbox GCP project by visiting [this page](https://about.gitlab.com/handbook/infrastructure-standards/#individual-environment) and following the instructions, or by requesting access to our existing group GCP project by using [this template](https://gitlab.com/gitlab-com/it/infra/issue-tracker/-/issues/new?issuable_template=gcp_group_account_iam_update_request).
-- Once you have access to an individual or shared GCP project, navigate to
- the project by visiting
- [https://gitlabsandbox.cloud](https://gitlabsandbox.cloud) and selecting the
- project name. On the project page, select `Open GCP Console`
-- In the GCP console, type `IAM & Admin` into the search box. Then go to `IAM & Admin` > `Service Accounts` and select `Create service account`.
-- Name the service account something specific to what you're using it for. Select `Create and Continue`. Under `Grant this service account access to project`, select the role `Vertex AI User`. Select `Continue` then `Done`
-- Select your new service account and `Keys` > `Add Key` > `Create new key`. Use default Key type of `JSON`. This will download the **private** JSON credentials for your service account.
- If you are using an individual GCP project, you may also need to enable the Vertex AI API:
1. Go to **APIs & Services > Enabled APIs & services**.
1. Select **+ Enable APIs and Services**.
1. Search for `Vertex AI API`.
1. Select **Vertex AI API**, then select **Enable**.
+- Install the [`gcloud` CLI](https://cloud.google.com/sdk/docs/install)
+- Authenticate locally with GCP using the [`gcloud auth application-default login`](https://cloud.google.com/sdk/gcloud/reference/auth/application-default/login) command.
- Open the Rails console. Update the settings to:
```ruby
# PROJECT_ID = "your-gcp-project-name"
-Gitlab::CurrentSettings.update(vertex_ai_credentials: File.read('/YOUR_FILE.json'))
Gitlab::CurrentSettings.update(vertex_ai_project: PROJECT_ID)
```
diff --git a/doc/user/project/issues/design_management.md b/doc/user/project/issues/design_management.md
index 0ea49ff387f..0a314bccc8f 100644
--- a/doc/user/project/issues/design_management.md
+++ b/doc/user/project/issues/design_management.md
@@ -190,17 +190,11 @@ To archive multiple designs at once:
## Markdown and rich text editors for descriptions
-<!-- When content_editor_on_issues flag is removed, move version notes
- to "Add a design to an issue", update that topic, and delete this one. -->
-
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/388449) in GitLab 16.1 [with a flag](../../../administration/feature_flags.md) named `content_editor_on_issues`. Disabled by default.
> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/375172) in GitLab 16.2.
+> - Feature flag `content_editor_on_issues` removed in GitLab 16.5.
-FLAG:
-On self-managed GitLab, by default the rich text editor is available. To hide it, an administrator can [disable the feature flag](../../../administration/feature_flags.md) named `content_editor_on_issues`.
-On GitLab.com, this feature is available.
-
-When this feature is enabled, you can use the Markdown and rich text editor in design descriptions.
+You can use the Markdown and rich text editor in design descriptions.
It's the same editor you use for comments across GitLab.
## Reorder designs
diff --git a/doc/user/project/merge_requests/reviews/suggestions.md b/doc/user/project/merge_requests/reviews/suggestions.md
index 2b046399c4e..90a276dc303 100644
--- a/doc/user/project/merge_requests/reviews/suggestions.md
+++ b/doc/user/project/merge_requests/reviews/suggestions.md
@@ -71,10 +71,7 @@ suggestion.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/388449) in GitLab 16.1 [with a flag](../../../../administration/feature_flags.md) named `content_editor_on_issues`. Disabled by default.
> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/375172) in GitLab 16.2.
-
-FLAG:
-On self-managed GitLab, by default this feature is available. To hide the feature, an administrator can [disable the feature flag](../../../../administration/feature_flags.md) named `content_editor_on_issues`.
-On GitLab.com, this feature is available.
+> - Feature flag `content_editor_on_issues` removed in GitLab 16.5.
When you insert suggestions, you can use the WYSIWYG
[rich text editor](https://about.gitlab.com/direction/plan/knowledge/content_editor/) to move
diff --git a/doc/user/rich_text_editor.md b/doc/user/rich_text_editor.md
index c60c89eb0de..fe3ac56b79c 100644
--- a/doc/user/rich_text_editor.md
+++ b/doc/user/rich_text_editor.md
@@ -12,15 +12,7 @@ type: index, reference
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/382636) for [discussions](discussions/index.md), and creating and editing issues and merge requests in GitLab 15.11 with the same flag.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/407507) for epics in GitLab 16.1 with the same flag.
> - Feature flag `content_editor_on_issues` enabled by default in GitLab 16.2.
-
-FLAG:
-On self-managed GitLab, by default this feature is available. To hide the feature, an administrator
-can [disable the feature flag](../administration/feature_flags.md) named `content_editor_on_issues`.
-On GitLab.com, this feature is available.
-
-The rich text editor is a "what you see is what you get" (WYSIWYG) editor so you can use
-[GitLab Flavored Markdown](markdown.md) in descriptions and comments, even if you can't remember all
-of its syntax.
+> - Feature flag `content_editor_on_issues` removed in GitLab 16.5.
![Rich text editor in GitLab](img/rich_text_editor_01_v16_2.png)
diff --git a/lib/api/ml/mlflow/runs.rb b/lib/api/ml/mlflow/runs.rb
index 5b6afffaae1..ac052d8bff5 100644
--- a/lib/api/ml/mlflow/runs.rb
+++ b/lib/api/ml/mlflow/runs.rb
@@ -65,7 +65,7 @@ module API
type: String,
desc: 'Token for pagination'
end
- get 'search', urgency: :low do
+ post 'search', urgency: :low do
params[:experiment_id] = params[:experiment_ids][0]
max_results = [params[:max_results], 1000].min
diff --git a/lib/gitlab/auth/ldap/auth_hash.rb b/lib/gitlab/auth/ldap/auth_hash.rb
index 5435355f136..6d1d1519fc2 100644
--- a/lib/gitlab/auth/ldap/auth_hash.rb
+++ b/lib/gitlab/auth/ldap/auth_hash.rb
@@ -6,6 +6,8 @@ module Gitlab
module Auth
module Ldap
class AuthHash < Gitlab::Auth::OAuth::AuthHash
+ extend ::Gitlab::Utils::Override
+
def uid
@uid ||= Gitlab::Auth::Ldap::Person.normalize_dn(super)
end
@@ -44,6 +46,12 @@ module Gitlab
def ldap_config
@ldap_config ||= Gitlab::Auth::Ldap::Config.new(self.provider)
end
+
+ # Overrding this method as LDAP allows email as the username !
+ override :get_username
+ def get_username
+ username_claims.map { |claim| get_from_auth_hash_or_info(claim) }.find(&:presence)
+ end
end
end
end
diff --git a/lib/gitlab/auth/o_auth/auth_hash.rb b/lib/gitlab/auth/o_auth/auth_hash.rb
index cce08750296..e5ab203044d 100644
--- a/lib/gitlab/auth/o_auth/auth_hash.rb
+++ b/lib/gitlab/auth/o_auth/auth_hash.rb
@@ -96,7 +96,10 @@ module Gitlab
end
def get_username
- username_claims.map { |claim| get_from_auth_hash_or_info(claim) }.find { |name| name.presence }
+ username_claims.map { |claim| get_from_auth_hash_or_info(claim) }
+ .find { |name| name.presence }
+ &.split("@")
+ &.first
end
def username_and_email
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index b5eaf6f7d65..9a8562f2852 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -30648,6 +30648,12 @@ msgstr ""
msgid "NamespaceLimits|Exclusion added successfully"
msgstr ""
+msgid "NamespaceLimits|Export .csv"
+msgstr ""
+
+msgid "NamespaceLimits|Export a csv file with Free Tier anonymized namespace storage usage statistics. This is an asynchronous operation, once the file is generated we will send it to your registered email."
+msgstr ""
+
msgid "NamespaceLimits|Free Tier"
msgstr ""
@@ -30657,6 +30663,9 @@ msgstr ""
msgid "NamespaceLimits|Namespace limits could not be loaded. Reload the page to try again."
msgstr ""
+msgid "NamespaceLimits|Namespaces Statistics"
+msgstr ""
+
msgid "NamespaceLimits|Notifications Limit"
msgstr ""
diff --git a/qa/qa/page/component/badges.rb b/qa/qa/page/component/badges.rb
index 9d2959c010e..8c0907d17b4 100644
--- a/qa/qa/page/component/badges.rb
+++ b/qa/qa/page/component/badges.rb
@@ -16,12 +16,12 @@ module QA
end
view 'app/assets/javascripts/badges/components/badge_list.vue' do
- element :badge_list_content
- element :badge_list
+ element 'badge-list-content'
+ element 'badge-list'
end
view 'app/assets/javascripts/badges/components/badge.vue' do
- element :badge_image_link
+ element 'badge-image-link'
end
def show_badge_add_form
@@ -45,14 +45,14 @@ module QA
end
def has_badge?(badge_name)
- within_element(:badge_list_content) do
- has_element?(:badge_list, text: badge_name)
+ within_element('badge-list-content') do
+ has_element?('badge-list', text: badge_name)
end
end
def has_visible_badge_image_link?(link_url)
- within_element(:badge_list_content) do
- has_element?(:badge_image_link, link_url: link_url)
+ within_element('badge-list-content') do
+ has_element?('badge-image-link', link_url: link_url)
end
end
end
diff --git a/qa/qa/page/component/members/invite_members_modal.rb b/qa/qa/page/component/members/invite_members_modal.rb
index ae51213b3e2..b9d0b382ba1 100644
--- a/qa/qa/page/component/members/invite_members_modal.rb
+++ b/qa/qa/page/component/members/invite_members_modal.rb
@@ -14,7 +14,7 @@ module QA
base.view 'app/assets/javascripts/invite_members/components/invite_modal_base.vue' do
element :invite_button
element :access_level_dropdown
- element :invite_members_modal_content
+ element 'invite-modal'
end
base.view 'app/assets/javascripts/invite_members/components/members_token_select.vue' do
@@ -41,7 +41,7 @@ module QA
def add_member(username, access_level = 'Developer', refresh_page: true)
open_invite_members_modal
- within_element(:invite_members_modal_content) do
+ within_element('invite-modal') do
fill_element(:members_token_select_input, username)
Support::WaitForRequests.wait_for_requests
click_button(username, match: :prefer_exact)
@@ -54,7 +54,7 @@ module QA
def invite_group(group_name, access_level = 'Guest', refresh_page: true)
open_invite_group_modal
- within_element(:invite_members_modal_content) do
+ within_element('invite-modal') do
click_button 'Select a group'
Support::WaitForRequests.wait_for_requests
diff --git a/qa/qa/page/component/members/members_table.rb b/qa/qa/page/component/members/members_table.rb
index b71455373e7..8bc20da83af 100644
--- a/qa/qa/page/component/members/members_table.rb
+++ b/qa/qa/page/component/members/members_table.rb
@@ -39,7 +39,7 @@ module QA
end
base.view 'app/assets/javascripts/members/components/members_tabs.vue' do
- element :groups_list_tab
+ element 'groups-list-tab'
end
base.view 'app/assets/javascripts/members/components/action_buttons/remove_group_link_button.vue' do
@@ -82,7 +82,7 @@ module QA
end
def remove_group(group_name)
- click_element :groups_list_tab
+ click_element 'groups-list-tab'
within_element(:member_row, text: group_name) do
click_element :remove_group_link_button
@@ -92,7 +92,7 @@ module QA
end
def has_group?(group_name)
- click_element :groups_list_tab
+ click_element 'groups-list-tab'
has_element?(:member_row, text: group_name)
end
end
diff --git a/qa/qa/page/dashboard/welcome.rb b/qa/qa/page/dashboard/welcome.rb
index 6f645e168c7..a7c293a2661 100644
--- a/qa/qa/page/dashboard/welcome.rb
+++ b/qa/qa/page/dashboard/welcome.rb
@@ -5,11 +5,11 @@ module QA
module Dashboard
class Welcome < Page::Base
view 'app/views/dashboard/projects/_zero_authorized_projects.html.haml' do
- element :welcome_title_content
+ element 'welcome-title-content'
end
def has_welcome_title?(text)
- has_element?(:welcome_title_content, text: text)
+ has_element?('welcome-title-content', text: text)
end
def self.path
diff --git a/qa/qa/page/search/results.rb b/qa/qa/page/search/results.rb
index 1fbd9a75dc5..9e56d000070 100644
--- a/qa/qa/page/search/results.rb
+++ b/qa/qa/page/search/results.rb
@@ -40,7 +40,7 @@ module QA
end
def has_project?(project_name)
- has_element?(:project_content, project_name: project_name)
+ has_element?('project-content', project_name: project_name)
end
private
diff --git a/spec/features/merge_request/user_views_open_merge_request_spec.rb b/spec/features/merge_request/user_views_open_merge_request_spec.rb
index 1a9d40ae926..bc93e6caccb 100644
--- a/spec/features/merge_request/user_views_open_merge_request_spec.rb
+++ b/spec/features/merge_request/user_views_open_merge_request_spec.rb
@@ -7,18 +7,6 @@ RSpec.describe 'User views an open merge request', feature_category: :code_revie
create(:merge_request, source_project: project, target_project: project, description: '# Description header')
end
- context 'feature flags' do
- let_it_be(:project) { create(:project, :public, :repository) }
-
- it 'pushes content_editor_on_issues feature flag to frontend' do
- stub_feature_flags(content_editor_on_issues: true)
-
- visit merge_request_path(merge_request)
-
- expect(page).to have_pushed_frontend_feature_flags(contentEditorOnIssues: true)
- end
- end
-
context 'when a merge request does not have repository' do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_environments_dropdown_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_environments_dropdown_spec.js
index 7942950494b..353b5fd3c47 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_environments_dropdown_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_environments_dropdown_spec.js
@@ -10,7 +10,6 @@ describe('Ci environments dropdown', () => {
const defaultProps = {
areEnvironmentsLoading: false,
environments: envs,
- hasEnvScopeQuery: false,
selectedEnvironmentScope: '',
};
@@ -51,32 +50,23 @@ describe('Ci environments dropdown', () => {
});
describe('Search term is empty', () => {
- describe.each`
- hasEnvScopeQuery | status | defaultEnvStatus | firstItemValue | envIndices
- ${true} | ${'exists'} | ${'prepends'} | ${'*'} | ${[1, 2, 3]}
- ${false} | ${'does not exist'} | ${'does not prepend'} | ${envs[0]} | ${[0, 1, 2]}
- `(
- 'when query for fetching environment scope $status',
- ({ defaultEnvStatus, firstItemValue, hasEnvScopeQuery, envIndices }) => {
- beforeEach(() => {
- createComponent({ props: { environments: envs, hasEnvScopeQuery } });
- });
-
- it(`${defaultEnvStatus} * in listbox`, () => {
- expect(findListboxItemByIndex(0).text()).toBe(firstItemValue);
- });
-
- it('renders all environments', () => {
- expect(findListboxItemByIndex(envIndices[0]).text()).toBe(envs[0]);
- expect(findListboxItemByIndex(envIndices[1]).text()).toBe(envs[1]);
- expect(findListboxItemByIndex(envIndices[2]).text()).toBe(envs[2]);
- });
-
- it('does not display active checkmark', () => {
- expect(findActiveIconByIndex(0).classes('gl-visibility-hidden')).toBe(true);
- });
- },
- );
+ beforeEach(() => {
+ createComponent({ props: { environments: envs } });
+ });
+
+ it(`prepends * in listbox`, () => {
+ expect(findListboxItemByIndex(0).text()).toBe('*');
+ });
+
+ it('renders all environments', () => {
+ expect(findListboxItemByIndex(1).text()).toBe(envs[0]);
+ expect(findListboxItemByIndex(2).text()).toBe(envs[1]);
+ expect(findListboxItemByIndex(3).text()).toBe(envs[2]);
+ });
+
+ it('does not display active checkmark', () => {
+ expect(findActiveIconByIndex(0).classes('gl-visibility-hidden')).toBe(true);
+ });
});
describe('when `*` is the value of selectedEnvironmentScope props', () => {
@@ -92,40 +82,13 @@ describe('Ci environments dropdown', () => {
});
});
- describe('when environments are not fetched via graphql', () => {
+ describe('when fetching environments', () => {
const currentEnv = envs[2];
beforeEach(() => {
createComponent();
});
- it('filters on the frontend and renders only the environment searched for', async () => {
- await findListbox().vm.$emit('search', currentEnv);
-
- expect(findAllListboxItems()).toHaveLength(1);
- expect(findListboxItemByIndex(0).text()).toBe(currentEnv);
- });
-
- it('does not emit event when searching', async () => {
- expect(wrapper.emitted('search-environment-scope')).toBeUndefined();
-
- await findListbox().vm.$emit('search', currentEnv);
-
- expect(wrapper.emitted('search-environment-scope')).toBeUndefined();
- });
-
- it('does not display note about max environments shown', () => {
- expect(findMaxEnvNote().exists()).toBe(false);
- });
- });
-
- describe('when fetching environments via graphql', () => {
- const currentEnv = envs[2];
-
- beforeEach(() => {
- createComponent({ props: { hasEnvScopeQuery: true } });
- });
-
it('renders dropdown divider', () => {
expect(findDropdownDivider().exists()).toBe(true);
});
@@ -137,7 +100,7 @@ describe('Ci environments dropdown', () => {
});
it('renders dropdown loading icon while fetch query is loading', () => {
- createComponent({ props: { areEnvironmentsLoading: true, hasEnvScopeQuery: true } });
+ createComponent({ props: { areEnvironmentsLoading: true } });
expect(findListbox().props('loading')).toBe(true);
expect(findListbox().props('searching')).toBe(false);
@@ -145,7 +108,7 @@ describe('Ci environments dropdown', () => {
});
it('renders search loading icon while search query is loading and dropdown is open', async () => {
- createComponent({ props: { areEnvironmentsLoading: true, hasEnvScopeQuery: true } });
+ createComponent({ props: { areEnvironmentsLoading: true } });
await findListbox().vm.$emit('shown');
expect(findListbox().props('loading')).toBe(false);
@@ -185,7 +148,7 @@ describe('Ci environments dropdown', () => {
describe('when creating a new environment scope from a search term', () => {
const searchTerm = 'new-env';
beforeEach(() => {
- createComponent({ searchTerm, props: { hasEnvScopeQuery: true } });
+ createComponent({ searchTerm });
});
it('sets new environment scope as the selected environment scope', async () => {
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_variable_modal_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_variable_modal_spec.js
index 7dce23f72c0..5ba9b3b8c20 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_variable_modal_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_variable_modal_spec.js
@@ -12,12 +12,10 @@ import {
ENVIRONMENT_SCOPE_LINK_TITLE,
AWS_TIP_TITLE,
AWS_TIP_MESSAGE,
- groupString,
instanceString,
- projectString,
variableOptions,
} from '~/ci/ci_variable_list/constants';
-import { mockEnvs, mockVariablesWithScopes, mockVariablesWithUniqueScopes } from '../mocks';
+import { mockVariablesWithScopes } from '../mocks';
import ModalStub from '../stubs';
describe('Ci variable modal', () => {
@@ -46,7 +44,6 @@ describe('Ci variable modal', () => {
areScopedVariablesAvailable: true,
environments: [],
hideEnvironmentScope: false,
- hasEnvScopeQuery: false,
mode: ADD_VARIABLE_ACTION,
selectedVariable: {},
variables: [],
@@ -352,42 +349,6 @@ describe('Ci variable modal', () => {
expect(link.attributes('title')).toBe(ENVIRONMENT_SCOPE_LINK_TITLE);
expect(link.attributes('href')).toBe(defaultProvide.environmentScopeLink);
});
-
- describe('when query for envioronment scope exists', () => {
- beforeEach(() => {
- createComponent({
- props: {
- environments: mockEnvs,
- hasEnvScopeQuery: true,
- variables: mockVariablesWithUniqueScopes(projectString),
- },
- });
- });
-
- it('does not merge environment scope sources', () => {
- const expectedLength = mockEnvs.length;
-
- expect(findCiEnvironmentsDropdown().props('environments')).toHaveLength(expectedLength);
- });
- });
-
- describe('when feature flag is disabled', () => {
- const mockGroupVariables = mockVariablesWithUniqueScopes(groupString);
- beforeEach(() => {
- createComponent({
- props: {
- environments: mockEnvs,
- variables: mockGroupVariables,
- },
- });
- });
-
- it('merges environment scope sources', () => {
- const expectedLength = mockGroupVariables.length + mockEnvs.length;
-
- expect(findCiEnvironmentsDropdown().props('environments')).toHaveLength(expectedLength);
- });
- });
});
describe('and section is hidden', () => {
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_variable_settings_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_variable_settings_spec.js
index 79dd638e2bd..527c15ffd25 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_variable_settings_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_variable_settings_spec.js
@@ -23,7 +23,6 @@ describe('Ci variable table', () => {
environments: mapEnvironmentNames(mockEnvs),
hideEnvironmentScope: false,
isLoading: false,
- hasEnvScopeQuery: false,
maxVariableLimit: 5,
pageInfo: { after: '' },
variables: mockVariablesWithScopes(projectString),
@@ -70,7 +69,6 @@ describe('Ci variable table', () => {
areEnvironmentsLoading: defaultProps.areEnvironmentsLoading,
areScopedVariablesAvailable: defaultProps.areScopedVariablesAvailable,
environments: defaultProps.environments,
- hasEnvScopeQuery: defaultProps.hasEnvScopeQuery,
hideEnvironmentScope: defaultProps.hideEnvironmentScope,
variables: defaultProps.variables,
mode: ADD_VARIABLE_ACTION,
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js
index 6fa1915f3c1..c90ff4cc682 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js
@@ -52,7 +52,6 @@ const mockProvide = {
const defaultProps = {
areScopedVariablesAvailable: true,
- hasEnvScopeQuery: false,
pageInfo: {},
hideEnvironmentScope: false,
refetchAfterMutation: false,
@@ -514,7 +513,6 @@ describe('Ci Variable Shared Component', () => {
areEnvironmentsLoading: false,
areScopedVariablesAvailable: wrapper.props().areScopedVariablesAvailable,
hideEnvironmentScope: defaultProps.hideEnvironmentScope,
- hasEnvScopeQuery: props.hasEnvScopeQuery,
pageInfo: defaultProps.pageInfo,
isLoading: false,
maxVariableLimit,
diff --git a/spec/frontend/ci/ci_variable_list/mocks.js b/spec/frontend/ci/ci_variable_list/mocks.js
index 41dfc0ebfda..9c9c99ad5ea 100644
--- a/spec/frontend/ci/ci_variable_list/mocks.js
+++ b/spec/frontend/ci/ci_variable_list/mocks.js
@@ -189,7 +189,6 @@ export const createProjectProps = () => {
componentName: 'ProjectVariable',
entity: 'project',
fullPath: '/namespace/project/',
- hasEnvScopeQuery: true,
id: 'gid://gitlab/Project/20',
mutationData: {
[ADD_MUTATION_ACTION]: addProjectVariable,
@@ -214,7 +213,6 @@ export const createGroupProps = () => {
componentName: 'GroupVariable',
entity: 'group',
fullPath: '/my-group',
- hasEnvScopeQuery: false,
id: 'gid://gitlab/Group/20',
mutationData: {
[ADD_MUTATION_ACTION]: addGroupVariable,
@@ -233,7 +231,6 @@ export const createGroupProps = () => {
export const createInstanceProps = () => {
return {
componentName: 'InstanceVariable',
- hasEnvScopeQuery: false,
entity: '',
mutationData: {
[ADD_MUTATION_ACTION]: addAdminVariable,
diff --git a/spec/frontend/ci/ci_variable_list/utils_spec.js b/spec/frontend/ci/ci_variable_list/utils_spec.js
index beeae71376a..fbcf0e7c5a5 100644
--- a/spec/frontend/ci/ci_variable_list/utils_spec.js
+++ b/spec/frontend/ci/ci_variable_list/utils_spec.js
@@ -1,58 +1,7 @@
-import {
- createJoinedEnvironments,
- convertEnvironmentScope,
- mapEnvironmentNames,
-} from '~/ci/ci_variable_list/utils';
+import { convertEnvironmentScope, mapEnvironmentNames } from '~/ci/ci_variable_list/utils';
import { allEnvironments } from '~/ci/ci_variable_list/constants';
describe('utils', () => {
- const environments = ['dev', 'prod'];
- const newEnvironments = ['staging'];
-
- describe('createJoinedEnvironments', () => {
- it('returns only `environments` if `variables` argument is undefined', () => {
- const variables = undefined;
-
- expect(createJoinedEnvironments(variables, environments, [])).toEqual(environments);
- });
-
- it('returns a list of environments and environment scopes taken from variables in alphabetical order', () => {
- const envScope1 = 'new1';
- const envScope2 = 'new2';
-
- const variables = [{ environmentScope: envScope1 }, { environmentScope: envScope2 }];
-
- expect(createJoinedEnvironments(variables, environments, [])).toEqual([
- environments[0],
- envScope1,
- envScope2,
- environments[1],
- ]);
- });
-
- it('returns combined list with new environments included', () => {
- const variables = undefined;
-
- expect(createJoinedEnvironments(variables, environments, newEnvironments)).toEqual([
- ...environments,
- ...newEnvironments,
- ]);
- });
-
- it('removes duplicate environments', () => {
- const envScope1 = environments[0];
- const envScope2 = 'new2';
-
- const variables = [{ environmentScope: envScope1 }, { environmentScope: envScope2 }];
-
- expect(createJoinedEnvironments(variables, environments, [])).toEqual([
- environments[0],
- envScope2,
- environments[1],
- ]);
- });
- });
-
describe('convertEnvironmentScope', () => {
it('converts the * to the `All environments` text', () => {
expect(convertEnvironmentScope('*')).toBe(allEnvironments.text);
diff --git a/spec/frontend/content_editor/services/markdown_serializer_spec.js b/spec/frontend/content_editor/services/markdown_serializer_spec.js
index 3eb00f69345..548c6030ed7 100644
--- a/spec/frontend/content_editor/services/markdown_serializer_spec.js
+++ b/spec/frontend/content_editor/services/markdown_serializer_spec.js
@@ -206,6 +206,14 @@ describe('markdownSerializer', () => {
);
});
+ it('correctly serializes a malformed URL-encoded link', () => {
+ expect(
+ serialize(
+ paragraph(link({ href: 'https://example.com/%E0%A4%A' }, 'https://example.com/%E0%A4%A')),
+ ),
+ ).toBe('https://example.com/%E0%A4%A');
+ });
+
it('correctly serializes a link with a title', () => {
expect(
serialize(
diff --git a/spec/frontend/design_management/components/design_description/description_form_spec.js b/spec/frontend/design_management/components/design_description/description_form_spec.js
index f7feff98da3..7d68a3b80d5 100644
--- a/spec/frontend/design_management/components/design_description/description_form_spec.js
+++ b/spec/frontend/design_management/components/design_description/description_form_spec.js
@@ -42,7 +42,6 @@ describe('Design description form', () => {
showEditor = false,
isSubmitting = false,
designVariables = mockDesignVariables,
- contentEditorOnIssues = false,
designUpdateMutationHandler = mockDesignUpdateMutationHandler,
} = {}) => {
mockApollo = createMockApollo([[updateDesignDescriptionMutation, designUpdateMutationHandler]]);
@@ -52,11 +51,6 @@ describe('Design description form', () => {
markdownPreviewPath: '/gitlab-org/gitlab-test/preview_markdown?target_type=Issue',
designVariables,
},
- provide: {
- glFeatures: {
- contentEditorOnIssues,
- },
- },
apolloProvider: mockApollo,
data() {
return {
@@ -131,7 +125,7 @@ describe('Design description form', () => {
expect(findMarkdownEditor().props()).toMatchObject({
value: 'Test description',
renderMarkdownPath: '/gitlab-org/gitlab-test/preview_markdown?target_type=Issue',
- enableContentEditor: false,
+ enableContentEditor: true,
formFieldProps,
autofocus: true,
enableAutocomplete: true,
diff --git a/spec/frontend/issues/show/components/description_spec.js b/spec/frontend/issues/show/components/description_spec.js
index 93860aaa925..25e89db7957 100644
--- a/spec/frontend/issues/show/components/description_spec.js
+++ b/spec/frontend/issues/show/components/description_spec.js
@@ -69,8 +69,8 @@ describe('Description component', () => {
wrapper = shallowMountExtended(Description, {
apolloProvider: mockApollo,
propsData: {
- issueId: 1,
- issueIid: 1,
+ issueId: '1',
+ issueIid: '1',
...initialProps,
...props,
},
diff --git a/spec/frontend/issues/show/components/fields/description_spec.js b/spec/frontend/issues/show/components/fields/description_spec.js
index 83b927d3699..e1d2809be9d 100644
--- a/spec/frontend/issues/show/components/fields/description_spec.js
+++ b/spec/frontend/issues/show/components/fields/description_spec.js
@@ -10,7 +10,7 @@ describe('Description field component', () => {
let trackingSpy;
const findMarkdownEditor = () => wrapper.findComponent(MarkdownEditor);
- const mountComponent = ({ description = 'test', contentEditorOnIssues = false } = {}) => {
+ const mountComponent = ({ description = 'test' } = {}) => {
wrapper = shallowMount(DescriptionField, {
attachTo: document.body,
propsData: {
@@ -18,11 +18,6 @@ describe('Description field component', () => {
markdownDocsPath: '/',
value: description,
},
- provide: {
- glFeatures: {
- contentEditorOnIssues,
- },
- },
stubs: {
MarkdownField,
},
@@ -33,15 +28,7 @@ describe('Description field component', () => {
trackingSpy = mockTracking(undefined, null, jest.spyOn);
jest.spyOn(eventHub, '$emit');
- mountComponent({ contentEditorOnIssues: true });
- });
-
- it('passes feature flag to the MarkdownEditorComponent', () => {
- expect(findMarkdownEditor().props('enableContentEditor')).toBe(true);
-
- mountComponent({ contentEditorOnIssues: false });
-
- expect(findMarkdownEditor().props('enableContentEditor')).toBe(false);
+ mountComponent();
});
it('uses the MarkdownEditor component to edit markdown', () => {
diff --git a/spec/frontend/notes/components/comment_form_spec.js b/spec/frontend/notes/components/comment_form_spec.js
index 4ce4ca92440..1309fd79c14 100644
--- a/spec/frontend/notes/components/comment_form_spec.js
+++ b/spec/frontend/notes/components/comment_form_spec.js
@@ -308,15 +308,8 @@ describe('issue_comment_form component', () => {
});
});
- it('hides content editor switcher if feature flag content_editor_on_issues is off', () => {
- mountComponent({ mountFunction: mount, features: { contentEditorOnIssues: false } });
-
- expect(wrapper.text()).not.toContain('Switch to rich text editing');
- });
-
- it('shows content editor switcher if feature flag content_editor_on_issues is on', () => {
- mountComponent({ mountFunction: mount, features: { contentEditorOnIssues: true } });
-
+ it('shows content editor switcher', () => {
+ mountComponent({ mountFunction: mount });
expect(wrapper.text()).toContain('Switch to rich text editing');
});
diff --git a/spec/frontend/notes/components/note_form_spec.js b/spec/frontend/notes/components/note_form_spec.js
index 83779f191f3..e2072ebd04d 100644
--- a/spec/frontend/notes/components/note_form_spec.js
+++ b/spec/frontend/notes/components/note_form_spec.js
@@ -76,14 +76,8 @@ describe('issue_note_form component', () => {
});
});
- it('hides content editor switcher if feature flag content_editor_on_issues is off', () => {
- createComponentWrapper({}, { contentEditorOnIssues: false });
-
- expect(wrapper.text()).not.toContain('Switch to rich text editing');
- });
-
- it('shows content editor switcher if feature flag content_editor_on_issues is on', () => {
- createComponentWrapper({}, { contentEditorOnIssues: true });
+ it('shows content editor switcher', () => {
+ createComponentWrapper();
expect(wrapper.text()).toContain('Switch to rich text editing');
});
diff --git a/spec/lib/gitlab/auth/o_auth/auth_hash_spec.rb b/spec/lib/gitlab/auth/o_auth/auth_hash_spec.rb
index 8c50b2acac6..9382f0f0cd6 100644
--- a/spec/lib/gitlab/auth/o_auth/auth_hash_spec.rb
+++ b/spec/lib/gitlab/auth/o_auth/auth_hash_spec.rb
@@ -90,6 +90,22 @@ RSpec.describe Gitlab::Auth::OAuth::AuthHash, feature_category: :user_management
end
end
+ context 'when username claim is in email format' do
+ let(:info_hash) do
+ {
+ email: nil,
+ name: 'GitLab test',
+ nickname: 'GitLab@gitlabsandbox.onmicrosoft.com',
+ uid: uid_ascii
+ }
+ end
+
+ it 'creates proper email and username fields' do
+ expect(auth_hash.username).to eql 'GitLab'
+ expect(auth_hash.email).to eql 'temp-email-for-oauth-GitLab@gitlab.localhost'
+ end
+ end
+
context 'name not provided' do
before do
info_hash.delete(:name)
diff --git a/spec/models/bulk_imports/entity_spec.rb b/spec/models/bulk_imports/entity_spec.rb
index 90b462ea515..3e98ba0973e 100644
--- a/spec/models/bulk_imports/entity_spec.rb
+++ b/spec/models/bulk_imports/entity_spec.rb
@@ -271,7 +271,7 @@ RSpec.describe BulkImports::Entity, type: :model, feature_category: :importers d
import = build(:bulk_import, source_version: '16.2.0')
entity = build(:bulk_import_entity, :project_entity, bulk_import: import)
- expect(entity.export_relations_url_path)
+ expect(entity.export_relations_url_path(batched: true))
.to eq("/projects/#{entity.source_xid}/export_relations?batched=true")
end
end
@@ -280,7 +280,7 @@ RSpec.describe BulkImports::Entity, type: :model, feature_category: :importers d
it 'returns export relations url' do
entity = build(:bulk_import_entity)
- expect(entity.export_relations_url_path)
+ expect(entity.export_relations_url_path(batched: true))
.to eq("/groups/#{entity.source_xid}/export_relations")
end
end
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index cd40a9f9c7d..96ef36a5b75 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -3456,13 +3456,6 @@ RSpec.describe Group, feature_category: :groups_and_projects do
end
end
- describe '#content_editor_on_issues_feature_flag_enabled?' do
- it_behaves_like 'checks self and root ancestor feature flag' do
- let(:feature_flag) { :content_editor_on_issues }
- let(:feature_flag_method) { :content_editor_on_issues_feature_flag_enabled? }
- end
- end
-
describe '#work_items_feature_flag_enabled?' do
it_behaves_like 'checks self and root ancestor feature flag' do
let(:feature_flag) { :work_items }
diff --git a/spec/models/integrations/discord_spec.rb b/spec/models/integrations/discord_spec.rb
index 76b5e89d04f..bff4529211f 100644
--- a/spec/models/integrations/discord_spec.rb
+++ b/spec/models/integrations/discord_spec.rb
@@ -3,7 +3,7 @@
require "spec_helper"
RSpec.describe Integrations::Discord, feature_category: :integrations do
- it_behaves_like "chat integration", "Discord notifications" do
+ it_behaves_like "chat integration", "Discord notifications", supports_deployments: true do
let(:client) { Discordrb::Webhooks::Client }
let(:client_arguments) { { url: webhook_url } }
let(:payload) do
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 23306e46237..2126e6a4cc2 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -8795,16 +8795,6 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
end
end
- describe '#content_editor_on_issues_feature_flag_enabled?' do
- let_it_be(:group_project) { create(:project, :in_subgroup) }
-
- it_behaves_like 'checks parent group feature flag' do
- let(:feature_flag_method) { :content_editor_on_issues_feature_flag_enabled? }
- let(:feature_flag) { :content_editor_on_issues }
- let(:subject_project) { group_project }
- end
- end
-
describe '#work_items_mvc_feature_flag_enabled?' do
let_it_be(:group_project) { create(:project, :in_subgroup) }
diff --git a/spec/requests/api/ml/mlflow/runs_spec.rb b/spec/requests/api/ml/mlflow/runs_spec.rb
index af04c387830..75b70dd867a 100644
--- a/spec/requests/api/ml/mlflow/runs_spec.rb
+++ b/spec/requests/api/ml/mlflow/runs_spec.rb
@@ -185,7 +185,7 @@ RSpec.describe API::Ml::Mlflow::Runs, feature_category: :mlops do
end
end
- describe 'GET /projects/:id/ml/mlflow/api/2.0/mlflow/runs/search' do
+ describe 'POST /projects/:id/ml/mlflow/api/2.0/mlflow/runs/search' do
let_it_be(:search_experiment) { create(:ml_experiments, user: nil, project: project) }
let_it_be(:first_candidate) do
create(:ml_candidates, experiment: search_experiment, name: 'c', user: nil).tap do |c|
@@ -215,6 +215,8 @@ RSpec.describe API::Ml::Mlflow::Runs, feature_category: :mlops do
}
end
+ let(:request) { post api(route), params: params, headers: headers }
+
it 'searches runs for a project', :aggregate_failures do
is_expected.to have_gitlab_http_status(:ok)
is_expected.to match_response_schema('ml/search_runs')
@@ -231,7 +233,7 @@ RSpec.describe API::Ml::Mlflow::Runs, feature_category: :mlops do
params = default_params.merge(page_token: json_response['next_page_token'])
- get api(route), params: params, headers: headers
+ post api(route), params: params, headers: headers
second_page_response = Gitlab::Json.parse(response.body)
second_page_runs = second_page_response['runs']
diff --git a/spec/services/auto_merge/base_service_spec.rb b/spec/services/auto_merge/base_service_spec.rb
index ba4f49c8c52..325a340a8ae 100644
--- a/spec/services/auto_merge/base_service_spec.rb
+++ b/spec/services/auto_merge/base_service_spec.rb
@@ -309,21 +309,23 @@ RSpec.describe AutoMerge::BaseService, feature_category: :code_review_workflow d
let(:merge_request) { create(:merge_request) }
- where(:can_be_merged, :open, :broken, :discussions, :blocked, :draft, :skip_draft, :result) do
- true | true | false | true | false | false | false | true
- true | true | false | true | false | false | true | true
- true | true | false | true | false | true | true | true
- true | true | false | true | false | true | false | false
- false | true | false | true | false | false | false | false
- true | false | false | true | false | false | false | false
- true | true | true | true | false | false | false | false
- true | true | false | false | false | false | false | false
- true | true | false | true | true | false | false | false
+ where(:can_be_merged, :open, :broken, :discussions, :blocked, :draft, :skip_draft, :skip_blocked, :result) do
+ true | true | false | true | false | false | false | false | true
+ true | true | false | true | false | false | true | true | true
+ true | true | false | true | false | true | true | false | true
+ true | true | false | true | true | false | false | true | true
+ true | true | false | true | false | true | false | false | false
+ false | true | false | true | false | false | false | false | false
+ true | false | false | true | false | false | false | false | false
+ true | true | true | true | false | false | false | false | false
+ true | true | false | false | false | false | false | false | false
+ true | true | false | true | true | false | false | false | false
end
with_them do
before do
allow(service).to receive(:skip_draft_check).and_return(skip_draft)
+ allow(service).to receive(:skip_blocked_check).and_return(skip_blocked)
allow(merge_request).to receive(:can_be_merged_by?).and_return(can_be_merged)
allow(merge_request).to receive(:open?).and_return(open)
allow(merge_request).to receive(:broken?).and_return(broken)
diff --git a/spec/support/shared_examples/models/chat_integration_shared_examples.rb b/spec/support/shared_examples/models/chat_integration_shared_examples.rb
index 0ce54fbc31f..27b9ca901ef 100644
--- a/spec/support/shared_examples/models/chat_integration_shared_examples.rb
+++ b/spec/support/shared_examples/models/chat_integration_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.shared_examples "chat integration" do |integration_name|
+RSpec.shared_examples "chat integration" do |integration_name, supports_deployments: false|
describe "Associations" do
it { is_expected.to belong_to :project }
end
@@ -26,8 +26,14 @@ RSpec.shared_examples "chat integration" do |integration_name|
end
describe '.supported_events' do
- it 'does not support deployment_events' do
- expect(described_class.supported_events).not_to include('deployment')
+ if supports_deployments
+ it 'supports deployment_events' do
+ expect(described_class.supported_events).to include('deployment')
+ end
+ else
+ it 'does not support deployment_events' do
+ expect(described_class.supported_events).not_to include('deployment')
+ end
end
end
@@ -375,7 +381,11 @@ RSpec.shared_examples "chat integration" do |integration_name|
let(:sample_data) { Gitlab::DataBuilder::Deployment.build(deployment, deployment.status, Time.now) }
- it_behaves_like "untriggered #{integration_name} integration"
+ if supports_deployments
+ it_behaves_like "triggered #{integration_name} integration"
+ else
+ it_behaves_like "untriggered #{integration_name} integration"
+ end
end
end
end
diff --git a/spec/workers/bulk_imports/export_request_worker_spec.rb b/spec/workers/bulk_imports/export_request_worker_spec.rb
index 7be25261cdc..0acc44c5cbf 100644
--- a/spec/workers/bulk_imports/export_request_worker_spec.rb
+++ b/spec/workers/bulk_imports/export_request_worker_spec.rb
@@ -127,6 +127,20 @@ RSpec.describe BulkImports::ExportRequestWorker, feature_category: :importers do
described_class.new.perform(entity.id)
end
+
+ context 'when bulk_imports_batched_import_export feature flag is disabled' do
+ it 'requests relation export without batched param' do
+ stub_feature_flags(bulk_imports_batched_import_export: false)
+
+ expected_url = "/projects/#{entity.source_xid}/export_relations"
+
+ expect_next_instance_of(BulkImports::Clients::HTTP) do |client|
+ expect(client).to receive(:post).with(expected_url)
+ end
+
+ described_class.new.perform(entity.id)
+ end
+ end
end
end
diff --git a/spec/workers/bulk_imports/finish_batched_pipeline_worker_spec.rb b/spec/workers/bulk_imports/finish_batched_pipeline_worker_spec.rb
index 5454aeb02b5..5beb11c64aa 100644
--- a/spec/workers/bulk_imports/finish_batched_pipeline_worker_spec.rb
+++ b/spec/workers/bulk_imports/finish_batched_pipeline_worker_spec.rb
@@ -39,7 +39,7 @@ RSpec.describe BulkImports::FinishBatchedPipelineWorker, feature_category: :impo
end
context 'when import is in progress' do
- it 're-enqueues' do
+ it 're-enqueues for any started batches' do
create(:bulk_import_batch_tracker, :started, tracker: pipeline_tracker)
expect(described_class)
@@ -48,6 +48,16 @@ RSpec.describe BulkImports::FinishBatchedPipelineWorker, feature_category: :impo
subject.perform(pipeline_tracker.id)
end
+
+ it 're-enqueues for any created batches' do
+ create(:bulk_import_batch_tracker, :created, tracker: pipeline_tracker)
+
+ expect(described_class)
+ .to receive(:perform_in)
+ .with(described_class::REQUEUE_DELAY, pipeline_tracker.id)
+
+ subject.perform(pipeline_tracker.id)
+ end
end
context 'when pipeline tracker is stale' do
diff --git a/spec/workers/bulk_imports/pipeline_batch_worker_spec.rb b/spec/workers/bulk_imports/pipeline_batch_worker_spec.rb
index 3c33910b62c..78ce52c41b4 100644
--- a/spec/workers/bulk_imports/pipeline_batch_worker_spec.rb
+++ b/spec/workers/bulk_imports/pipeline_batch_worker_spec.rb
@@ -102,6 +102,7 @@ RSpec.describe BulkImports::PipelineBatchWorker, feature_category: :importers do
end
expect(described_class).to receive(:perform_in).with(60, batch.id)
+ expect(BulkImports::FinishBatchedPipelineWorker).not_to receive(:perform_async).with(tracker.id)
subject.perform(batch.id)