Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
b4d76c5ac7
commit
187727e248
|
@ -1,9 +1,10 @@
|
|||
<script>
|
||||
import { GlDropdownItem } from '@gitlab/ui';
|
||||
import { GlDropdownItem, GlAvatarLabeled } from '@gitlab/ui';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlDropdownItem,
|
||||
GlAvatarLabeled,
|
||||
},
|
||||
|
||||
props: {
|
||||
|
@ -144,6 +145,10 @@ export default {
|
|||
});
|
||||
}
|
||||
},
|
||||
|
||||
avatarSubLabel(item) {
|
||||
return item.count ? `${item.name} (${item.count})` : item.name;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -161,18 +166,27 @@ export default {
|
|||
:class="{ 'gl-bg-gray-50': index === selectedIndex }"
|
||||
@click="selectItem(index)"
|
||||
>
|
||||
<span v-if="isUser">
|
||||
{{ item.username }}
|
||||
<small>{{ item.name }}</small>
|
||||
</span>
|
||||
<span v-if="isIssue || isMergeRequest || isMilestone">
|
||||
<gl-avatar-labeled
|
||||
v-if="isUser"
|
||||
:label="item.username"
|
||||
:sub-label="avatarSubLabel(item)"
|
||||
:src="item.avatar_url"
|
||||
:entity-name="item.username"
|
||||
:shape="item.type === 'Group' ? 'rect' : 'circle'"
|
||||
:size="32"
|
||||
/>
|
||||
<span v-if="isIssue || isMergeRequest">
|
||||
<small>{{ item.iid }}</small>
|
||||
{{ item.title }}
|
||||
</span>
|
||||
<span v-if="isMilestone">
|
||||
{{ item.title }}
|
||||
</span>
|
||||
<div v-if="isEmoji" class="gl-display-flex gl-flex gl-align-items-center">
|
||||
<div class="gl-pr-4 gl-font-lg">{{ item.e }}</div>
|
||||
<div class="gl-flex-grow-1">
|
||||
{{ item.name }}<br /><small>{{ item.d }}</small>
|
||||
{{ item.name }}<br />
|
||||
<small>{{ item.d }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</gl-dropdown-item>
|
||||
|
|
|
@ -161,7 +161,7 @@ class BulkImports::Entity < ApplicationRecord
|
|||
end
|
||||
|
||||
def validate_imported_entity_type
|
||||
if project_entity? && !BulkImports::Features.project_migration_enabled?(destination_name)
|
||||
if project_entity? && !BulkImports::Features.project_migration_enabled?(destination_namespace)
|
||||
errors.add(
|
||||
:base,
|
||||
s_('BulkImport|invalid entity source type')
|
||||
|
|
|
@ -58,7 +58,7 @@ module MergeRequests
|
|||
new_reviewers = merge_request.reviewers - old_reviewers
|
||||
merge_request_activity_counter.track_users_review_requested(users: new_reviewers)
|
||||
merge_request_activity_counter.track_reviewers_changed_action(user: current_user)
|
||||
GraphqlTriggers.merge_request_reviewers_updated(merge_request)
|
||||
trigger_merge_request_reviewers_updated(merge_request)
|
||||
end
|
||||
|
||||
def cleanup_environments(merge_request)
|
||||
|
@ -245,6 +245,10 @@ module MergeRequests
|
|||
|
||||
Milestones::MergeRequestsCountService.new(milestone).delete_cache
|
||||
end
|
||||
|
||||
def trigger_merge_request_reviewers_updated(merge_request)
|
||||
GraphqlTriggers.merge_request_reviewers_updated(merge_request)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@ module MergeRequests
|
|||
if reviewer
|
||||
return error("Failed to update reviewer") unless reviewer.update(state: :reviewed)
|
||||
|
||||
trigger_merge_request_reviewers_updated(merge_request)
|
||||
|
||||
success
|
||||
else
|
||||
error("Reviewer not found")
|
||||
|
|
|
@ -11,6 +11,7 @@ module MergeRequests
|
|||
return error("Failed to update reviewer") unless reviewer.update(state: :unreviewed)
|
||||
|
||||
notify_reviewer(merge_request, user)
|
||||
trigger_merge_request_reviewers_updated(merge_request)
|
||||
|
||||
success
|
||||
else
|
||||
|
|
|
@ -39,5 +39,5 @@
|
|||
%div
|
||||
= f.gitlab_ui_checkbox_component :active, _('Active'), checkbox_options: { value: @schedule.active, required: false }
|
||||
.footer-block
|
||||
= f.submit _('Save pipeline schedule'), class: 'btn gl-button btn-confirm'
|
||||
= f.submit _('Save pipeline schedule'), pajamas_button: true
|
||||
= link_to _('Cancel'), pipeline_schedules_path(@project), class: 'btn gl-button btn-default btn-cancel'
|
||||
|
|
|
@ -41,4 +41,4 @@
|
|||
= form.gitlab_ui_radio_component :deploy_strategy, 'timed_incremental', (s_('CICD|Continuous deployment to production using timed incremental rollout') + ' ' + help_link_timed).html_safe
|
||||
= form.gitlab_ui_radio_component :deploy_strategy, 'manual', (s_('CICD|Automatic deployment to staging, manual deployment to production') + ' ' + help_link_incremental).html_safe
|
||||
|
||||
= f.submit _('Save changes'), class: "btn gl-button btn-confirm gl-mt-5", data: { qa_selector: 'save_changes_button' }
|
||||
= f.submit _('Save changes'), class: "gl-mt-5", data: { qa_selector: 'save_changes_button' }, pajamas_button: true
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class TmpIndexMembersOnIdWhereNamespaceIdNull < Gitlab::Database::Migration[2.0]
|
||||
TMP_INDEX = 'tmp_index_members_on_id_where_namespace_id_null'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_concurrent_index :members, :id,
|
||||
name: TMP_INDEX,
|
||||
where: 'member_namespace_id IS NULL'
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index_by_name :members, name: TMP_INDEX
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
584d43304f92cc638783ffc5c8ab2dc8e511169c76da7661cb4c5ddded6c02d1
|
|
@ -30982,6 +30982,8 @@ CREATE INDEX tmp_index_for_project_namespace_id_migration_on_routes ON routes US
|
|||
|
||||
CREATE INDEX tmp_index_issues_on_issue_type_and_id ON issues USING btree (issue_type, id);
|
||||
|
||||
CREATE INDEX tmp_index_members_on_id_where_namespace_id_null ON members USING btree (id) WHERE (member_namespace_id IS NULL);
|
||||
|
||||
CREATE INDEX tmp_index_members_on_state ON members USING btree (state) WHERE (state = 2);
|
||||
|
||||
CREATE INDEX tmp_index_migrated_container_registries ON container_repositories USING btree (project_id) WHERE ((migration_state = 'import_done'::text) OR (created_at >= '2022-01-23 00:00:00'::timestamp without time zone));
|
||||
|
|
|
@ -188,6 +188,25 @@ You must have the Owner role for the group.
|
|||
|
||||
From this page, you can edit, pause, and remove runners from the group, its subgroups, and projects.
|
||||
|
||||
#### Filter group runners to show only inherited
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/337838/) in GitLab 15.5, [with a flag](../../administration/feature_flags.md) named `runners_finder_all_available`. Disabled by default.
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `runners_finder_all_available`. On GitLab.com, this feature is not available.
|
||||
|
||||
You can choose to show all runners in the list, or show only
|
||||
those that are inherited from the instance or other groups.
|
||||
|
||||
By default, only those that are inherited are shown.
|
||||
|
||||
To show all runners available in the instance, including shared runners and
|
||||
those in other groups:
|
||||
|
||||
1. On the top bar, select **Main menu > Groups** and find your group.
|
||||
1. On the left sidebar, select **CI/CD > Runners**.
|
||||
1. Above the list, turn off the **Show only inherited** toggle.
|
||||
|
||||
### Pause or remove a group runner
|
||||
|
||||
You can pause or remove a group runner for your self-managed GitLab instance or for GitLab.com.
|
||||
|
|
|
@ -889,6 +889,22 @@ aspects of the automated GLFM scripts and processes. They are located at
|
|||
|
||||
See the main [specification files](#specification-files) section for more context and details.
|
||||
|
||||
##### Configuration file validation
|
||||
|
||||
All of the manually curated example names in the configuration files must correspond to
|
||||
an existing [Markdown example](#markdown-examples) name found in
|
||||
[`example_snapshots/examples_index.yml`](#glfm_specificationexample_snapshotsexamples_indexyml),
|
||||
which is automatically generated based on the [input specification files](#input-specification-files).
|
||||
|
||||
If there is an invalid reference to an example name that does not exist, the
|
||||
[`scripts/glfm/update-example-snapshots.rb`](#update-example-snapshotsrb-script)
|
||||
script fails with a descriptive error.
|
||||
|
||||
The only exceptions to this validation are example names beginning with `00_`, which are reserved
|
||||
for [YAML aliases](https://yaml.org/spec/1.2.2/#692-node-anchors).
|
||||
See the section on [`glfm_example_normalizations.yml`](#glfm_example_normalizationsyml)
|
||||
for more details and examples.
|
||||
|
||||
##### `glfm_example_status.yml`
|
||||
|
||||
[`glfm_specification/input/gitlab_flavored_markdown/glfm_example_status.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/input/gitlab_flavored_markdown/glfm_example_status.yml)
|
||||
|
|
|
@ -44,6 +44,11 @@ module BulkImports
|
|||
wikis = client.get(context.entity.wikis_url_path).parsed_response
|
||||
|
||||
wikis.any?
|
||||
rescue BulkImports::NetworkError => e
|
||||
# 403 is returned when wiki is disabled in settings
|
||||
return if e.response&.forbidden? || e.response&.not_found?
|
||||
|
||||
raise
|
||||
end
|
||||
|
||||
def client
|
||||
|
|
|
@ -4,13 +4,18 @@ module BulkImports
|
|||
class NetworkError < Error
|
||||
COUNTER_KEY = 'bulk_imports/%{entity_id}/%{stage}/%{tracker_id}/network_error/%{error}'
|
||||
|
||||
RETRIABLE_EXCEPTIONS = Gitlab::HTTP::HTTP_TIMEOUT_ERRORS
|
||||
RETRIABLE_EXCEPTIONS = Gitlab::HTTP::HTTP_TIMEOUT_ERRORS + [
|
||||
EOFError, SocketError, OpenSSL::SSL::SSLError, OpenSSL::OpenSSLError,
|
||||
Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH
|
||||
].freeze
|
||||
RETRIABLE_HTTP_CODES = [429].freeze
|
||||
|
||||
DEFAULT_RETRY_DELAY_SECONDS = 30
|
||||
|
||||
MAX_RETRIABLE_COUNT = 10
|
||||
|
||||
attr_reader :response
|
||||
|
||||
def initialize(message = nil, response: nil)
|
||||
raise ArgumentError, 'message or response required' if message.blank? && response.blank?
|
||||
|
||||
|
@ -37,8 +42,6 @@ module BulkImports
|
|||
|
||||
private
|
||||
|
||||
attr_reader :response
|
||||
|
||||
def retriable_exception?
|
||||
RETRIABLE_EXCEPTIONS.include?(cause&.class)
|
||||
end
|
||||
|
|
|
@ -17083,6 +17083,9 @@ msgstr ""
|
|||
msgid "Framework successfully deleted"
|
||||
msgstr ""
|
||||
|
||||
msgid "Free"
|
||||
msgstr ""
|
||||
|
||||
msgid "Free Trial of GitLab.com Ultimate"
|
||||
msgstr ""
|
||||
|
||||
|
@ -17724,6 +17727,9 @@ msgstr ""
|
|||
msgid "Geo|There was an error updating the Geo Settings"
|
||||
msgstr ""
|
||||
|
||||
msgid "Geo|This GitLab instance is subscribed to the %{insufficient_license} tier. Geo is only available for users who have at least a Premium subscription."
|
||||
msgstr ""
|
||||
|
||||
msgid "Geo|This will resync all %{replicableType}. It may take some time to complete. Are you sure you want to continue?"
|
||||
msgstr ""
|
||||
|
||||
|
@ -24481,10 +24487,10 @@ msgstr ""
|
|||
msgid "Manage two-factor authentication"
|
||||
msgstr ""
|
||||
|
||||
msgid "Manage your license"
|
||||
msgid "Manage your project's triggers"
|
||||
msgstr ""
|
||||
|
||||
msgid "Manage your project's triggers"
|
||||
msgid "Manage your subscription"
|
||||
msgstr ""
|
||||
|
||||
msgid "Managed Account"
|
||||
|
@ -40833,9 +40839,6 @@ msgstr ""
|
|||
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
|
||||
msgstr ""
|
||||
|
||||
msgid "This GitLab instance is licensed at the %{insufficient_license} tier. Geo is only available for users who have at least a Premium license."
|
||||
msgstr ""
|
||||
|
||||
msgid "This PDF is too large to display. Please download to view."
|
||||
msgstr ""
|
||||
|
||||
|
@ -44123,6 +44126,9 @@ msgstr ""
|
|||
msgid "View blame prior to this change"
|
||||
msgstr ""
|
||||
|
||||
msgid "View card matches"
|
||||
msgstr ""
|
||||
|
||||
msgid "View chart"
|
||||
msgid_plural "View charts"
|
||||
msgstr[0] ""
|
||||
|
@ -48270,9 +48276,6 @@ msgstr ""
|
|||
msgid "organizations can only be added to root groups"
|
||||
msgstr ""
|
||||
|
||||
msgid "other card matches"
|
||||
msgstr ""
|
||||
|
||||
msgid "out of %d total test"
|
||||
msgid_plural "out of %d total tests"
|
||||
msgstr[0] ""
|
||||
|
|
|
@ -53,13 +53,13 @@
|
|||
"@gitlab/at.js": "1.5.7",
|
||||
"@gitlab/favicon-overlay": "2.0.0",
|
||||
"@gitlab/svgs": "3.4.0",
|
||||
"@gitlab/ui": "43.21.0",
|
||||
"@gitlab/ui": "44.0.0",
|
||||
"@gitlab/visual-review-tools": "1.7.3",
|
||||
"@gitlab/web-ide": "0.0.1-dev-20220815034418",
|
||||
"@rails/actioncable": "6.1.4-7",
|
||||
"@rails/ujs": "6.1.4-7",
|
||||
"@sentry/browser": "5.30.0",
|
||||
"@sourcegraph/code-host-integration": "0.0.60",
|
||||
"@sourcegraph/code-host-integration": "0.0.82",
|
||||
"@tiptap/core": "^2.0.0-beta.182",
|
||||
"@tiptap/extension-blockquote": "^2.0.0-beta.29",
|
||||
"@tiptap/extension-bold": "^2.0.0-beta.28",
|
||||
|
|
|
@ -4,7 +4,7 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe Projects::Prometheus::MetricsController do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:prometheus_project) }
|
||||
let_it_be(:project) { create(:project, :with_prometheus_integration) }
|
||||
|
||||
let(:prometheus_adapter) { double('prometheus_adapter', can_query?: true) }
|
||||
|
||||
|
|
|
@ -429,6 +429,24 @@ FactoryBot.define do
|
|||
error_tracking_setting { association :project_error_tracking_setting }
|
||||
end
|
||||
|
||||
trait :with_redmine_integration do
|
||||
has_external_issue_tracker { true }
|
||||
|
||||
redmine_integration
|
||||
end
|
||||
|
||||
trait :with_jira_integration do
|
||||
has_external_issue_tracker { true }
|
||||
|
||||
jira_integration
|
||||
end
|
||||
|
||||
trait :with_prometheus_integration do
|
||||
after :create do |project|
|
||||
create(:prometheus_integration, project: project)
|
||||
end
|
||||
end
|
||||
|
||||
# Project with empty repository
|
||||
#
|
||||
# This is a case when you just created a project
|
||||
|
@ -455,42 +473,6 @@ FactoryBot.define do
|
|||
end
|
||||
end
|
||||
|
||||
factory :redmine_project, parent: :project do
|
||||
has_external_issue_tracker { true }
|
||||
|
||||
redmine_integration
|
||||
end
|
||||
|
||||
factory :youtrack_project, parent: :project do
|
||||
has_external_issue_tracker { true }
|
||||
|
||||
youtrack_integration
|
||||
end
|
||||
|
||||
factory :jira_project, parent: :project do
|
||||
has_external_issue_tracker { true }
|
||||
|
||||
jira_integration
|
||||
end
|
||||
|
||||
factory :prometheus_project, parent: :project do
|
||||
after :create do |project|
|
||||
project.create_prometheus_integration(
|
||||
active: true,
|
||||
properties: {
|
||||
api_url: 'https://prometheus.example.com/',
|
||||
manual_configuration: true
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
factory :ewm_project, parent: :project do
|
||||
has_external_issue_tracker { true }
|
||||
|
||||
ewm_integration
|
||||
end
|
||||
|
||||
factory :project_with_design, parent: :project do
|
||||
after(:create) do |project|
|
||||
issue = create(:issue, project: project)
|
||||
|
|
|
@ -114,6 +114,53 @@ RSpec.describe "Group Runners" do
|
|||
end
|
||||
end
|
||||
|
||||
context "with an online instance runner" do
|
||||
let!(:instance_runner) do
|
||||
create(:ci_runner, :instance, description: 'runner-baz', contacted_at: Time.zone.now)
|
||||
end
|
||||
|
||||
context "when runners_finder_all_available is enabled" do
|
||||
before do
|
||||
stub_feature_flags(runners_finder_all_available: true)
|
||||
|
||||
visit group_runners_path(group)
|
||||
end
|
||||
|
||||
context "when selecting 'Show only inherited'" do
|
||||
before do
|
||||
find("[data-testid='runner-membership-toggle'] button").click
|
||||
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
it_behaves_like 'shows runner in list' do
|
||||
let(:runner) { instance_runner }
|
||||
end
|
||||
|
||||
it 'shows runner details page' do
|
||||
click_link("##{instance_runner.id} (#{instance_runner.short_sha})")
|
||||
|
||||
expect(current_url).to include(group_runner_path(group, instance_runner))
|
||||
expect(page).to have_content "#{s_('Runners|Description')} runner-baz"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when runners_finder_all_available is disabled" do
|
||||
before do
|
||||
stub_feature_flags(runners_finder_all_available: false)
|
||||
|
||||
visit group_runners_path(group)
|
||||
end
|
||||
|
||||
it "does not display 'Show only inherited' toggle" do
|
||||
expect(page).not_to have_content(s_('Runners|Show only inherited'))
|
||||
end
|
||||
|
||||
it_behaves_like 'shows no runners registered'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a multi-project runner' do
|
||||
let(:project) { create(:project, group: group) }
|
||||
let(:project_2) { create(:project, group: group) }
|
||||
|
|
|
@ -9,7 +9,7 @@ RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_st
|
|||
include MetricsDashboardUrlHelpers
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:prometheus_project) }
|
||||
let_it_be(:project) { create(:project, :with_prometheus_integration) }
|
||||
let_it_be(:environment) { create(:environment, project: project) }
|
||||
|
||||
let(:issue) { create(:issue, project: project, description: description) }
|
||||
|
|
|
@ -6,7 +6,7 @@ RSpec.describe 'Merge request > User posts diff notes', :js do
|
|||
include MergeRequestDiffHelpers
|
||||
include Spec::Support::Helpers::ModalHelpers
|
||||
|
||||
let(:merge_request) { create(:merge_request) }
|
||||
let_it_be(:merge_request) { create(:merge_request) }
|
||||
let(:project) { merge_request.source_project }
|
||||
let(:user) { project.creator }
|
||||
let(:comment_button_class) { '.add-diff-note' }
|
||||
|
|
|
@ -6,7 +6,7 @@ RSpec.describe 'Environment > Metrics' do
|
|||
include PrometheusHelpers
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:prometheus_project, :repository) }
|
||||
let(:project) { create(:project, :with_prometheus_integration, :repository) }
|
||||
let(:pipeline) { create(:ci_pipeline, project: project) }
|
||||
let(:build) { create(:ci_build, pipeline: pipeline) }
|
||||
let(:environment) { create(:environment, project: project) }
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
import { GlAvatarLabeled, GlDropdownItem } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import SuggestionsDropdown from '~/content_editor/components/suggestions_dropdown.vue';
|
||||
|
||||
describe('~/content_editor/components/suggestions_dropdown', () => {
|
||||
let wrapper;
|
||||
|
||||
const buildWrapper = ({ propsData = {} } = {}) => {
|
||||
wrapper = shallowMount(SuggestionsDropdown, {
|
||||
propsData: {
|
||||
nodeType: 'reference',
|
||||
...propsData,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const exampleUser = { username: 'root', avatar_url: 'root_avatar.png', type: 'User' };
|
||||
const exampleIssue = { iid: 123, title: 'Test Issue' };
|
||||
const exampleMergeRequest = { iid: 224, title: 'Test MR' };
|
||||
const exampleMilestone = { iid: 21, title: '1.3' };
|
||||
const exampleEmoji = {
|
||||
c: 'people',
|
||||
e: '😃',
|
||||
d: 'smiling face with open mouth',
|
||||
u: '6.0',
|
||||
name: 'smiley',
|
||||
};
|
||||
|
||||
const insertedEmojiProps = {
|
||||
name: 'smiley',
|
||||
title: 'smiling face with open mouth',
|
||||
moji: '😃',
|
||||
unicodeVersion: '6.0',
|
||||
};
|
||||
|
||||
describe('on item select', () => {
|
||||
it.each`
|
||||
nodeType | referenceType | char | reference | insertedText | insertedProps
|
||||
${'reference'} | ${'user'} | ${'@'} | ${exampleUser} | ${`@root`} | ${{}}
|
||||
${'reference'} | ${'issue'} | ${'#'} | ${exampleIssue} | ${`#123`} | ${{}}
|
||||
${'reference'} | ${'merge_request'} | ${'!'} | ${exampleMergeRequest} | ${`!224`} | ${{}}
|
||||
${'reference'} | ${'milestone'} | ${'%'} | ${exampleMilestone} | ${`%1.3`} | ${{}}
|
||||
${'emoji'} | ${'emoji'} | ${':'} | ${exampleEmoji} | ${`😃`} | ${insertedEmojiProps}
|
||||
`(
|
||||
'runs a command to insert the selected $referenceType',
|
||||
({ char, nodeType, referenceType, reference, insertedText, insertedProps }) => {
|
||||
const commandSpy = jest.fn();
|
||||
|
||||
buildWrapper({
|
||||
propsData: {
|
||||
char,
|
||||
command: commandSpy,
|
||||
nodeType,
|
||||
nodeProps: {
|
||||
referenceType,
|
||||
test: 'prop',
|
||||
},
|
||||
items: [reference],
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.findComponent(GlDropdownItem).vm.$emit('click');
|
||||
|
||||
expect(commandSpy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
text: insertedText,
|
||||
test: 'prop',
|
||||
...insertedProps,
|
||||
}),
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('rendering user references', () => {
|
||||
it('displays avatar labeled component', () => {
|
||||
const testUser = exampleUser;
|
||||
buildWrapper({
|
||||
propsData: {
|
||||
char: '@',
|
||||
command: jest.fn(),
|
||||
nodeType: 'reference',
|
||||
nodeProps: {
|
||||
referenceType: 'user',
|
||||
},
|
||||
items: [testUser],
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.findComponent(GlAvatarLabeled).attributes()).toEqual(
|
||||
expect.objectContaining({
|
||||
label: testUser.username,
|
||||
shape: 'circle',
|
||||
src: testUser.avatar_url,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
describe.each`
|
||||
referenceType | char | reference | displaysID
|
||||
${'issue'} | ${'#'} | ${exampleIssue} | ${true}
|
||||
${'merge_request'} | ${'!'} | ${exampleMergeRequest} | ${true}
|
||||
${'milestone'} | ${'%'} | ${exampleMilestone} | ${false}
|
||||
`('rendering $referenceType references', ({ referenceType, char, reference, displaysID }) => {
|
||||
it(`displays ${referenceType} ID and title`, () => {
|
||||
buildWrapper({
|
||||
propsData: {
|
||||
char,
|
||||
command: jest.fn(),
|
||||
nodeType: 'reference',
|
||||
nodeProps: {
|
||||
referenceType,
|
||||
},
|
||||
items: [reference],
|
||||
},
|
||||
});
|
||||
|
||||
if (displaysID) expect(wrapper.text()).toContain(`${reference.iid}`);
|
||||
else expect(wrapper.text()).not.toContain(`${reference.iid}`);
|
||||
expect(wrapper.text()).toContain(`${reference.title}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('rendering emoji references', () => {
|
||||
it('displays emoji', () => {
|
||||
const testEmojis = [
|
||||
{
|
||||
c: 'people',
|
||||
e: '😄',
|
||||
d: 'smiling face with open mouth and smiling eyes',
|
||||
u: '6.0',
|
||||
name: 'smile',
|
||||
},
|
||||
{
|
||||
c: 'people',
|
||||
e: '😸',
|
||||
d: 'grinning cat face with smiling eyes',
|
||||
u: '6.0',
|
||||
name: 'smile_cat',
|
||||
},
|
||||
{ c: 'people', e: '😃', d: 'smiling face with open mouth', u: '6.0', name: 'smiley' },
|
||||
];
|
||||
|
||||
buildWrapper({
|
||||
propsData: {
|
||||
char: ':',
|
||||
command: jest.fn(),
|
||||
nodeType: 'emoji',
|
||||
nodeProps: {},
|
||||
items: testEmojis,
|
||||
},
|
||||
});
|
||||
|
||||
testEmojis.forEach((testEmoji) => {
|
||||
expect(wrapper.text()).toContain(testEmoji.e);
|
||||
expect(wrapper.text()).toContain(testEmoji.d);
|
||||
expect(wrapper.text()).toContain(testEmoji.name);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -4,8 +4,8 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe IssuesHelper do
|
||||
let(:project) { create(:project) }
|
||||
let(:issue) { create :issue, project: project }
|
||||
let(:ext_project) { create :redmine_project }
|
||||
let(:issue) { create(:issue, project: project) }
|
||||
let(:ext_project) { create(:project, :with_redmine_integration) }
|
||||
|
||||
describe '#work_item_type_icon' do
|
||||
it 'returns icon of all standard base types' do
|
||||
|
|
|
@ -4,7 +4,7 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe Banzai::Pipeline::GfmPipeline do
|
||||
describe 'integration between parsing regular and external issue references' do
|
||||
let(:project) { create(:redmine_project, :public) }
|
||||
let(:project) { create(:project, :with_redmine_integration, :public) }
|
||||
|
||||
context 'when internal issue tracker is enabled' do
|
||||
context 'when shorthand pattern #ISSUE_ID is used' do
|
||||
|
|
|
@ -298,7 +298,7 @@ RSpec.describe Gitlab::ClosingIssueExtractor do
|
|||
|
||||
context 'with an external issue tracker reference' do
|
||||
it 'extracts the referenced issue' do
|
||||
jira_project = create(:jira_project, name: 'JIRA_EXT1')
|
||||
jira_project = create(:project, :with_jira_integration, name: 'JIRA_EXT1')
|
||||
jira_project.add_maintainer(jira_project.creator)
|
||||
jira_issue = ExternalIssue.new("#{jira_project.name}-1", project: jira_project)
|
||||
closing_issue_extractor = described_class.new(jira_project, jira_project.creator)
|
||||
|
|
|
@ -193,7 +193,7 @@ RSpec.describe Gitlab::ReferenceExtractor do
|
|||
end
|
||||
|
||||
context 'with an external issue tracker' do
|
||||
let(:project) { create(:jira_project) }
|
||||
let(:project) { create(:project, :with_jira_integration) }
|
||||
let(:issue) { create(:issue, project: project) }
|
||||
|
||||
context 'when GitLab issues are enabled' do
|
||||
|
|
|
@ -151,6 +151,18 @@ RSpec.describe BulkImports::Entity, type: :model do
|
|||
expect(entity).to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context 'when bulk_import_projects feature flag is enabled on root ancestor level and source_type is a project_entity' do
|
||||
it 'is valid' do
|
||||
top_level_namespace = create(:group)
|
||||
|
||||
stub_feature_flags(bulk_import_projects: top_level_namespace)
|
||||
|
||||
entity = build(:bulk_import_entity, :project_entity, destination_namespace: top_level_namespace.full_path)
|
||||
|
||||
expect(entity).to be_valid
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#encoded_source_full_path' do
|
||||
|
|
|
@ -225,7 +225,7 @@ RSpec.describe Commit, 'Mentionable' do
|
|||
end
|
||||
|
||||
context 'with external issue tracker' do
|
||||
let(:project) { create(:jira_project, :repository) }
|
||||
let(:project) { create(:project, :with_jira_integration, :repository) }
|
||||
|
||||
it 'is true if external issues referenced' do
|
||||
allow(commit.raw).to receive(:message).and_return 'JIRA-123'
|
||||
|
|
|
@ -6,7 +6,7 @@ RSpec.describe PrometheusAdapter, :use_clean_rails_memory_store_caching do
|
|||
include PrometheusHelpers
|
||||
include ReactiveCachingHelpers
|
||||
|
||||
let(:project) { create(:prometheus_project) }
|
||||
let(:project) { create(:project, :with_prometheus_integration) }
|
||||
let(:integration) { project.prometheus_integration }
|
||||
|
||||
let(:described_class) do
|
||||
|
|
|
@ -1291,7 +1291,7 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
|
|||
|
||||
context 'when the environment is available' do
|
||||
context 'with a deployment service' do
|
||||
let(:project) { create(:prometheus_project, :repository) }
|
||||
let(:project) { create(:project, :with_prometheus_integration, :repository) }
|
||||
|
||||
context 'and a deployment' do
|
||||
let!(:deployment) { create(:deployment, environment: environment) }
|
||||
|
@ -1364,7 +1364,7 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
|
|||
end
|
||||
|
||||
context 'when the environment is unavailable' do
|
||||
let(:project) { create(:prometheus_project) }
|
||||
let(:project) { create(:project, :with_prometheus_integration) }
|
||||
|
||||
before do
|
||||
environment.stop
|
||||
|
@ -1391,7 +1391,7 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
|
|||
end
|
||||
|
||||
describe '#metrics' do
|
||||
let(:project) { create(:prometheus_project) }
|
||||
let(:project) { create(:project, :with_prometheus_integration) }
|
||||
|
||||
subject { environment.metrics }
|
||||
|
||||
|
@ -1427,7 +1427,7 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
|
|||
end
|
||||
|
||||
describe '#additional_metrics' do
|
||||
let(:project) { create(:prometheus_project) }
|
||||
let(:project) { create(:project, :with_prometheus_integration) }
|
||||
let(:metric_params) { [] }
|
||||
|
||||
subject { environment.additional_metrics(*metric_params) }
|
||||
|
|
|
@ -8,7 +8,7 @@ RSpec.describe Integrations::Prometheus, :use_clean_rails_memory_store_caching,
|
|||
include PrometheusHelpers
|
||||
include ReactiveCachingHelpers
|
||||
|
||||
let_it_be_with_reload(:project) { create(:prometheus_project) }
|
||||
let_it_be_with_reload(:project) { create(:project, :with_prometheus_integration) }
|
||||
|
||||
let(:integration) { project.prometheus_integration }
|
||||
|
||||
|
@ -318,7 +318,7 @@ RSpec.describe Integrations::Prometheus, :use_clean_rails_memory_store_caching,
|
|||
context 'cluster belongs to projects group' do
|
||||
let_it_be(:group) { create(:group) }
|
||||
|
||||
let(:project) { create(:prometheus_project, group: group) }
|
||||
let(:project) { create(:project, :with_prometheus_integration, group: group) }
|
||||
let(:cluster) { create(:cluster_for_group, groups: [group]) }
|
||||
|
||||
it 'returns true' do
|
||||
|
|
|
@ -1415,7 +1415,7 @@ RSpec.describe Project, factory_default: :keep do
|
|||
|
||||
it "is false if used other tracker" do
|
||||
# NOTE: The current nature of this factory requires persistence
|
||||
project = create(:redmine_project)
|
||||
project = create(:project, :with_redmine_integration)
|
||||
|
||||
expect(project.default_issues_tracker?).to be_falsey
|
||||
end
|
||||
|
@ -1460,7 +1460,7 @@ RSpec.describe Project, factory_default: :keep do
|
|||
describe '#external_issue_tracker' do
|
||||
it 'sets Project#has_external_issue_tracker when it is nil' do
|
||||
project_with_no_tracker = create(:project, has_external_issue_tracker: nil)
|
||||
project_with_tracker = create(:redmine_project, has_external_issue_tracker: nil)
|
||||
project_with_tracker = create(:project, :with_redmine_integration, has_external_issue_tracker: nil)
|
||||
|
||||
expect do
|
||||
project_with_no_tracker.external_issue_tracker
|
||||
|
@ -1479,7 +1479,7 @@ RSpec.describe Project, factory_default: :keep do
|
|||
end
|
||||
|
||||
it 'retrieves external_issue_tracker querying services and cache it when there is external issue tracker' do
|
||||
project = create(:redmine_project)
|
||||
project = create(:project, :with_redmine_integration)
|
||||
|
||||
expect(project).to receive(:integrations).once.and_call_original
|
||||
2.times { expect(project.external_issue_tracker).to be_a_kind_of(Integrations::Redmine) }
|
||||
|
@ -5750,40 +5750,40 @@ RSpec.describe Project, factory_default: :keep do
|
|||
describe '#has_active_hooks?' do
|
||||
let_it_be_with_refind(:project) { create(:project) }
|
||||
|
||||
it { expect(project.has_active_hooks?).to be_falsey }
|
||||
it { expect(project.has_active_hooks?).to eq(false) }
|
||||
|
||||
it 'returns true when a matching push hook exists' do
|
||||
create(:project_hook, push_events: true, project: project)
|
||||
|
||||
expect(project.has_active_hooks?(:merge_request_events)).to be_falsey
|
||||
expect(project.has_active_hooks?).to be_truthy
|
||||
expect(project.has_active_hooks?(:merge_request_hooks)).to eq(false)
|
||||
expect(project.has_active_hooks?).to eq(true)
|
||||
end
|
||||
|
||||
it 'returns true when a matching system hook exists' do
|
||||
create(:system_hook, push_events: true)
|
||||
|
||||
expect(project.has_active_hooks?(:merge_request_events)).to be_falsey
|
||||
expect(project.has_active_hooks?).to be_truthy
|
||||
expect(project.has_active_hooks?(:merge_request_hooks)).to eq(false)
|
||||
expect(project.has_active_hooks?).to eq(true)
|
||||
end
|
||||
|
||||
it 'returns true when a plugin exists' do
|
||||
expect(Gitlab::FileHook).to receive(:any?).twice.and_return(true)
|
||||
|
||||
expect(project.has_active_hooks?(:merge_request_events)).to be_truthy
|
||||
expect(project.has_active_hooks?).to be_truthy
|
||||
expect(project.has_active_hooks?(:merge_request_hooks)).to eq(true)
|
||||
expect(project.has_active_hooks?).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#has_active_integrations?' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
||||
it { expect(project.has_active_integrations?).to be_falsey }
|
||||
it { expect(project.has_active_integrations?).to eq(false) }
|
||||
|
||||
it 'returns true when a matching service exists' do
|
||||
create(:custom_issue_tracker_integration, push_events: true, merge_requests_events: false, project: project)
|
||||
|
||||
expect(project.has_active_integrations?(:merge_request_hooks)).to be_falsey
|
||||
expect(project.has_active_integrations?).to be_truthy
|
||||
expect(project.has_active_integrations?(:merge_request_hooks)).to eq(false)
|
||||
expect(project.has_active_integrations?).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -3315,7 +3315,7 @@ RSpec.describe API::MergeRequests do
|
|||
end
|
||||
|
||||
it 'handles external issues' do
|
||||
jira_project = create(:jira_project, :public, :repository, name: 'JIR_EXT1')
|
||||
jira_project = create(:project, :with_jira_integration, :public, :repository, name: 'JIR_EXT1')
|
||||
ext_issue = ExternalIssue.new("#{jira_project.name}-123", jira_project)
|
||||
issue = create(:issue, project: jira_project)
|
||||
description = "Closes #{ext_issue.to_reference(jira_project)}\ncloses #{issue.to_reference}"
|
||||
|
|
|
@ -15,20 +15,28 @@ RSpec.describe MergeRequests::MarkReviewerReviewedService do
|
|||
end
|
||||
|
||||
describe '#execute' do
|
||||
describe 'invalid permissions' do
|
||||
let(:service) { described_class.new(project: project, current_user: create(:user)) }
|
||||
|
||||
shared_examples_for 'failed service execution' do
|
||||
it 'returns an error' do
|
||||
expect(result[:status]).to eq :error
|
||||
end
|
||||
|
||||
it 'does not trigger graphql subscription mergeRequestReviewersUpdated' do
|
||||
expect(GraphqlTriggers).not_to receive(:merge_request_reviewers_updated)
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
describe 'invalid permissions' do
|
||||
let(:service) { described_class.new(project: project, current_user: create(:user)) }
|
||||
|
||||
it_behaves_like 'failed service execution'
|
||||
end
|
||||
|
||||
describe 'reviewer does not exist' do
|
||||
let(:service) { described_class.new(project: project, current_user: create(:user)) }
|
||||
|
||||
it 'returns an error' do
|
||||
expect(result[:status]).to eq :error
|
||||
end
|
||||
it_behaves_like 'failed service execution'
|
||||
end
|
||||
|
||||
describe 'reviewer exists' do
|
||||
|
@ -40,6 +48,12 @@ RSpec.describe MergeRequests::MarkReviewerReviewedService do
|
|||
expect(result[:status]).to eq :success
|
||||
expect(reviewer.state).to eq 'reviewed'
|
||||
end
|
||||
|
||||
it 'triggers graphql subscription mergeRequestReviewersUpdated' do
|
||||
expect(GraphqlTriggers).to receive(:merge_request_reviewers_updated).with(merge_request)
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -25,20 +25,28 @@ RSpec.describe MergeRequests::RequestReviewService do
|
|||
end
|
||||
|
||||
describe '#execute' do
|
||||
describe 'invalid permissions' do
|
||||
let(:service) { described_class.new(project: project, current_user: create(:user)) }
|
||||
|
||||
shared_examples_for 'failed service execution' do
|
||||
it 'returns an error' do
|
||||
expect(result[:status]).to eq :error
|
||||
end
|
||||
|
||||
it 'does not trigger graphql subscription mergeRequestReviewersUpdated' do
|
||||
expect(GraphqlTriggers).not_to receive(:merge_request_reviewers_updated)
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
describe 'invalid permissions' do
|
||||
let(:service) { described_class.new(project: project, current_user: create(:user)) }
|
||||
|
||||
it_behaves_like 'failed service execution'
|
||||
end
|
||||
|
||||
describe 'reviewer does not exist' do
|
||||
let(:result) { service.execute(merge_request, create(:user)) }
|
||||
|
||||
it 'returns an error' do
|
||||
expect(result[:status]).to eq :error
|
||||
end
|
||||
it_behaves_like 'failed service execution'
|
||||
end
|
||||
|
||||
describe 'reviewer exists' do
|
||||
|
@ -64,6 +72,12 @@ RSpec.describe MergeRequests::RequestReviewService do
|
|||
|
||||
service.execute(merge_request, user)
|
||||
end
|
||||
|
||||
it 'triggers graphql subscription mergeRequestReviewersUpdated' do
|
||||
expect(GraphqlTriggers).to receive(:merge_request_reviewers_updated).with(merge_request)
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -57,5 +57,53 @@ RSpec.shared_examples 'wiki pipeline imports a wiki for an entity' do
|
|||
expect(tracker.entity.failures.first.exception_message).to eq('Only allowed schemes are http, https')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when wiki is disabled' do
|
||||
before do
|
||||
allow_next_instance_of(BulkImports::Clients::HTTP) do |client|
|
||||
allow(client)
|
||||
.to receive(:get)
|
||||
.and_raise(
|
||||
BulkImports::NetworkError.new(
|
||||
'Unsuccessful response 403 from ...',
|
||||
response: response_double
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'unsuccessful response' do
|
||||
shared_examples 'does not raise an error' do
|
||||
it 'does not raise an error' do
|
||||
expect(parent.wiki).not_to receive(:ensure_repository)
|
||||
expect(parent.wiki.repository).not_to receive(:ensure_repository)
|
||||
|
||||
expect { subject.run }.not_to raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context 'when response is forbidden' do
|
||||
let(:response_double) { instance_double(HTTParty::Response, forbidden?: true, code: 403) }
|
||||
|
||||
include_examples 'does not raise an error'
|
||||
end
|
||||
|
||||
context 'when response is not found' do
|
||||
let(:response_double) { instance_double(HTTParty::Response, forbidden?: false, not_found?: true) }
|
||||
|
||||
include_examples 'does not raise an error'
|
||||
end
|
||||
|
||||
context 'when response is not 403' do
|
||||
let(:response_double) { instance_double(HTTParty::Response, forbidden?: false, not_found?: false, code: 301) }
|
||||
|
||||
it 'marks tracker as failed' do
|
||||
subject.run
|
||||
|
||||
expect(tracker.failed?).to eq(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -245,11 +245,12 @@ RSpec.shared_examples 'edits content using the content editor' do
|
|||
type_in_content_editor :enter
|
||||
end
|
||||
|
||||
it 'shows suggestions for members' do
|
||||
it 'shows suggestions for members with descriptions' do
|
||||
type_in_content_editor '@a'
|
||||
|
||||
expect(find(suggestions_dropdown)).to have_text('abc123')
|
||||
expect(find(suggestions_dropdown)).to have_text('all')
|
||||
expect(find(suggestions_dropdown)).to have_text('Group Members (2)')
|
||||
|
||||
send_keys [:arrow_down, :enter]
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ RSpec.describe Integrations::CreateExternalCrossReferenceWorker do
|
|||
include AfterNextHelpers
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let_it_be(:project) { create(:jira_project, :repository) }
|
||||
let_it_be(:project) { create(:project, :with_jira_integration, :repository) }
|
||||
let_it_be(:author) { create(:user) }
|
||||
let_it_be(:commit) { project.commit }
|
||||
let_it_be(:issue) { create(:issue, project: project) }
|
||||
|
|
16
yarn.lock
16
yarn.lock
|
@ -1074,10 +1074,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.4.0.tgz#cfc8319e259e5914ad0f48ee0ab6e0eec75d03da"
|
||||
integrity sha512-myCYbjViOI2k6oHGRqL1iKaMKbYvPqWL6tYZ07QkUKziVz5kYjECWk5c0Qp6yu9NsFAMWuow5PkR3oFTGBHmbg==
|
||||
|
||||
"@gitlab/ui@43.21.0":
|
||||
version "43.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-43.21.0.tgz#189094170c7ff0545685eaed3a4c4c55ead915e3"
|
||||
integrity sha512-jKuZ3AGFfAA5UEOXxGaSxb2NHplLTcRJbbR+bl6/9ggGhoyGPhgl74WzX87ejDNVooY4vvWGGRzGJhN1NgDM+w==
|
||||
"@gitlab/ui@44.0.0":
|
||||
version "44.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-44.0.0.tgz#70693077ee9315e4743357a2306dd344b681203e"
|
||||
integrity sha512-zfYL4c0ziGry1bDBjfYtd1t2qQ+z4cXGYCNprNKOIQCXgG9759EuopytyOEHf8yMJDwunTzFNOAkPtOsD7DzQA==
|
||||
dependencies:
|
||||
"@popperjs/core" "^2.11.2"
|
||||
bootstrap-vue "2.20.1"
|
||||
|
@ -1668,10 +1668,10 @@
|
|||
dependencies:
|
||||
"@sinonjs/commons" "^1.7.0"
|
||||
|
||||
"@sourcegraph/code-host-integration@0.0.60":
|
||||
version "0.0.60"
|
||||
resolved "https://registry.yarnpkg.com/@sourcegraph/code-host-integration/-/code-host-integration-0.0.60.tgz#2043877fabb7eb986fcb61b67ee480afbb29f4f0"
|
||||
integrity sha512-T+MvM8SUF7daA279hyQgwmva3J5LvPqwgQ/mWwxdVshehOQIPLUd310I0c6x6nZ0F/x4UjDWgRWzAqy6NLwV1w==
|
||||
"@sourcegraph/code-host-integration@0.0.82":
|
||||
version "0.0.82"
|
||||
resolved "https://registry.yarnpkg.com/@sourcegraph/code-host-integration/-/code-host-integration-0.0.82.tgz#9bf45d9a4bfb44be2ecbf86a63028df169f9dfc4"
|
||||
integrity sha512-HOdCo1SZ5H2AXIdao77G+Hh4nJW6UVNA3b1TrcXXHqfYvXoWn6yzEoI9aZjRVR6K5gBk5FD7amd/FKmqLmyo5A==
|
||||
|
||||
"@testing-library/dom@^7.16.2":
|
||||
version "7.24.5"
|
||||
|
|
Loading…
Reference in New Issue