Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
696edc7f23
commit
efe8d31390
|
|
@ -1 +1 @@
|
|||
4586553167d1b1ce3932b76ea5b8721e860dada2
|
||||
d389b47d972835c6b4f5dbacf07f7965361d0c8f
|
||||
|
|
|
|||
|
|
@ -128,10 +128,11 @@ export default {
|
|||
<gl-sprintf
|
||||
:message="
|
||||
__(
|
||||
'The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported.',
|
||||
'The subject will be used as the title of the new %{name}, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported.',
|
||||
)
|
||||
"
|
||||
>
|
||||
<template #name>{{ issuableName }}</template>
|
||||
<template #quickActionsLink="{ content }">
|
||||
<gl-link :href="quickActionsHelpPath" target="_blank">{{ content }}</gl-link>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ export async function mountIssuesListApp() {
|
|||
wiNewCommentTemplatePaths,
|
||||
hasLinkedItemsEpicsFeature,
|
||||
timeTrackingLimitToHours,
|
||||
hasSubepicsFeature,
|
||||
} = el.dataset;
|
||||
|
||||
return new Vue({
|
||||
|
|
@ -200,7 +201,7 @@ export async function mountIssuesListApp() {
|
|||
issuesListPath: wiIssuesListPath,
|
||||
labelsManagePath: wiLabelsManagePath,
|
||||
reportAbusePath: wiReportAbusePath,
|
||||
hasSubepicsFeature: false,
|
||||
hasSubepicsFeature: parseBoolean(hasSubepicsFeature),
|
||||
hasLinkedItemsEpicsFeature: parseBoolean(hasLinkedItemsEpicsFeature),
|
||||
commentTemplatePaths: JSON.parse(wiNewCommentTemplatePaths),
|
||||
timeTrackingLimitToHours: parseBoolean(timeTrackingLimitToHours),
|
||||
|
|
|
|||
|
|
@ -261,6 +261,7 @@ export default {
|
|||
:work-item-iid="childItemIid"
|
||||
:work-item-web-url="childItemWebUrl"
|
||||
/>
|
||||
<slot name="child-contents"></slot>
|
||||
<span
|
||||
:id="`statusIcon-${childItem.id}`"
|
||||
class="gl-cursor-help"
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ export default {
|
|||
GlAlert,
|
||||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
inject: ['hasSubepicsFeature'],
|
||||
actionCancel: {
|
||||
text: __('Cancel'),
|
||||
},
|
||||
|
|
@ -352,7 +353,9 @@ export default {
|
|||
this.warningMessage = '';
|
||||
this.valueNotPresentWarning = '';
|
||||
|
||||
if (this.hasParent) {
|
||||
const isEpicWithSubepicsFeature =
|
||||
this.parentWorkItemType === WORK_ITEM_TYPE_NAME_EPIC && this.hasSubepicsFeature;
|
||||
if (this.hasParent && !isEpicWithSubepicsFeature) {
|
||||
this.warningMessage = sprintfWorkItem(
|
||||
s__(
|
||||
'WorkItem|Parent item type %{parentWorkItemType} is not supported on %{workItemType}. Remove the parent item to change type.',
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script>
|
||||
import { GlButton, GlTooltipDirective } from '@gitlab/ui';
|
||||
import WorkItemLinkChildContents from 'ee_else_ce/work_items/components/shared/work_item_link_child_contents.vue';
|
||||
import { __, s__ } from '~/locale';
|
||||
import { createAlert } from '~/alert';
|
||||
import { WORK_ITEM_TYPE_NAME_TASK } from '../../constants';
|
||||
|
|
@ -7,7 +8,6 @@ import { findHierarchyWidget, getDefaultHierarchyChildrenCount, getItems } from
|
|||
import toggleHierarchyTreeChildMutation from '../../graphql/client/toggle_hierarchy_tree_child.mutation.graphql';
|
||||
import isExpandedHierarchyTreeChildQuery from '../../graphql/client/is_expanded_hierarchy_tree_child.query.graphql';
|
||||
import getWorkItemTreeQuery from '../../graphql/work_item_tree.query.graphql';
|
||||
import WorkItemLinkChildContents from '../shared/work_item_link_child_contents.vue';
|
||||
import WorkItemChildrenLoadMore from '../shared/work_item_children_load_more.vue';
|
||||
|
||||
export default {
|
||||
|
|
@ -283,13 +283,9 @@ export default {
|
|||
:child-item="childItem"
|
||||
:can-update="canUpdate"
|
||||
:class="childItemClass"
|
||||
:parent-work-item-id="issuableGid"
|
||||
:work-item-type="workItemType"
|
||||
:show-labels="showLabels"
|
||||
:show-closed="showClosed"
|
||||
:work-item-full-path="workItemFullPath"
|
||||
:show-weight="shouldShowWeight"
|
||||
:is-active="isActive"
|
||||
@click="$emit('click', $event)"
|
||||
@removeChild="$emit('removeChild', childItem)"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { defaultSortableOptions, DRAG_DELAY } from '~/sortable/constants';
|
|||
import * as Sentry from '~/sentry/sentry_browser_wrapper';
|
||||
import { sortableStart, sortableEnd } from '~/sortable/utils';
|
||||
|
||||
import WorkItemLinkChildContents from '../shared/work_item_link_child_contents.vue';
|
||||
import WorkItemLinkChildContents from 'ee_else_ce/work_items/components/shared/work_item_link_child_contents.vue';
|
||||
|
||||
import removeLinkedItemsMutation from '../../graphql/remove_linked_items.mutation.graphql';
|
||||
import addLinkedItemsMutation from '../../graphql/add_linked_items.mutation.graphql';
|
||||
|
|
|
|||
|
|
@ -145,10 +145,21 @@ module IssuesHelper
|
|||
is_signed_in: current_user.present?.to_s,
|
||||
rss_path: url_for(safe_params.merge(rss_url_options)),
|
||||
sign_in_path: new_user_session_path,
|
||||
wi: work_items_data(namespace, current_user)
|
||||
wi: work_items_data(namespace, current_user),
|
||||
has_subepics_feature: has_subepics_feature?(namespace).to_s
|
||||
}
|
||||
end
|
||||
|
||||
def has_subepics_feature?(namespace)
|
||||
if namespace.is_a?(Group)
|
||||
return namespace.licensed_feature_available?(:subepics)
|
||||
elsif namespace.respond_to?(:group) && namespace.group
|
||||
return namespace.group.licensed_feature_available?(:subepics)
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
def has_issue_date_filter_feature?(namespace, current_user)
|
||||
enabled_for_user = Feature.enabled?(:issue_date_filter, current_user)
|
||||
return true if enabled_for_user
|
||||
|
|
|
|||
|
|
@ -1011,6 +1011,10 @@
|
|||
- 1
|
||||
- - vulnerabilities_namespace_statistics_adjustment
|
||||
- 1
|
||||
- - vulnerabilities_namespace_statistics_process_group_transfer_events
|
||||
- 1
|
||||
- - vulnerabilities_namespace_statistics_process_project_transfer_events
|
||||
- 1
|
||||
- - vulnerabilities_process_archived_events
|
||||
- 1
|
||||
- - vulnerabilities_process_bulk_dismissed_events
|
||||
|
|
|
|||
|
|
@ -9,14 +9,6 @@ description: The SHA referencing changes to individual designs made using the De
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/9801
|
||||
milestone: '11.10'
|
||||
gitlab_schema: gitlab_main_cell
|
||||
desired_sharding_key:
|
||||
namespace_id:
|
||||
references: namespaces
|
||||
backfill_via:
|
||||
parent:
|
||||
foreign_key: issue_id
|
||||
table: issues
|
||||
sharding_key: namespace_id
|
||||
belongs_to: issue
|
||||
desired_sharding_key_migration_job_name: BackfillDesignManagementVersionsNamespaceId
|
||||
sharding_key:
|
||||
namespace_id: namespaces
|
||||
table_size: small
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class UpdateAiTroubleshootJobEventsProjectFk < Gitlab::Database::Migration[2.3]
|
||||
include Gitlab::Database::PartitioningMigrationHelpers::ForeignKeyHelpers
|
||||
|
||||
disable_ddl_transaction!
|
||||
milestone '18.0'
|
||||
|
||||
def up
|
||||
with_lock_retries do
|
||||
remove_foreign_key_if_exists(:ai_troubleshoot_job_events, column: :project_id, reverse_lock_order: true)
|
||||
end
|
||||
|
||||
add_concurrent_partitioned_foreign_key :ai_troubleshoot_job_events, :projects, column: :project_id,
|
||||
on_delete: :cascade, reverse_lock_order: true
|
||||
end
|
||||
|
||||
def down
|
||||
with_lock_retries do
|
||||
remove_foreign_key_if_exists(:ai_troubleshoot_job_events, column: :project_id, reverse_lock_order: true)
|
||||
end
|
||||
|
||||
add_concurrent_partitioned_foreign_key :ai_troubleshoot_job_events, :projects, column: :project_id, on_delete: nil,
|
||||
reverse_lock_order: true
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddIndexToProjectRequirementStatusNamespaceProjectId < Gitlab::Database::Migration[2.3]
|
||||
milestone '18.0'
|
||||
disable_ddl_transaction!
|
||||
|
||||
INDEX_NAMESPACE_PROJECT_ID_DESC = 'i_project_requirement_statuses_on_namespace_id_project_id'
|
||||
|
||||
def up
|
||||
add_concurrent_index :project_requirement_compliance_statuses, [:namespace_id, :project_id, :id],
|
||||
order: { project_id: :asc, id: :asc }, using: :btree, name: INDEX_NAMESPACE_PROJECT_ID_DESC
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index_by_name :project_requirement_compliance_statuses, INDEX_NAMESPACE_PROJECT_ID_DESC
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddIndexToProjectRequirementStatusNamespaceRequirementId < Gitlab::Database::Migration[2.3]
|
||||
milestone '18.0'
|
||||
disable_ddl_transaction!
|
||||
|
||||
INDEX_NAMESPACE_REQUIREMENT_ID_DESC = 'i_project_requirement_statuses_on_namespace_id_requirement_id'
|
||||
|
||||
def up
|
||||
add_concurrent_index :project_requirement_compliance_statuses, [:namespace_id, :compliance_requirement_id, :id],
|
||||
order: { compliance_requirement_id: :asc, id: :asc }, using: :btree, name: INDEX_NAMESPACE_REQUIREMENT_ID_DESC
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index_by_name :project_requirement_compliance_statuses, INDEX_NAMESPACE_REQUIREMENT_ID_DESC
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddIndexToProjectRequirementStatusNamespaceFrameworkId < Gitlab::Database::Migration[2.3]
|
||||
milestone '18.0'
|
||||
disable_ddl_transaction!
|
||||
|
||||
INDEX_NAMESPACE_FRAMEWORK_ID_DESC = 'i_project_requirement_statuses_on_namespace_id_framework_id'
|
||||
|
||||
def up
|
||||
add_concurrent_index :project_requirement_compliance_statuses, [:namespace_id, :compliance_framework_id, :id],
|
||||
order: { compliance_framework_id: :asc, id: :asc }, using: :btree, name: INDEX_NAMESPACE_FRAMEWORK_ID_DESC
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index_by_name :project_requirement_compliance_statuses, INDEX_NAMESPACE_FRAMEWORK_ID_DESC
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddDesignManagementVersionsNamespaceIdNotNullConstraint < Gitlab::Database::Migration[2.2]
|
||||
disable_ddl_transaction!
|
||||
milestone '18.0'
|
||||
|
||||
def up
|
||||
add_not_null_constraint :design_management_versions, :namespace_id
|
||||
end
|
||||
|
||||
def down
|
||||
remove_not_null_constraint :design_management_versions, :namespace_id
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddBtreeIndexOnTraversalIdsVulNamespaceStatistics < Gitlab::Database::Migration[2.2]
|
||||
disable_ddl_transaction!
|
||||
milestone '18.0'
|
||||
|
||||
INDEX_NAME = 'index_vuln_namespace_statistics_btree_traversal_ids'
|
||||
|
||||
def up
|
||||
add_concurrent_index :vulnerability_namespace_statistics, :traversal_ids, unique: true, name: INDEX_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index_by_name :vulnerability_namespace_statistics, name: INDEX_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
3edbf476db3fbbc6005ce957db22db0f6b6060e38c1d5ac77c1d3d73f1343d0e
|
||||
|
|
@ -0,0 +1 @@
|
|||
51c23d9955d9a94bc84e9e40e5f7a7b24b35b6e5f02596c29c4da2693e1fc8ff
|
||||
|
|
@ -0,0 +1 @@
|
|||
03f74b80d288bf570e1e8547bab8e992031c4b100a73e4606652bf9f3fd124e9
|
||||
|
|
@ -0,0 +1 @@
|
|||
c25d19ea0cc74680d5dd48331e2cd8540492bedf4940a775bd33b43abadfed4d
|
||||
|
|
@ -0,0 +1 @@
|
|||
32c7f68dee6145388f4deac62338aa9c37d36d0bcfc827e4054491f006f5bb85
|
||||
|
|
@ -0,0 +1 @@
|
|||
a214e8bff3d1aca417ea6f0b6c6c50114830486286966dea83bfceea1df4eeb3
|
||||
|
|
@ -13753,7 +13753,8 @@ CREATE TABLE design_management_versions (
|
|||
issue_id bigint,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
author_id bigint,
|
||||
namespace_id bigint
|
||||
namespace_id bigint,
|
||||
CONSTRAINT check_1d0291f47a CHECK ((namespace_id IS NOT NULL))
|
||||
);
|
||||
|
||||
CREATE SEQUENCE design_management_versions_id_seq
|
||||
|
|
@ -32990,6 +32991,12 @@ CREATE UNIQUE INDEX i_pm_package_versions_on_package_id_and_version ON pm_packag
|
|||
|
||||
CREATE UNIQUE INDEX i_pm_packages_purl_type_and_name ON pm_packages USING btree (purl_type, name);
|
||||
|
||||
CREATE INDEX i_project_requirement_statuses_on_namespace_id_framework_id ON project_requirement_compliance_statuses USING btree (namespace_id, compliance_framework_id, id);
|
||||
|
||||
CREATE INDEX i_project_requirement_statuses_on_namespace_id_project_id ON project_requirement_compliance_statuses USING btree (namespace_id, project_id, id);
|
||||
|
||||
CREATE INDEX i_project_requirement_statuses_on_namespace_id_requirement_id ON project_requirement_compliance_statuses USING btree (namespace_id, compliance_requirement_id, id);
|
||||
|
||||
CREATE INDEX i_project_requirement_statuses_on_namespace_id_updated_at_id ON project_requirement_compliance_statuses USING btree (namespace_id, updated_at DESC, id DESC);
|
||||
|
||||
CREATE INDEX i_protected_branch_unprotect_access_levels_protected_branch_nam ON protected_branch_unprotect_access_levels USING btree (protected_branch_namespace_id);
|
||||
|
|
@ -37746,6 +37753,8 @@ CREATE INDEX index_vuln_namespace_hist_statistics_for_traversal_ids_update ON vu
|
|||
|
||||
CREATE UNIQUE INDEX index_vuln_namespace_historical_statistics_traversal_ids_date ON vulnerability_namespace_historical_statistics USING btree (traversal_ids, date);
|
||||
|
||||
CREATE UNIQUE INDEX index_vuln_namespace_statistics_btree_traversal_ids ON vulnerability_namespace_statistics USING btree (traversal_ids);
|
||||
|
||||
CREATE INDEX index_vuln_namespace_statistics_gin_traversal_ids ON vulnerability_namespace_statistics USING gin (traversal_ids);
|
||||
|
||||
CREATE UNIQUE INDEX index_vuln_namespace_statistics_on_namespace_id ON vulnerability_namespace_statistics USING btree (namespace_id);
|
||||
|
|
@ -44146,7 +44155,7 @@ ALTER TABLE ONLY external_status_checks
|
|||
ADD CONSTRAINT fk_rails_1f5a8aa809 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ai_troubleshoot_job_events
|
||||
ADD CONSTRAINT fk_rails_1fb7e812da FOREIGN KEY (project_id) REFERENCES projects(id);
|
||||
ADD CONSTRAINT fk_rails_1fb7e812da FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY dora_daily_metrics
|
||||
ADD CONSTRAINT fk_rails_1fd07aff6f FOREIGN KEY (environment_id) REFERENCES environments(id) ON DELETE CASCADE;
|
||||
|
|
|
|||
|
|
@ -13015,7 +13015,8 @@ Input type: `WorkspaceCreateInput`
|
|||
| <a id="mutationworkspacecreatemaxhoursbeforetermination"></a>`maxHoursBeforeTermination` {{< icon name="warning-solid" >}} | [`Int`](#int) | **Deprecated:** Field is not used. Deprecated in GitLab 17.9. |
|
||||
| <a id="mutationworkspacecreateprojectid"></a>`projectId` | [`ProjectID!`](#projectid) | ID of the project that will provide the Devfile for the created workspace. |
|
||||
| <a id="mutationworkspacecreateprojectref"></a>`projectRef` | [`String`](#string) | Project repo git ref. |
|
||||
| <a id="mutationworkspacecreatevariables"></a>`variables` | [`[WorkspaceVariableInput!]`](#workspacevariableinput) | Variables to inject into the workspace. |
|
||||
| <a id="mutationworkspacecreatevariables"></a>`variables` {{< icon name="warning-solid" >}} | [`[WorkspaceVariableInput!]`](#workspacevariableinput) | **Deprecated:** Argument is renamed to workspace_variables. Deprecated in GitLab 18.0. |
|
||||
| <a id="mutationworkspacecreateworkspacevariables"></a>`workspaceVariables` {{< icon name="warning-solid" >}} | [`[WorkspaceVariableInput!]`](#workspacevariableinput) | **Deprecated:** **Status**: Experiment. Introduced in GitLab 18.0. |
|
||||
|
||||
#### Fields
|
||||
|
||||
|
|
@ -28696,7 +28697,7 @@ four standard [pagination arguments](#pagination-arguments):
|
|||
|
||||
##### `Group.projectComplianceRequirementsStatus`
|
||||
|
||||
Compliance standards adherence for the projects in a group and its subgroups.
|
||||
Compliance statuses for the projects in a group and its subgroups.
|
||||
|
||||
{{< details >}}
|
||||
**Introduced** in GitLab 17.10.
|
||||
|
|
@ -28714,6 +28715,7 @@ four standard [pagination arguments](#pagination-arguments):
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="groupprojectcompliancerequirementsstatusfilters"></a>`filters` | [`GroupProjectRequirementComplianceStatusInput`](#groupprojectrequirementcompliancestatusinput) | Filters applied when retrieving compliance requirement statuses. |
|
||||
| <a id="groupprojectcompliancerequirementsstatusorderby"></a>`orderBy` | [`ProjectComplianceRequirementStatusOrderBy`](#projectcompliancerequirementstatusorderby) | Field used to sort compliance requirement statuses. |
|
||||
|
||||
##### `Group.projectComplianceStandardsAdherence`
|
||||
|
||||
|
|
@ -30502,7 +30504,18 @@ Represents an instance-level LDAP link.
|
|||
| <a id="ldapadminrolelinkcn"></a>`cn` | [`String`](#string) | Common Name (CN) of the LDAP group. |
|
||||
| <a id="ldapadminrolelinkfilter"></a>`filter` | [`String`](#string) | Search filter for the LDAP group. |
|
||||
| <a id="ldapadminrolelinkid"></a>`id` | [`ID!`](#id) | ID of the LDAP link. |
|
||||
| <a id="ldapadminrolelinkprovider"></a>`provider` | [`String!`](#string) | LDAP provider for the LDAP link. |
|
||||
| <a id="ldapadminrolelinkprovider"></a>`provider` | [`LdapProvider!`](#ldapprovider) | LDAP provider for the LDAP link. |
|
||||
|
||||
### `LdapProvider`
|
||||
|
||||
Represents a LDAP provider.
|
||||
|
||||
#### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="ldapproviderid"></a>`id` | [`String`](#string) | ID of the LDAP provider. |
|
||||
| <a id="ldapproviderlabel"></a>`label` | [`String`](#string) | Display name of the LDAP provider. |
|
||||
|
||||
### `LfsObjectRegistry`
|
||||
|
||||
|
|
@ -44994,6 +45007,16 @@ Compliance status of the project control.
|
|||
| <a id="projectcompliancecontrolstatuspass"></a>`PASS` | Pass. |
|
||||
| <a id="projectcompliancecontrolstatuspending"></a>`PENDING` | Pending. |
|
||||
|
||||
### `ProjectComplianceRequirementStatusOrderBy`
|
||||
|
||||
Values for order_by field for project requirement statuses.
|
||||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| <a id="projectcompliancerequirementstatusorderbyframework"></a>`FRAMEWORK` | Order by frameworks. |
|
||||
| <a id="projectcompliancerequirementstatusorderbyproject"></a>`PROJECT` | Order by projects. |
|
||||
| <a id="projectcompliancerequirementstatusorderbyrequirement"></a>`REQUIREMENT` | Order by requirements. |
|
||||
|
||||
### `ProjectFeatureAccessLevel`
|
||||
|
||||
Access level of a project feature.
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ We have developed a number of utilities to help ease development:
|
|||
|
||||
Refer to [`merge_hash.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/utils/merge_hash.rb):
|
||||
|
||||
- Deep merges an array of hashes:
|
||||
- Deep merges an array of elements which can be hashes, arrays, or other objects:
|
||||
|
||||
```ruby
|
||||
Gitlab::Utils::MergeHash.merge(
|
||||
|
|
|
|||
|
|
@ -235,8 +235,7 @@ For more information, see [issue 480328](https://gitlab.com/gitlab-org/gitlab/-/
|
|||
## Issues to be aware of when upgrading to 17.8
|
||||
|
||||
- In GitLab 17.8, three new secrets have been added to support the new encryption framework (started to be used in 17.9).
|
||||
If you have a multi-node configuration, follow the steps relevant to your installation from
|
||||
the [17.8.0](#1780) section below.
|
||||
If you have a multi-node configuration, you must [ensure these secrets are the same on all nodes](#unify-new-encryption-secrets).
|
||||
|
||||
- Migration failures when upgrading to GitLab 17.8.
|
||||
|
||||
|
|
@ -266,8 +265,7 @@ For more information, see [issue 480328](https://gitlab.com/gitlab-org/gitlab/-/
|
|||
## Issues to be aware of when upgrading to 17.9
|
||||
|
||||
- In GitLab 17.8, three new secrets have been added to support the new encryption framework (started to be used in 17.9).
|
||||
If you have a multi-node configuration, follow the steps relevant to your installation from
|
||||
the [17.9.0](#1790) section below.
|
||||
If you have a multi-node configuration, you must [ensure these secrets are the same on all nodes](#unify-new-encryption-secrets).
|
||||
|
||||
- Runner tags missing when upgrading to GitLab 17.9
|
||||
|
||||
|
|
@ -289,14 +287,12 @@ For more information, see [issue 480328](https://gitlab.com/gitlab-org/gitlab/-/
|
|||
## Issues to be aware of when upgrading to 17.10
|
||||
|
||||
- In GitLab 17.8, three new secrets have been added to support the new encryption framework (started to be used in 17.9).
|
||||
If you have a multi-node configuration, follow the steps relevant to your installation from
|
||||
the [17.9.0](#1790) section below.
|
||||
If you have a multi-node configuration, you must [ensure these secrets are the same on all nodes](#unify-new-encryption-secrets).
|
||||
|
||||
## Issues to be aware of when upgrading to 17.11
|
||||
|
||||
- In GitLab 17.8, three new secrets have been added to support the new encryption framework (started to be used in 17.9).
|
||||
If you have a multi-node configuration, follow the steps relevant to your installation from
|
||||
the [17.9.0](#1790) section below.
|
||||
If you have a multi-node configuration, you must [ensure these secrets are the same on all nodes](#unify-new-encryption-secrets).
|
||||
|
||||
## 17.11.0
|
||||
|
||||
|
|
@ -308,9 +304,7 @@ In GitLab 17.8, three new secrets have been added to support the new encryption
|
|||
- `active_record_encryption_deterministic_key`
|
||||
- `active_record_encryption_key_derivation_salt`
|
||||
|
||||
**If you have a multi-node configuration, you must ensure these secrets are the same on all nodes.** Otherwise, the application automatically generates the missing secrets at startup.
|
||||
|
||||
Follow the steps relevant to your installation from the [17.9.0](#1790) section below.
|
||||
If you have a multi-node configuration, you must [ensure these secrets are the same on all nodes](#unify-new-encryption-secrets).
|
||||
|
||||
## 17.10.0
|
||||
|
||||
|
|
@ -322,9 +316,7 @@ In GitLab 17.8, three new secrets have been added to support the new encryption
|
|||
- `active_record_encryption_deterministic_key`
|
||||
- `active_record_encryption_key_derivation_salt`
|
||||
|
||||
**If you have a multi-node configuration, you should ensure these secrets are the same on all nodes.** Otherwise, the application automatically generates the missing secrets at startup.
|
||||
|
||||
Follow the steps relevant to your installation from the [17.9.0](#1790) section below.
|
||||
If you have a multi-node configuration, you must [ensure these secrets are the same on all nodes](#unify-new-encryption-secrets).
|
||||
|
||||
## 17.9.0
|
||||
|
||||
|
|
@ -336,71 +328,7 @@ In GitLab 17.8, three new secrets have been added to support the new encryption
|
|||
- `active_record_encryption_deterministic_key`
|
||||
- `active_record_encryption_key_derivation_salt`
|
||||
|
||||
**If you have a multi-node configuration, you should ensure these secrets are the same on all nodes.** Otherwise, the application automatically generates the missing secrets at startup.
|
||||
|
||||
{{< tabs >}}
|
||||
|
||||
{{< tab title="Linux package (Omnibus)" >}}
|
||||
|
||||
1. Optional. If possible, put your instance in [maintenance mode](../../administration/maintenance_mode/_index.md) (otherwise if the steps 3 and 6 return `true`, it's fine).
|
||||
1. Delete all `CloudConnector::Keys` records:
|
||||
|
||||
```shell
|
||||
gitlab-rails r 'CloudConnector::Keys.delete_all'
|
||||
```
|
||||
|
||||
1. Check if any records with encrypted attributes exist:
|
||||
|
||||
```shell
|
||||
gitlab-rails r 'Rails.application.eager_load!; puts ApplicationRecord.descendants.select { |d| d.encrypted_attributes.present? }.index_with { |model| model.count }.values.all?(&:zero?)'
|
||||
```
|
||||
|
||||
If the result is `true`, you can proceed to the next step. Otherwise, we need to check what are the existing records
|
||||
and decide if we can delete them before proceeding further.
|
||||
|
||||
1. Pick one Sidekiq or Rails node as a reference node from which you will copy
|
||||
`/etc/gitlab/gitlab-secrets.json` to all other Sidekiq and Rails nodes.
|
||||
1. On all Sidekiq and Rails nodes (except the reference node):
|
||||
|
||||
1. Back up your [configuration files](https://docs.gitlab.com/omnibus/settings/backups/#backup-and-restore-configuration-on-a-linux-package-installation):
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl backup-etc
|
||||
```
|
||||
|
||||
1. Copy `/etc/gitlab/gitlab-secrets.json` from the reference node, and replace the file of the
|
||||
same name on the current node.
|
||||
1. Reconfigure GitLab:
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl reconfigure
|
||||
```
|
||||
|
||||
1. Check again if any records with encrypted attributes exist (to ensure no records were created while
|
||||
you performed the previous steps). The return value should be `true`:
|
||||
|
||||
```shell
|
||||
gitlab-rails r 'Rails.application.eager_load!; puts ApplicationRecord.descendants.select { |d| d.encrypted_attributes.present? }.index_with { |model| model.count }.values.all?(&:zero?)'
|
||||
```
|
||||
|
||||
1. Create a new Cloud Connector key: `gitlab-rake cloud_connector:keys:create`
|
||||
1. Optional. On all Sidekiq and Rails nodes, check that the encrypted attributes can be read
|
||||
(if no `ActiveRecord::Encryption::Errors::Decryption` exception is raised, it's good):
|
||||
|
||||
```shell
|
||||
gitlab-rails r 'CloudConnector::Keys.first.secret_key; nil'
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab title="Helm chart (Kubernetes)" >}}
|
||||
|
||||
If you disabled the [shared-secrets chart](https://docs.gitlab.com/charts/charts/shared-secrets/),
|
||||
you need to [manually create these secrets](https://docs.gitlab.com/charts/releases/8_0.html).
|
||||
|
||||
{{< /tab >}}
|
||||
|
||||
{{< /tabs >}}
|
||||
If you have a multi-node configuration, you must [ensure these secrets are the same on all nodes](#unify-new-encryption-secrets).
|
||||
|
||||
## 17.8.0
|
||||
|
||||
|
|
@ -412,57 +340,7 @@ In GitLab 17.8, three new secrets have been added to support the new encryption
|
|||
- `active_record_encryption_deterministic_key`
|
||||
- `active_record_encryption_key_derivation_salt`
|
||||
|
||||
**If you have a multi-node configuration, you should ensure these secrets are the same on all nodes.** Otherwise, the application automatically generates the missing secrets at startup.
|
||||
|
||||
{{< tabs >}}
|
||||
|
||||
{{< tab title="Linux package (Omnibus)" >}}
|
||||
|
||||
1. Optional. If possible, put your instance in [maintenance mode](../../administration/maintenance_mode/_index.md) (otherwise if the steps 2 and 5 return `true`, it's fine).
|
||||
1. Check if any records with encrypted attributes exist:
|
||||
|
||||
```shell
|
||||
gitlab-rails r 'Rails.application.eager_load!; puts ApplicationRecord.descendants.select { |d| d.encrypted_attributes.present? }.index_with { |model| model.count }.values.all?(&:zero?)'
|
||||
```
|
||||
|
||||
If the result is `true`, proceed to the next step. Otherwise, we need to check what are the existing records
|
||||
and decide if we can delete them before proceeding further.
|
||||
|
||||
1. Pick one Sidekiq or Rails node as a reference node from which you will copy
|
||||
`/etc/gitlab/gitlab-secrets.json` to all other Sidekiq and Rails nodes.
|
||||
1. On all Sidekiq and Rails nodes (except the reference node):
|
||||
|
||||
1. Back up your [configuration files](https://docs.gitlab.com/omnibus/settings/backups/#backup-and-restore-configuration-on-a-linux-package-installation):
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl backup-etc
|
||||
```
|
||||
|
||||
1. Copy `/etc/gitlab/gitlab-secrets.json` from the reference node, and replace the file of the
|
||||
same name on the current node.
|
||||
1. Reconfigure GitLab:
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl reconfigure
|
||||
```
|
||||
|
||||
1. Check again if any records with encrypted attributes exist (to ensure no records were created while
|
||||
you performed the previous steps). The return value should be `true`:
|
||||
|
||||
```shell
|
||||
gitlab-rails r 'Rails.application.eager_load!; puts ApplicationRecord.descendants.select { |d| d.encrypted_attributes.present? }.index_with { |model| model.count }.values.all?(&:zero?)'
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab title="Helm chart (Kubernetes)" >}}
|
||||
|
||||
If you disabled the [shared-secrets chart](https://docs.gitlab.com/charts/charts/shared-secrets/),
|
||||
you need to [manually create these secrets](https://docs.gitlab.com/charts/releases/8_0.html).
|
||||
|
||||
{{< /tab >}}
|
||||
|
||||
{{< /tabs >}}
|
||||
If you have a multi-node configuration, you must [ensure these secrets are the same on all nodes](#unify-new-encryption-secrets).
|
||||
|
||||
### Change to the GitLab agent server for Kubernetes
|
||||
|
||||
|
|
@ -809,3 +687,194 @@ Feedback about this conditional stop on the upgrade path can be provided [in the
|
|||
| 17.1 | All | 17.1.7 |
|
||||
| 17.2 | All | 17.2.5 |
|
||||
| 17.3 | All | 17.3.1 |
|
||||
|
||||
## Unify new encryption secrets
|
||||
|
||||
[GitLab 17.8 introduced three new secrets](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/175154) to support the new encryption framework, [which was introduced in GitLab 17.9](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/179559):
|
||||
|
||||
- `active_record_encryption_primary_key`
|
||||
- `active_record_encryption_deterministic_key`
|
||||
- `active_record_encryption_key_derivation_salt`
|
||||
|
||||
If you have a multi-node configuration, you must ensure these secrets are the same on all nodes. Otherwise, the application automatically generates the missing secrets at startup.
|
||||
|
||||
{{< tabs >}}
|
||||
|
||||
{{< tab title="Linux package (Omnibus)" >}}
|
||||
|
||||
1. If possible, [enable maintenance mode](../../administration/maintenance_mode/_index.md#enable-maintenance-mode).
|
||||
1. (Only for GitLab >= 17.9) Delete all `CloudConnector::Keys` records:
|
||||
|
||||
```shell
|
||||
gitlab-rails runner 'CloudConnector::Keys.delete_all'
|
||||
```
|
||||
|
||||
1. On all Sidekiq and GitLab application nodes, gather information about encryption keys and their usage.
|
||||
|
||||
On GitLab >= 18.0.0, >= 17.11.2, >= 17.10.6, or >= 17.9.8, run:
|
||||
|
||||
```shell
|
||||
gitlab-rake gitlab:doctor:encryption_keys
|
||||
```
|
||||
|
||||
If you're using other versions, check the content of [`encryption_keys.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/doctor/encryption_keys.rb) and
|
||||
then download it:
|
||||
|
||||
```shell
|
||||
wget -O encryption_keys.rb https://gitlab.com/gitlab-org/gitlab/-/raw/master/lib/gitlab/doctor/encryption_keys.rb?inline=false
|
||||
```
|
||||
|
||||
Then run the file:
|
||||
|
||||
```shell
|
||||
gitlab-rails runner 'require_relative Pathname(Dir.pwd).join("encryption_keys.rb"); Gitlab::Doctor::EncryptionKeys.new(Logger.new($stdout)).run!'
|
||||
```
|
||||
|
||||
The output of the command indicates which one of three possible processes you must follow.
|
||||
|
||||
- If all "Encryption keys usage for \<model\>" report `NONE`, select any Sidekiq or GitLab application node as a reference
|
||||
node from which to copy `/etc/gitlab/gitlab-secrets.json` to all other Sidekiq and GitLab application nodes.
|
||||
- If all reported keys usage are for the same key ID, select the node where the key exists as a reference node from which to copy `/etc/gitlab/gitlab-secrets.json` to all
|
||||
other Sidekiq and GitLab application nodes. For example, let's say you get the following output on node 1:
|
||||
|
||||
```shell
|
||||
Gathering existing encryption keys:
|
||||
- active_record_encryption_primary_key: ID => `bb32`; truncated secret => `bEt...eBU`
|
||||
- active_record_encryption_deterministic_key: ID => `445f`; truncated secret => `MJo...yg5`
|
||||
|
||||
[... snipped for brevity ...]
|
||||
|
||||
Encryption keys usage for VirtualRegistries::Packages::Maven::Upstream: NONE
|
||||
Encryption keys usage for Ai::ActiveContext::Connection: NONE
|
||||
Encryption keys usage for CloudConnector::Keys: NONE
|
||||
Encryption keys usage for DependencyProxy::GroupSetting:
|
||||
- `bb32` => 8
|
||||
Encryption keys usage for Ci::PipelineScheduleInput:
|
||||
- `bb32` => 1
|
||||
```
|
||||
|
||||
And let's say you get the following output on node 2 (the `(UNKNOWN KEY!)` is fine as long as a single key ID is used. For example, `bb32` here):
|
||||
|
||||
```shell
|
||||
Gathering existing encryption keys:
|
||||
- active_record_encryption_primary_key: ID => `83kf`; truncated secret => `pKq...ikC`
|
||||
- active_record_encryption_deterministic_key: ID => `b722`; truncated secret => `Lma...iJ7`
|
||||
|
||||
[... snipped for brevity ...]
|
||||
|
||||
Encryption keys usage for VirtualRegistries::Packages::Maven::Upstream: NONE
|
||||
Encryption keys usage for Ai::ActiveContext::Connection: NONE
|
||||
Encryption keys usage for CloudConnector::Keys: NONE
|
||||
Encryption keys usage for DependencyProxy::GroupSetting:
|
||||
- `bb32` (UNKNOWN KEY!) => 8
|
||||
Encryption keys usage for Ci::PipelineScheduleInput:
|
||||
- `bb32` (UNKNOWN KEY!) => 1
|
||||
```
|
||||
|
||||
With the above examples, you would pick node 1 as the reference node.
|
||||
1. Not all reported keys usage are for the same key ID. For instance, if node 1 shows `` -`bb32` => 1 `` and node 2 shows
|
||||
`` - `83kf` => 1 ``. In that case, the resolution is more complex as it involves re-encrypting all data with a single encryption key.
|
||||
Alternatively, if you're ok losing some data, you can delete records so that all remaining records use the same key ID.
|
||||
Contact [support](https://about.gitlab.com/support/) for further assistance.
|
||||
|
||||
1. After deciding which node is the reference node, decide which of the reference node's secrets must be copied to the other nodes.
|
||||
1. On all Sidekiq and Rails nodes except the reference node:
|
||||
|
||||
1. Back up your [configuration files](https://docs.gitlab.com/omnibus/settings/backups/#backup-and-restore-configuration-on-a-linux-package-installation):
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl backup-etc
|
||||
```
|
||||
|
||||
1. Copy `/etc/gitlab/gitlab-secrets.json` from the reference node, and replace the file of the
|
||||
same name on the current node.
|
||||
1. Reconfigure GitLab:
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl reconfigure
|
||||
```
|
||||
|
||||
1. Check again encryption keys and their usage with one of the following command depending on your version:
|
||||
|
||||
On GitLab >= 18.0.0, >= 17.11.2, >= 17.10.6, or >= 17.9.8, run:
|
||||
|
||||
```shell
|
||||
gitlab-rake gitlab:doctor:encryption_keys
|
||||
```
|
||||
|
||||
If you're using other versions:
|
||||
|
||||
```shell
|
||||
gitlab-rails runner 'require_relative Pathname(Dir.pwd).join("encryption_keys.rb"); Gitlab::Doctor::EncryptionKeys.new(Logger.new($stdout)).run!'
|
||||
```
|
||||
|
||||
All reported keys usage are for the same key ID. For example, on node 1:
|
||||
|
||||
```shell
|
||||
Gathering existing encryption keys:
|
||||
- active_record_encryption_primary_key: ID => `bb32`; truncated secret => `bEt...eBU`
|
||||
- active_record_encryption_deterministic_key: ID => `445f`; truncated secret => `MJo...yg5`
|
||||
|
||||
[... snipped for brevity ...]
|
||||
|
||||
Encryption keys usage for VirtualRegistries::Packages::Maven::Upstream: NONE
|
||||
Encryption keys usage for Ai::ActiveContext::Connection: NONE
|
||||
Encryption keys usage for CloudConnector::Keys:
|
||||
- `bb32` => 1
|
||||
Encryption keys usage for DependencyProxy::GroupSetting:
|
||||
- `bb32` => 8
|
||||
Encryption keys usage for Ci::PipelineScheduleInput:
|
||||
- `bb32` => 1
|
||||
```
|
||||
|
||||
And for example, on node 2 (you should not see any `(UNKNOWN KEY!)` this time):
|
||||
|
||||
```shell
|
||||
Gathering existing encryption keys:
|
||||
- active_record_encryption_primary_key: ID => `bb32`; truncated secret => `bEt...eBU`
|
||||
- active_record_encryption_deterministic_key: ID => `445f`; truncated secret => `MJo...yg5`
|
||||
|
||||
[... snipped for brevity ...]
|
||||
|
||||
Encryption keys usage for VirtualRegistries::Packages::Maven::Upstream: NONE
|
||||
Encryption keys usage for Ai::ActiveContext::Connection: NONE
|
||||
Encryption keys usage for CloudConnector::Keys:
|
||||
- `bb32` => 1
|
||||
Encryption keys usage for DependencyProxy::GroupSetting:
|
||||
- `bb32` => 8
|
||||
Encryption keys usage for Ci::PipelineScheduleInput:
|
||||
- `bb32` => 1
|
||||
```
|
||||
|
||||
1. Remove the `encryption_keys.rb` file if you downloaded it previously:
|
||||
|
||||
```shell
|
||||
rm encryption_keys.rb
|
||||
```
|
||||
|
||||
1. Create a new Cloud Connector key:
|
||||
|
||||
For GitLab >= 17.10:
|
||||
|
||||
```shell
|
||||
gitlab-rake cloud_connector:keys:create
|
||||
```
|
||||
|
||||
For GitLab 17.9:
|
||||
|
||||
```shell
|
||||
gitlab-rails runner 'CloudConnector::Keys.create!(secret_key: OpenSSL::PKey::RSA.new(2048).to_pem)'
|
||||
```
|
||||
|
||||
1. [Disable maintenance mode](../../administration/maintenance_mode/_index.md#disable-maintenance-mode).
|
||||
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab title="Helm chart (Kubernetes)" >}}
|
||||
|
||||
If you disabled the [shared-secrets chart](https://docs.gitlab.com/charts/charts/shared-secrets/),
|
||||
you need to [manually create these secrets](https://docs.gitlab.com/charts/releases/8_0.html).
|
||||
|
||||
{{< /tab >}}
|
||||
|
||||
{{< /tabs >}}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ module Gitlab
|
|||
module Utils
|
||||
module MergeHash
|
||||
extend self
|
||||
# Deep merges an array of hashes
|
||||
# Deep merges an array of elements which can be hashes, arrays, or other objects.
|
||||
#
|
||||
# [{ hello: ["world"] },
|
||||
# { hello: "Everyone" },
|
||||
|
|
@ -49,8 +49,14 @@ module Gitlab
|
|||
|
||||
def merge_hash_into_array(array, new_hash)
|
||||
crushed_new_hash = crush_hash(new_hash)
|
||||
|
||||
# Merge the hash into an existing element of the array if there is overlap
|
||||
if mergeable_index = array.index { |element| crushable?(element) && (crush(element) & crushed_new_hash).any? }
|
||||
mergeable_index = array.index do |element|
|
||||
crushed_element = crushable?(element) ? crush(element) : Array.wrap(element)
|
||||
(crushed_element & crushed_new_hash).any?
|
||||
end
|
||||
|
||||
if mergeable_index
|
||||
array[mergeable_index] = merge_hash_tree(array[mergeable_index], new_hash)
|
||||
else
|
||||
array << new_hash
|
||||
|
|
|
|||
|
|
@ -61196,7 +61196,7 @@ msgstr ""
|
|||
msgid "The subdomain setting."
|
||||
msgstr ""
|
||||
|
||||
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
|
||||
msgid "The subject will be used as the title of the new %{name}, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
|
||||
msgstr ""
|
||||
|
||||
msgid "The tag name can't be changed for an existing release."
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import {
|
|||
convertWorkItemMutationResponse,
|
||||
workItemChangeTypeWidgets,
|
||||
workItemQueryResponse,
|
||||
workItemWithEpicParentQueryResponse,
|
||||
} from '../mock_data';
|
||||
import { designCollectionResponse, mockDesign } from './design_management/mock_data';
|
||||
|
||||
|
|
@ -78,6 +79,7 @@ describe('WorkItemChangeTypeModal component', () => {
|
|||
convertWorkItemMutationHandler = convertWorkItemMutationSuccessHandler,
|
||||
designQueryHandler = noDesignQueryHandler,
|
||||
allowedConversionTypesEE = [],
|
||||
hasSubepicsFeature = true,
|
||||
} = {}) => {
|
||||
wrapper = mountExtended(WorkItemChangeTypeModal, {
|
||||
apolloProvider: createMockApollo([
|
||||
|
|
@ -100,6 +102,7 @@ describe('WorkItemChangeTypeModal component', () => {
|
|||
glFeatures: {
|
||||
workItemsAlpha,
|
||||
},
|
||||
hasSubepicsFeature,
|
||||
},
|
||||
stubs: {
|
||||
GlModal: stubComponent(GlModal, {
|
||||
|
|
@ -141,20 +144,34 @@ describe('WorkItemChangeTypeModal component', () => {
|
|||
expect(findGlFormSelect().findAll('option')).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('does not allow to change type and disables `Change type` button when the work item has a parent', async () => {
|
||||
createComponent({ hasParent: true, widgets: workItemQueryResponse.data.workItem.widgets });
|
||||
describe('work item type change tests', () => {
|
||||
it.each`
|
||||
scenario | widgets | hasSubepicsFeature | btnDisabled | parentType
|
||||
${'epic parent with subepics enabled'} | ${workItemWithEpicParentQueryResponse.data.workItem.widgets} | ${true} | ${false} | ${''}
|
||||
${'epic parent with subepics disabled'} | ${workItemWithEpicParentQueryResponse.data.workItem.widgets} | ${false} | ${true} | ${'epic'}
|
||||
${'non-epic parent with subepics enabled'} | ${workItemQueryResponse.data.workItem.widgets} | ${true} | ${true} | ${'issue'}
|
||||
${'non-epic parent with subepics disabled'} | ${workItemQueryResponse.data.workItem.widgets} | ${false} | ${true} | ${'issue'}
|
||||
`('$scenario', async ({ widgets, hasSubepicsFeature, btnDisabled, parentType }) => {
|
||||
createComponent({
|
||||
hasParent: true,
|
||||
widgets,
|
||||
hasSubepicsFeature,
|
||||
});
|
||||
|
||||
await waitForPromises();
|
||||
await waitForPromises();
|
||||
|
||||
findGlFormSelect().vm.$emit('change', issueTypeId);
|
||||
findGlFormSelect().vm.$emit('change', issueTypeId);
|
||||
|
||||
await nextTick();
|
||||
await nextTick();
|
||||
|
||||
expect(findWarningAlert().text()).toBe(
|
||||
'Parent item type issue is not supported on issue. Remove the parent item to change type.',
|
||||
);
|
||||
|
||||
expect(findChangeTypeModal().props('actionPrimary').attributes.disabled).toBe(true);
|
||||
const hasWarning = parentType !== '';
|
||||
expect(findWarningAlert().exists()).toBe(hasWarning);
|
||||
if (hasWarning) {
|
||||
const warningText = `Parent item type ${parentType} is not supported on issue. Remove the parent item to change type.`;
|
||||
expect(findWarningAlert().text()).toBe(warningText);
|
||||
}
|
||||
expect(findChangeTypeModal().props('actionPrimary').attributes.disabled).toBe(btnDisabled);
|
||||
});
|
||||
});
|
||||
|
||||
it('does not allow to change type and disables `Change type` button when the work item has child items', async () => {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import getWorkItemTreeQuery from '~/work_items/graphql/work_item_tree.query.grap
|
|||
import isExpandedHierarchyTreeChildQuery from '~/work_items/graphql/client/is_expanded_hierarchy_tree_child.query.graphql';
|
||||
import WorkItemLinkChild from '~/work_items/components/work_item_links/work_item_link_child.vue';
|
||||
import WorkItemChildrenWrapper from '~/work_items/components/work_item_links/work_item_children_wrapper.vue';
|
||||
import WorkItemLinkChildContents from '~/work_items/components/shared/work_item_link_child_contents.vue';
|
||||
import WorkItemLinkChildContents from 'ee_else_ce/work_items/components/shared/work_item_link_child_contents.vue';
|
||||
import {
|
||||
WIDGET_TYPE_HIERARCHY,
|
||||
WORK_ITEM_TYPE_NAME_OBJECTIVE,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
|||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import WorkItemRelationshipList from '~/work_items/components/work_item_relationships/work_item_relationship_list.vue';
|
||||
import WorkItemLinkChildContents from '~/work_items/components/shared/work_item_link_child_contents.vue';
|
||||
import WorkItemLinkChildContents from 'ee_else_ce/work_items/components/shared/work_item_link_child_contents.vue';
|
||||
|
||||
import removeLinkedItemsMutation from '~/work_items/graphql/remove_linked_items.mutation.graphql';
|
||||
import addLinkedItemsMutation from '~/work_items/graphql/add_linked_items.mutation.graphql';
|
||||
|
|
@ -87,7 +87,6 @@ describe('WorkItemRelationshipList', () => {
|
|||
childItem: mockLinkedItems[0].workItem,
|
||||
canUpdate: true,
|
||||
workItemFullPath,
|
||||
showWeight: true,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -333,6 +333,85 @@ export const workItemQueryResponse = {
|
|||
},
|
||||
};
|
||||
|
||||
export const workItemWithEpicParentQueryResponse = {
|
||||
data: {
|
||||
workItem: {
|
||||
__typename: 'WorkItem',
|
||||
id: 'gid://gitlab/WorkItem/1',
|
||||
iid: '1',
|
||||
archived: false,
|
||||
title: 'Test',
|
||||
movedToWorkItemUrl: null,
|
||||
duplicatedToWorkItemUrl: null,
|
||||
promotedToEpicUrl: null,
|
||||
state: 'OPEN',
|
||||
description: 'description',
|
||||
confidential: false,
|
||||
createdAt: '2022-08-03T12:41:54Z',
|
||||
updatedAt: null,
|
||||
closedAt: null,
|
||||
author: {
|
||||
avatarUrl: 'http://127.0.0.1:3000/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
|
||||
id: 'gid://gitlab/User/1',
|
||||
name: 'Administrator',
|
||||
username: 'root',
|
||||
webUrl: 'http://127.0.0.1:3000/root',
|
||||
webPath: '/root',
|
||||
__typename: 'UserCore',
|
||||
},
|
||||
project: {
|
||||
id: 'gid://gitlab/Project/7',
|
||||
__typename: 'Project',
|
||||
},
|
||||
namespace: {
|
||||
__typename: 'Project',
|
||||
id: '1',
|
||||
fullPath: 'test-project-path',
|
||||
name: 'Project name',
|
||||
fullName: 'Group name',
|
||||
},
|
||||
workItemType: {
|
||||
__typename: 'WorkItemType',
|
||||
id: 'gid://gitlab/WorkItems::Type/5',
|
||||
name: 'Task',
|
||||
iconName: 'issue-type-task',
|
||||
},
|
||||
userPermissions: {
|
||||
adminParentLink: false,
|
||||
adminWorkItemLink: true,
|
||||
deleteWorkItem: false,
|
||||
createNote: false,
|
||||
markNoteAsInternal: true,
|
||||
moveWorkItem: false,
|
||||
reportSpam: false,
|
||||
setWorkItemMetadata: false,
|
||||
summarizeComments: false,
|
||||
updateWorkItem: false,
|
||||
__typename: 'WorkItemPermissions',
|
||||
},
|
||||
widgets: [
|
||||
{
|
||||
__typename: 'WorkItemWidgetHierarchy',
|
||||
type: 'HIERARCHY',
|
||||
hasChildren: true,
|
||||
parent: {
|
||||
id: 'gid://gitlab/WorkItem/3',
|
||||
title: 'Work Item Epic',
|
||||
webUrl: 'http://127.0.0.1:3000/groups/gitlab-org/-/work_items/130',
|
||||
__typename: 'WorkItem',
|
||||
workItemType: {
|
||||
id: 'gid://gitlab/WorkItems::Type/6',
|
||||
name: 'Epic',
|
||||
iconName: 'issue-type-epic',
|
||||
__typename: 'WorkItemType',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const updateWorkItemMutationResponse = {
|
||||
data: {
|
||||
workItemUpdate: {
|
||||
|
|
|
|||
|
|
@ -289,6 +289,7 @@ RSpec.describe IssuesHelper, feature_category: :team_planning do
|
|||
allow(helper).to receive(:can?).with(current_user, :read_crm_organization, group.crm_group).and_return(false)
|
||||
allow(helper).to receive(:image_path).and_return('#')
|
||||
allow(helper).to receive(:url_for).and_return('#')
|
||||
allow(helper).to receive(:licensed_feature_available?).with(:subepics).and_return(false)
|
||||
|
||||
assign(:has_issues, false)
|
||||
assign(:has_projects, true)
|
||||
|
|
@ -307,7 +308,8 @@ RSpec.describe IssuesHelper, feature_category: :team_planning do
|
|||
rss_path: '#',
|
||||
sign_in_path: new_user_session_path,
|
||||
group_id: group.id,
|
||||
time_tracking_limit_to_hours: "false"
|
||||
time_tracking_limit_to_hours: "false",
|
||||
has_subepics_feature: "false"
|
||||
}
|
||||
|
||||
expect(helper.group_issues_list_data(group, current_user)).to include(expected)
|
||||
|
|
@ -498,4 +500,59 @@ RSpec.describe IssuesHelper, feature_category: :team_planning do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#has_subepics_feature?' do
|
||||
subject(:has_subepics_feature) { helper.has_subepics_feature?(namespace) }
|
||||
|
||||
context 'when namespace is a group project' do
|
||||
let_it_be(:namespace) { create(:project, namespace: group) }
|
||||
|
||||
context 'when subepics feature is licensed and available for group' do
|
||||
before do
|
||||
allow(namespace.group).to receive(:licensed_feature_available?).with(:subepics).and_return(true)
|
||||
end
|
||||
|
||||
it { is_expected.to be_truthy }
|
||||
end
|
||||
|
||||
context 'when subepics feature is not licensed for group' do
|
||||
before do
|
||||
allow(namespace.group).to receive(:licensed_feature_available?).with(:subepics).and_return(false)
|
||||
end
|
||||
|
||||
it { is_expected.to be_falsey }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when namespace is a group' do
|
||||
let_it_be(:namespace) { group }
|
||||
|
||||
context 'when subepics feature is licensed and available' do
|
||||
before do
|
||||
allow(namespace).to receive(:licensed_feature_available?).with(:subepics).and_return(true)
|
||||
end
|
||||
|
||||
it { is_expected.to be_truthy }
|
||||
end
|
||||
|
||||
context 'when subepics feature is not licensed' do
|
||||
before do
|
||||
allow(namespace).to receive(:licensed_feature_available?).with(:subepics).and_return(false)
|
||||
end
|
||||
|
||||
it { is_expected.to be_falsey }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when namespace is neither a group nor has a group' do
|
||||
let_it_be(:namespace) { create(:namespace) }
|
||||
|
||||
before do
|
||||
allow(namespace).to receive(:is_a?).with(Group).and_return(false)
|
||||
allow(namespace).to receive(:respond_to?).with(:group).and_return(false)
|
||||
end
|
||||
|
||||
it { is_expected.to be_falsey }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,10 +13,15 @@ RSpec.describe Gitlab::Utils::MergeHash do
|
|||
|
||||
describe '.elements' do
|
||||
it 'deep merges an array of elements' do
|
||||
input = [{ hello: ["world"] },
|
||||
{ hello: "Everyone" },
|
||||
{ hello: { greetings: ['Bonjour', 'Hello', 'Hallo', 'Dzień dobry'] } },
|
||||
"Goodbye", "Hallo"]
|
||||
input = [
|
||||
:hello,
|
||||
"Howdy",
|
||||
{ hello: ["world"] },
|
||||
{ hello: "Everyone" },
|
||||
{ hello: { greetings: ['Bonjour', 'Hello', 'Hallo', 'Dzień dobry'] } },
|
||||
"Goodbye",
|
||||
"Hallo"
|
||||
]
|
||||
expected_output = [
|
||||
{
|
||||
hello:
|
||||
|
|
@ -26,6 +31,7 @@ RSpec.describe Gitlab::Utils::MergeHash do
|
|||
{ greetings: ['Bonjour', 'Hello', 'Hallo', 'Dzień dobry'] }
|
||||
]
|
||||
},
|
||||
"Howdy",
|
||||
"Goodbye"
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ RSpec.describe DesignManagement::Version do
|
|||
|
||||
it 'has an appropriate cause' do
|
||||
expect { call_with_empty_actions }
|
||||
.to raise_error(have_attributes(cause: ActiveRecord::RecordInvalid))
|
||||
.to raise_error(have_attributes(cause: ActiveRecord::StatementInvalid))
|
||||
end
|
||||
|
||||
it 'provides extra data sentry can consume' do
|
||||
|
|
|
|||
Loading…
Reference in New Issue