Commit 0fccbbc0 authored by Markus Koller's avatar Markus Koller Committed by Stan Hu

Add integrations.type_new column and sync with type

parent a6bfebb3
# frozen_string_literal: true
class AddTypeNewToIntegrations < ActiveRecord::Migration[6.1]
# rubocop:disable Migration/AddLimitToTextColumns
# limit is added in 20210721134707_add_text_limit_to_integrations_type_new
def change
add_column :integrations, :type_new, :text
end
# rubocop:enable Migration/AddLimitToTextColumns
end
# frozen_string_literal: true
class AddTextLimitToIntegrationsTypeNew < ActiveRecord::Migration[6.1]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
def up
add_text_limit :integrations, :type_new, 255
end
def down
remove_text_limit :integrations, :type_new
end
end
# frozen_string_literal: true
class AddTriggersToIntegrationsTypeNew < ActiveRecord::Migration[6.1]
include Gitlab::Database::SchemaHelpers
FUNCTION_NAME = 'integrations_set_type_new'
TRIGGER_ON_INSERT_NAME = 'trigger_type_new_on_insert'
def up
create_trigger_function(FUNCTION_NAME, replace: true) do
# This list matches `Gitlab::Integrations::StiType::NAMESPACED_INTEGRATIONS`.
#
# If we add new integrations after this migration we can directly use the
# correct class name in `type`, and don't need to add it to `NAMESPACED_INTEGRATIONS`.
<<~SQL
WITH mapping(old_type, new_type) AS (VALUES
('AsanaService', 'Integrations::Asana'),
('AssemblaService', 'Integrations::Assembla'),
('BambooService', 'Integrations::Bamboo'),
('BugzillaService', 'Integrations::Bugzilla'),
('BuildkiteService', 'Integrations::Buildkite'),
('CampfireService', 'Integrations::Campfire'),
('ConfluenceService', 'Integrations::Confluence'),
('CustomIssueTrackerService', 'Integrations::CustomIssueTracker'),
('DatadogService', 'Integrations::Datadog'),
('DiscordService', 'Integrations::Discord'),
('DroneCiService', 'Integrations::DroneCi'),
('EmailsOnPushService', 'Integrations::EmailsOnPush'),
('EwmService', 'Integrations::Ewm'),
('ExternalWikiService', 'Integrations::ExternalWiki'),
('FlowdockService', 'Integrations::Flowdock'),
('HangoutsChatService', 'Integrations::HangoutsChat'),
('IrkerService', 'Integrations::Irker'),
('JenkinsService', 'Integrations::Jenkins'),
('JiraService', 'Integrations::Jira'),
('MattermostService', 'Integrations::Mattermost'),
('MattermostSlashCommandsService', 'Integrations::MattermostSlashCommands'),
('MicrosoftTeamsService', 'Integrations::MicrosoftTeams'),
('MockCiService', 'Integrations::MockCi'),
('MockMonitoringService', 'Integrations::MockMonitoring'),
('PackagistService', 'Integrations::Packagist'),
('PipelinesEmailService', 'Integrations::PipelinesEmail'),
('PivotaltrackerService', 'Integrations::Pivotaltracker'),
('PrometheusService', 'Integrations::Prometheus'),
('PushoverService', 'Integrations::Pushover'),
('RedmineService', 'Integrations::Redmine'),
('SlackService', 'Integrations::Slack'),
('SlackSlashCommandsService', 'Integrations::SlackSlashCommands'),
('TeamcityService', 'Integrations::Teamcity'),
('UnifyCircuitService', 'Integrations::UnifyCircuit'),
('YoutrackService', 'Integrations::Youtrack'),
('WebexTeamsService', 'Integrations::WebexTeams'),
-- EE-only integrations
('GithubService', 'Integrations::Github'),
('GitlabSlackApplicationService', 'Integrations::GitlabSlackApplication')
)
UPDATE integrations SET type_new = mapping.new_type
FROM mapping
WHERE integrations.id = NEW.id
AND mapping.old_type = NEW.type;
RETURN NULL;
SQL
end
execute(<<~SQL)
CREATE TRIGGER #{TRIGGER_ON_INSERT_NAME}
AFTER INSERT ON integrations
FOR EACH ROW
EXECUTE FUNCTION #{FUNCTION_NAME}();
SQL
end
def down
drop_trigger(:integrations, TRIGGER_ON_INSERT_NAME)
drop_function(FUNCTION_NAME)
end
end
e6c8fd913f591fed24072e9b0032b47dbb1165f2c1cf50ed01cfcd5f7da32cba
\ No newline at end of file
a795dad532a5ed2a645e49e586c6fb73167e9ae38843cf5cbcf37cf8661b765a
\ No newline at end of file
a4219ce93f790ec372991adca4b1cc5c0410d57e92817082344b11758ca5ae93
\ No newline at end of file
...@@ -10,6 +10,62 @@ CREATE EXTENSION IF NOT EXISTS btree_gist; ...@@ -10,6 +10,62 @@ CREATE EXTENSION IF NOT EXISTS btree_gist;
CREATE EXTENSION IF NOT EXISTS pg_trgm; CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE FUNCTION integrations_set_type_new() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
WITH mapping(old_type, new_type) AS (VALUES
('AsanaService', 'Integrations::Asana'),
('AssemblaService', 'Integrations::Assembla'),
('BambooService', 'Integrations::Bamboo'),
('BugzillaService', 'Integrations::Bugzilla'),
('BuildkiteService', 'Integrations::Buildkite'),
('CampfireService', 'Integrations::Campfire'),
('ConfluenceService', 'Integrations::Confluence'),
('CustomIssueTrackerService', 'Integrations::CustomIssueTracker'),
('DatadogService', 'Integrations::Datadog'),
('DiscordService', 'Integrations::Discord'),
('DroneCiService', 'Integrations::DroneCi'),
('EmailsOnPushService', 'Integrations::EmailsOnPush'),
('EwmService', 'Integrations::Ewm'),
('ExternalWikiService', 'Integrations::ExternalWiki'),
('FlowdockService', 'Integrations::Flowdock'),
('HangoutsChatService', 'Integrations::HangoutsChat'),
('IrkerService', 'Integrations::Irker'),
('JenkinsService', 'Integrations::Jenkins'),
('JiraService', 'Integrations::Jira'),
('MattermostService', 'Integrations::Mattermost'),
('MattermostSlashCommandsService', 'Integrations::MattermostSlashCommands'),
('MicrosoftTeamsService', 'Integrations::MicrosoftTeams'),
('MockCiService', 'Integrations::MockCi'),
('MockMonitoringService', 'Integrations::MockMonitoring'),
('PackagistService', 'Integrations::Packagist'),
('PipelinesEmailService', 'Integrations::PipelinesEmail'),
('PivotaltrackerService', 'Integrations::Pivotaltracker'),
('PrometheusService', 'Integrations::Prometheus'),
('PushoverService', 'Integrations::Pushover'),
('RedmineService', 'Integrations::Redmine'),
('SlackService', 'Integrations::Slack'),
('SlackSlashCommandsService', 'Integrations::SlackSlashCommands'),
('TeamcityService', 'Integrations::Teamcity'),
('UnifyCircuitService', 'Integrations::UnifyCircuit'),
('YoutrackService', 'Integrations::Youtrack'),
('WebexTeamsService', 'Integrations::WebexTeams'),
-- EE-only integrations
('GithubService', 'Integrations::Github'),
('GitlabSlackApplicationService', 'Integrations::GitlabSlackApplication')
)
UPDATE integrations SET type_new = mapping.new_type
FROM mapping
WHERE integrations.id = NEW.id
AND mapping.old_type = NEW.type;
RETURN NULL;
END
$$;
CREATE FUNCTION set_has_external_issue_tracker() RETURNS trigger CREATE FUNCTION set_has_external_issue_tracker() RETURNS trigger
LANGUAGE plpgsql LANGUAGE plpgsql
AS $$ AS $$
...@@ -14085,7 +14141,9 @@ CREATE TABLE integrations ( ...@@ -14085,7 +14141,9 @@ CREATE TABLE integrations (
comment_detail smallint, comment_detail smallint,
inherit_from_id bigint, inherit_from_id bigint,
alert_events boolean, alert_events boolean,
group_id bigint group_id bigint,
type_new text,
CONSTRAINT check_a948a0aa7e CHECK ((char_length(type_new) <= 255))
); );
CREATE SEQUENCE integrations_id_seq CREATE SEQUENCE integrations_id_seq
...@@ -25827,6 +25885,8 @@ CREATE TRIGGER trigger_has_external_wiki_on_insert AFTER INSERT ON integrations ...@@ -25827,6 +25885,8 @@ CREATE TRIGGER trigger_has_external_wiki_on_insert AFTER INSERT ON integrations
CREATE TRIGGER trigger_has_external_wiki_on_update AFTER UPDATE ON integrations FOR EACH ROW WHEN ((((new.type)::text = 'ExternalWikiService'::text) AND (old.active <> new.active) AND (new.project_id IS NOT NULL))) EXECUTE FUNCTION set_has_external_wiki(); CREATE TRIGGER trigger_has_external_wiki_on_update AFTER UPDATE ON integrations FOR EACH ROW WHEN ((((new.type)::text = 'ExternalWikiService'::text) AND (old.active <> new.active) AND (new.project_id IS NOT NULL))) EXECUTE FUNCTION set_has_external_wiki();
CREATE TRIGGER trigger_type_new_on_insert AFTER INSERT ON integrations FOR EACH ROW EXECUTE FUNCTION integrations_set_type_new();
ALTER TABLE ONLY chat_names ALTER TABLE ONLY chat_names
ADD CONSTRAINT fk_00797a2bf9 FOREIGN KEY (service_id) REFERENCES integrations(id) ON DELETE CASCADE; ADD CONSTRAINT fk_00797a2bf9 FOREIGN KEY (service_id) REFERENCES integrations(id) ON DELETE CASCADE;
...@@ -5,17 +5,18 @@ module EE ...@@ -5,17 +5,18 @@ module EE
module Integrations module Integrations
module StiType module StiType
extend ActiveSupport::Concern extend ActiveSupport::Concern
extend ::Gitlab::Utils::Override
EE_NAMESPACED_INTEGRATIONS = (::Gitlab::Integrations::StiType::NAMESPACED_INTEGRATIONS + %w( EE_NAMESPACED_INTEGRATIONS = (::Gitlab::Integrations::StiType::NAMESPACED_INTEGRATIONS + %w(
Github GitlabSlackApplication Github GitlabSlackApplication
)).freeze )).freeze
private class_methods do
extend ::Gitlab::Utils::Override
override :namespaced_integrations override :namespaced_integrations
def namespaced_integrations def namespaced_integrations
EE_NAMESPACED_INTEGRATIONS EE_NAMESPACED_INTEGRATIONS
end
end end
end end
end end
......
...@@ -10,6 +10,10 @@ module Gitlab ...@@ -10,6 +10,10 @@ module Gitlab
Prometheus Pushover Redmine Slack SlackSlashCommands Teamcity UnifyCircuit Youtrack WebexTeams Prometheus Pushover Redmine Slack SlackSlashCommands Teamcity UnifyCircuit Youtrack WebexTeams
)).freeze )).freeze
def self.namespaced_integrations
NAMESPACED_INTEGRATIONS
end
def cast(value) def cast(value)
new_cast(value) || super new_cast(value) || super
end end
...@@ -32,16 +36,12 @@ module Gitlab ...@@ -32,16 +36,12 @@ module Gitlab
private private
def namespaced_integrations
NAMESPACED_INTEGRATIONS
end
def new_cast(value) def new_cast(value)
value = prepare_value(value) value = prepare_value(value)
return unless value return unless value
stripped_name = value.delete_suffix('Service') stripped_name = value.delete_suffix('Service')
return unless namespaced_integrations.include?(stripped_name) return unless self.class.namespaced_integrations.include?(stripped_name)
"Integrations::#{stripped_name}" "Integrations::#{stripped_name}"
end end
......
# frozen_string_literal: true
require 'spec_helper'
require_migration!
RSpec.describe AddTriggersToIntegrationsTypeNew do
let(:migration) { described_class.new }
let(:integrations) { table(:integrations) }
describe '#up' do
before do
migrate!
end
describe 'INSERT trigger' do
it 'sets `type_new` to the transformed `type` class name' do
Gitlab::Integrations::StiType.namespaced_integrations.each do |type|
integration = integrations.create!(type: "#{type}Service")
expect(integration.reload).to have_attributes(
type: "#{type}Service",
type_new: "Integrations::#{type}"
)
end
end
it 'ignores types that are not namespaced' do
# We don't actually have any integrations without namespaces,
# but we can abuse one of the integration base classes.
integration = integrations.create!(type: 'BaseIssueTracker')
expect(integration.reload).to have_attributes(
type: 'BaseIssueTracker',
type_new: nil
)
end
it 'ignores types that are unknown' do
integration = integrations.create!(type: 'FooBar')
expect(integration.reload).to have_attributes(
type: 'FooBar',
type_new: nil
)
end
end
end
describe '#down' do
before do
migration.up
migration.down
end
it 'drops the INSERT trigger' do
integration = integrations.create!(type: 'JiraService')
expect(integration.reload).to have_attributes(
type: 'JiraService',
type_new: nil
)
end
end
end
...@@ -21,7 +21,7 @@ RSpec.describe BulkCreateIntegrationService do ...@@ -21,7 +21,7 @@ RSpec.describe BulkCreateIntegrationService do
described_class.new(integration, batch, association).execute described_class.new(integration, batch, association).execute
expect(created_integration.attributes.except(*excluded_attributes)) expect(created_integration.attributes.except(*excluded_attributes))
.to eq(integration.attributes.except(*excluded_attributes)) .to eq(integration.reload.attributes.except(*excluded_attributes))
end end
context 'integration with data fields' do context 'integration with data fields' do
......
...@@ -51,11 +51,11 @@ RSpec.describe BulkUpdateIntegrationService do ...@@ -51,11 +51,11 @@ RSpec.describe BulkUpdateIntegrationService do
context 'with inherited integration' do context 'with inherited integration' do
it 'updates the integration', :aggregate_failures do it 'updates the integration', :aggregate_failures do
described_class.new(subgroup_integration, batch).execute described_class.new(subgroup_integration.reload, batch).execute
expect(integration.reload.inherit_from_id).to eq(group_integration.id) expect(integration.reload.inherit_from_id).to eq(group_integration.id)
expect(integration.reload.attributes.except(*excluded_attributes)) expect(integration.reload.attributes.except(*excluded_attributes))
.to eq(subgroup_integration.attributes.except(*excluded_attributes)) .to eq(subgroup_integration.reload.attributes.except(*excluded_attributes))
expect(excluded_integration.reload.inherit_from_id).not_to eq(group_integration.id) expect(excluded_integration.reload.inherit_from_id).not_to eq(group_integration.id)
expect(excluded_integration.reload.attributes.except(*excluded_attributes)) expect(excluded_integration.reload.attributes.except(*excluded_attributes))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment