Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-06-21 06:08:36 +00:00
parent bc69b91579
commit 2b9f6cfb3f
45 changed files with 637 additions and 335 deletions

View File

@ -1058,29 +1058,6 @@ Layout/ArgumentAlignment:
- 'ee/spec/features/projects/merge_requests/user_edits_merge_request_spec.rb'
- 'ee/spec/features/projects/milestones/milestone_spec.rb'
- 'ee/spec/features/projects/security/user_views_security_configuration_spec.rb'
- 'ee/spec/features/projects/settings/ee/repository_mirrors_settings_spec.rb'
- 'ee/spec/features/projects/settings/merge_requests/user_manages_approval_settings_spec.rb'
- 'ee/spec/features/projects/settings/merge_requests/user_manages_merge_pipelines_spec.rb'
- 'ee/spec/features/projects/settings/merge_requests/user_manages_merge_requests_template_spec.rb'
- 'ee/spec/features/projects/settings/merge_requests/user_manages_merge_trains_spec.rb'
- 'ee/spec/features/projects/settings/user_manages_approval_settings_spec.rb'
- 'ee/spec/features/projects/settings/user_manages_merge_requests_template_spec.rb'
- 'ee/spec/features/registrations/email_confirmation_spec.rb'
- 'ee/spec/features/registrations/saas/standard_flow_company_creating_project_spec.rb'
- 'ee/spec/features/registrations/saas/standard_flow_company_joining_project_spec.rb'
- 'ee/spec/features/registrations/saas/standard_flow_just_me_creating_project_spec.rb'
- 'ee/spec/features/registrations/saas/standard_flow_just_me_importing_project_spec.rb'
- 'ee/spec/features/registrations/saas/standard_flow_just_me_joining_project_spec.rb'
- 'ee/spec/features/registrations/saas/subscription_flow_paid_plan_spec.rb'
- 'ee/spec/features/registrations/saas/trial_flow_company_creating_project_spec.rb'
- 'ee/spec/features/registrations/saas/trial_flow_company_importing_project_spec.rb'
- 'ee/spec/features/registrations/saas/trial_flow_just_me_creating_project_spec.rb'
- 'ee/spec/features/registrations/saas/trial_flow_just_me_importing_project_spec.rb'
- 'ee/spec/features/registrations/sign_up_with_trial_from_external_site_without_confirmation_spec.rb'
- 'ee/spec/features/search/elastic/global_search_spec.rb'
- 'ee/spec/features/search/elastic/group_search_spec.rb'
- 'ee/spec/features/security/project/discover_spec.rb'
- 'ee/spec/features/users/identity_verification_spec.rb'
- 'ee/spec/frontend/fixtures/dora/metrics.rb'
- 'ee/spec/frontend/fixtures/oncall_schedule.rb'
- 'ee/spec/graphql/ee/mutations/boards/lists/create_spec.rb'
@ -1570,22 +1547,6 @@ Layout/ArgumentAlignment:
- 'spec/components/previews/pajamas/alert_component_preview.rb'
- 'spec/components/previews/pajamas/banner_component_preview.rb'
- 'spec/components/previews/pajamas/button_component_preview.rb'
- 'spec/features/admin/admin_mode/login_spec.rb'
- 'spec/features/admin/integrations/user_activates_mattermost_slash_command_spec.rb'
- 'spec/features/atom/issues_spec.rb'
- 'spec/features/atom/merge_requests_spec.rb'
- 'spec/features/atom/users_spec.rb'
- 'spec/features/boards/issue_ordering_spec.rb'
- 'spec/features/boards/multi_select_spec.rb'
- 'spec/features/boards/sidebar_assignee_spec.rb'
- 'spec/features/calendar_spec.rb'
- 'spec/features/clusters/cluster_health_dashboard_spec.rb'
- 'spec/features/commits_spec.rb'
- 'spec/features/dashboard/activity_spec.rb'
- 'spec/features/dashboard/datetime_on_tooltips_spec.rb'
- 'spec/features/dashboard/merge_requests_spec.rb'
- 'spec/features/dashboard/todos/todos_sorting_spec.rb'
- 'spec/features/dashboard/todos/todos_spec.rb'
- 'spec/features/error_tracking/user_filters_errors_by_status_spec.rb'
- 'spec/features/error_tracking/user_searches_sentry_errors_spec.rb'
- 'spec/features/error_tracking/user_sees_error_details_spec.rb'

View File

@ -69,7 +69,7 @@ export default {
this.openModal();
},
extraAttrs: {
'data-qa-selector': 'delete_merged_branches_button',
'data-testid': 'delete-merged-branches-button',
class: 'gl-text-red-500!',
},
},
@ -102,12 +102,11 @@ export default {
category="tertiary"
no-caret
placement="right"
data-qa-selector="delete_merged_branches_dropdown_button"
class="gl-display-none gl-md-display-block!"
:items="dropdownItems"
/>
<gl-button
data-qa-selector="delete_merged_branches_button"
data-testid="delete-merged-branches-button"
category="secondary"
variant="danger"
class="gl-display-block gl-md-display-none!"
@ -153,7 +152,6 @@ export default {
</gl-sprintf>
<gl-form-input
v-model="enteredText"
data-qa-selector="delete_merged_branches_input"
type="text"
size="sm"
class="gl-mt-2"
@ -178,7 +176,6 @@ export default {
ref="deleteMergedBrancesButton"
:disabled="isDeleteButtonDisabled"
variant="danger"
data-qa-selector="delete_merged_branches_confirmation_button"
data-testid="delete-merged-branches-confirmation-button"
@click="submitForm"
>{{ $options.i18n.deleteButtonText }}</gl-button

View File

@ -3,8 +3,8 @@ import {
GlAlert,
GlLink,
GlTable,
GlDropdownItem,
GlDropdown,
GlDisclosureDropdown,
GlDisclosureDropdownItem,
GlButton,
GlFormCheckbox,
GlLoadingIcon,
@ -51,8 +51,8 @@ export default {
GlAlert,
GlLink,
GlTable,
GlDropdown,
GlDropdownItem,
GlDisclosureDropdown,
GlDisclosureDropdownItem,
GlFormCheckbox,
GlButton,
GlLoadingIcon,
@ -426,6 +426,7 @@ export default {
v-if="hasDetails(item)"
:icon="detailsShowing ? 'chevron-up' : 'chevron-down'"
:aria-label="detailsShowing ? __('Collapse') : __('Expand')"
data-testid="toggle-details-button"
category="tertiary"
size="small"
@click="
@ -453,18 +454,23 @@ export default {
</template>
<template #cell(actions)="{ item }">
<gl-dropdown
<gl-disclosure-dropdown
category="tertiary"
icon="ellipsis_v"
:text-sr-only="true"
:text="$options.i18n.moreActionsText"
placement="right"
:toggle-text="$options.i18n.moreActionsText"
text-sr-only
no-caret
right
>
<gl-dropdown-item data-testid="delete-file" @click="handleFileDelete([item])">
{{ $options.i18n.deleteFile }}
</gl-dropdown-item>
</gl-dropdown>
<gl-disclosure-dropdown-item
data-testid="delete-file"
@action="handleFileDelete([item])"
>
<template #list-item>
{{ $options.i18n.deleteFile }}
</template>
</gl-disclosure-dropdown-item>
</gl-disclosure-dropdown>
</template>
<template #row-details="{ item }">

View File

@ -11,9 +11,9 @@
= branch.name
= clipboard_button(text: branch.name, title: _("Copy branch name"))
- if is_default_branch
= gl_badge_tag s_('DefaultBranchLabel|default'), { variant: :neutral, size: :sm }, { class: 'gl-ml-2', data: { qa_selector: 'badge_content' } }
= gl_badge_tag s_('DefaultBranchLabel|default'), { variant: :neutral, size: :sm }, { class: 'gl-ml-2' }
- if protected_branch?(@project, branch)
= gl_badge_tag s_('Branches|protected'), { variant: :muted, size: :sm }, { class: 'gl-ml-2', data: { qa_selector: 'badge_content' } }
= gl_badge_tag s_('Branches|protected'), { variant: :muted, size: :sm }, { class: 'gl-ml-2' }
= render_if_exists 'projects/branches/diverged_from_upstream', branch: branch
@ -39,7 +39,7 @@
.issuable-reference.gl-display-flex.gl-justify-content-end.gl-overflow-hidden
= gl_badge_tag issuable_reference(related_merge_request),
{ icon: mr_status[:icon], variant: mr_status[:variant], size: :md, href: merge_request_path(related_merge_request) },
{ class: 'gl-display-block gl-text-truncate', title: mr_status[:title], data: { toggle: 'tooltip', container: 'body', qa_selector: 'badge_content' } }
{ class: 'gl-display-block gl-text-truncate', title: mr_status[:title], data: { toggle: 'tooltip', container: 'body' } }
- elsif mr_status.nil? && create_mr_button?(from: branch.name, source_project: @project)
= render Pajamas::ButtonComponent.new(icon: 'merge-request', href: create_mr_path(from: branch.name, source_project: @project), button_options: { class: 'has-tooltip', title: _('New merge request') }) do

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class ScheduleIndexEventsOnProjectIdAndIdDescOnMergedActionForRemoval < Gitlab::Database::Migration[2.1]
INDEX_NAME = 'index_events_on_project_id_and_id_desc_on_merged_action'
# TODO: Index to be destroyed synchronously in https://gitlab.com/gitlab-org/gitlab/-/issues/415091
def up
prepare_async_index_removal :events, [:project_id, :id], order: { id: :desc },
where: "action = 7", name: INDEX_NAME
end
def down
unprepare_async_index :events, [:project_id, :id], order: { id: :desc },
where: "action = 7", name: INDEX_NAME
end
end

View File

@ -0,0 +1,18 @@
# frozen_string_literal: true
class PrepareIndexForVulnerabilityReadsOnCommonProjectFilters < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
INDEX_NAME = 'index_project_vulnerability_reads_common_finder_query_desc'
def up
prepare_async_index :vulnerability_reads,
[:project_id, :state, :report_type, :severity, :vulnerability_id],
order: { severity: :desc, vulnerability_id: :desc },
name: INDEX_NAME
end
def down
unprepare_async_index_by_name :vulnerability_reads, INDEX_NAME
end
end

View File

@ -0,0 +1 @@
6bf4fa6d2e43f1b589204f3b58323f32d9db2344882507e14bc487913cbe6f8e

View File

@ -0,0 +1 @@
248e7dabf83e225c5f5ee0de87e0842e8c3ec13f6098720830ce3b817a4d36a8

View File

@ -33596,7 +33596,7 @@ CREATE UNIQUE INDEX unique_index_for_project_pages_unique_domain ON project_sett
CREATE UNIQUE INDEX unique_index_on_system_note_metadata_id ON resource_link_events USING btree (system_note_metadata_id);
CREATE UNIQUE INDEX unique_instance_audit_event_destination_namespace_id_and_name ON audit_events_instance_external_audit_event_destinations USING btree (name);
CREATE UNIQUE INDEX unique_instance_audit_event_destination_name ON audit_events_instance_external_audit_event_destinations USING btree (name);
CREATE UNIQUE INDEX unique_merge_request_diff_llm_summaries_on_mr_diff_id ON merge_request_diff_llm_summaries USING btree (merge_request_diff_id);

View File

@ -183,8 +183,8 @@ see the [Tomcat Documentation](https://tomcat.apache.org/tomcat-10.1-doc/index.h
1. Install and configure Tomcat 10:
```shell
cd /tmp & wget https://dlcdn.apache.org/tomcat/tomcat-10/v10.1.9/bin/apache-tomcat-10.1.9.tar.gz
sudo tar xzvf apache-tomcat-10*tar.gz -C /opt/tomcat --strip-components=1
wget https://dlcdn.apache.org/tomcat/tomcat-10/v10.1.9/bin/apache-tomcat-10.1.9.tar.gz -P /tmp
sudo tar xzvf /tmp/apache-tomcat-10*tar.gz -C /opt/tomcat --strip-components=1
sudo chown -R tomcat:tomcat /opt/tomcat/
sudo chmod -R u+x /opt/tomcat/bin
```
@ -270,7 +270,8 @@ see the [Tomcat Documentation](https://tomcat.apache.org/tomcat-10.1-doc/index.h
1. Install PlantUML and copy the `.war` file:
```shell
cd / & git clone https://github.com/plantuml/plantuml-server.git
cd /
git clone https://github.com/plantuml/plantuml-server.git
cd plantuml-server
mvn package
cp /plantuml-server/target/plantuml.war /opt/tomcat/webapps/plantuml.war

View File

@ -115,9 +115,20 @@ Example response:
```
Users on [GitLab Premium or Ultimate](https://about.gitlab.com/pricing/) may also see
the `group_owners_can_manage_default_branch_protection`, `file_template_project_id`, `delayed_project_deletion`,
`delayed_group_deletion`, `default_project_deletion_protection`, `deletion_adjourned_period`, `disable_personal_access_tokens`, `geo_node_allowed_ips`,
or the `security_policy_global_group_approvers_enabled` parameters.
these parameters:
- `group_owners_can_manage_default_branch_protection`
- `file_template_project_id`
- `geo_node_allowed_ips`
- `geo_status_timeout`
- `delayed_project_deletion`
- `delayed_group_deletion`
- `default_project_deletion_protection`
- `deletion_adjourned_period`
- `disable_personal_access_tokens`
- `security_policy_global_group_approvers_enabled`
- `delete_unconfirmed_users`
- `unconfirmed_users_delete_after_days`
From [GitLab 15.11](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113332), with the `always_perform_delayed_deletion` feature flag enabled,
the `delayed_project_deletion` and `delayed_group_deletion` attributes will not be exposed. These attributes will be removed in GitLab 16.0.
@ -257,6 +268,8 @@ these parameters:
- `deletion_adjourned_period`
- `disable_personal_access_tokens`
- `security_policy_global_group_approvers_enabled`
- `delete_unconfirmed_users`
- `unconfirmed_users_delete_after_days`
From [GitLab 15.11](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113332), with the `always_perform_delayed_deletion` feature flag enabled,
the `delayed_project_deletion` and `delayed_group_deletion` attributes will not be exposed. These attributes will be removed in GitLab 16.0.
@ -328,6 +341,7 @@ listed in the descriptions of the relevant settings.
| `delayed_project_deletion` **(PREMIUM SELF)** | boolean | no | Enable delayed project deletion by default in new groups. Default is `false`. [From GitLab 15.1](https://gitlab.com/gitlab-org/gitlab/-/issues/352960), can only be enabled when `delayed_group_deletion` is true. From [GitLab 15.11](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113332), with the `always_perform_delayed_deletion` feature flag enabled, this attribute has been removed. This attribute will be completely removed in GitLab 16.0. |
| `delayed_group_deletion` **(PREMIUM SELF)** | boolean | no | Enable delayed group deletion. Default is `true`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/352959) in GitLab 15.0. [From GitLab 15.1](https://gitlab.com/gitlab-org/gitlab/-/issues/352960), disables and locks the group-level setting for delayed protect deletion when set to `false`. From [GitLab 15.11](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113332), with the `always_perform_delayed_deletion` feature flag enabled, this attribute has been removed. This attribute will be completely removed in GitLab 16.0. |
| `default_project_deletion_protection` **(PREMIUM SELF)** | boolean | no | Enable default project deletion protection so only administrators can delete projects. Default is `false`. |
| `delete_unconfirmed_users` **(PREMIUM SELF)** | boolean | no | Specifies whether users who have not confirmed their email should be deleted. Default is `false`. When set to `true`, unconfirmed users are deleted after `unconfirmed_users_delete_after_days` days. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/352514) in GitLab 16.1. |
| `deletion_adjourned_period` **(PREMIUM SELF)** | integer | no | The number of days to wait before deleting a project or group that is marked for deletion. Value must be between `1` and `90`. Defaults to `7`. [From GitLab 15.1](https://gitlab.com/gitlab-org/gitlab/-/issues/352960), a hook on `deletion_adjourned_period` sets the period to `1` on every update, and sets both `delayed_project_deletion` and `delayed_group_deletion` to `false` if the period is `0`. |
| `diagramsnet_enabled` | boolean | no | (If enabled, requires `diagramsnet_url`) Enable [Diagrams.net integration](../administration/integration/diagrams_net.md). Default is `true`. |
| `diagramsnet_url` | string | required by: `diagramsnet_enabled` | The Diagrams.net instance URL for integration. |
@ -534,6 +548,7 @@ listed in the descriptions of the relevant settings.
| `throttle_unauthenticated_web_requests_per_period` | integer | required by:<br>`throttle_unauthenticated_web_enabled` | Max requests per period per IP. |
| `time_tracking_limit_to_hours` | boolean | no | Limit display of time tracking units to hours. Default is `false`. |
| `two_factor_grace_period` | integer | required by: `require_two_factor_authentication` | Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication. |
| `unconfirmed_users_delete_after_days` **(PREMIUM SELF)** | integer | no | Specifies how many days after sign-up to delete users who have not confirmed their email. Only applicable if `delete_unconfirmed_users` is set to `true`. Must be `1` or greater. Default is `7`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/352514) in GitLab 16.1. |
| `unique_ips_limit_enabled` | boolean | no | (**If enabled, requires:** `unique_ips_limit_per_user` and `unique_ips_limit_time_window`) Limit sign in from multiple IPs. |
| `unique_ips_limit_per_user` | integer | required by: `unique_ips_limit_enabled` | Maximum number of IPs per user. |
| `unique_ips_limit_time_window` | integer | required by: `unique_ips_limit_enabled` | How many seconds an IP is counted towards the limit. |

View File

@ -872,20 +872,21 @@ If you want to reduce risk slightly, consider putting the migrations into a
second merge request after the application changes are merged. This approach
provides an opportunity to roll back.
Removing the foreign key on the `projects` table:
Removing the foreign key on the `projects` table using a non-transactional migration:
```ruby
# first migration file
class RemovingForeignKeyMigrationClass < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
def up
with_lock_retries do
remove_foreign_key :my_table, :projects
def up
with_lock_retries do
remove_foreign_key :my_table, :projects
end
end
end
def down
with_lock_retries do
add_foreign_key :my_table, :projects
def down
add_concurrent_foreign_key :my_table, :projects, column: COLUMN_NAME
end
end
```
@ -894,17 +895,19 @@ Dropping the table:
```ruby
# second migration file
class DroppingTableMigrationClass < Gitlab::Database::Migration[2.1]
def up
drop_table :my_table
end
def up
drop_table :my_table
end
def down
# create_table ...
def down
# create_table with the same schema but without the removed foreign key ...
end
end
```
After a table has been dropped, it should be added to the database dictionary, following the steps in the [database dictionary guide](database/database_dictionary.md#dropping-tables).
After a table has been dropped, it should be added to the database dictionary, following the
steps in the [database dictionary guide](database/database_dictionary.md#dropping-tables).
## Dropping a sequence

View File

@ -139,3 +139,165 @@ end
If classes that are defined into a namespace have a lot in common with classes in other namespaces,
chances are that these two namespaces are part of the same bounded context.
## Taming Omniscient classes
We must consider not adding new data and behavior to [omniscient classes](https://en.wikipedia.org/wiki/God_object) (also known as god objects).
We consider `Project`, `User`, `MergeRequest`, `Ci::Pipeline` and any classes above 1000 LOC to be omniscient.
Such classes are overloaded with responsibilities. New data and behavior can most of the time be added
as a separate and dedicated class.
Guidelines:
- If you mostly need a reference to the object ID (for example `Project#id`) you could add a new model
that uses the foreign key or a thin wrapper around the object to add special behavior.
- If you find out that by adding a method to the omniscient class you also end up adding a couple of other methods
(private or public) it's a sign that these methods should be encapsulated in a dedicated class.
- It's temping to add a method to `Project` because that's the starting point of data and associations.
Try to define behavior in the bounded context where it belongs, not where the data (or some of it) is.
This helps creating facets of the omniscient object that are much more relevant in the bounded context than
having generic and overloaded objects which bring more coupling and complexity.
### Example: Define a thin domain object around a generic model
Instead of adding multiple methods to `User` because it has an association to `abuse_trust_scores`,
try inverting the dependency.
```ruby
##
# BAD: Behavior added to User object.
class User
def spam_score
abuse_trust_scores.spamcheck.average(:score) || 0.0
end
def spammer?
# Warning sign: we use a constant that belongs to a specific bounded context!
spam_score > Abuse::TrustScore::SPAMCHECK_HAM_THRESHOLD
end
def telesign_score
abuse_trust_scores.telesign.recent_first.first&.score || 0.0
end
def arkose_global_score
abuse_trust_scores.arkose_global_score.recent_first.first&.score || 0.0
end
def arkose_custom_score
abuse_trust_scores.arkose_custom_score.recent_first.first&.score || 0.0
end
end
# Usage:
user = User.find(1)
user.spam_score
user.telesign_score
user.arkose_global_score
```
```ruby
##
# GOOD: Define a thin class that represents a user trust score
class Abuse::UserTrustScore
def initialize(user)
@user = user
end
def spam
scores.spamcheck.average(:score) || 0.0
end
def spammer?
spam > Abuse::TrustScore::SPAMCHECK_HAM_THRESHOLD
end
def telesign
scores.telesign.recent_first.first&.score || 0.0
end
def arkose_global
scores.arkose_global_score.recent_first.first&.score || 0.0
end
def arkose_custom
scores.arkose_custom_score.recent_first.first&.score || 0.0
end
private
def scores
Abuse::TrustScore.for_user(@user)
end
end
# Usage:
user = User.find(1)
user_score = Abuse::UserTrustScore.new(user)
user_score.spam
user_score.spammer?
user_score.telesign
user_score.arkose_global
```
See a real example [merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/117853#note_1423070054).
### Example: Use Dependency Inversion to extract a domain concept
```ruby
##
# BAD: methods related to integrations defined in Project.
class Project
has_many :integrations
def find_or_initialize_integrations
# ...
end
def find_or_initialize_integration(name)
# ...
end
def disabled_integrations
# ...
end
def ci_integrations
# ...
end
# many more methods...
end
```
```ruby
##
# GOOD: All logic related to Integrations is enclosed inside the `Integrations::`
# bounded context.
module Integrations
class ProjectIntegrations
def initialize(project)
@project = project
end
def all_integrations
@project.integrations # can still leverage caching of AR associations
end
def find_or_initialize(name)
# ...
end
def all_disabled
all_integrations.disabled
end
def all_ci
all_integrations.ci_integration
end
end
end
```
Real example of [similar refactoring](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92985).

View File

@ -262,7 +262,7 @@ PKG_METADATA_MANIFEST_OUTPUT_FILE="/tmp/license_db_export_manifest.json"
PKG_METADATA_DOWNLOADS_OUTPUT_FILE="/tmp/license_db_object_links.tsv"
# Download the contents of the bucket
curl --silent --show-error --request GET "https://storage.googleapis.com/storage/v1/b/prod-export-license-bucket-1a6c642fc4de57d4/o" > "$PKG_METADATA_MANIFEST_OUTPUT_FILE"
curl --silent --show-error --request GET "https://storage.googleapis.com/storage/v1/b/prod-export-license-bucket-1a6c642fc4de57d4/o?maxResults=7500" > "$PKG_METADATA_MANIFEST_OUTPUT_FILE"
# Parse the links and names for the bucket objects and output them into a tsv file
jq -r '.items[] | [.name, .mediaLink] | @tsv' "$PKG_METADATA_MANIFEST_OUTPUT_FILE" > "$PKG_METADATA_DOWNLOADS_OUTPUT_FILE"

View File

@ -186,6 +186,15 @@ If you don't want any downtime, read how to [upgrade with zero downtime](zero_do
For a dynamic view of examples of supported upgrade paths, try the [Upgrade Path tool](https://gitlab-com.gitlab.io/support/toolbox/upgrade-path/) maintained by the [GitLab Support team](https://about.gitlab.com/handbook/support/#about-the-support-team). To share feedback and help improve the tool, create an issue or MR in the [upgrade-path project](https://gitlab.com/gitlab-com/support/toolbox/upgrade-path).
Required upgrade stops are versions of GitLab that you must upgrade to before upgrading to later versions. Required upgrade stops allow required background
migrations to finish.
During GitLab 16.x, we are scheduling two or three required upgrade stops. We will give at least two milestones of notice when we
schedule a required upgrade stop.
The first planned required upgrade stop is scheduled for GitLab 16.3. If nothing is introduced requiring an upgrade stop, GitLab 16.3 will be treated as a
regular upgrade.
Find where your version sits in the upgrade path below, and upgrade GitLab
accordingly, while also consulting the
[version-specific upgrade instructions](#version-specific-upgrading-instructions):

View File

@ -200,6 +200,33 @@ When this feature is enabled, GitLab runs a job once a day to deactivate the dor
A maximum of 100,000 users can be deactivated per day.
### Automatically delete unconfirmed users **(PREMIUM SELF)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/352514) in GitLab 16.1 [with a flag](../../administration/feature_flags.md) named `delete_unconfirmed_users_setting`. Disabled by default.
Prerequisites:
- You must be an administrator.
You can enable automatic deletion of users who both:
- Never confirmed their email address.
- Signed up for GitLab more than a specified number of days in the past.
You can configure these settings using either the [Settings API](../../api/settings.md) or in a Rails console:
```ruby
Gitlab::CurrentSettings.update(delete_unconfirmed_users: true)
Gitlab::CurrentSettings.update(unconfirmed_users_delete_after_days: 365)
```
When the `delete_unconfirmed_users` setting is enabled, GitLab runs a job once an hour to delete the unconfirmed users.
The job only deletes users who signed up more than `unconfirmed_users_delete_after_days` days in the past.
This job only runs when the `email_confirmation_setting` is set to `soft` or `hard`.
A maximum of 240,000 users can be deleted per day.
### Activate a user
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/22257) in GitLab 12.4.

View File

@ -11,9 +11,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
You can create a compliance framework that is a label to identify that your project has certain compliance
requirements or needs additional oversight. The label can optionally enforce
[compliance pipeline configuration](#compliance-pipelines) to the projects on which it is
applied. Refer to our
applied. For more information, see [Add a compliance framework to a project](../project/settings/index.md#add-a-compliance-framework-to-a-project).
[compliance pipeline configuration](#compliance-pipelines) to the projects on which it is applied.
Compliance frameworks are created on top-level groups. Group owners can create, edit, and delete compliance frameworks:
@ -25,6 +23,33 @@ Compliance frameworks are created on top-level groups. Group owners can create,
Subgroups and projects have access to all compliance frameworks created on their top-level group. However, compliance frameworks cannot be created, edited,
or deleted at the subgroup or project level. Project owners can choose a framework to apply to their projects.
## Add a compliance framework to a project
Prerequisite:
- The group to which the project belongs must have a compliance framework.
To assign a compliance framework to a project:
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
1. Select **Settings** > **General**.
1. Expand **Compliance frameworks**.
1. Select a compliance framework.
1. Select **Save changes**.
NOTE:
Frameworks cannot be added to projects in personal namespaces.
### GraphQL API
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/333249) in GitLab 14.2.
You can use the [GraphQL API](../../api/graphql/reference/index.md#mutationprojectsetcomplianceframework) to add a
compliance framework to a project.
If you create compliance frameworks on subgroups with GraphQL, the framework is created on the root ancestor if the user
has the correct permissions. The GitLab UI presents a read-only view to discourage this behavior.
## Default compliance frameworks
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/375036) in GitLab 15.6.

View File

@ -45,22 +45,9 @@ If you're an instance administrator, you can administer all project topics from
## Add a compliance framework to a project **(PREMIUM)**
[Compliance frameworks](../../group/compliance_frameworks.md) can be assigned to projects within group that has a
compliance framework using either:
- The GitLab UI:
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
1. Select **Settings** > **General**.
1. Expand **Compliance frameworks**.
1. Select a compliance framework.
1. Select **Save changes**.
- In [GitLab 14.2](https://gitlab.com/gitlab-org/gitlab/-/issues/333249) and later, using the
[GraphQL API](../../../api/graphql/reference/index.md#mutationprojectsetcomplianceframework). If you create
compliance frameworks on subgroups with GraphQL, the framework is created on the root ancestor if the user has the
correct permissions. The GitLab UI presents a read-only view to discourage this behavior.
NOTE:
Frameworks can not be added to projects in personal namespaces.
You can
[add compliance frameworks to projects](../../group/compliance_frameworks.md#add-a-compliance-framework-to-a-project)
in a group that has a compliance framework.
## Configure project visibility, features, and permissions

View File

@ -6540,6 +6540,9 @@ msgstr ""
msgid "AuditStreams|An error occurred when updating external audit event stream destination. Please try it again."
msgstr ""
msgid "AuditStreams|Are you sure about deleting this destination?"
msgstr ""
msgid "AuditStreams|Cancel editing"
msgstr ""
@ -6549,6 +6552,12 @@ msgstr ""
msgid "AuditStreams|Delete %{link}"
msgstr ""
msgid "AuditStreams|Delete destination"
msgstr ""
msgid "AuditStreams|Deleting the streaming destination %{destination} will stop audit events being streamed"
msgstr ""
msgid "AuditStreams|Destination URL"
msgstr ""

View File

@ -144,7 +144,7 @@ module QA
end
def init_repository
run_git("git init")
run_git("git init --initial-branch=#{default_branch}")
end
def pull(repository = nil, branch = nil)

View File

@ -14,7 +14,6 @@ module QA
end
view 'app/views/projects/branches/_branch.html.haml' do
element :badge_content
element :branch_container
element :branch_link
end
@ -23,13 +22,6 @@ module QA
element :all_branches_container
end
view 'app/assets/javascripts/branches/components/delete_merged_branches.vue' do
element :delete_merged_branches_dropdown_button
element :delete_merged_branches_button
element :delete_merged_branches_input
element :delete_merged_branches_confirmation_button
end
def delete_branch(branch_name)
within_element(:branch_container, name: branch_name) do
click_element(:delete_branch_button)
@ -47,20 +39,6 @@ module QA
end
end
end
def has_branch_with_badge?(branch_name, badge)
within_element(:branch_container, name: branch_name) do
has_element?(:badge_content, text: badge)
end
end
def delete_merged_branches(branches_length)
click_element(:delete_merged_branches_dropdown_button)
click_element(:delete_merged_branches_button)
fill_element(:delete_merged_branches_input, branches_length)
click_element(:delete_merged_branches_confirmation_button)
finished_loading?
end
end
end
end

View File

@ -0,0 +1,52 @@
# frozen_string_literal: true
module QA
module Resource
module Repository
class Branch < Base
attr_accessor :name, :ref
attribute :project do
Project.fabricate_via_api! do |resource|
resource.name = 'branch-project'
resource.initialize_with_readme = true
end
end
def initialize
@name = 'test'
@ref = Runtime::Env.default_branch
end
def fabricate!
raise NotImplementedError
end
def fabricate_via_api!
resource_web_url(api_get)
rescue ResourceNotFoundError
super
end
def api_get_path
"/projects/#{project.id}/repository/branches/#{name}"
end
def api_delete_path
api_get_path
end
def api_post_path
"/projects/#{project.id}/repository/branches"
end
def api_post_body
{
branch: name,
ref: ref
}
end
end
end
end
end

View File

@ -0,0 +1,77 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Create' do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'project-qa-test'
project.description = 'project for qa test'
end
end
describe 'Create, Retrieve and Delete branches via API', :requires_admin, product_group: :source_code do
created_branch = 'create-branch'
deleted_branch = 'delete-branch'
filename = 'file.txt'
default_branch_commit_message = "Add #{filename}"
before do
Git::Repository.perform do |repository|
repository.uri = project.repository_http_location.uri
repository.use_default_credentials
repository.try_add_credentials_to_netrc
repository.act do
init_repository
configure_identity('GitLab QA', 'root@gitlab.com')
commit_file(filename, 'Test file content', default_branch_commit_message)
push_changes
checkout(deleted_branch, new_branch: true)
push_changes(deleted_branch)
end
end
project.wait_for_push default_branch_commit_message
end
it(
'creates, retrieves and deletes branches',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347740'
) do
# Create branch
Resource::Repository::Branch.fabricate_via_api! do |branch|
branch.name = created_branch
branch.project = project
end
# Retrieve branch
delete_branch = Resource::Repository::Branch.fabricate_via_api! do |branch|
branch.name = deleted_branch
branch.project = project
end
# Delete branch
delete_branch.remove_via_api!
# Clone repository, verify branches and commits
Git::Repository.perform do |repository|
repository.uri = project.repository_http_location.uri
repository.use_default_credentials
repository.try_add_credentials_to_netrc
repository.clone
branches = repository.remote_branches
expect(branches).to include(created_branch)
expect(branches).not_to include(deleted_branch)
expect(repository.commits.first).to include(default_branch_commit_message)
repository.checkout(created_branch)
expect(repository.commits.first).to include(default_branch_commit_message)
end
end
end
end
end

View File

@ -1,99 +0,0 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Create' do
describe 'Create, list, and delete branches via web', :requires_admin, product_group: :source_code do
master_branch = nil
second_branch = 'second-branch'
third_branch = 'third-branch'
file_1_master = 'file.txt'
file_2_master = 'other-file.txt'
file_second_branch = 'file-2.txt'
file_third_branch = 'file-3.txt'
first_commit_message_of_master_branch = "Add #{file_1_master}"
second_commit_message_of_master_branch = "Add #{file_2_master}"
commit_message_of_second_branch = "Add #{file_second_branch}"
commit_message_of_third_branch = "Add #{file_third_branch}"
before do
Flow::Login.sign_in
project = Resource::Project.fabricate_via_api! do |proj|
proj.name = 'project-qa-test'
proj.description = 'project for qa test'
proj.initialize_with_readme = true
end
master_branch = project.default_branch
Git::Repository.perform do |repository|
repository.uri = project.repository_http_location.uri
repository.use_default_credentials
repository.try_add_credentials_to_netrc
repository.default_branch = master_branch
repository.act do
clone
configure_identity('GitLab QA', 'root@gitlab.com')
commit_file(file_1_master, 'Test file content', first_commit_message_of_master_branch)
push_changes
checkout(second_branch, new_branch: true)
commit_file(file_second_branch, 'File 2 content', commit_message_of_second_branch)
push_changes(second_branch)
checkout(master_branch)
# This second commit on master is needed for the master branch to be ahead
# of the second branch, and when the second branch is merged to master it will
# show the 'merged' badge on it.
# Refer to the below issue note:
# https://gitlab.com/gitlab-org/gitlab-foss/issues/55524#note_126100848
commit_file(file_2_master, 'Other test file content', second_commit_message_of_master_branch)
push_changes
merge(second_branch)
push_changes
checkout(third_branch, new_branch: true)
commit_file(file_third_branch, 'File 3 content', commit_message_of_third_branch)
push_changes(third_branch)
end
end
project.wait_for_push commit_message_of_third_branch
project.visit!
end
it(
'lists branches correctly after CRUD operations',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347740',
quarantine: {
issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/414026',
type: :stale
}
) do
Page::Project::Menu.perform(&:go_to_repository_branches)
expect(page).to have_content(master_branch)
expect(page).to have_content(second_branch)
expect(page).to have_content(third_branch)
expect(page).to have_content("Merge branch 'second-branch'")
expect(page).to have_content(commit_message_of_second_branch)
expect(page).to have_content(commit_message_of_third_branch)
Page::Project::Branches::Show.perform do |branches_page|
expect(branches_page).to have_branch_with_badge(second_branch, 'merged')
branches_page.delete_branch(third_branch)
expect(branches_page).to have_no_branch(third_branch)
branches_page.delete_merged_branches('delete')
expect(branches_page).to have_content(
'Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes.'
)
branches_page.refresh
expect(branches_page).to have_no_branch(second_branch, reload: true)
end
end
end
end
end

View File

@ -139,8 +139,10 @@ RSpec.describe 'Admin Mode Login', feature_category: :system_access do
context 'when authn_context is worth two factors' do
let(:mock_saml_response) do
File.read('spec/fixtures/authentication/saml_response.xml')
.gsub('urn:oasis:names:tc:SAML:2.0:ac:classes:Password',
'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS')
.gsub(
'urn:oasis:names:tc:SAML:2.0:ac:classes:Password',
'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS'
)
end
it 'signs user in without prompting for second factor' do

View File

@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'User activates the instance-level Mattermost Slash Command integration', :js,
feature_category: :integrations do
feature_category: :integrations do
include_context 'instance integration activation'
before do

View File

@ -49,8 +49,11 @@ RSpec.describe 'Issues Feed', feature_category: :devops_reports do
before do
personal_access_token = create(:personal_access_token, user: user)
visit project_issues_path(project, :atom,
private_token: personal_access_token.token)
visit project_issues_path(
project,
:atom,
private_token: personal_access_token.token
)
end
it_behaves_like 'an authenticated issuable atom feed'
@ -59,8 +62,11 @@ RSpec.describe 'Issues Feed', feature_category: :devops_reports do
context 'when authenticated via feed token' do
before do
visit project_issues_path(project, :atom,
feed_token: user.feed_token)
visit project_issues_path(
project,
:atom,
feed_token: user.feed_token
)
end
it_behaves_like 'an authenticated issuable atom feed'

View File

@ -46,8 +46,11 @@ RSpec.describe 'Merge Requests Feed', feature_category: :devops_reports do
before do
personal_access_token = create(:personal_access_token, user: user)
visit project_merge_requests_path(project, :atom,
private_token: personal_access_token.token)
visit project_merge_requests_path(
project,
:atom,
private_token: personal_access_token.token
)
end
it_behaves_like 'an authenticated issuable atom feed'
@ -56,8 +59,11 @@ RSpec.describe 'Merge Requests Feed', feature_category: :devops_reports do
context 'when authenticated via feed token' do
before do
visit project_merge_requests_path(project, :atom,
feed_token: user.feed_token)
visit project_merge_requests_path(
project,
:atom,
feed_token: user.feed_token
)
end
it_behaves_like 'an authenticated issuable atom feed'

View File

@ -25,27 +25,33 @@ RSpec.describe "User Feed", feature_category: :devops_reports do
context 'feed content' do
let(:project) { create(:project, :repository) }
let(:issue) do
create(:issue,
project: project,
author: user,
description: "Houston, we have a bug!\n\n***\n\nI guess.")
create(
:issue,
project: project,
author: user,
description: "Houston, we have a bug!\n\n***\n\nI guess."
)
end
let(:note) do
create(:note,
noteable: issue,
author: user,
note: 'Bug confirmed :+1:',
project: project)
create(
:note,
noteable: issue,
author: user,
note: 'Bug confirmed :+1:',
project: project
)
end
let(:merge_request) do
create(:merge_request,
title: 'Fix bug',
author: user,
source_project: project,
target_project: project,
description: "Here is the fix: ![an image](image.png)")
create(
:merge_request,
title: 'Fix bug',
author: user,
source_project: project,
target_project: project,
description: "Here is the fix: ![an image](image.png)"
)
end
let(:push_event) { create(:push_event, project: project, author: user) }

View File

@ -220,12 +220,14 @@ RSpec.describe 'Issue Boards', :js, feature_category: :team_planning do
end
def drag(selector: '.board-list', list_from_index: 1, from_index: 0, to_index: 0, list_to_index: 1, duration: 1000)
drag_to(selector: selector,
scrollable: '#board-app',
list_from_index: list_from_index,
from_index: from_index,
to_index: to_index,
list_to_index: list_to_index,
duration: duration)
drag_to(
selector: selector,
scrollable: '#board-app',
list_from_index: list_from_index,
from_index: from_index,
to_index: to_index,
list_to_index: list_to_index,
duration: duration
)
end
end

View File

@ -11,13 +11,15 @@ RSpec.describe 'Multi Select Issue', :js, feature_category: :team_planning do
let(:user) { create(:user) }
def drag(selector: '.board-list', list_from_index: 1, from_index: 0, to_index: 0, list_to_index: 1, duration: 1000)
drag_to(selector: selector,
scrollable: '#board-app',
list_from_index: list_from_index,
from_index: from_index,
to_index: to_index,
list_to_index: list_to_index,
duration: duration)
drag_to(
selector: selector,
scrollable: '#board-app',
list_from_index: list_from_index,
from_index: from_index,
to_index: to_index,
list_to_index: list_to_index,
duration: duration
)
end
def wait_for_board_cards(board_number, expected_cards)

View File

@ -2,8 +2,9 @@
require 'spec_helper'
RSpec.describe 'Project issue boards sidebar assignee', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/332078',
feature_category: :team_planning do
RSpec.describe 'Project issue boards sidebar assignee', :js,
quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/332078',
feature_category: :team_planning do
include BoardHelpers
let_it_be(:user) { create(:user) }

View File

@ -15,13 +15,15 @@ RSpec.describe 'Commits', feature_category: :source_code_management do
let(:creator) { create(:user, developer_projects: [project]) }
let!(:pipeline) do
create(:ci_pipeline,
project: project,
user: creator,
ref: project.default_branch,
sha: project.commit.sha,
status: :success,
created_at: 5.months.ago)
create(
:ci_pipeline,
project: project,
user: creator,
ref: project.default_branch,
sha: project.commit.sha,
status: :success,
created_at: 5.months.ago
)
end
context 'commit status is Generic Commit Status' do
@ -61,11 +63,13 @@ RSpec.describe 'Commits', feature_category: :source_code_management do
describe 'Project commits' do
let!(:pipeline_from_other_branch) do
create(:ci_pipeline,
project: project,
ref: 'fix',
sha: project.commit.sha,
status: :failed)
create(
:ci_pipeline,
project: project,
ref: 'fix',
sha: project.commit.sha,
status: :failed
)
end
before do

View File

@ -59,12 +59,14 @@ RSpec.describe 'Dashboard > Activity', feature_category: :user_profile do
let!(:push_event) do
event = create(:push_event, project: project, author: user)
create(:push_event_payload,
event: event,
action: :created,
commit_to: '0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e',
ref: 'new_design',
commit_count: 1)
create(
:push_event_payload,
event: event,
action: :created,
commit_to: '0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e',
ref: 'new_design',
commit_count: 1
)
event
end

View File

@ -18,8 +18,13 @@ RSpec.describe 'Tooltips on .timeago dates', :js, feature_category: :user_profil
context 'on the activity tab' do
before do
Event.create!(project: project, author_id: user.id, action: :joined,
updated_at: created_date, created_at: created_date)
Event.create!(
project: project,
author_id: user.id,
action: :joined,
updated_at: created_date,
created_at: created_date
)
sign_in user
visit user_activity_path(user)

View File

@ -79,39 +79,52 @@ RSpec.describe 'Dashboard Merge Requests', feature_category: :code_review_workfl
end
let!(:assigned_merge_request_from_fork) do
create(:merge_request,
source_branch: 'markdown', assignees: [current_user],
target_project: public_project, source_project: forked_project,
author: author_user)
create(
:merge_request,
source_branch: 'markdown',
assignees: [current_user],
target_project: public_project,
source_project: forked_project,
author: author_user
)
end
let!(:authored_merge_request) do
create(:merge_request,
source_branch: 'markdown',
source_project: project,
author: current_user)
create(
:merge_request,
source_branch: 'markdown',
source_project: project,
author: current_user
)
end
let!(:authored_merge_request_from_fork) do
create(:merge_request,
source_branch: 'feature_conflict',
author: current_user,
target_project: public_project, source_project: forked_project)
create(
:merge_request,
source_branch: 'feature_conflict',
author: current_user,
target_project: public_project,
source_project: forked_project
)
end
let!(:labeled_merge_request) do
create(:labeled_merge_request,
source_branch: 'labeled',
labels: [label],
author: current_user,
source_project: project)
create(
:labeled_merge_request,
source_branch: 'labeled',
labels: [label],
author: current_user,
source_project: project
)
end
let!(:other_merge_request) do
create(:merge_request,
source_branch: 'fix',
source_project: project,
author: author_user)
create(
:merge_request,
source_branch: 'fix',
source_project: project,
author: author_user
)
end
before do

View File

@ -27,8 +27,9 @@ RSpec.describe 'Dashboard > User sorts todos', feature_category: :team_planning
create(:todo, user: user, project: project, target: issue_2, created_at: 4.hours.ago, updated_at: 4.hours.ago)
create(:todo, user: user, project: project, target: issue_3, created_at: 3.hours.ago, updated_at: 2.minutes.ago)
create(:todo, user: user, project: project, target: issue_1, created_at: 2.hours.ago, updated_at: 2.hours.ago)
create(:todo, user: user, project: project, target: merge_request_1, created_at: 1.hour.ago,
updated_at: 1.hour.ago)
create(
:todo, user: user, project: project, target: merge_request_1, created_at: 1.hour.ago, updated_at: 1.hour.ago
)
merge_request_1.labels << label_1
issue_3.labels << label_1

View File

@ -443,12 +443,15 @@ RSpec.describe 'Dashboard Todos', feature_category: :team_planning do
let_it_be(:target) { create(:design, issue: issue, project: project) }
let_it_be(:note) { create(:note, project: project, note: 'I am note, hear me roar') }
let_it_be(:todo) do
create(:todo, :mentioned,
user: user,
project: project,
target: target,
author: author,
note: note)
create(
:todo,
:mentioned,
user: user,
project: project,
target: target,
author: author,
note: note
)
end
before do
@ -467,10 +470,12 @@ RSpec.describe 'Dashboard Todos', feature_category: :team_planning do
context 'User requested access' do
shared_examples 'has todo present with access request content' do
specify do
create(:todo, :member_access_requested,
user: user,
target: target,
author: author
create(
:todo,
:member_access_requested,
user: user,
target: target,
author: author
)
target.add_owner(user)

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe 'File blame', :js, feature_category: :groups_and_projects do
RSpec.describe 'File blame', :js, feature_category: :source_code_management do
include TreeHelper
let_it_be(:project) { create(:project, :public, :repository) }

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe 'Environments page', :js, feature_category: :groups_and_projects do
RSpec.describe 'Environments page', :js, feature_category: :continuous_delivery do
include Spec::Support::Helpers::ModalHelpers
let(:project) { create(:project) }

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe 'Pipelines', :js, feature_category: :groups_and_projects do
RSpec.describe 'Pipelines', :js, feature_category: :continuous_integration do
include ListboxHelpers
include ProjectForksHelper
include Spec::Support::Helpers::ModalHelpers

View File

@ -5,7 +5,6 @@ exports[`Delete merged branches component Delete merged branches confirmation mo
<gl-base-dropdown-stub
category="tertiary"
class="gl-disclosure-dropdown gl-display-none gl-md-display-block!"
data-qa-selector="delete_merged_branches_dropdown_button"
icon="ellipsis_v"
nocaret="true"
offset="[object Object]"
@ -34,7 +33,7 @@ exports[`Delete merged branches component Delete merged branches confirmation mo
<b-button-stub
class="gl-display-block gl-md-display-none! gl-button btn-danger-secondary"
data-qa-selector="delete_merged_branches_button"
data-testid="delete-merged-branches-button"
size="md"
tag="button"
type="button"
@ -100,7 +99,6 @@ exports[`Delete merged branches component Delete merged branches confirmation mo
aria-labelledby="input-label"
autocomplete="off"
class="gl-form-input gl-mt-2 gl-form-input-sm"
data-qa-selector="delete_merged_branches_input"
debounce="0"
formatter="[Function]"
type="text"
@ -146,7 +144,6 @@ exports[`Delete merged branches component Delete merged branches confirmation mo
<b-button-stub
class="gl-button"
data-qa-selector="delete_merged_branches_confirmation_button"
data-testid="delete-merged-branches-confirmation-button"
disabled="true"
size="md"

View File

@ -37,7 +37,7 @@ const createComponent = (mountFn = shallowMountExtended, stubs = {}) => {
};
const findDeleteButton = () =>
wrapper.findComponent('[data-qa-selector="delete_merged_branches_button"]');
wrapper.findComponent('[data-testid="delete-merged-branches-button"]');
const findModal = () => wrapper.findComponent(GlModal);
const findConfirmationButton = () =>
wrapper.findByTestId('delete-merged-branches-confirmation-button');

View File

@ -37,11 +37,14 @@ describe('DeleteIssueModal component', () => {
});
describe('when "primary" event is emitted', () => {
let formSubmitSpy;
const submitMock = jest.fn();
// Mock the form submit method
Object.defineProperty(HTMLFormElement.prototype, 'submit', {
value: submitMock,
});
beforeEach(() => {
wrapper = mountComponent();
formSubmitSpy = jest.spyOn(wrapper.vm.$refs.form, 'submit');
findModal().vm.$emit('primary');
});
@ -50,7 +53,7 @@ describe('DeleteIssueModal component', () => {
});
it('submits the form', () => {
expect(formSubmitSpy).toHaveBeenCalled();
expect(submitMock).toHaveBeenCalledTimes(1);
});
});
});

View File

@ -1,7 +1,6 @@
import {
GlAlert,
GlDropdown,
GlButton,
GlDisclosureDropdown,
GlFormCheckbox,
GlLoadingIcon,
GlModal,
@ -64,9 +63,10 @@ describe('Package Files', () => {
const findFirstRowDownloadLink = () => findFirstRow().findByTestId('download-link');
const findFirstRowFileIcon = () => findFirstRow().findComponent(FileIcon);
const findFirstRowCreatedAt = () => findFirstRow().findComponent(TimeAgoTooltip);
const findFirstActionMenu = () => extendedWrapper(findFirstRow().findComponent(GlDropdown));
const findFirstActionMenu = () =>
extendedWrapper(findFirstRow().findComponent(GlDisclosureDropdown));
const findActionMenuDelete = () => findFirstActionMenu().findByTestId('delete-file');
const findFirstToggleDetailsButton = () => findFirstRow().findComponent(GlButton);
const findFirstToggleDetailsButton = () => findFirstRow().findByTestId('toggle-details-button');
const findFirstRowShaComponent = (id) => wrapper.findByTestId(id);
const findCheckAllCheckbox = () => wrapper.findByTestId('package-files-checkbox-all');
const findAllRowCheckboxes = () => wrapper.findAllByTestId('package-files-checkbox');
@ -262,7 +262,7 @@ describe('Package Files', () => {
expect(findFirstActionMenu().exists()).toBe(true);
expect(findFirstActionMenu().props('icon')).toBe('ellipsis_v');
expect(findFirstActionMenu().props('textSrOnly')).toBe(true);
expect(findFirstActionMenu().props('text')).toMatchInterpolatedText('More actions');
expect(findFirstActionMenu().props('toggleText')).toMatchInterpolatedText('More actions');
});
describe('menu items', () => {
@ -272,7 +272,7 @@ describe('Package Files', () => {
});
it('shows delete file confirmation modal', async () => {
await findActionMenuDelete().trigger('click');
await findActionMenuDelete().vm.$emit('action');
expect(showMock).toHaveBeenCalledTimes(1);