Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-10-20 06:09:59 +00:00
parent e83144f0ee
commit ba2e4183d9
40 changed files with 418 additions and 276 deletions

View File

@ -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)

View File

@ -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|Youre about to stop all jobs. This will halt all current jobs that are running.',
);

View File

@ -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|Youre 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>

View File

@ -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,
},

View File

@ -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')

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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!

View File

@ -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') },

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
250ec3ff701dacd333d669f128762e9f035a626f2f7720c6e7e1dc61499d431d

View File

@ -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);

View File

@ -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.

View File

@ -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.

View File

@ -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)**

View File

@ -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).

View File

@ -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:

View File

@ -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:

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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 ""

View File

@ -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

View File

@ -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

View File

@ -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: {

View File

@ -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' }

View File

@ -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')

View File

@ -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
}

View File

@ -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>

View File

@ -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', () => {

View File

@ -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) }

View File

@ -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 }

View File

@ -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) }

View File

@ -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

View File

@ -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