Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
53716bea26
commit
20c68317f8
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :integration, aliases: [:service] do
|
||||
factory :integration do
|
||||
project
|
||||
type { 'Integration' }
|
||||
end
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
export * from './to_have_sprite_icon';
|
||||
export * from './to_have_tracking_attributes';
|
||||
export * from './to_match_interpolated_text';
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
};
|
||||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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' } }
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
47
yarn.lock
47
yarn.lock
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in New Issue