Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-01-10 18:14:07 +00:00
parent 53716bea26
commit 20c68317f8
32 changed files with 375 additions and 378 deletions

View File

@ -1,5 +1,5 @@
- object = @target_project || @project || @group
- noteable_type = @noteable.class if @noteable.present?
- noteable_type = @noteable_type || @noteable&.class
- datasources = autocomplete_data_sources(object, noteable_type)

View File

@ -1,14 +0,0 @@
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
# Background migration for cleaning up a concurrent column rename.
class CleanupConcurrentRename < CleanupConcurrentSchemaChange
RESCHEDULE_DELAY = 10.minutes
def cleanup_concurrent_schema_change(table, old_column, new_column)
cleanup_concurrent_column_rename(table, old_column, new_column)
end
end
end
end

View File

@ -1,56 +0,0 @@
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
# Base class for background migration for rename/type changes.
class CleanupConcurrentSchemaChange
include Database::MigrationHelpers
# table - The name of the table the migration is performed for.
# old_column - The name of the old (to drop) column.
# new_column - The name of the new column.
def perform(table, old_column, new_column)
return unless column_exists?(table, new_column) && column_exists?(table, old_column)
rows_to_migrate = define_model_for(table)
.where(new_column => nil)
.where
.not(old_column => nil)
if rows_to_migrate.any?
BackgroundMigrationWorker.perform_in(
RESCHEDULE_DELAY,
self.class.name,
[table, old_column, new_column]
)
else
cleanup_concurrent_schema_change(table, old_column, new_column)
end
end
def cleanup_concurrent_schema_change(_table, _old_column, _new_column)
raise NotImplementedError
end
# These methods are necessary so we can re-use the migration helpers in
# this class.
def connection
ActiveRecord::Base.connection
end
def method_missing(name, *args, &block)
connection.__send__(name, *args, &block) # rubocop: disable GitlabSecurity/PublicSend
end
def respond_to_missing?(*args)
connection.respond_to?(*args) || super
end
def define_model_for(table)
Class.new(ActiveRecord::Base) do
self.table_name = table
end
end
end
end
end

View File

@ -1,14 +0,0 @@
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
# Background migration for cleaning up a concurrent column type changeb.
class CleanupConcurrentTypeChange < CleanupConcurrentSchemaChange
RESCHEDULE_DELAY = 10.minutes
def cleanup_concurrent_schema_change(table, old_column, new_column)
cleanup_concurrent_column_type_change(table, old_column)
end
end
end
end

View File

@ -1,41 +0,0 @@
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
# CopyColumn is a simple (reusable) background migration that can be used to
# update the value of a column based on the value of another column in the
# same table.
#
# For this background migration to work the table that is migrated _has_ to
# have an `id` column as the primary key.
class CopyColumn
# table - The name of the table that contains the columns.
# copy_from - The column containing the data to copy.
# copy_to - The column to copy the data to.
# start_id - The start ID of the range of rows to update.
# end_id - The end ID of the range of rows to update.
def perform(table, copy_from, copy_to, start_id, end_id)
return unless connection.column_exists?(table, copy_to)
quoted_table = connection.quote_table_name(table)
quoted_copy_from = connection.quote_column_name(copy_from)
quoted_copy_to = connection.quote_column_name(copy_to)
# We're using raw SQL here since this job may be frequently executed. As
# a result dynamically defining models would lead to many unnecessary
# schema information queries.
connection.execute <<-SQL.strip_heredoc
UPDATE #{quoted_table}
SET #{quoted_copy_to} = #{quoted_copy_from}
WHERE id BETWEEN #{start_id} AND #{end_id}
AND #{quoted_copy_from} IS NOT NULL
AND #{quoted_copy_to} IS NULL
SQL
end
def connection
ActiveRecord::Base.connection
end
end
end
end

View File

@ -53,6 +53,8 @@ module Gitlab
# 'args' in :job => from default error handler
job_holder = sidekiq.key?('args') ? sidekiq : sidekiq[:job]
return event unless job_holder
if job_holder['args']
job_holder['args'] = filter_arguments(job_holder['args'], job_holder['class']).to_a
end

View File

@ -57,7 +57,7 @@
"@gitlab/favicon-overlay": "2.0.0",
"@gitlab/svgs": "2.0.0",
"@gitlab/tributejs": "1.0.0",
"@gitlab/ui": "32.50.0",
"@gitlab/ui": "32.51.3",
"@gitlab/visual-review-tools": "1.6.1",
"@rails/actioncable": "6.1.4-1",
"@rails/ujs": "6.1.4-1",
@ -234,6 +234,7 @@
"istanbul-reports": "^3.0.0",
"jest": "^26.5.2",
"jest-canvas-mock": "^2.1.2",
"jest-diff": "^27.4.6",
"jest-environment-jsdom": "^26.5.2",
"jest-junit": "^12.0.0",
"jest-raw-loader": "^1.0.1",

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
FactoryBot.define do
factory :integration, aliases: [:service] do
factory :integration do
project
type { 'Integration' }
end

View File

@ -19,16 +19,16 @@ FactoryBot.define do
create(:jira_import_state, :finished, project: projects[1], label: jira_label, imported_issues_count: 3)
create(:jira_import_state, :scheduled, project: projects[1], label: jira_label)
create(:prometheus_integration, project: projects[1])
create(:service, project: projects[1], type: 'JenkinsService', active: true)
create(:service, project: projects[0], type: 'SlackSlashCommandsService', active: true)
create(:service, project: projects[1], type: 'SlackService', active: true)
create(:service, project: projects[2], type: 'SlackService', active: true)
create(:service, project: projects[2], type: 'MattermostService', active: false)
create(:service, group: group, project: nil, type: 'MattermostService', active: true)
mattermost_instance = create(:service, :instance, type: 'MattermostService', active: true)
create(:service, project: projects[1], type: 'MattermostService', active: true, inherit_from_id: mattermost_instance.id)
create(:service, group: group, project: nil, type: 'SlackService', active: true, inherit_from_id: mattermost_instance.id)
create(:service, project: projects[2], type: 'CustomIssueTrackerService', active: true)
create(:integration, project: projects[1], type: 'JenkinsService', active: true)
create(:integration, project: projects[0], type: 'SlackSlashCommandsService', active: true)
create(:integration, project: projects[1], type: 'SlackService', active: true)
create(:integration, project: projects[2], type: 'SlackService', active: true)
create(:integration, project: projects[2], type: 'MattermostService', active: false)
create(:integration, group: group, project: nil, type: 'MattermostService', active: true)
mattermost_instance = create(:integration, :instance, type: 'MattermostService', active: true)
create(:integration, project: projects[1], type: 'MattermostService', active: true, inherit_from_id: mattermost_instance.id)
create(:integration, group: group, project: nil, type: 'SlackService', active: true, inherit_from_id: mattermost_instance.id)
create(:integration, project: projects[2], type: 'CustomIssueTrackerService', active: true)
create(:project_error_tracking_setting, project: projects[0])
create(:project_error_tracking_setting, project: projects[1], enabled: false)
alert_bot_issues = create_list(:incident, 2, project: projects[0], author: User.alert_bot)

