Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
e83144f0ee
commit
ba2e4183d9
|
@ -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)
|
||||
|
|
|
@ -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.',
|
||||
);
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -281,76 +281,28 @@ module Nav
|
|||
end
|
||||
|
||||
def projects_submenu_items(builder:)
|
||||
if Feature.enabled?(:remove_extra_primary_submenu_options)
|
||||
title = _('View all projects')
|
||||
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
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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') },
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
250ec3ff701dacd333d669f128762e9f035a626f2f7720c6e7e1dc61499d431d
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)**
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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 ""
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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' }
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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) }
|
||||
|
|
|
@ -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 }
|
||||
|
||||
|
|
|
@ -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) }
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue