Commit fa43d2e1 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents f59fcd60 795b4598
......@@ -14,7 +14,7 @@ import IssuableAssignees from '~/sidebar/components/assignees/issuable_assignees
import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue';
import MultiSelectDropdown from '~/vue_shared/components/sidebar/multiselect_dropdown.vue';
import getIssueParticipants from '~/vue_shared/components/sidebar/queries/getIssueParticipants.query.graphql';
import searchUsers from '~/boards/queries/users_search.query.graphql';
import searchUsers from '~/boards/graphql/users_search.query.graphql';
export default {
noSearchDelay: 0,
......
......@@ -12,8 +12,8 @@ import {
import httpStatusCodes from '~/lib/utils/http_status';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import projectQuery from '../queries/project_boards.query.graphql';
import groupQuery from '../queries/group_boards.query.graphql';
import projectQuery from '../graphql/project_boards.query.graphql';
import groupQuery from '../graphql/group_boards.query.graphql';
import boardsStore from '../stores/boards_store';
import BoardForm from './board_form.vue';
......
......@@ -10,7 +10,7 @@ import {
} from '@gitlab/ui';
import { fetchPolicies } from '~/lib/graphql';
import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue';
import groupMilestones from '../../queries/group_milestones.query.graphql';
import groupMilestones from '../../graphql/group_milestones.query.graphql';
import createFlash from '~/flash';
import { __, s__ } from '~/locale';
......
#import "ee_else_ce/boards/queries/board_list.fragment.graphql"
#import "ee_else_ce/boards/graphql/board_list.fragment.graphql"
mutation CreateBoardList(
$boardId: BoardID!
......
#import "ee_else_ce/boards/queries/board_list.fragment.graphql"
#import "ee_else_ce/boards/graphql/board_list.fragment.graphql"
query ListIssues(
$fullPath: ID!
......
#import "ee_else_ce/boards/queries/board.fragment.graphql"
#import "ee_else_ce/boards/graphql/board.fragment.graphql"
query group_boards($fullPath: ID!) {
group(fullPath: $fullPath) {
......
#import "ee_else_ce/boards/queries/issue.fragment.graphql"
#import "ee_else_ce/boards/graphql/issue.fragment.graphql"
mutation CreateIssue($input: CreateIssueInput!) {
createIssue(input: $input) {
......
#import "ee_else_ce/boards/queries/issue.fragment.graphql"
#import "ee_else_ce/boards/graphql/issue.fragment.graphql"
mutation IssueMoveList(
$projectPath: ID!
......
#import "ee_else_ce/boards/queries/issue.fragment.graphql"
#import "ee_else_ce/boards/graphql/issue.fragment.graphql"
query ListIssues(
$fullPath: ID!
......
#import "ee_else_ce/boards/queries/board.fragment.graphql"
#import "ee_else_ce/boards/graphql/board.fragment.graphql"
query project_boards($fullPath: ID!) {
project(fullPath: $fullPath) {
......
import { pick } from 'lodash';
import boardListsQuery from 'ee_else_ce/boards/queries/board_lists.query.graphql';
import boardListsQuery from 'ee_else_ce/boards/graphql/board_lists.query.graphql';
import createGqClient, { fetchPolicies } from '~/lib/graphql';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { BoardType, ListType, inactiveId, DEFAULT_LABELS } from '~/boards/constants';
......@@ -14,18 +14,18 @@ import {
} from '../boards_util';
import boardStore from '~/boards/stores/boards_store';
import updateAssignees from '~/vue_shared/components/sidebar/queries/updateAssignees.mutation.graphql';
import listsIssuesQuery from '../queries/lists_issues.query.graphql';
import boardLabelsQuery from '../queries/board_labels.query.graphql';
import createBoardListMutation from '../queries/board_list_create.mutation.graphql';
import updateBoardListMutation from '../queries/board_list_update.mutation.graphql';
import issueMoveListMutation from '../queries/issue_move_list.mutation.graphql';
import destroyBoardListMutation from '../queries/board_list_destroy.mutation.graphql';
import issueCreateMutation from '../queries/issue_create.mutation.graphql';
import issueSetLabels from '../queries/issue_set_labels.mutation.graphql';
import issueSetDueDate from '../queries/issue_set_due_date.mutation.graphql';
import issueSetSubscriptionMutation from '../graphql/mutations/issue_set_subscription.mutation.graphql';
import issueSetMilestone from '../queries/issue_set_milestone.mutation.graphql';
import updateAssigneesMutation from '~/vue_shared/components/sidebar/queries/updateAssignees.mutation.graphql';
import listsIssuesQuery from '../graphql/lists_issues.query.graphql';
import boardLabelsQuery from '../graphql/board_labels.query.graphql';
import createBoardListMutation from '../graphql/board_list_create.mutation.graphql';
import updateBoardListMutation from '../graphql/board_list_update.mutation.graphql';
import issueMoveListMutation from '../graphql/issue_move_list.mutation.graphql';
import destroyBoardListMutation from '../graphql/board_list_destroy.mutation.graphql';
import issueCreateMutation from '../graphql/issue_create.mutation.graphql';
import issueSetLabelsMutation from '../graphql/issue_set_labels.mutation.graphql';
import issueSetDueDateMutation from '../graphql/issue_set_due_date.mutation.graphql';
import issueSetSubscriptionMutation from '../graphql/issue_set_subscription.mutation.graphql';
import issueSetMilestoneMutation from '../graphql/issue_set_milestone.mutation.graphql';
const notImplemented = () => {
/* eslint-disable-next-line @gitlab/require-i18n-strings */
......@@ -324,7 +324,7 @@ export default {
return gqlClient
.mutate({
mutation: updateAssignees,
mutation: updateAssigneesMutation,
variables: {
iid: getters.activeIssue.iid,
projectPath: getters.activeIssue.referencePath.split('#')[0],
......@@ -350,7 +350,7 @@ export default {
setActiveIssueMilestone: async ({ commit, getters }, input) => {
const { activeIssue } = getters;
const { data } = await gqlClient.mutate({
mutation: issueSetMilestone,
mutation: issueSetMilestoneMutation,
variables: {
input: {
iid: String(activeIssue.iid),
......@@ -416,7 +416,7 @@ export default {
setActiveIssueLabels: async ({ commit, getters }, input) => {
const { activeIssue } = getters;
const { data } = await gqlClient.mutate({
mutation: issueSetLabels,
mutation: issueSetLabelsMutation,
variables: {
input: {
iid: String(activeIssue.iid),
......@@ -441,7 +441,7 @@ export default {
setActiveIssueDueDate: async ({ commit, getters }, input) => {
const { activeIssue } = getters;
const { data } = await gqlClient.mutate({
mutation: issueSetDueDate,
mutation: issueSetDueDateMutation,
variables: {
input: {
iid: String(activeIssue.iid),
......
......@@ -22,7 +22,7 @@ import ListLabel from '../models/label';
import ListAssignee from '../models/assignee';
import ListMilestone from '../models/milestone';
import createBoardMutation from '../queries/board.mutation.graphql';
import createBoardMutation from '../graphql/board.mutation.graphql';
const PER_PAGE = 20;
export const gqlClient = createDefaultClient();
......
<script>
import $ from 'jquery';
import { camelCase, difference, union } from 'lodash';
import updateIssueLabelsMutation from '~/boards/queries/issue_set_labels.mutation.graphql';
import updateIssueLabelsMutation from '~/boards/graphql/issue_set_labels.mutation.graphql';
import createFlash from '~/flash';
import { IssuableType } from '~/issue_show/constants';
import { __ } from '~/locale';
......
......@@ -70,6 +70,7 @@ class Service < ApplicationRecord
scope :by_type, -> (type) { where(type: type) }
scope :by_active_flag, -> (flag) { where(active: flag) }
scope :inherit_from_id, -> (id) { where(inherit_from_id: id) }
scope :inherit, -> { where.not(inherit_from_id: nil) }
scope :for_group, -> (group) { where(group_id: group, type: available_services_types(include_project_specific: false)) }
scope :for_template, -> { where(template: true, type: available_services_types(include_project_specific: false)) }
scope :for_instance, -> { where(instance: true, type: available_services_types(include_project_specific: false)) }
......@@ -278,7 +279,7 @@ class Service < ApplicationRecord
active.where(instance: true),
active.where(group_id: group_ids, inherit_from_id: nil)
]).order(Arel.sql("type ASC, array_position(#{array}::bigint[], services.group_id), instance DESC")).group_by(&:type).each do |type, records|
build_from_integration(records.first, association => scope.id).save!
build_from_integration(records.first, association => scope.id).save
end
end
......
......@@ -28,9 +28,11 @@ module Groups
Group.transaction do
update_group_attributes
ensure_ownership
update_integrations
end
post_update_hooks(@updated_project_ids)
propagate_integrations
true
end
......@@ -196,6 +198,17 @@ module Groups
raise TransferError, result[:message] unless result[:status] == :success
end
end
def update_integrations
@group.services.inherit.delete_all
Service.create_from_active_default_integrations(@group, :group_id)
end
def propagate_integrations
@group.services.inherit.each do |integration|
PropagateIntegrationWorker.perform_async(integration.id)
end
end
end
end
......
......@@ -59,7 +59,7 @@ module Projects
raise TransferError.new(s_("TransferProject|Root namespace can't be updated if project has NPM packages"))
end
attempt_transfer_transaction
proceed_to_transfer
end
# rubocop: enable CodeReuse/ActiveRecord
......@@ -67,7 +67,7 @@ module Projects
new_namespace.root_ancestor == project.namespace.root_ancestor
end
def attempt_transfer_transaction
def proceed_to_transfer
Project.transaction do
project.expire_caches_before_rename(@old_path)
......@@ -87,6 +87,8 @@ module Projects
# Move uploads
move_project_uploads(project)
update_integrations
project.old_path_with_namespace = @old_path
update_repository_configuration(@new_path)
......@@ -214,6 +216,11 @@ module Projects
project.shared_runners_enabled = false
end
end
def update_integrations
project.services.inherit.delete_all
Service.create_from_active_default_integrations(project, :project_id)
end
end
end
......
---
title: Transfer a project/group to a new namespace inheriting integrations
merge_request: 48621
author:
type: changed
#import "~/boards/queries/board_list_shared.fragment.graphql"
#import "~/boards/graphql/board_list_shared.fragment.graphql"
fragment BoardListFragment on BoardList {
...BoardListShared
......
#import "ee_else_ce/boards/queries/board_list.fragment.graphql"
#import "ee_else_ce/boards/graphql/board_list.fragment.graphql"
query ListIssues(
$fullPath: ID!
......
#import "ee_else_ce/boards/queries/board_list.fragment.graphql"
#import "ee_else_ce/boards/graphql/board_list.fragment.graphql"
#import "./board_epic.fragment.graphql"
query BoardEE(
......
#import "ee_else_ce/boards/queries/issue.fragment.graphql"
#import "ee_else_ce/boards/graphql/issue.fragment.graphql"
mutation IssueMoveList(
$projectPath: ID!
......
#import "ee_else_ce/boards/queries/board_list.fragment.graphql"
#import "ee_else_ce/boards/graphql/board_list.fragment.graphql"
mutation boardListUpdateLimitMetrics($input: BoardListUpdateLimitMetricsInput!) {
boardListUpdateLimitMetrics(input: $input) {
......
......@@ -22,13 +22,13 @@ import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import eventHub from '~/boards/eventhub';
import createGqClient, { fetchPolicies } from '~/lib/graphql';
import epicsSwimlanesQuery from '../queries/epics_swimlanes.query.graphql';
import issueSetEpic from '../queries/issue_set_epic.mutation.graphql';
import issueSetWeight from '../queries/issue_set_weight.mutation.graphql';
import listsIssuesQuery from '~/boards/queries/lists_issues.query.graphql';
import issueMoveListMutation from '../queries/issue_move_list.mutation.graphql';
import listUpdateLimitMetrics from '../queries/list_update_limit_metrics.mutation.graphql';
import updateBoardEpicUserPreferencesMutation from '../queries/updateBoardEpicUserPreferences.mutation.graphql';
import epicsSwimlanesQuery from '../graphql/epics_swimlanes.query.graphql';
import issueSetEpicMutation from '../graphql/issue_set_epic.mutation.graphql';
import issueSetWeightMutation from '../graphql/issue_set_weight.mutation.graphql';
import listsIssuesQuery from '~/boards/graphql/lists_issues.query.graphql';
import issueMoveListMutation from '../graphql/issue_move_list.mutation.graphql';
import listUpdateLimitMetricsMutation from '../graphql/list_update_limit_metrics.mutation.graphql';
import updateBoardEpicUserPreferencesMutation from '../graphql/updateBoardEpicUserPreferences.mutation.graphql';
const notImplemented = () => {
/* eslint-disable-next-line @gitlab/require-i18n-strings */
......@@ -198,7 +198,7 @@ export default {
if (getters.shouldUseGraphQL) {
return gqlClient
.mutate({
mutation: listUpdateLimitMetrics,
mutation: listUpdateLimitMetricsMutation,
variables: {
input: {
listId,
......@@ -339,7 +339,7 @@ export default {
setActiveIssueEpic: async ({ getters }, input) => {
const { data } = await gqlClient.mutate({
mutation: issueSetEpic,
mutation: issueSetEpicMutation,
variables: {
input: {
iid: String(getters.activeIssue.iid),
......@@ -358,7 +358,7 @@ export default {
setActiveIssueWeight: async ({ commit, getters }, input) => {
const { data } = await gqlClient.mutate({
mutation: issueSetWeight,
mutation: issueSetWeightMutation,
variables: {
input: {
iid: String(getters.activeIssue.iid),
......
......@@ -5,7 +5,10 @@
# Utility module for A/B testing experimental features. Define your experiments in the `EXPERIMENTS` constant.
# Experiment options:
# - tracking_category (optional, used to set the category when tracking an experiment event)
# - use_backwards_compatible_subject_index (optional, set this to true if you need backwards compatibility)
# - use_backwards_compatible_subject_index (optional, set this to true if you need backwards compatibility -- you likely do not need this, see note in the next paragraph.)
#
# Using the backwards-compatible subject index (use_backwards_compatible_subject_index option):
# This option was added when [the calculation of experimentation_subject_index was changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45733/diffs#41af4a6fa5a10c7068559ce21c5188483751d934_157_173). It is not intended to be used by new experiments, it exists merely for the segmentation integrity of in-flight experiments at the time the change was deployed. That is, we want users who were assigned to the "experimental" group or the "control" group before the change to still be in those same groups after the change. See [the original issue](https://gitlab.com/gitlab-org/gitlab/-/issues/270858) and [this related comment](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/48110#note_458223745) for more information.
#
# The experiment is controlled by a Feature Flag (https://docs.gitlab.com/ee/development/feature_flags/controls.html),
# which is named "#{experiment_key}_experiment_percentage" and *must* be set with a percentage and not be used for other purposes.
......
......@@ -14,7 +14,7 @@ import MultiSelectDropdown from '~/vue_shared/components/sidebar/multiselect_dro
import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue';
import store from '~/boards/stores';
import getIssueParticipants from '~/vue_shared/components/sidebar/queries/getIssueParticipants.query.graphql';
import searchUsers from '~/boards/queries/users_search.query.graphql';
import searchUsers from '~/boards/graphql/users_search.query.graphql';
import { participants } from '../mock_data';
const localVue = createLocalVue();
......
......@@ -14,8 +14,8 @@ import {
import actions, { gqlClient } from '~/boards/stores/actions';
import * as types from '~/boards/stores/mutation_types';
import { inactiveId } from '~/boards/constants';
import issueMoveListMutation from '~/boards/queries/issue_move_list.mutation.graphql';
import destroyBoardListMutation from '~/boards/queries/board_list_destroy.mutation.graphql';
import issueMoveListMutation from '~/boards/graphql/issue_move_list.mutation.graphql';
import destroyBoardListMutation from '~/boards/graphql/board_list_destroy.mutation.graphql';
import updateAssignees from '~/vue_shared/components/sidebar/queries/updateAssignees.mutation.graphql';
import { fullBoardId, formatListIssues, formatBoardLists } from '~/boards/boards_util';
......
......@@ -3,7 +3,7 @@ import {
mockLabels,
mockRegularLabel,
} from 'jest/vue_shared/components/sidebar/labels_select_vue/mock_data';
import updateIssueLabelsMutation from '~/boards/queries/issue_set_labels.mutation.graphql';
import updateIssueLabelsMutation from '~/boards/graphql/issue_set_labels.mutation.graphql';
import { MutationOperationMode } from '~/graphql_shared/utils';
import { IssuableType } from '~/issue_show/constants';
import SidebarLabels from '~/sidebar/components/labels/sidebar_labels.vue';
......
......@@ -3,15 +3,15 @@
require 'spec_helper'
RSpec.describe Groups::TransferService do
let(:user) { create(:user) }
let(:new_parent_group) { create(:group, :public) }
let_it_be(:user) { create(:user) }
let_it_be(:new_parent_group) { create(:group, :public) }
let!(:group_member) { create(:group_member, :owner, group: group, user: user) }
let(:transfer_service) { described_class.new(group, user) }
context 'handling packages' do
let_it_be(:group) { create(:group, :public) }
let_it_be(:new_group) { create(:group, :public) }
let(:project) { create(:project, :public, namespace: group) }
let(:new_group) { create(:group, :public) }
before do
group.add_owner(user)
......@@ -35,8 +35,8 @@ RSpec.describe Groups::TransferService do
it_behaves_like 'transfer not allowed'
context 'with a project within subgroup' do
let(:root_group) { create(:group) }
let(:group) { create(:group, parent: root_group) }
let_it_be(:root_group) { create(:group) }
let_it_be(:group) { create(:group, parent: root_group) }
before do
root_group.add_owner(user)
......@@ -79,8 +79,6 @@ RSpec.describe Groups::TransferService do
shared_examples 'ensuring allowed transfer for a group' do
context "when there's an exception on GitLab shell directories" do
let(:new_parent_group) { create(:group, :public) }
before do
allow_next_instance_of(described_class) do |instance|
allow(instance).to receive(:update_group_attributes).and_raise(Gitlab::UpdatePathError, 'namespace directory cannot be moved')
......@@ -101,7 +99,7 @@ RSpec.describe Groups::TransferService do
describe '#execute' do
context 'when transforming a group into a root group' do
let!(:group) { create(:group, :public, :nested) }
let_it_be_with_reload(:group) { create(:group, :public, :nested) }
it_behaves_like 'ensuring allowed transfer for a group'
......@@ -115,7 +113,7 @@ RSpec.describe Groups::TransferService do
end
context 'when the user does not have the right policies' do
let!(:group_member) { create(:group_member, :guest, group: group, user: user) }
let_it_be(:group_member) { create(:group_member, :guest, group: group, user: user) }
it "returns false" do
expect(transfer_service.execute(nil)).to be_falsy
......@@ -128,7 +126,7 @@ RSpec.describe Groups::TransferService do
end
context 'when there is a group with the same path' do
let!(:group) { create(:group, :public, :nested, path: 'not-unique') }
let_it_be(:group) { create(:group, :public, :nested, path: 'not-unique') }
before do
create(:group, path: 'not-unique')
......@@ -145,9 +143,9 @@ RSpec.describe Groups::TransferService do
end
context 'when the group is a subgroup and the transfer is valid' do
let!(:subgroup1) { create(:group, :private, parent: group) }
let!(:subgroup2) { create(:group, :internal, parent: group) }
let!(:project1) { create(:project, :repository, :private, namespace: group) }
let_it_be(:subgroup1) { create(:group, :private, parent: group) }
let_it_be(:subgroup2) { create(:group, :internal, parent: group) }
let_it_be(:project1) { create(:project, :repository, :private, namespace: group) }
before do
transfer_service.execute(nil)
......@@ -173,12 +171,12 @@ RSpec.describe Groups::TransferService do
end
context 'when transferring a subgroup into another group' do
let(:group) { create(:group, :public, :nested) }
let_it_be_with_reload(:group) { create(:group, :public, :nested) }
it_behaves_like 'ensuring allowed transfer for a group'
context 'when the new parent group is the same as the previous parent group' do
let(:group) { create(:group, :public, :nested, parent: new_parent_group) }
let_it_be(:group) { create(:group, :public, :nested, parent: new_parent_group) }
it 'returns false' do
expect(transfer_service.execute(new_parent_group)).to be_falsy
......@@ -191,7 +189,7 @@ RSpec.describe Groups::TransferService do
end
context 'when the user does not have the right policies' do
let!(:group_member) { create(:group_member, :guest, group: group, user: user) }
let_it_be(:group_member) { create(:group_member, :guest, group: group, user: user) }
it "returns false" do
expect(transfer_service.execute(new_parent_group)).to be_falsy
......@@ -221,7 +219,7 @@ RSpec.describe Groups::TransferService do
end
context 'when the parent group has a project with the same path' do
let!(:group) { create(:group, :public, :nested, path: 'foo') }
let_it_be_with_reload(:group) { create(:group, :public, :nested, path: 'foo') }
before do
create(:group_member, :owner, group: new_parent_group, user: user)
......@@ -240,8 +238,13 @@ RSpec.describe Groups::TransferService do
end
context 'when the group is allowed to be transferred' do
let_it_be(:new_parent_group_integration) { create(:slack_service, group: new_parent_group, project: nil, webhook: 'http://new-group.slack.com') }
before do
allow(PropagateIntegrationWorker).to receive(:perform_async)
create(:group_member, :owner, group: new_parent_group, user: user)
transfer_service.execute(new_parent_group)
end
......@@ -267,6 +270,30 @@ RSpec.describe Groups::TransferService do
end
end
context 'with a group integration' do
let_it_be(:instance_integration) { create(:slack_service, :instance, webhook: 'http://project.slack.com') }
let(:new_created_integration) { Service.find_by(group: group) }
context 'with an inherited integration' do
let_it_be(:group_integration) { create(:slack_service, group: group, project: nil, webhook: 'http://group.slack.com', inherit_from_id: instance_integration.id) }
it 'replaces inherited integrations', :aggregate_failures do
expect(new_created_integration.webhook).to eq(new_parent_group_integration.webhook)
expect(PropagateIntegrationWorker).to have_received(:perform_async).with(new_created_integration.id)
expect(Service.count).to eq(3)
end
end
context 'with a custom integration' do
let_it_be(:group_integration) { create(:slack_service, group: group, project: nil, webhook: 'http://group.slack.com') }
it 'does not updates the integrations', :aggregate_failures do
expect { transfer_service.execute(new_parent_group) }.not_to change { group_integration.webhook }
expect(PropagateIntegrationWorker).not_to have_received(:perform_async)
end
end
end
it 'updates visibility for the group based on the parent group' do
expect(group.visibility_level).to eq(new_parent_group.visibility_level)
end
......@@ -464,7 +491,7 @@ RSpec.describe Groups::TransferService do
end
context 'updated paths' do
let(:group) { create(:group, :public) }
let_it_be_with_reload(:group) { create(:group, :public) }
before do
transfer_service.execute(new_parent_group)
......@@ -500,10 +527,10 @@ RSpec.describe Groups::TransferService do
end
context 'resets project authorizations' do
let(:old_parent_group) { create(:group) }
let(:group) { create(:group, :private, parent: old_parent_group) }
let(:new_group_member) { create(:user) }
let(:old_group_member) { create(:user) }
let_it_be(:old_parent_group) { create(:group) }
let_it_be_with_reload(:group) { create(:group, :private, parent: old_parent_group) }
let_it_be(:new_group_member) { create(:user) }
let_it_be(:old_group_member) { create(:user) }
before do
new_parent_group.add_maintainer(new_group_member)
......
......@@ -7,6 +7,7 @@ RSpec.describe Projects::TransferService do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:group_integration) { create(:slack_service, group: group, project: nil, webhook: 'http://group.slack.com') }
let(:project) { create(:project, :repository, :legacy_storage, namespace: user.namespace) }
subject(:execute_transfer) { described_class.new(project, user).execute(group).tap { project.reload } }
......@@ -117,6 +118,30 @@ RSpec.describe Projects::TransferService do
shard_name: project.repository_storage
)
end
context 'with a project integration' do
let_it_be_with_reload(:project) { create(:project, namespace: user.namespace) }
let_it_be(:instance_integration) { create(:slack_service, :instance, webhook: 'http://project.slack.com') }
context 'with an inherited integration' do
let_it_be(:project_integration) { create(:slack_service, project: project, webhook: 'http://project.slack.com', inherit_from_id: instance_integration.id) }
it 'replaces inherited integrations', :aggregate_failures do
execute_transfer
expect(project.slack_service.webhook).to eq(group_integration.webhook)
expect(Service.count).to eq(3)
end
end
context 'with a custom integration' do
let_it_be(:project_integration) { create(:slack_service, project: project, webhook: 'http://project.slack.com') }
it 'does not updates the integrations' do
expect { execute_transfer }.not_to change { project.slack_service.webhook }
end
end
end
end
context 'when transfer fails' do
......@@ -527,7 +552,7 @@ RSpec.describe Projects::TransferService do
group.add_owner(user)
end
it 'schedules a job when pages are deployed' do
it 'schedules a job when pages are deployed' do
project.mark_pages_as_deployed
expect(PagesTransferWorker).to receive(:perform_async)
......
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