View File

@ -96,7 +96,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
context 'view merge request with external CI service' do
before do
create(:service, project: project,
create(:integration, project: project,
active: true,
type: 'DroneCiService',
category: 'ci')

View File

@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Profile > Chat' do
let(:user) { create(:user) }
let(:integration) { create(:service) }
let(:integration) { create(:integration) }
before do
sign_in(user)

View File

@ -1,2 +1,3 @@
export * from './to_have_sprite_icon';
export * from './to_have_tracking_attributes';
export * from './to_match_interpolated_text';

View File

@ -0,0 +1,35 @@
import { diff } from 'jest-diff';
import { isObject, mapValues, isEqual } from 'lodash';
export const toHaveTrackingAttributes = (actual, obj) => {
if (!(actual instanceof Element)) {
return { actual, message: () => 'The received value must be an Element.', pass: false };
}
if (!isObject(obj)) {
return {
message: () => `The matching object must be an object. Found ${obj}.`,
pass: false,
};
}
const actualAttributes = mapValues(obj, (val, key) => actual.getAttribute(`data-track-${key}`));
const matcherPass = isEqual(actualAttributes, obj);
const failMessage = () => {
// We can match, but still fail because we're in a `expect...not.` context
if (matcherPass) {
return `Expected the element's tracking attributes not to match. Found that they matched ${JSON.stringify(
obj,
)}.`;
}
const objDiff = diff(actualAttributes, obj);
return `Expected the element's tracking attributes to match the given object. Diff:
${objDiff}
`;
};
return { actual, message: failMessage, pass: matcherPass };
};

View File

@ -0,0 +1,65 @@
import { diff } from 'jest-diff';
describe('custom matcher toHaveTrackingAttributes', () => {
const createElementWithAttrs = (attributes) => {
const el = document.createElement('div');
Object.entries(attributes).forEach(([key, value]) => {
el.setAttribute(key, value);
});
return el;
};
it('blows up if actual is not an element', () => {
expect(() => {
expect({}).toHaveTrackingAttributes({});
}).toThrow('The received value must be an Element.');
});
it('blows up if expected is not an object', () => {
expect(() => {
expect(createElementWithAttrs({})).toHaveTrackingAttributes('foo');
}).toThrow('The matching object must be an object.');
});
it('prints diff when fails', () => {
const expectedDiff = diff({ label: 'foo' }, { label: 'a' });
expect(() => {
expect(createElementWithAttrs({ 'data-track-label': 'foo' })).toHaveTrackingAttributes({
label: 'a',
});
}).toThrow(
`Expected the element's tracking attributes to match the given object. Diff:\n${expectedDiff}\n`,
);
});
describe('positive assertions', () => {
it.each`
attrs | expected
${{ 'data-track-label': 'foo' }} | ${{ label: 'foo' }}
${{ 'data-track-label': 'foo' }} | ${{}}
${{ 'data-track-label': 'foo', label: 'bar' }} | ${{ label: 'foo' }}
${{ 'data-track-label': 'foo', 'data-track-extra': '123' }} | ${{ label: 'foo', extra: '123' }}
${{ 'data-track-label': 'foo', 'data-track-extra': '123' }} | ${{ extra: '123' }}
${{ label: 'foo', extra: '123', id: '7' }} | ${{}}
`('$expected matches element with attrs $attrs', ({ attrs, expected }) => {
expect(createElementWithAttrs(attrs)).toHaveTrackingAttributes(expected);
});
});
describe('negative assertions', () => {
it.each`
attrs | expected
${{}} | ${{ label: 'foo' }}
${{ label: 'foo' }} | ${{ label: 'foo' }}
${{ 'data-track-label': 'bar', label: 'foo' }} | ${{ label: 'foo' }}
${{ 'data-track-label': 'foo' }} | ${{ extra: '123' }}
${{ 'data-track-label': 'foo', 'data-track-extra': '123' }} | ${{ label: 'foo', extra: '456' }}
${{ 'data-track-label': 'foo', 'data-track-extra': '123' }} | ${{ label: 'foo', extra: '123', action: 'click' }}
${{ label: 'foo', extra: '123', id: '7' }} | ${{ id: '7' }}
`('$expected does not match element with attrs $attrs', ({ attrs, expected }) => {
expect(createElementWithAttrs(attrs)).not.toHaveTrackingAttributes(expected);
});
});
});

View File

@ -10,10 +10,10 @@ exports[`packages_list_app renders 1`] = `
<div>
<section
class="row empty-state text-center"
class="gl-display-flex gl-flex-wrap empty-state gl-text-center gl-flex-direction-column"
>
<div
class="col-12"
class="gl-max-w-full"
>
<div
class="svg-250 svg-content"
@ -28,10 +28,10 @@ exports[`packages_list_app renders 1`] = `
</div>
<div
class="col-12"
class="gl-max-w-full gl-m-auto"
>
<div
class="text-content gl-mx-auto gl-my-0 gl-p-5"
class="gl-mx-auto gl-my-0 gl-p-5"
>
<h1
class="gl-font-size-h-display gl-line-height-36 h4"

View File

@ -11,10 +11,10 @@ exports[`PackagesListApp renders 1`] = `
<div>
<section
class="row empty-state text-center"
class="gl-display-flex gl-flex-wrap empty-state gl-text-center gl-flex-direction-column"
>
<div
class="col-12"
class="gl-max-w-full"
>
<div
class="svg-250 svg-content"
@ -29,10 +29,10 @@ exports[`PackagesListApp renders 1`] = `
</div>
<div
class="col-12"
class="gl-max-w-full gl-m-auto"
>
<div
class="text-content gl-mx-auto gl-my-0 gl-p-5"
class="gl-mx-auto gl-my-0 gl-p-5"
>
<h1
class="gl-font-size-h-display gl-line-height-36 h4"

View File

@ -57,9 +57,9 @@ describe('~/pages/shared/nav/sidebar_tracking.js', () => {
menu.classList.add('is-over', 'is-showing-fly-out');
menuLink.click();
expect(menu.dataset).toMatchObject({
trackAction: 'click_menu',
trackExtra: JSON.stringify({
expect(menu).toHaveTrackingAttributes({
action: 'click_menu',
extra: JSON.stringify({
sidebar_display: 'Expanded',
menu_display: 'Fly out',
}),
@ -74,9 +74,9 @@ describe('~/pages/shared/nav/sidebar_tracking.js', () => {
submenuList.classList.add('fly-out-list');
menuLink.click();
expect(menu.dataset).toMatchObject({
trackAction: 'click_menu_item',
trackExtra: JSON.stringify({
expect(menu).toHaveTrackingAttributes({
action: 'click_menu_item',
extra: JSON.stringify({
sidebar_display: 'Expanded',
menu_display: 'Fly out',
}),
@ -92,9 +92,9 @@ describe('~/pages/shared/nav/sidebar_tracking.js', () => {
menu.classList.add('active');
menuLink.click();
expect(menu.dataset).toMatchObject({
trackAction: 'click_menu',
trackExtra: JSON.stringify({
expect(menu).toHaveTrackingAttributes({
action: 'click_menu',
extra: JSON.stringify({
sidebar_display: 'Expanded',
menu_display: 'Expanded',
}),
@ -108,9 +108,9 @@ describe('~/pages/shared/nav/sidebar_tracking.js', () => {
menu.classList.add('active');
menuLink.click();
expect(menu.dataset).toMatchObject({
trackAction: 'click_menu_item',
trackExtra: JSON.stringify({
expect(menu).toHaveTrackingAttributes({
action: 'click_menu_item',
extra: JSON.stringify({
sidebar_display: 'Expanded',
menu_display: 'Expanded',
}),
@ -131,9 +131,9 @@ describe('~/pages/shared/nav/sidebar_tracking.js', () => {
menu.classList.add('is-over', 'is-showing-fly-out');
menuLink.click();
expect(menu.dataset).toMatchObject({
trackAction: 'click_menu',
trackExtra: JSON.stringify({
expect(menu).toHaveTrackingAttributes({
action: 'click_menu',
extra: JSON.stringify({
sidebar_display: 'Collapsed',
menu_display: 'Fly out',
}),
@ -148,9 +148,9 @@ describe('~/pages/shared/nav/sidebar_tracking.js', () => {
submenuList.classList.add('fly-out-list');
menuLink.click();
expect(menu.dataset).toMatchObject({
trackAction: 'click_menu_item',
trackExtra: JSON.stringify({
expect(menu).toHaveTrackingAttributes({
action: 'click_menu_item',
extra: JSON.stringify({
sidebar_display: 'Collapsed',
menu_display: 'Fly out',
}),

View File

@ -1,12 +1,12 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`EmptyStateComponent should render content 1`] = `
"<section class=\\"row empty-state text-center\\">
<div class=\\"col-12\\">
"<section class=\\"gl-display-flex gl-flex-wrap empty-state gl-text-center gl-flex-direction-column\\">
<div class=\\"gl-max-w-full\\">
<div class=\\"svg-250 svg-content\\"><img src=\\"/image.svg\\" alt=\\"\\" role=\\"img\\" class=\\"gl-max-w-full\\"></div>
</div>
<div class=\\"col-12\\">
<div class=\\"text-content gl-mx-auto gl-my-0 gl-p-5\\">
<div class=\\"gl-max-w-full gl-m-auto\\">
<div class=\\"gl-mx-auto gl-my-0 gl-p-5\\">
<h1 class=\\"gl-font-size-h-display gl-line-height-36 h4\\">
Getting started with serverless
</h1>

View File

@ -8,7 +8,7 @@ RSpec.describe Types::Projects::ServiceType do
describe ".resolve_type" do
it 'resolves the corresponding type for objects' do
expect(described_class.resolve_type(build(:jira_integration), {})).to eq(Types::Projects::Services::JiraServiceType)
expect(described_class.resolve_type(build(:service), {})).to eq(Types::Projects::Services::BaseServiceType)
expect(described_class.resolve_type(build(:integration), {})).to eq(Types::Projects::Services::BaseServiceType)
expect(described_class.resolve_type(build(:drone_ci_integration), {})).to eq(Types::Projects::Services::BaseServiceType)
expect(described_class.resolve_type(build(:custom_issue_tracker_integration), {})).to eq(Types::Projects::Services::BaseServiceType)
end

View File

@ -86,7 +86,7 @@ RSpec.describe AutoDevopsHelper do
context 'when another service is enabled' do
before do
create(:service, project: project, category: :ci, active: true)
create(:integration, project: project, category: :ci, active: true)
end
it { is_expected.to eq(false) }

View File

@ -1,28 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::CleanupConcurrentSchemaChange do
describe '#perform' do
it 'new column does not exist' do
expect(subject).to receive(:column_exists?).with(:issues, :closed_at_timestamp).and_return(false)
expect(subject).not_to receive(:column_exists?).with(:issues, :closed_at)
expect(subject).not_to receive(:define_model_for)
expect(subject.perform(:issues, :closed_at, :closed_at_timestamp)).to be_nil
end
it 'old column does not exist' do
expect(subject).to receive(:column_exists?).with(:issues, :closed_at_timestamp).and_return(true)
expect(subject).to receive(:column_exists?).with(:issues, :closed_at).and_return(false)
expect(subject).not_to receive(:define_model_for)
expect(subject.perform(:issues, :closed_at, :closed_at_timestamp)).to be_nil
end
it 'has both old and new columns' do
expect(subject).to receive(:column_exists?).twice.and_return(true)
expect { subject.perform('issues', :closed_at, :created_at) }.to raise_error(NotImplementedError)
end
end
end

View File

@ -178,5 +178,14 @@ RSpec.describe Gitlab::ErrorTracking::Processor::SidekiqProcessor do
expect(result_hash.dig(:extra, :sidekiq)).to be_nil
end
end
context 'when there is Sidekiq data but no job' do
let(:value) { { other: 'foo' } }
let(:wrapped_value) { { extra: { sidekiq: value } } }
it 'does nothing' do
expect(result_hash.dig(:extra, :sidekiq)).to eq(value)
end
end
end
end

View File

@ -258,7 +258,7 @@ RSpec.describe Gitlab::ImportExport::FastHashSerializer do
create(:resource_label_event, label: group_label, merge_request: merge_request)
create(:event, :created, target: milestone, project: project, author: user)
create(:service, project: project, type: 'CustomIssueTrackerService', category: 'issue_tracker', properties: { one: 'value' })
create(:integration, project: project, type: 'CustomIssueTrackerService', category: 'issue_tracker', properties: { one: 'value' })
create(:project_custom_attribute, project: project)
create(:project_custom_attribute, project: project)

View File

@ -88,7 +88,7 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory, :use_clean_rails_
end
context 'original service exists' do
let(:service_id) { create(:service, project: project).id }
let(:service_id) { create(:integration, project: project).id }
it 'does not have the original service_id' do
expect(created_object.service_id).not_to eq(service_id)

View File

@ -46,11 +46,11 @@ RSpec.describe Gitlab::Integrations::StiType do
SQL
end
let_it_be(:service) { create(:service) }
let_it_be(:integration) { create(:integration) }
it 'forms SQL UPDATE statements correctly' do
sql_statements = types.map do |type|
record = ActiveRecord::QueryRecorder.new { service.update_column(:type, type) }
record = ActiveRecord::QueryRecorder.new { integration.update_column(:type, type) }
record.log.first
end
@ -65,8 +65,6 @@ RSpec.describe Gitlab::Integrations::StiType do
SQL
end
let(:service) { create(:service) }
it 'forms SQL DELETE statements correctly' do
sql_statements = types.map do |type|
record = ActiveRecord::QueryRecorder.new { Integration.delete_by(type: type) }
@ -81,7 +79,7 @@ RSpec.describe Gitlab::Integrations::StiType do
describe '#deserialize' do
specify 'it deserializes type correctly', :aggregate_failures do
types.each do |type|
service = create(:service, type: type)
service = create(:integration, type: type)
expect(service.type).to eq('AsanaService')
end
@ -90,7 +88,7 @@ RSpec.describe Gitlab::Integrations::StiType do
describe '#cast' do
it 'casts type as model correctly', :aggregate_failures do
create(:service, type: 'AsanaService')
create(:integration, type: 'AsanaService')
types.each do |type|
expect(Integration.find_by(type: type)).to be_kind_of(Integrations::Asana)
@ -100,7 +98,7 @@ RSpec.describe Gitlab::Integrations::StiType do
describe '#changed?' do
it 'detects changes correctly', :aggregate_failures do
service = create(:service, type: 'AsanaService')
service = create(:integration, type: 'AsanaService')
types.each do |type|
service.type = type

View File

@ -33,28 +33,28 @@ RSpec.describe Integration do
end
with_them do
it 'validates the service' do
expect(build(:service, project_id: project_id, group_id: group_id, instance: instance).valid?).to eq(valid)
it 'validates the integration' do
expect(build(:integration, project_id: project_id, group_id: group_id, instance: instance).valid?).to eq(valid)
end
end
context 'with existing services' do
context 'with existing integrations' do
before_all do
create(:service, :instance)
create(:service, project: project)
create(:service, group: group, project: nil)
create(:integration, :instance)
create(:integration, project: project)
create(:integration, group: group, project: nil)
end
it 'allows only one instance service per type' do
expect(build(:service, :instance)).to be_invalid
it 'allows only one instance integration per type' do
expect(build(:integration, :instance)).to be_invalid
end
it 'allows only one project service per type' do
expect(build(:service, project: project)).to be_invalid
it 'allows only one project integration per type' do
expect(build(:integration, project: project)).to be_invalid
end
it 'allows only one group service per type' do
expect(build(:service, group: group, project: nil)).to be_invalid
it 'allows only one group integration per type' do
expect(build(:integration, group: group, project: nil)).to be_invalid
end
end
end
@ -79,57 +79,57 @@ RSpec.describe Integration do
end
describe '.by_type' do
let!(:service1) { create(:jira_integration) }
let!(:service2) { create(:jira_integration) }
let!(:service3) { create(:redmine_integration) }
let!(:integration1) { create(:jira_integration) }
let!(:integration2) { create(:jira_integration) }
let!(:integration3) { create(:redmine_integration) }
subject { described_class.by_type(type) }
context 'when type is "JiraService"' do
let(:type) { 'JiraService' }
it { is_expected.to match_array([service1, service2]) }
it { is_expected.to match_array([integration1, integration2]) }
end
context 'when type is "RedmineService"' do
let(:type) { 'RedmineService' }
it { is_expected.to match_array([service3]) }
it { is_expected.to match_array([integration3]) }
end
end
describe '.for_group' do
let!(:service1) { create(:jira_integration, project_id: nil, group_id: group.id) }
let!(:service2) { create(:jira_integration) }
let!(:integration1) { create(:jira_integration, project_id: nil, group_id: group.id) }
let!(:integration2) { create(:jira_integration) }
it 'returns the right group service' do
expect(described_class.for_group(group)).to match_array([service1])
it 'returns the right group integration' do
expect(described_class.for_group(group)).to match_array([integration1])
end
end
describe '.confidential_note_hooks' do
it 'includes services where confidential_note_events is true' do
create(:service, active: true, confidential_note_events: true)
it 'includes integrations where confidential_note_events is true' do
create(:integration, active: true, confidential_note_events: true)
expect(described_class.confidential_note_hooks.count).to eq 1
end
it 'excludes services where confidential_note_events is false' do
create(:service, active: true, confidential_note_events: false)
it 'excludes integrations where confidential_note_events is false' do
create(:integration, active: true, confidential_note_events: false)
expect(described_class.confidential_note_hooks.count).to eq 0
end
end
describe '.alert_hooks' do
it 'includes services where alert_events is true' do
create(:service, active: true, alert_events: true)
it 'includes integrations where alert_events is true' do
create(:integration, active: true, alert_events: true)
expect(described_class.alert_hooks.count).to eq 1
end
it 'excludes services where alert_events is false' do
create(:service, active: true, alert_events: false)
it 'excludes integrations where alert_events is false' do
create(:integration, active: true, alert_events: false)
expect(described_class.alert_hooks.count).to eq 0
end
@ -137,35 +137,35 @@ RSpec.describe Integration do
end
describe '#operating?' do
it 'is false when the service is not active' do
expect(build(:service).operating?).to eq(false)
it 'is false when the integration is not active' do
expect(build(:integration).operating?).to eq(false)
end
it 'is false when the service is not persisted' do
expect(build(:service, active: true).operating?).to eq(false)
it 'is false when the integration is not persisted' do
expect(build(:integration, active: true).operating?).to eq(false)
end
it 'is true when the service is active and persisted' do
expect(create(:service, active: true).operating?).to eq(true)
it 'is true when the integration is active and persisted' do
expect(create(:integration, active: true).operating?).to eq(true)
end
end
describe '#testable?' do
context 'when integration is project-level' do
subject { build(:service, project: project) }
subject { build(:integration, project: project) }
it { is_expected.to be_testable }
end
context 'when integration is not project-level' do
subject { build(:service, project: nil) }
subject { build(:integration, project: nil) }
it { is_expected.not_to be_testable }
end
end
describe '#test' do
let(:integration) { build(:service, project: project) }
let(:integration) { build(:integration, project: project) }
let(:data) { 'test' }
it 'calls #execute' do
@ -186,32 +186,32 @@ RSpec.describe Integration do
end
describe '#project_level?' do
it 'is true when service has a project' do
expect(build(:service, project: project)).to be_project_level
it 'is true when integration has a project' do
expect(build(:integration, project: project)).to be_project_level
end
it 'is false when service has no project' do
expect(build(:service, project: nil)).not_to be_project_level
it 'is false when integration has no project' do
expect(build(:integration, project: nil)).not_to be_project_level
end
end
describe '#group_level?' do
it 'is true when service has a group' do
expect(build(:service, group: group)).to be_group_level
it 'is true when integration has a group' do
expect(build(:integration, group: group)).to be_group_level
end
it 'is false when service has no group' do
expect(build(:service, group: nil)).not_to be_group_level
it 'is false when integration has no group' do
expect(build(:integration, group: nil)).not_to be_group_level
end
end
describe '#instance_level?' do
it 'is true when service has instance-level integration' do
expect(build(:service, :instance)).to be_instance_level
it 'is true when integration has instance-level integration' do
expect(build(:integration, :instance)).to be_instance_level
end
it 'is false when service does not have instance-level integration' do
expect(build(:service, instance: false)).not_to be_instance_level
it 'is false when integration does not have instance-level integration' do
expect(build(:integration, instance: false)).not_to be_instance_level
end
end
@ -231,19 +231,19 @@ RSpec.describe Integration do
end
describe '.find_or_initialize_all_non_project_specific' do
shared_examples 'service instances' do
it 'returns the available service instances' do
shared_examples 'integration instances' do
it 'returns the available integration instances' do
expect(Integration.find_or_initialize_all_non_project_specific(Integration.for_instance).map(&:to_param))
.to match_array(Integration.available_integration_names(include_project_specific: false))
end
it 'does not create service instances' do
it 'does not create integration instances' do
expect { Integration.find_or_initialize_all_non_project_specific(Integration.for_instance) }
.not_to change(Integration, :count)
end
end
it_behaves_like 'service instances'
it_behaves_like 'integration instances'
context 'with all existing instances' do
before do
@ -252,15 +252,15 @@ RSpec.describe Integration do
)
end
it_behaves_like 'service instances'
it_behaves_like 'integration instances'
context 'with a previous existing service (MockCiService) and a new service (Asana)' do
context 'with a previous existing integration (MockCiService) and a new integration (Asana)' do
before do
Integration.insert({ type: 'MockCiService', instance: true })
Integration.delete_by(type: 'AsanaService', instance: true)
end
it_behaves_like 'service instances'
it_behaves_like 'integration instances'
end
end
@ -269,7 +269,7 @@ RSpec.describe Integration do
create(:jira_integration, :instance)
end
it_behaves_like 'service instances'
it_behaves_like 'integration instances'
end
end
@ -320,31 +320,31 @@ RSpec.describe Integration do
}
end
shared_examples 'service creation from an integration' do
it 'creates a correct service for a project integration' do
service = described_class.build_from_integration(integration, project_id: project.id)
shared_examples 'integration creation from an integration' do
it 'creates a correct integration for a project integration' do
new_integration = described_class.build_from_integration(integration, project_id: project.id)
expect(service).to be_active
expect(service.url).to eq(url)
expect(service.api_url).to eq(api_url)
expect(service.username).to eq(username)
expect(service.password).to eq(password)
expect(service.instance).to eq(false)
expect(service.project).to eq(project)
expect(service.group).to eq(nil)
expect(new_integration).to be_active
expect(new_integration.url).to eq(url)
expect(new_integration.api_url).to eq(api_url)
expect(new_integration.username).to eq(username)
expect(new_integration.password).to eq(password)
expect(new_integration.instance).to eq(false)
expect(new_integration.project).to eq(project)
expect(new_integration.group).to eq(nil)
end
it 'creates a correct service for a group integration' do
service = described_class.build_from_integration(integration, group_id: group.id)
it 'creates a correct integration for a group integration' do
new_integration = described_class.build_from_integration(integration, group_id: group.id)
expect(service).to be_active
expect(service.url).to eq(url)
expect(service.api_url).to eq(api_url)
expect(service.username).to eq(username)
expect(service.password).to eq(password)
expect(service.instance).to eq(false)
expect(service.project).to eq(nil)
expect(service.group).to eq(group)
expect(new_integration).to be_active
expect(new_integration.url).to eq(url)
expect(new_integration.api_url).to eq(api_url)
expect(new_integration.username).to eq(username)
expect(new_integration.password).to eq(password)
expect(new_integration.instance).to eq(false)
expect(new_integration.project).to eq(nil)
expect(new_integration.group).to eq(group)
end
end
@ -355,7 +355,7 @@ RSpec.describe Integration do
create(:jira_integration, :without_properties_callback, properties: properties.merge(additional: 'something'))
end
it_behaves_like 'service creation from an integration'
it_behaves_like 'integration creation from an integration'
end
context 'when data are stored in separated fields' do
@ -363,7 +363,7 @@ RSpec.describe Integration do
create(:jira_integration, data_params.merge(properties: {}))
end
it_behaves_like 'service creation from an integration'
it_behaves_like 'integration creation from an integration'
end
context 'when data are stored in both properties and separated fields' do
@ -374,7 +374,7 @@ RSpec.describe Integration do
end
end
it_behaves_like 'service creation from an integration'
it_behaves_like 'integration creation from an integration'
end
end
end
@ -565,17 +565,17 @@ RSpec.describe Integration do
end
describe '.integration_name_to_model' do
it 'returns the model for the given service name' do
it 'returns the model for the given integration name' do
expect(described_class.integration_name_to_model('asana')).to eq(Integrations::Asana)
end
it 'raises an error if service name is invalid' do
it 'raises an error if integration name is invalid' do
expect { described_class.integration_name_to_model('foo') }.to raise_exception(NameError, /uninitialized constant FooService/)
end
end
describe "{property}_changed?" do
let(:service) do
let(:integration) do
Integrations::Bamboo.create!(
project: project,
properties: {
@ -587,35 +587,35 @@ RSpec.describe Integration do
end
it "returns false when the property has not been assigned a new value" do
service.username = "key_changed"
expect(service.bamboo_url_changed?).to be_falsy
integration.username = "key_changed"
expect(integration.bamboo_url_changed?).to be_falsy
end
it "returns true when the property has been assigned a different value" do
service.bamboo_url = "http://example.com"
expect(service.bamboo_url_changed?).to be_truthy
integration.bamboo_url = "http://example.com"
expect(integration.bamboo_url_changed?).to be_truthy
end
it "returns true when the property has been assigned a different value twice" do
service.bamboo_url = "http://example.com"
service.bamboo_url = "http://example.com"
expect(service.bamboo_url_changed?).to be_truthy
integration.bamboo_url = "http://example.com"
integration.bamboo_url = "http://example.com"
expect(integration.bamboo_url_changed?).to be_truthy
end
it "returns false when the property has been re-assigned the same value" do
service.bamboo_url = 'http://gitlab.com'
expect(service.bamboo_url_changed?).to be_falsy
integration.bamboo_url = 'http://gitlab.com'
expect(integration.bamboo_url_changed?).to be_falsy
end
it "returns false when the property has been assigned a new value then saved" do
service.bamboo_url = 'http://example.com'
service.save!
expect(service.bamboo_url_changed?).to be_falsy
integration.bamboo_url = 'http://example.com'
integration.save!
expect(integration.bamboo_url_changed?).to be_falsy
end
end
describe "{property}_touched?" do
let(:service) do
let(:integration) do
Integrations::Bamboo.create!(
project: project,
properties: {
@ -627,35 +627,35 @@ RSpec.describe Integration do
end
it "returns false when the property has not been assigned a new value" do
service.username = "key_changed"
expect(service.bamboo_url_touched?).to be_falsy
integration.username = "key_changed"
expect(integration.bamboo_url_touched?).to be_falsy
end
it "returns true when the property has been assigned a different value" do
service.bamboo_url = "http://example.com"
expect(service.bamboo_url_touched?).to be_truthy
integration.bamboo_url = "http://example.com"
expect(integration.bamboo_url_touched?).to be_truthy
end
it "returns true when the property has been assigned a different value twice" do
service.bamboo_url = "http://example.com"
service.bamboo_url = "http://example.com"
expect(service.bamboo_url_touched?).to be_truthy
integration.bamboo_url = "http://example.com"
integration.bamboo_url = "http://example.com"
expect(integration.bamboo_url_touched?).to be_truthy
end
it "returns true when the property has been re-assigned the same value" do
service.bamboo_url = 'http://gitlab.com'
expect(service.bamboo_url_touched?).to be_truthy
integration.bamboo_url = 'http://gitlab.com'
expect(integration.bamboo_url_touched?).to be_truthy
end
it "returns false when the property has been assigned a new value then saved" do
service.bamboo_url = 'http://example.com'
service.save!
expect(service.bamboo_url_changed?).to be_falsy
integration.bamboo_url = 'http://example.com'
integration.save!
expect(integration.bamboo_url_changed?).to be_falsy
end
end
describe "{property}_was" do
let(:service) do
let(:integration) do
Integrations::Bamboo.create!(
project: project,
properties: {
@ -667,35 +667,35 @@ RSpec.describe Integration do
end
it "returns nil when the property has not been assigned a new value" do
service.username = "key_changed"
expect(service.bamboo_url_was).to be_nil
integration.username = "key_changed"
expect(integration.bamboo_url_was).to be_nil
end
it "returns the previous value when the property has been assigned a different value" do
service.bamboo_url = "http://example.com"
expect(service.bamboo_url_was).to eq('http://gitlab.com')
integration.bamboo_url = "http://example.com"
expect(integration.bamboo_url_was).to eq('http://gitlab.com')
end
it "returns initial value when the property has been re-assigned the same value" do
service.bamboo_url = 'http://gitlab.com'
expect(service.bamboo_url_was).to eq('http://gitlab.com')
integration.bamboo_url = 'http://gitlab.com'
expect(integration.bamboo_url_was).to eq('http://gitlab.com')
end
it "returns initial value when the property has been assigned multiple values" do
service.bamboo_url = "http://example.com"
service.bamboo_url = "http://example.org"
expect(service.bamboo_url_was).to eq('http://gitlab.com')
integration.bamboo_url = "http://example.com"
integration.bamboo_url = "http://example.org"
expect(integration.bamboo_url_was).to eq('http://gitlab.com')
end
it "returns nil when the property has been assigned a new value then saved" do
service.bamboo_url = 'http://example.com'
service.save!
expect(service.bamboo_url_was).to be_nil
integration.bamboo_url = 'http://example.com'
integration.save!
expect(integration.bamboo_url_was).to be_nil
end
end
describe 'initialize service with no properties' do
let(:service) do
describe 'initialize integration with no properties' do
let(:integration) do
Integrations::Bugzilla.create!(
project: project,
project_url: 'http://gitlab.example.com'
@ -703,16 +703,16 @@ RSpec.describe Integration do
end
it 'does not raise error' do
expect { service }.not_to raise_error
expect { integration }.not_to raise_error
end
it 'sets data correctly' do
expect(service.data_fields.project_url).to eq('http://gitlab.example.com')
expect(integration.data_fields.project_url).to eq('http://gitlab.example.com')
end
end
describe '#api_field_names' do
let(:fake_service) do
let(:fake_integration) do
Class.new(Integration) do
def fields
[
@ -728,8 +728,8 @@ RSpec.describe Integration do
end
end
let(:service) do
fake_service.new(properties: [
let(:integration) do
fake_integration.new(properties: [
{ token: 'token-value' },
{ api_token: 'api_token-value' },
{ key: 'key-value' },
@ -741,16 +741,16 @@ RSpec.describe Integration do
end
it 'filters out sensitive fields' do
expect(service.api_field_names).to eq(['safe_field'])
expect(integration.api_field_names).to eq(['safe_field'])
end
end
context 'logging' do
let(:service) { build(:service, project: project) }
let(:integration) { build(:integration, project: project) }
let(:test_message) { "test message" }
let(:arguments) do
{
service_class: service.class.name,
service_class: integration.class.name,
project_path: project.full_path,
project_id: project.id,
message: test_message,
@ -761,20 +761,20 @@ RSpec.describe Integration do
it 'logs info messages using json logger' do
expect(Gitlab::JsonLogger).to receive(:info).with(arguments)
service.log_info(test_message, additional_argument: 'some argument')
integration.log_info(test_message, additional_argument: 'some argument')
end
it 'logs error messages using json logger' do
expect(Gitlab::JsonLogger).to receive(:error).with(arguments)
service.log_error(test_message, additional_argument: 'some argument')
integration.log_error(test_message, additional_argument: 'some argument')
end
context 'when project is nil' do
let(:project) { nil }
let(:arguments) do
{
service_class: service.class.name,
service_class: integration.class.name,
project_path: nil,
project_id: nil,
message: test_message,
@ -785,7 +785,7 @@ RSpec.describe Integration do
it 'logs info messages using json logger' do
expect(Gitlab::JsonLogger).to receive(:info).with(arguments)
service.log_info(test_message, additional_argument: 'some argument')
integration.log_info(test_message, additional_argument: 'some argument')
end
end
end

View File

@ -1359,51 +1359,51 @@ RSpec.describe Project, factory_default: :keep do
project.reload.has_external_issue_tracker
end
it 'is false when external issue tracker service is not active' do
create(:service, project: project, category: 'issue_tracker', active: false)
it 'is false when external issue tracker integration is not active' do
create(:integration, project: project, category: 'issue_tracker', active: false)
is_expected.to eq(false)
end
it 'is false when other service is active' do
create(:service, project: project, category: 'not_issue_tracker', active: true)
it 'is false when other integration is active' do
create(:integration, project: project, category: 'not_issue_tracker', active: true)
is_expected.to eq(false)
end
context 'when there is an active external issue tracker service' do
let!(:service) do
create(:service, project: project, type: 'JiraService', category: 'issue_tracker', active: true)
context 'when there is an active external issue tracker integration' do
let!(:integration) do
create(:integration, project: project, type: 'JiraService', category: 'issue_tracker', active: true)
end
specify { is_expected.to eq(true) }
it 'becomes false when external issue tracker service is destroyed' do
it 'becomes false when external issue tracker integration is destroyed' do
expect do
Integration.find(service.id).delete
Integration.find(integration.id).delete
end.to change { subject }.to(false)
end
it 'becomes false when external issue tracker service becomes inactive' do
it 'becomes false when external issue tracker integration becomes inactive' do
expect do
service.update_column(:active, false)
integration.update_column(:active, false)
end.to change { subject }.to(false)
end
context 'when there are two active external issue tracker services' do
let_it_be(:second_service) do
create(:service, project: project, type: 'CustomIssueTracker', category: 'issue_tracker', active: true)
context 'when there are two active external issue tracker integrations' do
let_it_be(:second_integration) do
create(:integration, project: project, type: 'CustomIssueTracker', category: 'issue_tracker', active: true)
end
it 'does not become false when external issue tracker service is destroyed' do
it 'does not become false when external issue tracker integration is destroyed' do
expect do
Integration.find(service.id).delete
Integration.find(integration.id).delete
end.not_to change { subject }
end
it 'does not become false when external issue tracker service becomes inactive' do
it 'does not become false when external issue tracker integration becomes inactive' do
expect do
service.update_column(:active, false)
integration.update_column(:active, false)
end.not_to change { subject }
end
end
@ -1455,13 +1455,13 @@ RSpec.describe Project, factory_default: :keep do
specify { expect(has_external_wiki).to eq(true) }
it 'becomes false if the external wiki service is destroyed' do
it 'becomes false if the external wiki integration is destroyed' do
expect do
Integration.find(integration.id).delete
end.to change { has_external_wiki }.to(false)
end
it 'becomes false if the external wiki service becomes inactive' do
it 'becomes false if the external wiki integration becomes inactive' do
expect do
integration.update_column(:active, false)
end.to change { has_external_wiki }.to(false)
@ -6836,7 +6836,7 @@ RSpec.describe Project, factory_default: :keep do
describe 'with integrations and chat names' do
subject { create(:project) }
let(:integration) { create(:service, project: subject) }
let(:integration) { create(:integration, project: subject) }
before do
create_list(:chat_name, 5, integration: integration)

View File

@ -4,10 +4,10 @@ require 'spec_helper'
RSpec.describe ChatNames::AuthorizeUserService do
describe '#execute' do
subject { described_class.new(service, params) }
let(:integration) { create(:integration) }
let(:result) { subject.execute }
let(:service) { create(:service) }
subject { described_class.new(integration, params) }
context 'when all parameters are valid' do
let(:params) { { team_id: 'T0001', team_domain: 'myteam', user_id: 'U0001', user_name: 'user' } }

View File

@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe ChatNames::FindUserService, :clean_gitlab_redis_shared_state do
describe '#execute' do
let(:integration) { create(:service) }
let(:integration) { create(:integration) }
subject { described_class.new(integration, params).execute }

View File

@ -44,7 +44,7 @@ module ExportFileHelper
create(:ci_trigger, project: project)
key = create(:deploy_key)
key.projects << project
create(:service, project: project)
create(:integration, project: project)
create(:project_hook, project: project, token: 'token')
create(:protected_branch, project: project)

View File

@ -13,7 +13,7 @@ RSpec.describe Deployments::HooksWorker do
it 'executes project services for deployment_hooks' do
deployment = create(:deployment, :running)
project = deployment.project
service = create(:service, type: 'SlackService', project: project, deployment_events: true, active: true)
service = create(:integration, type: 'SlackService', project: project, deployment_events: true, active: true)
expect(ProjectServiceWorker).to receive(:perform_async).with(service.id, an_instance_of(Hash))
@ -23,7 +23,7 @@ RSpec.describe Deployments::HooksWorker do
it 'does not execute an inactive service' do
deployment = create(:deployment, :running)
project = deployment.project
create(:service, type: 'SlackService', project: project, deployment_events: true, active: false)
create(:integration, type: 'SlackService', project: project, deployment_events: true, active: false)
expect(ProjectServiceWorker).not_to receive(:perform_async)

View File

@ -924,10 +924,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/tributejs/-/tributejs-1.0.0.tgz#672befa222aeffc83e7d799b0500a7a4418e59b8"
integrity sha512-nmKw1+hB6MHvlmPz63yPwVs1qQkycHwsKgxpEbzmky16Y6mL4EJMk3w1b8QlOAF/AIAzjCERPhe/R4MJiohbZw==
"@gitlab/ui@32.50.0":
version "32.50.0"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-32.50.0.tgz#ac50617a8b84f78949e177f495ade276f8560679"
integrity sha512-7wPEgbOn7M9hqzq5LZND5b8/OEajoFCjwaXzO42FBNJ+pb80JBsTg1Mu8dyXMGQP/SPcxO58BdQLUSjE0WER4w==
"@gitlab/ui@32.51.3":
version "32.51.3"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-32.51.3.tgz#1ba4802a16ecf5465774f4083e5ec1ed6adc4579"
integrity sha512-PWC0FtpsW9SM3O935XPU2el/JtLtvHQCL9qblKCeR98eJNYmIpjrw45ow+01jsqpjufcUI49n4id/sYHq8b6og==
dependencies:
"@babel/standalone" "^7.0.0"
bootstrap-vue "2.20.1"
@ -2395,6 +2395,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
dependencies:
color-convert "^2.0.1"
ansi-styles@^5.0.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
anymatch@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
@ -4778,6 +4783,11 @@ diff-sequences@^26.5.0:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.5.0.tgz#ef766cf09d43ed40406611f11c6d8d9dd8b2fefd"
integrity sha512-ZXx86srb/iYy6jG71k++wBN9P9J05UNQ5hQHQd9MtMPvcqXPx/vKU69jfHV637D00Q2gSgPk2D+jSx3l1lDW/Q==
diff-sequences@^27.4.0:
version "27.4.0"
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.4.0.tgz#d783920ad8d06ec718a060d00196dfef25b132a5"
integrity sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww==
diff@^3.4.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
@ -7253,6 +7263,16 @@ jest-diff@^26.5.2:
jest-get-type "^26.3.0"
pretty-format "^26.5.2"
jest-diff@^27.4.6:
version "27.4.6"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.4.6.tgz#93815774d2012a2cbb6cf23f84d48c7a2618f98d"
integrity sha512-zjaB0sh0Lb13VyPsd92V7HkqF6yKRH9vm33rwBt7rPYrpQvS1nCvlIy2pICbKta+ZjWngYLNn4cCK4nyZkjS/w==
dependencies:
chalk "^4.0.0"
diff-sequences "^27.4.0"
jest-get-type "^27.4.0"
pretty-format "^27.4.6"
jest-docblock@^26.0.0:
version "26.0.0"
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5"
@ -7301,6 +7321,11 @@ jest-get-type@^26.3.0:
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0"
integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==
jest-get-type@^27.4.0:
version "27.4.0"
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.4.0.tgz#7503d2663fffa431638337b3998d39c5e928e9b5"
integrity sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==
jest-haste-map@^26.5.2:
version "26.5.2"
resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.5.2.tgz#a15008abfc502c18aa56e4919ed8c96304ceb23d"
@ -9716,6 +9741,15 @@ pretty-format@^26.4.2, pretty-format@^26.5.2:
ansi-styles "^4.0.0"
react-is "^16.12.0"
pretty-format@^27.4.6:
version "27.4.6"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.4.6.tgz#1b784d2f53c68db31797b2348fa39b49e31846b7"
integrity sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==
dependencies:
ansi-regex "^5.0.1"
ansi-styles "^5.0.0"
react-is "^17.0.1"
pretty@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/pretty/-/pretty-2.0.0.tgz#adbc7960b7bbfe289a557dc5f737619a220d06a5"
@ -10103,6 +10137,11 @@ react-is@^16.12.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-is@^17.0.1:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
read-pkg-up@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be"