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--app/assets/javascripts/gl_field_errors.js11
-rw-r--r--app/assets/javascripts/pages/admin/jobs/index/components/constants.js11
-rw-r--r--app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue31
-rw-r--r--app/assets/javascripts/pages/admin/jobs/index/index.js8
-rw-r--r--app/graphql/types/deployment_details_type.rb4
-rw-r--r--app/graphql/types/deployment_type.rb2
-rw-r--r--app/helpers/nav/top_nav_helper.rb78
-rw-r--r--app/models/merge_request.rb6
-rw-r--r--app/services/merge_requests/after_create_service.rb2
-rw-r--r--app/services/merge_requests/create_service.rb7
-rw-r--r--app/views/layouts/header/_default.html.haml15
-rw-r--r--config/feature_flags/development/async_merge_request_diff_creation.yml8
-rw-r--r--config/feature_flags/development/new_navbar_layout.yml8
-rw-r--r--config/feature_flags/development/remove_extra_primary_submenu_options.yml8
-rw-r--r--db/post_migrate/20221010141500_add_index_author_id_target_project_id_on_merge_requests.rb15
-rw-r--r--db/schema_migrations/202210101415001
-rw-r--r--db/structure.sql2
-rw-r--r--doc/api/graphql/reference/index.md64
-rw-r--r--doc/api/projects.md36
-rw-r--r--doc/api/users.md2
-rw-r--r--doc/user/admin_area/moderate_users.md2
-rw-r--r--doc/user/group/manage.md7
-rw-r--r--doc/user/profile/personal_access_tokens.md6
-rw-r--r--doc/user/project/members/index.md15
-rw-r--r--lib/api/entities/pull_mirror.rb17
-rw-r--r--lib/gitlab/nav/top_nav_view_model_builder.rb5
-rw-r--r--locale/gitlab.pot21
-rw-r--r--qa/qa/page/main/menu.rb14
-rw-r--r--qa/qa/support/formatters/allure_metadata_formatter.rb16
-rw-r--r--qa/qa/support/formatters/test_stats_formatter.rb1
-rw-r--r--qa/spec/support/formatters/test_stats_formatter_spec.rb15
-rw-r--r--spec/features/cycle_analytics_spec.rb8
-rw-r--r--spec/fixtures/api/schemas/project_mirror.json48
-rw-r--r--spec/frontend/fixtures/static/gl_field_errors.html3
-rw-r--r--spec/frontend/gl_field_errors_spec.js2
-rw-r--r--spec/graphql/types/deployment_details_type_spec.rb2
-rw-r--r--spec/helpers/nav/top_nav_helper_spec.rb126
-rw-r--r--spec/models/merge_request_spec.rb28
-rw-r--r--spec/requests/projects/cycle_analytics_events_spec.rb4
-rw-r--r--spec/services/merge_requests/create_service_spec.rb37
40 files changed, 419 insertions, 277 deletions
diff --git a/app/assets/javascripts/gl_field_errors.js b/app/assets/javascripts/gl_field_errors.js
index eec7a138ea7..28aa9906116 100644
--- a/app/assets/javascripts/gl_field_errors.js
+++ b/app/assets/javascripts/gl_field_errors.js
@@ -15,9 +15,14 @@ export default class GlFieldErrors {
initValidators() {
// register selectors here as needed
- const validateSelectors = [':text', ':password', '[type=email]', '[type=url]', '[type=number]']
- .map((selector) => `input${selector}`)
- .join(',');
+ const validateSelectors = [
+ 'input:text',
+ 'input:password',
+ 'input[type=email]',
+ 'input[type=url]',
+ 'input[type=number]',
+ 'textarea',
+ ].join(',');
this.state.inputs = this.form
.find(validateSelectors)
diff --git a/app/assets/javascripts/pages/admin/jobs/index/components/constants.js b/app/assets/javascripts/pages/admin/jobs/index/components/constants.js
new file mode 100644
index 00000000000..9e2d464bc4d
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/jobs/index/components/constants.js
@@ -0,0 +1,11 @@
+import { s__, __ } from '~/locale';
+
+export const STOP_JOBS_MODAL_ID = 'stop-jobs-modal';
+export const STOP_JOBS_MODAL_TITLE = s__('AdminArea|Stop all jobs?');
+export const STOP_JOBS_BUTTON_TEXT = s__('AdminArea|Stop all jobs');
+export const CANCEL_TEXT = __('Cancel');
+export const STOP_JOBS_FAILED_TEXT = s__('AdminArea|Stopping jobs failed');
+export const PRIMARY_ACTION_TEXT = s__('AdminArea|Stop jobs');
+export const STOP_JOBS_WARNING = s__(
+ 'AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running.',
+);
diff --git a/app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue b/app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue
index 4f42ef2892d..b608b3b9492 100644
--- a/app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue
+++ b/app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue
@@ -3,7 +3,14 @@ import { GlModal } from '@gitlab/ui';
import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { redirectTo } from '~/lib/utils/url_utility';
-import { __, s__ } from '~/locale';
+import {
+ CANCEL_TEXT,
+ STOP_JOBS_MODAL_ID,
+ STOP_JOBS_FAILED_TEXT,
+ STOP_JOBS_MODAL_TITLE,
+ STOP_JOBS_WARNING,
+ PRIMARY_ACTION_TEXT,
+} from './constants';
export default {
components: {
@@ -15,13 +22,6 @@ export default {
required: true,
},
},
- computed: {
- text() {
- return s__(
- 'AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running.',
- );
- },
- },
methods: {
onSubmit() {
return axios
@@ -32,30 +32,33 @@ export default {
})
.catch((error) => {
createAlert({
- message: s__('AdminArea|Stopping jobs failed'),
+ message: STOP_JOBS_FAILED_TEXT,
});
throw error;
});
},
},
primaryAction: {
- text: s__('AdminArea|Stop jobs'),
+ text: PRIMARY_ACTION_TEXT,
attributes: [{ variant: 'danger' }],
},
cancelAction: {
- text: __('Cancel'),
+ text: CANCEL_TEXT,
},
+ STOP_JOBS_WARNING,
+ STOP_JOBS_MODAL_ID,
+ STOP_JOBS_MODAL_TITLE,
};
</script>
<template>
<gl-modal
- modal-id="stop-jobs-modal"
+ :modal-id="$options.STOP_JOBS_MODAL_ID"
:action-primary="$options.primaryAction"
:action-cancel="$options.cancelAction"
@primary="onSubmit"
>
- <template #modal-title>{{ s__('AdminArea|Stop all jobs?') }}</template>
- {{ text }}
+ <template #modal-title>{{ $options.STOP_JOBS_MODAL_TITLE }}</template>
+ {{ $options.STOP_JOBS_WARNING }}
</gl-modal>
</template>
diff --git a/app/assets/javascripts/pages/admin/jobs/index/index.js b/app/assets/javascripts/pages/admin/jobs/index/index.js
index 4cd312b403c..c82b186f671 100644
--- a/app/assets/javascripts/pages/admin/jobs/index/index.js
+++ b/app/assets/javascripts/pages/admin/jobs/index/index.js
@@ -1,29 +1,29 @@
import Vue from 'vue';
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
import Translate from '~/vue_shared/translate';
+import { STOP_JOBS_MODAL_ID } from './components/constants';
import StopJobsModal from './components/stop_jobs_modal.vue';
Vue.use(Translate);
function initJobs() {
const buttonId = 'js-stop-jobs-button';
- const modalId = 'stop-jobs-modal';
const stopJobsButton = document.getElementById(buttonId);
if (stopJobsButton) {
// eslint-disable-next-line no-new
new Vue({
- el: `#js-${modalId}`,
+ el: `#js-${STOP_JOBS_MODAL_ID}`,
components: {
StopJobsModal,
},
mounted() {
stopJobsButton.classList.remove('disabled');
stopJobsButton.addEventListener('click', () => {
- this.$root.$emit(BV_SHOW_MODAL, modalId, `#${buttonId}`);
+ this.$root.$emit(BV_SHOW_MODAL, STOP_JOBS_MODAL_ID, `#${buttonId}`);
});
},
render(createElement) {
- return createElement(modalId, {
+ return createElement(STOP_JOBS_MODAL_ID, {
props: {
url: stopJobsButton.dataset.url,
},
diff --git a/app/graphql/types/deployment_details_type.rb b/app/graphql/types/deployment_details_type.rb
index f8ba0cb1b24..bbb5cc8e3f1 100644
--- a/app/graphql/types/deployment_details_type.rb
+++ b/app/graphql/types/deployment_details_type.rb
@@ -5,7 +5,7 @@ module Types
graphql_name 'DeploymentDetails'
description 'The details of the deployment'
authorize :read_deployment
- present_using Deployments::DeploymentPresenter
+ present_using ::Deployments::DeploymentPresenter
field :tags,
[Types::DeploymentTagType],
@@ -13,3 +13,5 @@ module Types
calls_gitaly: true
end
end
+
+Types::DeploymentDetailsType.prepend_mod_with('Types::DeploymentDetailsType')
diff --git a/app/graphql/types/deployment_type.rb b/app/graphql/types/deployment_type.rb
index 70a3a4cb574..59b59dc4e1d 100644
--- a/app/graphql/types/deployment_type.rb
+++ b/app/graphql/types/deployment_type.rb
@@ -11,7 +11,7 @@ module Types
graphql_name 'Deployment'
description 'The deployment of an environment'
- present_using Deployments::DeploymentPresenter
+ present_using ::Deployments::DeploymentPresenter
authorize :read_deployment
diff --git a/app/helpers/nav/top_nav_helper.rb b/app/helpers/nav/top_nav_helper.rb
index 32d3f4aebb4..751900f4593 100644
--- a/app/helpers/nav/top_nav_helper.rb
+++ b/app/helpers/nav/top_nav_helper.rb
@@ -281,76 +281,28 @@ module Nav
end
def projects_submenu_items(builder:)
- if Feature.enabled?(:remove_extra_primary_submenu_options)
- title = _('View all projects')
-
- builder.add_primary_menu_item(
- id: 'your',
- title: title,
- href: dashboard_projects_path,
- data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
- )
- else
- # These project links come from `app/views/layouts/nav/projects_dropdown/_show.html.haml`
- [
- { id: 'your', title: _('Your projects'), href: dashboard_projects_path },
- { id: 'starred', title: _('Starred projects'), href: starred_dashboard_projects_path },
- { id: 'explore', title: _('Explore projects'), href: explore_root_path },
- { id: 'topics', title: _('Explore topics'), href: topics_explore_projects_path }
- ].each do |item|
- builder.add_primary_menu_item(
- **item,
- data: { qa_selector: 'menu_item_link', qa_title: item[:title], **menu_data_tracking_attrs(item[:title]) }
- )
- end
-
- title = _('Create new project')
-
- builder.add_secondary_menu_item(
- id: 'create',
- title: title,
- href: new_project_path,
- data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
- )
- end
+ title = _('View all projects')
+
+ builder.add_primary_menu_item(
+ id: 'your',
+ title: title,
+ href: dashboard_projects_path,
+ data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
+ )
end
def groups_submenu
# These group links come from `app/views/layouts/nav/groups_dropdown/_show.html.haml`
builder = ::Gitlab::Nav::TopNavMenuBuilder.new
- if Feature.enabled?(:remove_extra_primary_submenu_options)
- title = _('View all groups')
-
- builder.add_primary_menu_item(
- id: 'your',
- title: title,
- href: dashboard_groups_path,
- data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
- )
- else
- [
- { id: 'your', title: _('Your groups'), href: dashboard_groups_path },
- { id: 'explore', title: _('Explore groups'), href: explore_groups_path }
- ].each do |item|
- builder.add_primary_menu_item(
- **item,
- data: { qa_selector: 'menu_item_link', qa_title: item[:title], **menu_data_tracking_attrs(item[:title]) }
- )
- end
-
- if current_user.can_create_group?
- title = _('Create group')
-
- builder.add_secondary_menu_item(
- id: 'create',
- title: title,
- href: new_group_path,
- data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
- )
- end
- end
+ title = _('View all groups')
+ builder.add_primary_menu_item(
+ id: 'your',
+ title: title,
+ href: dashboard_groups_path,
+ data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
+ )
builder.build
end
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index fb20d91fa20..0f47e6d3936 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -136,7 +136,7 @@ class MergeRequest < ApplicationRecord
before_validation :set_draft_status
- after_create :ensure_merge_request_diff
+ after_create :ensure_merge_request_diff, unless: :skip_ensure_merge_request_diff
after_update :clear_memoized_shas
after_update :reload_diff_if_branch_changed
after_commit :ensure_metrics, on: [:create, :update], unless: :importing?
@@ -146,6 +146,10 @@ class MergeRequest < ApplicationRecord
# It allows us to close or modify broken merge requests
attr_accessor :allow_broken
+ # Temporary flag to skip merge_request_diff creation on create.
+ # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100390
+ attr_accessor :skip_ensure_merge_request_diff
+
# Temporary fields to store compare vars
# when creating new merge request
attr_accessor :can_be_created, :compare_commits, :diff_options, :compare
diff --git a/app/services/merge_requests/after_create_service.rb b/app/services/merge_requests/after_create_service.rb
index 9d12eb80eb6..20b32dbc2a0 100644
--- a/app/services/merge_requests/after_create_service.rb
+++ b/app/services/merge_requests/after_create_service.rb
@@ -5,6 +5,8 @@ module MergeRequests
include Gitlab::Utils::StrongMemoize
def execute(merge_request)
+ merge_request.ensure_merge_request_diff
+
prepare_for_mergeability(merge_request)
prepare_merge_request(merge_request)
end
diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb
index 8e0f72eb380..9303b0c4e51 100644
--- a/app/services/merge_requests/create_service.rb
+++ b/app/services/merge_requests/create_service.rb
@@ -34,7 +34,12 @@ module MergeRequests
# callback (e.g. after_create), a database transaction will be
# open while the Gitaly RPC waits. To avoid an idle in transaction
# timeout, we do this before we attempt to save the merge request.
- merge_request.eager_fetch_ref!
+
+ if Feature.enabled?(:async_merge_request_diff_creation, current_user)
+ merge_request.skip_ensure_merge_request_diff = true
+ else
+ merge_request.eager_fetch_ref!
+ end
end
def set_projects!
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index b74dfd4d3a1..0dbeebd0ad0 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -28,7 +28,7 @@
.gl-display-none.gl-sm-display-block
= render "layouts/nav/top_nav"
- - if top_nav_show_search && Feature.enabled?(:new_navbar_layout)
+ - if top_nav_show_search
.navbar-collapse.gl-transition-medium.collapse.gl-mr-auto.global-search-container.hide-when-top-nav-responsive-open
- search_menu_item = top_nav_search_menu_item_attrs
%ul.nav.navbar-nav.gl-w-full.gl-align-items-center
@@ -42,21 +42,10 @@
= link_to search_menu_item.fetch(:href), title: search_menu_item.fetch(:title), aria: { label: search_menu_item.fetch(:title) }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= sprite_icon(search_menu_item.fetch(:icon))
- .navbar-collapse.gl-transition-medium.collapse{ class: ('global-search-container' unless Feature.enabled?(:new_navbar_layout)) }
+ .navbar-collapse.gl-transition-medium.collapse
%ul.nav.navbar-nav.gl-w-full.gl-align-items-center.gl-justify-content-end
- if current_user
= render 'layouts/header/new_dropdown', class: 'gl-display-none gl-sm-display-block gl-white-space-nowrap gl-text-right'
- - if top_nav_show_search && Feature.disabled?(:new_navbar_layout)
- - search_menu_item = top_nav_search_menu_item_attrs
- %li.nav-item.header-search-new.gl-display-none.gl-lg-display-block.gl-w-full
- - unless current_controller?(:search)
- - if Feature.enabled?(:new_header_search)
- = render 'layouts/header_search'
- - else
- = render 'layouts/search'
- %li.nav-item{ class: 'd-none d-sm-inline-block d-lg-none' }
- = link_to search_menu_item.fetch(:href), title: search_menu_item.fetch(:title), aria: { label: search_menu_item.fetch(:title) }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
- = sprite_icon(search_menu_item.fetch(:icon))
- if header_link?(:issues)
= nav_link(path: 'dashboard#issues', html_options: { class: "user-counter" }) do
= link_to assigned_issues_dashboard_path, title: _('Issues'), class: 'dashboard-shortcuts-issues js-prefetch-document', aria: { label: _('Issues') },
diff --git a/config/feature_flags/development/async_merge_request_diff_creation.yml b/config/feature_flags/development/async_merge_request_diff_creation.yml
new file mode 100644
index 00000000000..8e4bdd13b2b
--- /dev/null
+++ b/config/feature_flags/development/async_merge_request_diff_creation.yml
@@ -0,0 +1,8 @@
+---
+name: async_merge_request_diff_creation
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100390"
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/376759
+milestone: '15.6'
+type: development
+group: group::code review
+default_enabled: false
diff --git a/config/feature_flags/development/new_navbar_layout.yml b/config/feature_flags/development/new_navbar_layout.yml
deleted file mode 100644
index 2d212922fcc..00000000000
--- a/config/feature_flags/development/new_navbar_layout.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: new_navbar_layout
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96853
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/373078
-milestone: '15.4'
-type: development
-group: group::foundations
-default_enabled: true
diff --git a/config/feature_flags/development/remove_extra_primary_submenu_options.yml b/config/feature_flags/development/remove_extra_primary_submenu_options.yml
deleted file mode 100644
index dda22c5d57e..00000000000
--- a/config/feature_flags/development/remove_extra_primary_submenu_options.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: remove_extra_primary_submenu_options
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96931
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/373078
-milestone: '15.4'
-type: development
-group: group::foundations
-default_enabled: true
diff --git a/db/post_migrate/20221010141500_add_index_author_id_target_project_id_on_merge_requests.rb b/db/post_migrate/20221010141500_add_index_author_id_target_project_id_on_merge_requests.rb
new file mode 100644
index 00000000000..5b9d5be2b3f
--- /dev/null
+++ b/db/post_migrate/20221010141500_add_index_author_id_target_project_id_on_merge_requests.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddIndexAuthorIdTargetProjectIdOnMergeRequests < Gitlab::Database::Migration[2.0]
+ INDEX_NAME = 'index_merge_requests_on_author_id_and_target_project_id'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :merge_requests, %i[author_id target_project_id], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :merge_requests, INDEX_NAME
+ end
+end
diff --git a/db/schema_migrations/20221010141500 b/db/schema_migrations/20221010141500
new file mode 100644
index 00000000000..8479fb0519c
--- /dev/null
+++ b/db/schema_migrations/20221010141500
@@ -0,0 +1 @@
+250ec3ff701dacd333d669f128762e9f035a626f2f7720c6e7e1dc61499d431d \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 2dab5e7abc9..13ba431e5e5 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -29481,6 +29481,8 @@ CREATE INDEX index_merge_requests_on_assignee_id ON merge_requests USING btree (
CREATE INDEX index_merge_requests_on_author_id ON merge_requests USING btree (author_id);
+CREATE INDEX index_merge_requests_on_author_id_and_target_project_id ON merge_requests USING btree (author_id, target_project_id);
+
CREATE INDEX index_merge_requests_on_created_at ON merge_requests USING btree (created_at);
CREATE INDEX index_merge_requests_on_description_trigram ON merge_requests USING gin (description gin_trgm_ops);
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 64ac83ef46e..649df9a835a 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -11442,6 +11442,33 @@ The deployment of an environment.
| <a id="deploymenttriggerer"></a>`triggerer` | [`UserCore`](#usercore) | User who executed the deployment. |
| <a id="deploymentupdatedat"></a>`updatedAt` | [`Time`](#time) | When the deployment record was updated. |
+### `DeploymentApproval`
+
+Approval of the deployment.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="deploymentapprovalcomment"></a>`comment` | [`String`](#string) | Additional comment. |
+| <a id="deploymentapprovalcreatedat"></a>`createdAt` | [`Time`](#time) | When the user approved/rejected first time. |
+| <a id="deploymentapprovalstatus"></a>`status` | [`DeploymentsApprovalStatus`](#deploymentsapprovalstatus) | Whether the deployment was approved/rejected. |
+| <a id="deploymentapprovalupdatedat"></a>`updatedAt` | [`Time`](#time) | When the user updated the approval. |
+| <a id="deploymentapprovaluser"></a>`user` | [`UserCore`](#usercore) | User who approved or rejected the deployment. |
+
+### `DeploymentApprovalSummary`
+
+Approval summary of the deployment.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="deploymentapprovalsummaryrules"></a>`rules` | [`[ProtectedEnvironmentApprovalRuleForSummary!]`](#protectedenvironmentapprovalruleforsummary) | Approval Rules for the deployment. |
+| <a id="deploymentapprovalsummarystatus"></a>`status` | [`DeploymentApprovalSummaryStatus`](#deploymentapprovalsummarystatus) | Status of the approvals. |
+| <a id="deploymentapprovalsummarytotalpendingapprovalcount"></a>`totalPendingApprovalCount` | [`Int`](#int) | Total pending approval count. |
+| <a id="deploymentapprovalsummarytotalrequiredapprovals"></a>`totalRequiredApprovals` | [`Int`](#int) | Total number of required approvals. |
+
### `DeploymentDetails`
The details of the deployment.
@@ -11450,6 +11477,7 @@ The details of the deployment.
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="deploymentdetailsapprovalsummary"></a>`approvalSummary` | [`DeploymentApprovalSummary`](#deploymentapprovalsummary) | Approval summary of the deployment. |
| <a id="deploymentdetailscommit"></a>`commit` | [`Commit`](#commit) | Commit details of the deployment. |
| <a id="deploymentdetailscreatedat"></a>`createdAt` | [`Time`](#time) | When the deployment record was created. |
| <a id="deploymentdetailsfinishedat"></a>`finishedAt` | [`Time`](#time) | When the deployment finished. |
@@ -17605,6 +17633,23 @@ Which group, user or role is allowed to approve deployments to the environment.
| <a id="protectedenvironmentapprovalrulerequiredapprovals"></a>`requiredApprovals` | [`Int`](#int) | Number of required approvals. |
| <a id="protectedenvironmentapprovalruleuser"></a>`user` | [`UserCore`](#usercore) | User details. Present if it's user specific access control. |
+### `ProtectedEnvironmentApprovalRuleForSummary`
+
+Which group, user or role is allowed to approve deployments to the environment.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="protectedenvironmentapprovalruleforsummaryaccesslevel"></a>`accessLevel` | [`AccessLevel`](#accesslevel) | Role details. Present if it's role specific access control. |
+| <a id="protectedenvironmentapprovalruleforsummaryapprovals"></a>`approvals` | [`[DeploymentApproval!]`](#deploymentapproval) | Current approvals of the deployment. |
+| <a id="protectedenvironmentapprovalruleforsummaryapprovedcount"></a>`approvedCount` | [`Int`](#int) | Approved count. |
+| <a id="protectedenvironmentapprovalruleforsummarygroup"></a>`group` | [`Group`](#group) | Group details. Present if it's group specific access control. |
+| <a id="protectedenvironmentapprovalruleforsummarypendingapprovalcount"></a>`pendingApprovalCount` | [`Int`](#int) | Pending approval count. |
+| <a id="protectedenvironmentapprovalruleforsummaryrequiredapprovals"></a>`requiredApprovals` | [`Int`](#int) | Number of required approvals. |
+| <a id="protectedenvironmentapprovalruleforsummarystatus"></a>`status` | [`DeploymentApprovalSummaryStatus`](#deploymentapprovalsummarystatus) | Status of the approval summary. |
+| <a id="protectedenvironmentapprovalruleforsummaryuser"></a>`user` | [`UserCore`](#usercore) | User details. Present if it's user specific access control. |
+
### `ProtectedEnvironmentDeployAccessLevel`
Which group, user or role is allowed to execute deployments to the environment.
@@ -20479,6 +20524,16 @@ Weight of the data visualization palette.
| <a id="dependencyproxymanifeststatuspending_destruction"></a>`PENDING_DESTRUCTION` | Dependency proxy manifest has a status of pending_destruction. |
| <a id="dependencyproxymanifeststatusprocessing"></a>`PROCESSING` | Dependency proxy manifest has a status of processing. |
+### `DeploymentApprovalSummaryStatus`
+
+Status of the deployment approval summary.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="deploymentapprovalsummarystatusapproved"></a>`APPROVED` | Summarized deployment approval status that is approved. |
+| <a id="deploymentapprovalsummarystatuspending_approval"></a>`PENDING_APPROVAL` | Summarized deployment approval status that is pending approval. |
+| <a id="deploymentapprovalsummarystatusrejected"></a>`REJECTED` | Summarized deployment approval status that is rejected. |
+
### `DeploymentStatus`
All deployment statuses.
@@ -20505,6 +20560,15 @@ All environment deployment tiers.
| <a id="deploymenttierstaging"></a>`STAGING` | Staging. |
| <a id="deploymenttiertesting"></a>`TESTING` | Testing. |
+### `DeploymentsApprovalStatus`
+
+Status of the deployment approval.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="deploymentsapprovalstatusapproved"></a>`APPROVED` | A deployment approval that is approved. |
+| <a id="deploymentsapprovalstatusrejected"></a>`REJECTED` | A deployment approval that is rejected. |
+
### `DesignCollectionCopyState`
Copy state of a DesignCollection.
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 0eab8e485a8..50a2e1b9f34 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -2830,6 +2830,42 @@ Read more in the [Project members](members.md) documentation.
Read more in the [Project vulnerabilities](project_vulnerabilities.md) documentation.
+## Get a project's pull mirror details **(PREMIUM)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/354506) in GitLab 15.5.
+
+Returns the details of the project's pull mirror.
+
+```plaintext
+GET /projects/:id/mirror/pull
+```
+
+Supported attributes:
+
+| Attribute | Type | Required | Description |
+|:----------|:------|:------------|:------------|
+| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). |
+
+Example request:
+
+```shell
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/:id/mirror/pull"
+```
+
+Example response:
+
+```json
+{
+ "id": 101486,
+ "last_error": null,
+ "last_successful_update_at": "2020-01-06T17:32:02.823Z",
+ "last_update_at": "2020-01-06T17:32:02.823Z",
+ "last_update_started_at": "2020-01-06T17:31:55.864Z",
+ "update_status": "finished",
+ "url": "https://*****:*****@gitlab.com/gitlab-org/security/gitlab.git"
+}
+```
+
## Configure pull mirroring for a project **(PREMIUM)**
> Moved to GitLab Premium in 13.9.
diff --git a/doc/api/users.md b/doc/api/users.md
index dd712cc881c..f4aadfd33db 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -1580,7 +1580,7 @@ Returns:
- `404 User Not Found` if user cannot be found.
- `403 Forbidden` when trying to deactivate a user:
- Blocked by administrator or by LDAP synchronization.
- - That has any activity in past 90 days. These users cannot be deactivated.
+ - That is not [dormant](../user/admin_area/moderate_users.md#automatically-deactivate-dormant-users).
- That is internal.
## Activate user **(FREE SELF)**
diff --git a/doc/user/admin_area/moderate_users.md b/doc/user/admin_area/moderate_users.md
index ace1c6be5f8..52bb376d1fd 100644
--- a/doc/user/admin_area/moderate_users.md
+++ b/doc/user/admin_area/moderate_users.md
@@ -162,7 +162,7 @@ A user can be deactivated from the Admin Area. To do this:
For the deactivation option to be visible to an administrator, the user:
- Must be currently active.
-- Must not have signed in, or have any activity, in the last 90 days.
+- Must not be [dormant](#automatically-deactivate-dormant-users).
NOTE:
Users can also be deactivated using the [GitLab API](../../api/users.md#deactivate-user).
diff --git a/doc/user/group/manage.md b/doc/user/group/manage.md
index f11d9035a52..66d939894c2 100644
--- a/doc/user/group/manage.md
+++ b/doc/user/group/manage.md
@@ -201,6 +201,13 @@ To remove a member from a group:
- To unassign the user from linked issues and merge requests, select the **Also unassign this user from linked issues and merge requests** checkbox.
1. Select **Remove member**.
+## Ensure removed users cannot invite themselves back
+
+Malicious users with the Maintainer or Owner role could exploit a race condition that allows
+them to invite themselves back to a group or project that a GitLab administrator has removed them from.
+
+To avoid this problem, GitLab administrators can [ensure removed users cannot invite themselves back](../project/members/index.md#ensure-removed-users-cannot-invite-themselves-back).
+
## Add projects to a group
There are two different ways to add a new project to a group:
diff --git a/doc/user/profile/personal_access_tokens.md b/doc/user/profile/personal_access_tokens.md
index c7fe68c0609..c5958c4fd11 100644
--- a/doc/user/profile/personal_access_tokens.md
+++ b/doc/user/profile/personal_access_tokens.md
@@ -89,8 +89,10 @@ At any time, you can revoke a personal access token.
## View the last time a token was used
-Token usage is updated once every 24 hours. It is updated each time the token is used to request
-[API resources](../../api/api_resources.md) and the [GraphQL API](../../api/graphql/index.md).
+Token usage information is updated every 24 hours. GitLab considers a token used when the token is used to:
+
+- Authenticate with the [REST](../../api/index.md) or [GraphQL](../../api/graphql/index.md) APIs.
+- Perform a Git operation.
To view the last time a token was used:
diff --git a/doc/user/project/members/index.md b/doc/user/project/members/index.md
index a8f1b634127..61181f157f4 100644
--- a/doc/user/project/members/index.md
+++ b/doc/user/project/members/index.md
@@ -187,6 +187,21 @@ To remove a member from a project:
[from being forked outside their group](../../group/access_and_permissions.md#prevent-project-forking-outside-group).
1. Select **Remove member**.
+## Ensure removed users cannot invite themselves back
+
+Malicious users with the Maintainer or Owner role could exploit a race condition that allows
+them to invite themselves back to a group or project that a GitLab administrator has removed them from.
+
+To avoid this problem, GitLab administrators can:
+
+- Remove the malicious user session from the [GitLab Rails console](../../../administration/operations/rails_console.md).
+- Impersonate the malicious user to:
+ - Remove the user from the project.
+ - Log the user out of GitLab.
+- Block the malicious user account.
+- Remove the malicious user account.
+- Change the password for the malicious user account.
+
## Filter and sort members
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21727) in GitLab 12.6.
diff --git a/lib/api/entities/pull_mirror.rb b/lib/api/entities/pull_mirror.rb
new file mode 100644
index 00000000000..6914a79b18e
--- /dev/null
+++ b/lib/api/entities/pull_mirror.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class PullMirror < Grape::Entity
+ expose :id
+ expose :status, as: :update_status
+ expose :url do |import_state|
+ import_state.project.safe_import_url
+ end
+ expose :last_error
+ expose :last_update_at
+ expose :last_update_started_at
+ expose :last_successful_update_at
+ end
+ end
+end
diff --git a/lib/gitlab/nav/top_nav_view_model_builder.rb b/lib/gitlab/nav/top_nav_view_model_builder.rb
index a8e25708107..8cb2729ff61 100644
--- a/lib/gitlab/nav/top_nav_view_model_builder.rb
+++ b/lib/gitlab/nav/top_nav_view_model_builder.rb
@@ -42,13 +42,10 @@ module Gitlab
def build
menu = @menu_builder.build
- hide_menu_text = Feature.enabled?(:new_navbar_layout)
-
menu.merge({
views: @views,
shortcuts: @shortcuts,
- menuTitle: (_('Menu') unless hide_menu_text),
- menuTooltip: (_('Main menu') if hide_menu_text)
+ menuTooltip: _('Main menu')
}.compact)
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index a31b04ec47b..e4b18209a14 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2689,6 +2689,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -11226,9 +11244,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb
index 2f618224a73..ecd71e7c2f4 100644
--- a/qa/qa/page/main/menu.rb
+++ b/qa/qa/page/main/menu.rb
@@ -64,12 +64,7 @@ module QA
def go_to_groups
within_groups_menu do
- # Remove if statement once :remove_extra_primary_submenu_options ff is enabled by default
- if has_element?(:menu_item_link, title: 'Your groups')
- click_element(:menu_item_link, title: 'Your groups')
- else
- click_element(:menu_item_link, title: 'View all groups')
- end
+ click_element(:menu_item_link, title: 'View all groups')
end
end
@@ -80,12 +75,7 @@ module QA
def go_to_projects
within_projects_menu do
- # Remove if statement once :remove_extra_primary_submenu_options ff is enabled by default
- if has_element?(:menu_item_link, title: 'Your projects')
- click_element(:menu_item_link, title: 'Your projects')
- else
- click_element(:menu_item_link, title: 'View all projects')
- end
+ click_element(:menu_item_link, title: 'View all projects')
end
end
diff --git a/qa/qa/support/formatters/allure_metadata_formatter.rb b/qa/qa/support/formatters/allure_metadata_formatter.rb
index d1baf87799a..02719536b17 100644
--- a/qa/qa/support/formatters/allure_metadata_formatter.rb
+++ b/qa/qa/support/formatters/allure_metadata_formatter.rb
@@ -39,6 +39,7 @@ module QA
add_failure_issues_link(example)
add_ci_job_link(example)
set_flaky_status(example)
+ set_behaviour_categories(example)
end
private
@@ -97,6 +98,19 @@ module QA
log(:error, "Failed to add spec pass rate data for example '#{example.description}', error: #{e}")
end
+ # Add behaviour categories to report
+ #
+ # @param [RSpec::Core::Example] example
+ # @return [void]
+ def set_behaviour_categories(example)
+ file_path = example.file_path.gsub('./qa/specs/features', '')
+ devops_stage = file_path.match(%r{\d{1,2}_(\w+)/})&.captures&.first
+ product_group = example.metadata[:product_group]
+
+ example.epic(devops_stage) if devops_stage
+ example.feature(product_group) if product_group
+ end
+
# Flaky specs with pass rate below 98%
#
# @return [Array]
@@ -107,7 +121,7 @@ module QA
runs = records.count
failed = records.count { |r| r.values["status"] == "failed" }
- pass_rate = 100 - ((failed.to_f / runs.to_f) * 100)
+ pass_rate = 100 - ((failed.to_f / runs) * 100)
# Consider spec with a pass rate less than 98% as flaky
result[records.last.values["testcase"]] = pass_rate if pass_rate < 98
diff --git a/qa/qa/support/formatters/test_stats_formatter.rb b/qa/qa/support/formatters/test_stats_formatter.rb
index 2cde2d0928e..818b0a61120 100644
--- a/qa/qa/support/formatters/test_stats_formatter.rb
+++ b/qa/qa/support/formatters/test_stats_formatter.rb
@@ -72,6 +72,7 @@ module QA
merge_request: merge_request,
run_type: run_type,
stage: devops_stage(file_path),
+ product_group: example.metadata[:product_group],
testcase: example.metadata[:testcase]
},
fields: {
diff --git a/qa/spec/support/formatters/test_stats_formatter_spec.rb b/qa/spec/support/formatters/test_stats_formatter_spec.rb
index d0d89b5ee73..a8e0ae62280 100644
--- a/qa/spec/support/formatters/test_stats_formatter_spec.rb
+++ b/qa/spec/support/formatters/test_stats_formatter_spec.rb
@@ -28,6 +28,7 @@ describe QA::Support::Formatters::TestStatsFormatter do
let(:api_fabrication) { 0 }
let(:fabrication_resources) { {} }
let(:testcase) { 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234' }
+ let(:product_group) { nil }
let(:influx_client_args) do
{
@@ -53,6 +54,7 @@ describe QA::Support::Formatters::TestStatsFormatter do
merge_request: 'false',
run_type: run_type,
stage: stage.match(%r{\d{1,2}_(\w+)}).captures.first,
+ product_group: product_group,
testcase: testcase
},
fields: {
@@ -146,6 +148,19 @@ describe QA::Support::Formatters::TestStatsFormatter do
end
end
+ context 'with product group tag' do
+ let(:product_group) { :import }
+
+ it 'exports data to influxdb with correct reliable tag' do
+ run_spec do
+ it('spec', product_group: :import, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234') {}
+ end
+
+ expect(influx_write_api).to have_received(:write).once
+ expect(influx_write_api).to have_received(:write).with(data: [data])
+ end
+ end
+
context 'with smoke spec' do
let(:smoke) { 'true' }
diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb
index 488a4f84297..8de4c66c62f 100644
--- a/spec/features/cycle_analytics_spec.rb
+++ b/spec/features/cycle_analytics_spec.rb
@@ -56,7 +56,7 @@ RSpec.describe 'Value Stream Analytics', :js do
end
end
- context "when there's value stream analytics data" do
+ context "when there's value stream analytics data", :sidekiq_inline do
# NOTE: in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68595 travel back
# 5 days in time before we create data for these specs, to mitigate some flakiness
# So setting the date range to be the last 2 days should skip past the existing data
@@ -103,7 +103,7 @@ RSpec.describe 'Value Stream Analytics', :js do
end
end
- it 'shows data on each stage', :sidekiq_might_not_need_inline, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/338332' do
+ it 'shows data on each stage', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/338332' do
expect_issue_to_be_present
click_stage('Plan')
@@ -207,11 +207,11 @@ RSpec.describe 'Value Stream Analytics', :js do
wait_for_requests
end
- it 'does not show the commit stats' do
+ it 'does not show the commit stats', :sidekiq_inline do
expect(page.find(metrics_selector)).not_to have_selector("#commits")
end
- it 'does not show restricted stages', :aggregate_failures do
+ it 'does not show restricted stages', :aggregate_failures, :sidekiq_inline do
expect(find(stage_table_selector)).to have_content(issue.title)
expect(page).to have_selector('.gl-path-nav-list-item', text: 'Issue')
diff --git a/spec/fixtures/api/schemas/project_mirror.json b/spec/fixtures/api/schemas/project_mirror.json
new file mode 100644
index 00000000000..0f626c04f24
--- /dev/null
+++ b/spec/fixtures/api/schemas/project_mirror.json
@@ -0,0 +1,48 @@
+{
+ "type": "object",
+ "required": [
+ "id",
+ "url",
+ "update_status",
+ "last_update_at",
+ "last_update_started_at",
+ "last_successful_update_at",
+ "last_error"
+ ],
+ "properties": {
+ "id": {
+ "type": "integer"
+ },
+ "url": {
+ "type": "string"
+ },
+ "update_status": {
+ "type": "string"
+ },
+ "last_update_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "last_update_started_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "last_successful_update_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "last_error": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ },
+ "additionalProperties": false
+} \ No newline at end of file
diff --git a/spec/frontend/fixtures/static/gl_field_errors.html b/spec/frontend/fixtures/static/gl_field_errors.html
index f8470e02b7c..a53366fc29f 100644
--- a/spec/frontend/fixtures/static/gl_field_errors.html
+++ b/spec/frontend/fixtures/static/gl_field_errors.html
@@ -17,6 +17,9 @@
<div class="form-group">
<input class="custom gl-field-error-ignore" type="text">Custom, do not validate</input>
</div>
+<div class="form-group">
+<textarea required title="Textarea is required">Textarea</textarea>
+</div>
<div class="form-group"></div>
<input class="submit" type="submit">Submit</input>
</form>
diff --git a/spec/frontend/gl_field_errors_spec.js b/spec/frontend/gl_field_errors_spec.js
index 92d04927ee5..1f6929baa75 100644
--- a/spec/frontend/gl_field_errors_spec.js
+++ b/spec/frontend/gl_field_errors_spec.js
@@ -27,7 +27,7 @@ describe('GL Style Field Errors', () => {
expect(testContext.fieldErrors).toBeDefined();
const { inputs } = testContext.fieldErrors.state;
- expect(inputs.length).toBe(4);
+ expect(inputs.length).toBe(5);
});
it('should ignore elements with custom error handling', () => {
diff --git a/spec/graphql/types/deployment_details_type_spec.rb b/spec/graphql/types/deployment_details_type_spec.rb
index 70fdc38019e..7dc0c8f97ac 100644
--- a/spec/graphql/types/deployment_details_type_spec.rb
+++ b/spec/graphql/types/deployment_details_type_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe GitlabSchema.types['DeploymentDetails'] do
id iid ref tag tags sha created_at updated_at finished_at status commit job triggerer
]
- expect(described_class).to have_graphql_fields(*expected_fields)
+ expect(described_class).to include_graphql_fields(*expected_fields)
end
specify { expect(described_class).to require_graphql_authorizations(:read_deployment) }
diff --git a/spec/helpers/nav/top_nav_helper_spec.rb b/spec/helpers/nav/top_nav_helper_spec.rb
index 9c396d6bf25..0d43cfaae90 100644
--- a/spec/helpers/nav/top_nav_helper_spec.rb
+++ b/spec/helpers/nav/top_nav_helper_spec.rb
@@ -27,11 +27,9 @@ RSpec.describe Nav::TopNavHelper do
let(:subject) { helper.top_nav_view_model(project: current_project, group: current_group) }
- let(:menu_title) { 'Menu' }
+ let(:menu_tooltip) { 'Main menu' }
before do
- stub_feature_flags(new_navbar_layout: false)
-
allow(Gitlab::CurrentSettings).to receive(:admin_mode) { with_current_settings_admin_mode }
allow(helper).to receive(:header_link?).with(:admin_mode) { with_header_link_admin_mode }
@@ -46,8 +44,8 @@ RSpec.describe Nav::TopNavHelper do
allow(helper).to receive(:dashboard_nav_link?).with(:activity) { with_activity }
end
- it 'has :menuTitle' do
- expect(subject[:menuTitle]).to eq(menu_title)
+ it 'has :menuTooltip' do
+ expect(subject[:menuTooltip]).to eq(menu_tooltip)
end
context 'when current_user is nil (anonymous)' do
@@ -108,7 +106,7 @@ RSpec.describe Nav::TopNavHelper do
let(:current_user) { user }
it 'has no menu items or views by default' do
- expect(subject).to eq({ menuTitle: menu_title,
+ expect(subject).to eq({ menuTooltip: menu_tooltip,
primary: [],
secondary: [],
shortcuts: [],
@@ -176,74 +174,6 @@ RSpec.describe Nav::TopNavHelper do
expect(projects_view[:linksSecondary]).to eq([])
end
- context 'when extra submenu options are not hidden' do
- before do
- stub_feature_flags(remove_extra_primary_submenu_options: false)
- end
-
- it 'has expected :linksPrimary' do
- expected_links_primary = [
- ::Gitlab::Nav::TopNavMenuItem.build(
- data: {
- qa_selector: 'menu_item_link',
- qa_title: 'Your projects',
- **menu_data_tracking_attrs('your_projects')
- },
- href: '/dashboard/projects',
- id: 'your',
- title: 'Your projects'
- ),
- ::Gitlab::Nav::TopNavMenuItem.build(
- data: {
- qa_selector: 'menu_item_link',
- qa_title: 'Starred projects',
- **menu_data_tracking_attrs('starred_projects')
- },
- href: '/dashboard/projects/starred',
- id: 'starred',
- title: 'Starred projects'
- ),
- ::Gitlab::Nav::TopNavMenuItem.build(
- data: {
- qa_selector: 'menu_item_link',
- qa_title: 'Explore projects',
- **menu_data_tracking_attrs('explore_projects')
- },
- href: '/explore',
- id: 'explore',
- title: 'Explore projects'
- ),
- ::Gitlab::Nav::TopNavMenuItem.build(
- data: {
- qa_selector: 'menu_item_link',
- qa_title: 'Explore topics',
- **menu_data_tracking_attrs('explore_topics')
- },
- href: '/explore/projects/topics',
- id: 'topics',
- title: 'Explore topics'
- )
- ]
- expect(projects_view[:linksPrimary]).to eq(expected_links_primary)
- end
-
- it 'has expected :linksSecondary' do
- expected_links_secondary = [
- ::Gitlab::Nav::TopNavMenuItem.build(
- data: {
- qa_selector: 'menu_item_link',
- qa_title: 'Create new project',
- **menu_data_tracking_attrs('create_new_project')
- },
- href: '/projects/new',
- id: 'create',
- title: 'Create new project'
- )
- ]
- expect(projects_view[:linksSecondary]).to eq(expected_links_secondary)
- end
- end
-
context 'with current nav as project' do
before do
helper.nav('project')
@@ -341,54 +271,6 @@ RSpec.describe Nav::TopNavHelper do
expect(groups_view[:linksSecondary]).to eq([])
end
- context 'when extra submenu options are not hidden' do
- before do
- stub_feature_flags(remove_extra_primary_submenu_options: false)
- end
-
- it 'has expected :linksPrimary' do
- expected_links_primary = [
- ::Gitlab::Nav::TopNavMenuItem.build(
- data: {
- qa_selector: 'menu_item_link',
- qa_title: 'Your groups',
- **menu_data_tracking_attrs('your_groups')
- },
- href: '/dashboard/groups',
- id: 'your',
- title: 'Your groups'
- ),
- ::Gitlab::Nav::TopNavMenuItem.build(
- data: {
- qa_selector: 'menu_item_link',
- qa_title: 'Explore groups',
- **menu_data_tracking_attrs('explore_groups')
- },
- href: '/explore/groups',
- id: 'explore',
- title: 'Explore groups'
- )
- ]
- expect(groups_view[:linksPrimary]).to eq(expected_links_primary)
- end
-
- it 'has expected :linksSecondary' do
- expected_links_secondary = [
- ::Gitlab::Nav::TopNavMenuItem.build(
- data: {
- qa_selector: 'menu_item_link',
- qa_title: 'Create group',
- **menu_data_tracking_attrs('create_group')
- },
- href: '/groups/new',
- id: 'create',
- title: 'Create group'
- )
- ]
- expect(groups_view[:linksSecondary]).to eq(expected_links_secondary)
- end
- end
-
context 'with external user' do
let(:current_user) { external_user }
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 32518b867cb..21bba0c270d 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -278,6 +278,34 @@ RSpec.describe MergeRequest, factory_default: :keep do
end
describe 'callbacks' do
+ describe '#ensure_merge_request_diff' do
+ let(:merge_request) { build(:merge_request) }
+
+ context 'when async_merge_request_diff_creation is true' do
+ before do
+ merge_request.skip_ensure_merge_request_diff = true
+ end
+
+ it 'does not create a merge_request_diff after create' do
+ merge_request.save!
+
+ expect(merge_request.merge_request_diff).to be_empty
+ end
+ end
+
+ context 'when async_merge_request_diff_creation is false' do
+ before do
+ merge_request.skip_ensure_merge_request_diff = false
+ end
+
+ it 'creates merge_request_diff after create' do
+ merge_request.save!
+
+ expect(merge_request.merge_request_diff).not_to be_empty
+ end
+ end
+ end
+
describe '#ensure_merge_request_metrics' do
let(:merge_request) { create(:merge_request) }
diff --git a/spec/requests/projects/cycle_analytics_events_spec.rb b/spec/requests/projects/cycle_analytics_events_spec.rb
index 65540f86d34..370febf82ff 100644
--- a/spec/requests/projects/cycle_analytics_events_spec.rb
+++ b/spec/requests/projects/cycle_analytics_events_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe 'value stream analytics events' do
let(:project) { create(:project, :repository, public_builds: false) }
let(:issue) { create(:issue, project: project, created_at: 2.days.ago) }
- describe 'GET /:namespace/:project/value_stream_analytics/events/issues' do
+ describe 'GET /:namespace/:project/value_stream_analytics/events/issues', :sidekiq_inline do
let(:first_issue_iid) { project.issues.sort_by_attribute(:created_desc).pick(:iid).to_s }
let(:first_mr_iid) { project.merge_requests.sort_by_attribute(:created_desc).pick(:iid).to_s }
@@ -65,7 +65,7 @@ RSpec.describe 'value stream analytics events' do
expect(json_response['events'].first['iid']).to eq(first_mr_iid)
end
- it 'lists the staging events', :sidekiq_inline do
+ it 'lists the staging events' do
get project_cycle_analytics_staging_path(project, format: :json)
expect(json_response['events']).not_to be_empty
diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb
index 0bc8258af42..0892b91032b 100644
--- a/spec/services/merge_requests/create_service_spec.rb
+++ b/spec/services/merge_requests/create_service_spec.rb
@@ -495,15 +495,40 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do
project.add_developer(user)
end
- it 'creates the merge request', :sidekiq_might_not_need_inline do
- expect_next_instance_of(MergeRequest) do |instance|
- expect(instance).to receive(:eager_fetch_ref!).and_call_original
+ context 'when async_merge_request_diff_creation is enabled' do
+ before do
+ stub_feature_flags(async_merge_request_diff_creation: true)
end
- merge_request = described_class.new(project: project, current_user: user, params: opts).execute
+ it 'creates the merge request', :sidekiq_inline do
+ expect_next_instance_of(MergeRequest) do |instance|
+ expect(instance).not_to receive(:eager_fetch_ref!)
+ end
- expect(merge_request).to be_persisted
- expect(merge_request.iid).to be > 0
+ merge_request = described_class.new(project: project, current_user: user, params: opts).execute
+
+ expect(merge_request).to be_persisted
+ expect(merge_request.iid).to be > 0
+ expect(merge_request.merge_request_diff).not_to be_empty
+ end
+ end
+
+ context 'when async_merge_request_diff_creation is disabled' do
+ before do
+ stub_feature_flags(async_merge_request_diff_creation: false)
+ end
+
+ it 'creates the merge request' do
+ expect_next_instance_of(MergeRequest) do |instance|
+ expect(instance).to receive(:eager_fetch_ref!).and_call_original
+ end
+
+ merge_request = described_class.new(project: project, current_user: user, params: opts).execute
+
+ expect(merge_request).to be_persisted
+ expect(merge_request.iid).to be > 0
+ expect(merge_request.merge_request_diff).not_to be_empty
+ end
end
it 'does not create the merge request when the target project is archived' do