Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-06-03 09:08:43 +00:00
parent b646822e52
commit 6be8ed5a95
55 changed files with 3059 additions and 937 deletions

View File

@ -1626,7 +1626,6 @@
.review:rules:review-qa-all:
rules:
- <<: *if-merge-request-labels-run-review-app # we explicitly don't allow the job to fail in that case
- <<: *if-dot-com-gitlab-org-merge-request
changes: *code-patterns
when: manual

View File

@ -126,14 +126,6 @@ export function findDiffFile(files, match, matchKey = 'file_hash') {
return files.find((file) => file[matchKey] === match);
}
export const getReversePosition = (linePosition) => {
if (linePosition === LINE_POSITION_RIGHT) {
return LINE_POSITION_LEFT;
}
return LINE_POSITION_RIGHT;
};
export function getFormData(params) {
const {
commit,

View File

@ -131,6 +131,7 @@
"VulnerabilityLocationSecretDetection"
],
"WorkItemWidget": [
"WorkItemWidgetDescription"
"WorkItemWidgetDescription",
"WorkItemWidgetHierarchy"
]
}

View File

@ -67,17 +67,6 @@ export const parseBooleanDataAttributes = ({ dataset }, names) =>
export const isElementVisible = (element) =>
Boolean(element.offsetWidth || element.offsetHeight || element.getClientRects().length);
/**
* The opposite of `isElementVisible`.
* Returns whether or not the provided element is currently hidden.
* This function operates identically to jQuery's `:hidden` pseudo-selector.
* Documentation for this selector: https://api.jquery.com/hidden-selector/
* Implementation of this selector: https://github.com/jquery/jquery/blob/d0ce00cdfa680f1f0c38460bc51ea14079ae8b07/src/css/hiddenVisibleSelectors.js#L6
* @param {HTMLElement} element The element to test
* @returns {Boolean} `true` if the element is currently hidden, otherwise false
*/
export const isElementHidden = (element) => !isElementVisible(element);
export const getParents = (element) => {
const parents = [];
let parent = element.parentNode;

View File

@ -1,25 +1,4 @@
import dateFormat from 'dateformat';
import { secondsToMilliseconds } from '~/lib/utils/datetime_utility';
import { dateFormatMask } from './constants';
/**
* Returns a time range (`start`, `end`) where `start` is the
* current time minus a given number of seconds and `end`
* is the current time (`now()`).
*
* @param {Number} seconds Seconds duration, defaults to 0.
* @returns {Object} range Time range
* @returns {String} range.start ISO String of current time minus given seconds
* @returns {String} range.end ISO String of current time
*/
export const getTimeRange = (seconds = 0) => {
const end = Math.floor(Date.now() / 1000); // convert milliseconds to seconds
const start = end - seconds;
return {
start: new Date(secondsToMilliseconds(start)).toISOString(),
end: new Date(secondsToMilliseconds(end)).toISOString(),
};
};
export const formatDate = (timestamp) => dateFormat(timestamp, dateFormatMask);

View File

@ -1 +0,0 @@
export const toLabelGid = (id) => `gid://gitlab/Label/${id}`;

View File

@ -233,6 +233,9 @@ export default {
shouldShowSecurityExtension() {
return window.gon?.features?.refactorSecurityExtension;
},
shouldShowCodeQualityExtension() {
return window.gon?.features?.refactorCodeQualityExtension;
},
isRestructuredMrWidgetEnabled() {
return window.gon?.features?.restructuredMrWidget;
},
@ -520,7 +523,7 @@ export default {
}
},
registerCodeQualityExtension() {
if (this.shouldRenderCodeQuality && this.shouldShowExtension) {
if (this.shouldRenderCodeQuality && this.shouldShowCodeQualityExtension) {
registerExtension(codeQualityExtension);
}
},

View File

@ -5,10 +5,12 @@ module SortingPreference
include CookiesHelper
def set_sort_order(field = sorting_field, default_order = default_sort_order)
set_sort_order_from_user_preference(field) ||
set_sort_order_from_cookie(field) ||
params[:sort] ||
default_order
sort_order = set_sort_order_from_user_preference(field) || set_sort_order_from_cookie(field) || params[:sort]
# some types of sorting might not be available on the dashboard
return default_order unless valid_sort_order?(sort_order)
sort_order
end
# Implement sorting_field method on controllers
@ -85,4 +87,11 @@ module SortingPreference
else value
end
end
def valid_sort_order?(sort_order)
return false unless sort_order
return can_sort_by_issue_weight?(action_name == 'issues') if sort_order.include?('weight')
true
end
end

View File

@ -39,6 +39,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:confidential_notes, project)
push_frontend_feature_flag(:restructured_mr_widget, project)
push_frontend_feature_flag(:refactor_mr_widgets_extensions, project)
push_frontend_feature_flag(:refactor_code_quality_extension, project)
push_frontend_feature_flag(:refactor_mr_widget_test_summary, project)
push_frontend_feature_flag(:rebase_without_ci_ui, project)
push_frontend_feature_flag(:issue_assignees_widget, @project)

View File

@ -14,12 +14,15 @@ module Types
case object
when ::WorkItems::Widgets::Description
::Types::WorkItems::Widgets::DescriptionType
when ::WorkItems::Widgets::Hierarchy
::Types::WorkItems::Widgets::HierarchyType
else
raise "Unknown GraphQL type for widget #{object}"
end
end
orphan_types ::Types::WorkItems::Widgets::DescriptionType
orphan_types ::Types::WorkItems::Widgets::DescriptionType,
::Types::WorkItems::Widgets::HierarchyType
end
end
end

View File

@ -0,0 +1,30 @@
# frozen_string_literal: true
module Types
module WorkItems
module Widgets
# Disabling widget level authorization as it might be too granular
# and we already authorize the parent work item
# rubocop:disable Graphql/AuthorizeTypes
class HierarchyType < BaseObject
graphql_name 'WorkItemWidgetHierarchy'
description 'Represents a hierarchy widget'
implements Types::WorkItems::WidgetInterface
field :parent, ::Types::WorkItemType, null: true,
description: 'Parent work item.',
complexity: 5
field :children, ::Types::WorkItemType.connection_type, null: true,
description: 'Child work items.',
complexity: 5
def children
object.children.inc_relations_for_permission_check
end
end
# rubocop:enable Graphql/AuthorizeTypes
end
end
end

View File

@ -267,6 +267,10 @@ module SortingHelper
options.concat([title_option])
end
def can_sort_by_issue_weight?(_viewing_issues)
false
end
def due_date_option
{ value: sort_value_due_date, text: sort_title_due_date, href: page_filter_path(sort: sort_value_due_date) }
end

View File

@ -1010,7 +1010,7 @@ module Ci
end
def collect_test_reports!(test_reports)
test_reports.get_suite(group_name).tap do |test_suite|
test_reports.get_suite(test_suite_name).tap do |test_suite|
each_report(Ci::JobArtifact::TEST_REPORT_FILE_TYPES) do |file_type, blob|
Gitlab::Ci::Parsers.fabricate!(file_type).parse!(
blob,
@ -1184,6 +1184,18 @@ module Ci
private
def test_suite_name
if matrix_build?
name
else
group_name
end
end
def matrix_build?
options.dig(:parallel, :matrix).present?
end
def stick_build_if_status_changed
return unless saved_change_to_status?
return unless running?

View File

@ -1055,7 +1055,7 @@ module Ci
end
def latest_test_report_builds
latest_report_builds(Ci::JobArtifact.test_reports).preload(:project)
latest_report_builds(Ci::JobArtifact.test_reports).preload(:project, :metadata)
end
def builds_with_coverage

View File

@ -11,6 +11,8 @@ class WorkItem < Issue
has_many :work_item_children, through: :child_links, class_name: 'WorkItem',
foreign_key: :work_item_id, source: :work_item
scope :inc_relations_for_permission_check, -> { includes(:author, project: :project_feature) }
def noteable_target_type_name
'issue'
end

View File

@ -21,11 +21,11 @@ module WorkItems
}.freeze
WIDGETS_FOR_TYPE = {
issue: [Widgets::Description],
issue: [Widgets::Description, Widgets::Hierarchy],
incident: [Widgets::Description],
test_case: [Widgets::Description],
requirement: [Widgets::Description],
task: [Widgets::Description]
task: [Widgets::Description, Widgets::Hierarchy]
}.freeze
cache_markdown_field :description, pipeline: :single_line

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
module WorkItems
module Widgets
class Hierarchy < Base
def parent
return unless Feature.enabled?(:work_items_hierarchy, work_item.project)
work_item.work_item_parent
end
def children
return WorkItem.none unless Feature.enabled?(:work_items_hierarchy, work_item.project)
work_item.work_item_children
end
end
end
end

View File

@ -0,0 +1,8 @@
---
name: refactor_code_quality_extension
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/88865
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/363845
milestone: '15.1'
type: development
group: group::secure
default_enabled: false

View File

@ -1,8 +0,0 @@
---
name: usage_data_i_incident_management_oncall_notification_sent
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58606
rollout_issue_url:
milestone: '13.11'
type: development
group: group::respond
default_enabled: true

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
class ScheduleDeleteInvalidEpicIssuesRevised < Gitlab::Database::Migration[1.0]
disable_ddl_transaction!
MIGRATION = 'DeleteInvalidEpicIssues'
INTERVAL = 2.minutes
BATCH_SIZE = 1_000
MAX_BATCH_SIZE = 2_000
SUB_BATCH_SIZE = 50
def up
queue_batched_background_migration(
MIGRATION,
:epics,
:id,
job_interval: INTERVAL,
batch_size: BATCH_SIZE,
max_batch_size: MAX_BATCH_SIZE,
sub_batch_size: SUB_BATCH_SIZE
)
end
def down
delete_batched_background_migration(MIGRATION, :epics, :id, [])
end
end

View File

@ -0,0 +1 @@
57813d4c107938d8e58d6223719c2c67206172342b52655ca4a068c845edeb3a

View File

@ -8811,6 +8811,29 @@ The edge type for [`VulnerabilityScanner`](#vulnerabilityscanner).
| <a id="vulnerabilityscanneredgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="vulnerabilityscanneredgenode"></a>`node` | [`VulnerabilityScanner`](#vulnerabilityscanner) | The item at the end of the edge. |
#### `WorkItemConnection`
The connection type for [`WorkItem`](#workitem).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="workitemconnectionedges"></a>`edges` | [`[WorkItemEdge]`](#workitemedge) | A list of edges. |
| <a id="workitemconnectionnodes"></a>`nodes` | [`[WorkItem]`](#workitem) | A list of nodes. |
| <a id="workitemconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
#### `WorkItemEdge`
The edge type for [`WorkItem`](#workitem).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="workitemedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="workitemedgenode"></a>`node` | [`WorkItem`](#workitem) | The item at the end of the edge. |
#### `WorkItemTypeConnection`
The connection type for [`WorkItemType`](#workitemtype).
@ -9196,6 +9219,10 @@ Represents an epic on an issue board.
| ---- | ---- | ----------- |
| <a id="boardepicauthor"></a>`author` | [`UserCore!`](#usercore) | Author of the epic. |
| <a id="boardepicawardemoji"></a>`awardEmoji` | [`AwardEmojiConnection`](#awardemojiconnection) | List of award emojis associated with the epic. (see [Connections](#connections)) |
| <a id="boardepicblocked"></a>`blocked` | [`Boolean`](#boolean) | Indicates the epic is blocked. |
| <a id="boardepicblockedbycount"></a>`blockedByCount` | [`Int`](#int) | Count of epics blocking this epic. |
| <a id="boardepicblockedbyepics"></a>`blockedByEpics` | [`EpicConnection`](#epicconnection) | Epics blocking this epic. (see [Connections](#connections)) |
| <a id="boardepicblockingcount"></a>`blockingCount` | [`Int`](#int) | Count of epics that this epic is blocking. |
| <a id="boardepicclosedat"></a>`closedAt` | [`Time`](#time) | Timestamp of when the epic was closed. |
| <a id="boardepiccolor"></a>`color` | [`String!`](#string) | Color of the epic. Available only when feature flag `epic_color_highlight` is enabled. This flag is disabled by default, because the feature is experimental and is subject to change without notice. |
| <a id="boardepicconfidential"></a>`confidential` | [`Boolean`](#boolean) | Indicates if the epic is confidential. |
@ -10776,6 +10803,10 @@ Represents an epic.
| ---- | ---- | ----------- |
| <a id="epicauthor"></a>`author` | [`UserCore!`](#usercore) | Author of the epic. |
| <a id="epicawardemoji"></a>`awardEmoji` | [`AwardEmojiConnection`](#awardemojiconnection) | List of award emojis associated with the epic. (see [Connections](#connections)) |
| <a id="epicblocked"></a>`blocked` | [`Boolean`](#boolean) | Indicates the epic is blocked. |
| <a id="epicblockedbycount"></a>`blockedByCount` | [`Int`](#int) | Count of epics blocking this epic. |
| <a id="epicblockedbyepics"></a>`blockedByEpics` | [`EpicConnection`](#epicconnection) | Epics blocking this epic. (see [Connections](#connections)) |
| <a id="epicblockingcount"></a>`blockingCount` | [`Int`](#int) | Count of epics that this epic is blocking. |
| <a id="epicclosedat"></a>`closedAt` | [`Time`](#time) | Timestamp of when the epic was closed. |
| <a id="epiccolor"></a>`color` | [`String!`](#string) | Color of the epic. Available only when feature flag `epic_color_highlight` is enabled. This flag is disabled by default, because the feature is experimental and is subject to change without notice. |
| <a id="epicconfidential"></a>`confidential` | [`Boolean`](#boolean) | Indicates if the epic is confidential. |
@ -17955,6 +17986,18 @@ Represents a description widget.
| <a id="workitemwidgetdescriptiondescriptionhtml"></a>`descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. |
| <a id="workitemwidgetdescriptiontype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. |
### `WorkItemWidgetHierarchy`
Represents a hierarchy widget.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="workitemwidgethierarchychildren"></a>`children` | [`WorkItemConnection`](#workitemconnection) | Child work items. (see [Connections](#connections)) |
| <a id="workitemwidgethierarchyparent"></a>`parent` | [`WorkItem`](#workitem) | Parent work item. |
| <a id="workitemwidgethierarchytype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. |
## Enumeration types
Also called _Enums_, enumeration types are a special kind of scalar that
@ -19730,6 +19773,7 @@ Type of a work item widget.
| Value | Description |
| ----- | ----------- |
| <a id="workitemwidgettypedescription"></a>`DESCRIPTION` | Description widget. |
| <a id="workitemwidgettypehierarchy"></a>`HIERARCHY` | Hierarchy widget. |
## Scalar types
@ -20937,6 +20981,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
Implementations:
- [`WorkItemWidgetDescription`](#workitemwidgetdescription)
- [`WorkItemWidgetHierarchy`](#workitemwidgethierarchy)
##### Fields

View File

@ -107,6 +107,11 @@ use the [`artifacts:when:always`](../yaml/index.md#artifactswhen) keyword.
You cannot have multiple tests with the same name and class in your JUnit report format XML file.
In GitLab 15.0 and earlier, test reports from [parallel:matrix](../yaml/index.md#parallel:matrix)
jobs are aggregated together, which can cause some report information to not be displayed.
In GitLab 15.1 and later, [this bug is fixed](https://gitlab.com/gitlab-org/gitlab/-/issues/296814),
and all report information is displayed.
## View Unit test reports on GitLab
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/24792) in GitLab 12.5 behind a feature flag (`junit_pipeline_view`), disabled by default.

View File

@ -128,9 +128,12 @@ The general flow of contributing to GitLab is:
1. In the merge request's description:
- Ensure you provide complete and accurate information.
- Review the provided checklist.
1. Assign the merge request (if possible) to, or [mention](../../user/discussions/index.md#mentions),
one of the [code owners](../../user/project/code_owners.md) for the relevant project,
and explain that you are ready for review.
1. Once you're ready, mark your MR as ready for review with `@gitlab-bot ready`.
- This will add the `~"workflow::ready for review"` label, and then automatically assign a merge request coach as reviewer.
- If you know a relevant reviewer (e.g. someone that was involved a related issue), you can also
assign them directly with `@gitlab-bot ready @username`.
#### Review process
When you submit code to GitLab, we really want it to get merged! However, we always review
submissions carefully, and this takes time. Code submissions will usually be reviewed by two
@ -139,7 +142,11 @@ submissions carefully, and this takes time. Code submissions will usually be rev
- A [reviewer](../code_review.md#the-responsibility-of-the-reviewer).
- A [maintainer](../code_review.md#the-responsibility-of-the-maintainer).
Keep the following in mind when submitting merge requests:
After review, the reviewer could ask the author to update the merge request. In that case, the reviewer would set the `~"workflow::in dev"` label.
Once the merge request has been updated and set as ready for review again (e.g. with `@gitlab-bot ready`), they will review the code again.
This process may repeat any number of times before merge, to help make the contribution the best it can be.
Lastly, keep the following in mind when submitting merge requests:
- When reviewers are reading through a merge request they may request guidance from other
reviewers.
@ -154,13 +161,11 @@ Keep the following in mind when submitting merge requests:
[approval](../../user/project/merge_requests/approvals/index.md) of merge requests, the
maintainer may require [approvals from certain reviewers](../code_review.md#approval-guidelines)
before merging a merge request.
- After review, the author may be asked to update the merge request. Once the merge request has been
updated and reassigned to the reviewer, they will review the code again. This process may repeat
any number of times before merge, to help make the contribution the best it can be.
- Sometimes a maintainer may choose to close a merge request. They will fully disclose why it will not
be merged, as well as some guidance. The maintainers will be open to discussion about how to change
the code so it can be approved and merged in the future.
Sometimes a maintainer may choose to close a merge request. They will fully disclose why it will not
be merged, as well as some guidance. The maintainers will be open to discussion about how to change
the code so it can be approved and merged in the future.
#### Getting attention on your merge request
GitLab will do its best to review community contributions as quickly as possible. Specially
appointed developers review community contributions daily. Look at the
@ -170,8 +175,9 @@ written some front-end code, you should mention the frontend merge request coach
your code has multiple disciplines, you may mention multiple merge request coaches.
GitLab receives a lot of community contributions. If your code has not been reviewed within two
working days of its initial submission, feel free to mention all merge request coaches with
`@gitlab-org/coaches` to get their attention.
working days of its initial submission, you can ask for help with `@gitlab-bot help`.
#### Addition of external libraries
When submitting code to GitLab, you may feel that your contribution requires the aid of an external
library. If your code includes an external library, please provide a link to the library, as well as

View File

@ -191,11 +191,11 @@ to ignore AMI changes.
#### Ansible: Specify the FIPS Omnibus builds
The standard Omnibus GitLab releases build their own OpenSSL library,
which is not FIPS-validated. However, we have nightly builds that create
Omnibus packages that link against the operating system's OpenSSL library. To
use this package, update the `gitlab_repo_script_url` field in the
Ansible `vars.yml`. For example, you might modify
The standard Omnibus GitLab releases build their own OpenSSL library, which is
not FIPS-validated. However, we have nightly builds that create Omnibus packages
that link against the operating system's OpenSSL library. To use this package,
update the `gitlab_edition` and `gitlab_repo_script_url` fields in the Ansible
`vars.yml`. For example, you might modify
`gitlab-environment-toolkit/ansible/environments/gitlab-10k/inventory/vars.yml`
in this way:
@ -204,6 +204,7 @@ all:
vars:
...
gitlab_repo_script_url: "https://packages.gitlab.com/install/repositories/gitlab/nightly-fips-builds/script.deb.sh"
gitlab_edition: "gitlab-fips"
```
### Cloud Native Hybrid

View File

@ -10,7 +10,7 @@ Configure your organization and its users. Determine user roles
and give everyone access to the projects they need.
- [Members](../user/project/members/index.md)
- [Workspace](../user/workspace/index.md) _(Coming soon)_
- [Workspace](../user/workspace/index.md) _(In development)_
- [Groups](../user/group/index.md)
- [User account options](../user/profile/index.md)
- [SSH keys](../user/ssh.md)

View File

@ -231,7 +231,7 @@ To configure project permissions:
1. Expand the **Visibility, project features, permissions** section.
1. To change the project visibility, select the dropdown list. If you select to **Public**, you limit access to some features to **Only Project Members**.
1. To allow users to request access to the project, select the **Users can request access** checkbox.
1. Use the toggles to enable or disable features in the project.
1. Use the [toggles](#project-feature-settings) to enable or disable features in the project.
1. Select **Save changes**.
When you disable a feature, the following additional features are disabled:
@ -255,6 +255,29 @@ When you disable a feature, the following additional features are disabled:
- Metrics dashboard access requires reading project environments and deployments.
Users with access to the metrics dashboard can also access environments and deployments.
### Project feature settings
Use the toggles to enable or disable features in the project.
| Option | More access limit options | Description |
|:---------------------------------|:--------------------------|:--------------|
| **Issues** | ✓ | Activates the GitLab issues tracker. |
| **Repository** | ✓ | Enables [repository](../repository/) functionality |
| **Merge requests** | ✓ | Enables [merge request](../merge_requests/) functionality; also see [Merge request settings](#configure-merge-request-settings-for-a-project). |
| **Forks** | ✓ | Enables [forking](../repository/forking_workflow.md) functionality. |
| **Git Large File Storage (LFS)** | | Enables the use of [large files](../../../topics/git/lfs/index.md#git-large-file-storage-lfs). |
| **Packages** | | Supports configuration of a [package registry](../../../administration/packages/index.md#gitlab-package-registry-administration) functionality. |
| **CI/CD** | ✓ | Enables [CI/CD](../../../ci/index.md) functionality. |
| **Container Registry** | | Activates a [registry](../../packages/container_registry/) for your Docker images. |
| **Analytics** | ✓ | Enables [analytics](../../analytics/). |
| **Requirements** | ✓ | Control access to [Requirements Management](../requirements/index.md). |
| **Security & Compliance** | ✓ | Control access to [security features](../../application_security/index.md). |
| **Wiki** | ✓ | Enables a separate system for [documentation](../wiki/). |
| **Snippets** | ✓ | Enables [sharing of code and text](../../snippets.md). |
| **Pages** | ✓ | Allows you to [publish static websites](../pages/). |
| **Operations** | ✓ | Control access to Operations-related features, including [Operations Dashboard](../../../operations/index.md), [Environments and Deployments](../../../ci/environments/index.md), [Feature Flags](../../../operations/feature_flags.md). |
| **Metrics Dashboard** | ✓ | Control access to [metrics dashboard](../integrations/prometheus.md). |
## Disabling the CVE ID request button **(FREE SAAS)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41203) in GitLab 13.4, only for public projects on GitLab.com.

View File

@ -145,7 +145,7 @@ module API
use :with_custom_attributes
end
# rubocop: disable CodeReuse/ActiveRecord
get ":id", feature_category: :users, urgency: :default do
get ":id", feature_category: :users, urgency: :low do
forbidden!('Not authorized!') unless current_user
unless current_user.admin?
@ -921,7 +921,7 @@ module API
desc 'Get the currently authenticated user' do
success Entities::UserPublic
end
get feature_category: :users, urgency: :default do
get feature_category: :users, urgency: :low do
entity =
if current_user.admin?
Entities::UserWithAdmin

View File

@ -0,0 +1,14 @@
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
# rubocop: disable Style/Documentation
class DeleteInvalidEpicIssues < BatchedMigrationJob
def perform
end
end
end
end
# rubocop:disable Layout/LineLength
Gitlab::BackgroundMigration::DeleteInvalidEpicIssues.prepend_mod_with('Gitlab::BackgroundMigration::DeleteInvalidEpicIssues')

View File

@ -19,7 +19,7 @@ module Gitlab
::Projects::CreateService.new(
current_user,
name: name,
path: name,
path: repo_slug,
description: repo.description,
namespace_id: namespace.id,
visibility_level: repo.visibility_level,

View File

@ -139,7 +139,6 @@
redis_slot: incident_management
category: incident_management_oncall
aggregation: weekly
feature_flag: usage_data_i_incident_management_oncall_notification_sent
# Testing category
- name: i_testing_test_case_parsed
category: testing

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Non-devops' do
RSpec.describe 'Product Intelligence' do
describe 'Performance bar display', :requires_admin, :skip_live_env do
context 'when logged in as an admin user' do
# performance metrics: pg, gitaly, redis, rugged (feature flagged), total (not always provided)
@ -20,7 +20,10 @@ module QA
end
end
it 'shows results for the original request and AJAX requests', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348030' do
it(
'shows results for the original request and AJAX requests',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348030'
) do
# Issue pages always make AJAX requests
Resource::Issue.fabricate_via_browser_ui! do |issue|
issue.title = 'Performance bar test'

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Non-devops' do
RSpec.describe 'Product Intelligence' do
describe 'Service ping default enabled' do
context 'when using default enabled from gitlab.yml config', :requires_admin, except: { job: 'review-qa-*' } do
before do
@ -11,7 +11,10 @@ module QA
Page::Admin::Menu.perform(&:go_to_metrics_and_profiling_settings)
end
it 'has service ping toggle enabled', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348335' do
it(
'has service ping toggle enabled',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348335'
) do
Page::Admin::Settings::MetricsAndProfiling.perform do |setting|
setting.expand_usage_statistics do |page|
expect(page).not_to have_disabled_usage_data_checkbox

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Non-devops' do
RSpec.describe 'Product Intelligence' do
describe 'Service ping disabled', :orchestrated, :service_ping_disabled, :requires_admin do
context 'when disabled from gitlab.yml config' do
before do
@ -11,7 +11,10 @@ module QA
Page::Admin::Menu.perform(&:go_to_metrics_and_profiling_settings)
end
it 'has service ping toggle is disabled', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348340' do
it(
'has service ping toggle is disabled',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348340'
) do
Page::Admin::Settings::MetricsAndProfiling.perform do |settings|
settings.expand_usage_statistics do |usage_statistics|
expect(usage_statistics).to have_disabled_usage_data_checkbox

View File

@ -19,13 +19,15 @@ module Glfm
markdown_yml_path = ARGV[0]
markdown_hash = YAML.load_file(markdown_yml_path)
context = build_context
# NOTE: We COULD parallelize this loop like the Javascript WYSIWYG example generation does,
# but it wouldn't save much time. Most of the time is spent loading the Rails environment
# via `rails runner`. In initial testing, this loop only took ~7 seconds while the entire
# script took ~20 seconds. Unfortunately, there's no easy way to execute
# `ApplicationController.helpers.markdown` without using `rails runner`
# `Banzai.render_and_post_process` without using `rails runner`
static_html_hash = markdown_hash.transform_values do |markdown|
ApplicationController.helpers.markdown(markdown)
Banzai.render_and_post_process(markdown, context)
end
static_html_tempfile_path = Dir::Tmpname.create(STATIC_HTML_TEMPFILE_BASENAME) do |path|
@ -37,14 +39,42 @@ module Glfm
# Write the path to the output file to stdout
print static_html_tempfile_path
end
private
def build_context
user_username = 'glfm_user_username'
user = User.find_by_username(user_username) ||
User.create!(
email: "glfm_user_email@example.com",
name: "glfm_user_name",
password: "glfm_user_password",
username: user_username
)
# Ensure that we never try to hit Gitaly, even if we
# reload the project
Project.define_method(:skip_disk_validation) do
true
end
project_name = 'glfm_project_name'
project = Project.find_by_name(project_name) ||
Project.create!(
creator: user,
description: "glfm_project_description",
name: project_name,
namespace: user.namespace,
path: 'glfm_project_path'
)
{
only_path: false,
current_user: user,
project: project
}
end
end
end
# current_user must be in global scope for `markdown` helper to work. Currently it's not supported
# to pass it in the context.
def current_user
# TODO: This will likely need to be a more realistic user object for some of the GLFM examples
User.new
end
Glfm::RenderStaticHtml.new.process

View File

@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe SortingPreference do
let(:user) { create(:user) }
let(:params) { {} }
let(:controller_class) do
Class.new do
@ -23,6 +24,46 @@ RSpec.describe SortingPreference do
allow(controller).to receive(:sorting_field).and_return(:issues_sort)
end
describe '#set_sort_order' do
let(:group) { build(:group) }
let(:issue_weights_available) { true }
before do
allow(controller).to receive(:default_sort_order).and_return('updated_desc')
allow(controller).to receive(:action_name).and_return('issues')
allow(controller).to receive(:can_sort_by_issue_weight?).and_return(issue_weights_available)
user.user_preference.update!(issues_sort: sorting_field)
end
subject { controller.send(:set_sort_order) }
context 'when user preference contains allowed sorting' do
let(:sorting_field) { 'updated_asc' }
it 'sets sort order from user_preference' do
is_expected.to eq('updated_asc')
end
end
context 'when user preference contains weight sorting' do
let(:sorting_field) { 'weight_desc' }
context 'when user can sort by issue weight' do
it 'sets sort order from user_preference' do
is_expected.to eq('weight_desc')
end
end
context 'when user cannot sort by issue weight' do
let(:issue_weights_available) { false }
it 'sets default sort order' do
is_expected.to eq('updated_desc')
end
end
end
end
describe '#set_sort_order_from_user_preference' do
subject { controller.send(:set_sort_order_from_user_preference) }
@ -49,8 +90,6 @@ RSpec.describe SortingPreference do
end
context 'when a user sorting preference exists' do
let(:params) { {} }
before do
user.user_preference.update!(issues_sort: 'updated_asc')
end
@ -81,7 +120,6 @@ RSpec.describe SortingPreference do
context 'when cookie exists' do
let(:cookies) { { 'issue_sort' => 'id_asc' } }
let(:params) { {} }
it 'sets the cookie with the right values and flags' do
subject

View File

@ -33,6 +33,18 @@ FactoryBot.define do
name { generate(:job_name) }
end
trait :matrix do
sequence(:name) { |n| "job: [#{n}]" }
options do
{
parallel: {
total: 2,
matrix: [{ ID: %w[1 2] }]
}
}
end
end
trait :dependent do
scheduling_type { 'dag' }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -30,13 +30,6 @@ describe('DiffsStoreUtils', () => {
});
});
describe('getReversePosition', () => {
it('should return correct line position name', () => {
expect(utils.getReversePosition(LINE_POSITION_RIGHT)).toEqual(LINE_POSITION_LEFT);
expect(utils.getReversePosition(LINE_POSITION_LEFT)).toEqual(LINE_POSITION_RIGHT);
});
});
describe('findIndexInInlineLines', () => {
const expectSet = (method, lines, invalidLines) => {
expect(method(lines, { oldLineNumber: 3, newLineNumber: 5 })).toEqual(4);

View File

@ -5,7 +5,6 @@ import {
canScrollDown,
parseBooleanDataAttributes,
isElementVisible,
isElementHidden,
getParents,
getParentByTagName,
setAttributes,
@ -181,30 +180,21 @@ describe('DOM Utils', () => {
${1} | ${0} | ${0} | ${true}
${0} | ${1} | ${0} | ${true}
${0} | ${0} | ${1} | ${true}
`(
'isElementVisible and isElementHidden',
({ offsetWidth, offsetHeight, clientRectsLength, visible }) => {
const element = {
offsetWidth,
offsetHeight,
getClientRects: () => new Array(clientRectsLength),
};
`('isElementVisible', ({ offsetWidth, offsetHeight, clientRectsLength, visible }) => {
const element = {
offsetWidth,
offsetHeight,
getClientRects: () => new Array(clientRectsLength),
};
const paramDescription = `offsetWidth=${offsetWidth}, offsetHeight=${offsetHeight}, and getClientRects().length=${clientRectsLength}`;
const paramDescription = `offsetWidth=${offsetWidth}, offsetHeight=${offsetHeight}, and getClientRects().length=${clientRectsLength}`;
describe('isElementVisible', () => {
it(`returns ${visible} when ${paramDescription}`, () => {
expect(isElementVisible(element)).toBe(visible);
});
describe('isElementVisible', () => {
it(`returns ${visible} when ${paramDescription}`, () => {
expect(isElementVisible(element)).toBe(visible);
});
describe('isElementHidden', () => {
it(`returns ${!visible} when ${paramDescription}`, () => {
expect(isElementHidden(element)).toBe(!visible);
});
});
},
);
});
});
describe('getParents', () => {
it('gets all parents of an element', () => {

View File

@ -1,38 +0,0 @@
import { getTimeRange } from '~/logs/utils';
describe('logs/utils', () => {
describe('getTimeRange', () => {
const nowTimestamp = 1577836800000;
const nowString = '2020-01-01T00:00:00.000Z';
beforeEach(() => {
jest.spyOn(Date, 'now').mockImplementation(() => nowTimestamp);
});
afterEach(() => {
Date.now.mockRestore();
});
it('returns the right values', () => {
expect(getTimeRange(0)).toEqual({
start: '2020-01-01T00:00:00.000Z',
end: nowString,
});
expect(getTimeRange(60 * 30)).toEqual({
start: '2019-12-31T23:30:00.000Z',
end: nowString,
});
expect(getTimeRange(60 * 60 * 24 * 7 * 1)).toEqual({
start: '2019-12-25T00:00:00.000Z',
end: nowString,
});
expect(getTimeRange(60 * 60 * 24 * 7 * 4)).toEqual({
start: '2019-12-04T00:00:00.000Z',
end: nowString,
});
});
});
});

View File

@ -12,10 +12,19 @@ RSpec.describe Types::WorkItems::WidgetInterface do
end
describe ".resolve_type" do
it 'knows the correct type for objects' do
expect(
described_class.resolve_type(WorkItems::Widgets::Description.new(build(:work_item)), {})
).to eq(Types::WorkItems::Widgets::DescriptionType)
using RSpec::Parameterized::TableSyntax
where(:widget_class, :widget_type_name) do
WorkItems::Widgets::Description | Types::WorkItems::Widgets::DescriptionType
WorkItems::Widgets::Hierarchy | Types::WorkItems::Widgets::HierarchyType
end
with_them do
it 'knows the correct type for objects' do
expect(
described_class.resolve_type(widget_class.new(build(:work_item)), {})
).to eq(widget_type_name)
end
end
it 'raises an error for an unknown type' do

View File

@ -0,0 +1,11 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Types::WorkItems::Widgets::HierarchyType do
it 'exposes the expected fields' do
expected_fields = %i[parent children type]
expect(described_class).to have_graphql_fields(*expected_fields)
end
end

View File

@ -62,6 +62,12 @@ RSpec.describe SortingHelper do
end
end
describe '#can_sort_by_issue_weight?' do
it 'returns false' do
expect(helper.can_sort_by_issue_weight?(false)).to be_falsey
end
end
def stub_controller_path(value)
allow(helper.controller).to receive(:controller_path).and_return(value)
end

View File

@ -12,7 +12,7 @@ RSpec.describe Gitlab::BitbucketServerImport::Importer do
let(:project) { create(:project, :repository, import_url: import_url, creator: project_creator) }
let(:now) { Time.now.utc.change(usec: 0) }
let(:project_key) { 'TEST' }
let(:repo_slug) { 'rouge' }
let(:repo_slug) { 'rouge-repo' }
let(:sample) { RepoHelpers.sample_compare }
subject { described_class.new(project, recover_missing_commits: true) }

View File

@ -4350,6 +4350,56 @@ RSpec.describe Ci::Build do
end
end
end
context 'when build is part of parallel build' do
let(:build_1) { create(:ci_build, name: 'build 1/2') }
let(:test_report) { Gitlab::Ci::Reports::TestReports.new }
before do
build_1.collect_test_reports!(test_report)
end
it 'uses the group name for test suite name' do
expect(test_report.test_suites.keys).to contain_exactly('build')
end
context 'when there are more than one parallel builds' do
let(:build_2) { create(:ci_build, name: 'build 2/2') }
before do
build_2.collect_test_reports!(test_report)
end
it 'merges the test suite from parallel builds' do
expect(test_report.test_suites.keys).to contain_exactly('build')
end
end
end
context 'when build is part of matrix build' do
let(:test_report) { Gitlab::Ci::Reports::TestReports.new }
let(:matrix_build_1) { create(:ci_build, :matrix) }
before do
matrix_build_1.collect_test_reports!(test_report)
end
it 'uses the job name for the test suite' do
expect(test_report.test_suites.keys).to contain_exactly(matrix_build_1.name)
end
context 'when there are more than one matrix builds' do
let(:matrix_build_2) { create(:ci_build, :matrix) }
before do
matrix_build_2.collect_test_reports!(test_report)
end
it 'keeps separate test suites' do
expect(test_report.test_suites.keys).to match_array([matrix_build_1.name, matrix_build_2.name])
end
end
end
end
describe '#collect_accessibility_reports!' do

View File

@ -36,7 +36,10 @@ RSpec.describe WorkItem do
describe '#widgets' do
subject { build(:work_item).widgets }
it { is_expected.to contain_exactly(instance_of(WorkItems::Widgets::Description)) }
it 'returns instances of supported widgets' do
is_expected.to match_array([instance_of(WorkItems::Widgets::Description),
instance_of(WorkItems::Widgets::Hierarchy)])
end
end
describe 'callbacks' do

View File

@ -63,7 +63,10 @@ RSpec.describe WorkItems::Type do
describe '.available_widgets' do
subject { described_class.available_widgets }
it { is_expected.to contain_exactly(::WorkItems::Widgets::Description) }
it 'returns list of all possible widgets' do
is_expected.to match_array([::WorkItems::Widgets::Description,
::WorkItems::Widgets::Hierarchy])
end
end
describe '#default?' do

View File

@ -0,0 +1,52 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WorkItems::Widgets::Hierarchy do
let_it_be(:work_item) { create(:work_item) }
describe '.type' do
subject { described_class.type }
it { is_expected.to eq(:hierarchy) }
end
describe '#type' do
subject { described_class.new(work_item).type }
it { is_expected.to eq(:hierarchy) }
end
describe '#parent' do
let_it_be(:parent_link) { create(:parent_link) }
subject { described_class.new(parent_link.work_item).parent }
it { is_expected.to eq parent_link.work_item_parent }
context 'when work_items_hierarchy flag is disabled' do
before do
stub_feature_flags(work_items_hierarchy: false)
end
it { is_expected.to be_nil }
end
end
describe '#children' do
let_it_be(:parent_link1) { create(:parent_link, work_item_parent: work_item) }
let_it_be(:parent_link2) { create(:parent_link, work_item_parent: work_item) }
subject { described_class.new(work_item).children }
it { is_expected.to match_array([parent_link1.work_item, parent_link2.work_item]) }
context 'when work_items_hierarchy flag is disabled' do
before do
stub_feature_flags(work_items_hierarchy: false)
end
it { is_expected.to be_empty }
end
end
end

View File

@ -6,8 +6,13 @@ RSpec.describe 'Query.work_item(id)' do
include GraphqlHelpers
let_it_be(:developer) { create(:user) }
let_it_be(:project) { create(:project, :private).tap { |project| project.add_developer(developer) } }
let_it_be(:guest) { create(:user) }
let_it_be(:project) { create(:project, :private) }
let_it_be(:work_item) { create(:work_item, project: project, description: '- List item') }
let_it_be(:child_item1) { create(:work_item, :task, project: project) }
let_it_be(:child_item2) { create(:work_item, :task, confidential: true, project: project) }
let_it_be(:child_link1) { create(:parent_link, work_item_parent: work_item, work_item: child_item1) }
let_it_be(:child_link2) { create(:parent_link, work_item_parent: work_item, work_item: child_item2) }
let(:current_user) { developer }
let(:work_item_data) { graphql_data['workItem'] }
@ -20,6 +25,9 @@ RSpec.describe 'Query.work_item(id)' do
context 'when the user can read the work item' do
before do
project.add_developer(developer)
project.add_guest(guest)
post_graphql(query, current_user: current_user)
end
@ -39,30 +47,132 @@ RSpec.describe 'Query.work_item(id)' do
end
context 'when querying widgets' do
let(:work_item_fields) do
<<~GRAPHQL
id
widgets {
type
... on WorkItemWidgetDescription {
description
descriptionHtml
describe 'description widget' do
let(:work_item_fields) do
<<~GRAPHQL
id
widgets {
type
... on WorkItemWidgetDescription {
description
descriptionHtml
}
}
}
GRAPHQL
GRAPHQL
end
it 'returns widget information' do
expect(work_item_data).to include(
'id' => work_item.to_gid.to_s,
'widgets' => match_array([
hash_including(
'type' => 'DESCRIPTION',
'description' => work_item.description,
'descriptionHtml' => ::MarkupHelper.markdown_field(work_item, :description, {})
),
hash_including(
'type' => 'HIERARCHY'
)
])
)
end
end
it 'returns widget information' do
expect(work_item_data).to include(
'id' => work_item.to_gid.to_s,
'widgets' => contain_exactly(
hash_including(
'type' => 'DESCRIPTION',
'description' => work_item.description,
'descriptionHtml' => ::MarkupHelper.markdown_field(work_item, :description, {})
)
describe 'hierarchy widget' do
let(:work_item_fields) do
<<~GRAPHQL
id
widgets {
type
... on WorkItemWidgetHierarchy {
parent {
id
}
children {
nodes {
id
}
}
}
}
GRAPHQL
end
it 'returns widget information' do
expect(work_item_data).to include(
'id' => work_item.to_gid.to_s,
'widgets' => match_array([
hash_including(
'type' => 'DESCRIPTION'
),
hash_including(
'type' => 'HIERARCHY',
'parent' => nil,
'children' => { 'nodes' => match_array([
hash_including('id' => child_link1.work_item.to_gid.to_s),
hash_including('id' => child_link2.work_item.to_gid.to_s)
]) }
)
])
)
)
end
it 'avoids N+1 queries' do
post_graphql(query, current_user: current_user) # warm up
control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do
post_graphql(query, current_user: current_user)
end
create_list(:parent_link, 3, work_item_parent: work_item)
expect do
post_graphql(query, current_user: current_user)
end.not_to exceed_all_query_limit(control_count)
end
context 'when user is guest' do
let(:current_user) { guest }
it 'filters out not accessible children or parent' do
expect(work_item_data).to include(
'id' => work_item.to_gid.to_s,
'widgets' => match_array([
hash_including(
'type' => 'DESCRIPTION'
),
hash_including(
'type' => 'HIERARCHY',
'parent' => nil,
'children' => { 'nodes' => match_array([
hash_including('id' => child_link1.work_item.to_gid.to_s)
]) }
)
])
)
end
end
context 'when requesting child item' do
let_it_be(:work_item) { create(:work_item, :task, project: project, description: '- List item') }
let_it_be(:parent_link) { create(:parent_link, work_item: work_item) }
it 'returns parent information' do
expect(work_item_data).to include(
'id' => work_item.to_gid.to_s,
'widgets' => match_array([
hash_including(
'type' => 'DESCRIPTION'
),
hash_including(
'type' => 'HIERARCHY',
'parent' => hash_including('id' => parent_link.work_item_parent.to_gid.to_s),
'children' => { 'nodes' => match_array([]) }
)
])
)
end
end
end
end

View File

@ -431,7 +431,9 @@ RSpec.describe Glfm::UpdateExampleSnapshots, '#process' do
bold
</strong></p>
static: |-
<strong>&#x000A;bold&#x000A;</strong>
<strong>
bold
</strong>
05_02__third_gitlab_specific_section_with_skipped_examples__strong_but_manually_modified_and_skipped__001:
canonical: |
<p><strong>This example will have its manually modified static HTML, WYSIWYG HTML, and ProseMirror JSON preserved</strong></p>

View File

@ -79,7 +79,7 @@ require (
github.com/jtolds/gls v4.20.0+incompatible // indirect
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20210210170715-a8dfcb80d3a7 // indirect
github.com/lightstep/lightstep-tracer-go v0.25.0 // indirect
github.com/mattn/go-ieproxy v0.0.3 // indirect
github.com/mattn/go-ieproxy v0.0.6 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mitchellh/reflectwalk v1.0.0 // indirect
github.com/oklog/ulid/v2 v2.0.2 // indirect

View File

@ -768,8 +768,9 @@ github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
github.com/mattn/go-ieproxy v0.0.3 h1:YkaHmK1CzE5C4O7A3hv3TCbfNDPSCf0RKZFX+VhBeYk=
github.com/mattn/go-ieproxy v0.0.3/go.mod h1:6ZpRmhBaYuBX1U2za+9rC9iCGLsSp2tftelZne7CPko=
github.com/mattn/go-ieproxy v0.0.6 h1:tVDlituRyeHMMkHpGpUu8CJG+hxPMwbYCkIUK2PUCbo=
github.com/mattn/go-ieproxy v0.0.6/go.mod h1:6ZpRmhBaYuBX1U2za+9rC9iCGLsSp2tftelZne7CPko=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=