Add command to make sure v1.8 workspaces are not using FULL or PARTIAL sync stages (that should be already deprecated) (#15545)

In v1.8, we have already run a command to deprecate FULL or PARTIAL sync
stages.

However the code was fully deprecated in v1.10 and some workspaces might
still have this status used. This is to double check
This commit is contained in:
Charles Bochet
2025-11-03 12:36:46 +01:00
committed by GitHub
parent 0480ea048c
commit 50eb8c5558
4 changed files with 147 additions and 7 deletions
@@ -0,0 +1,134 @@
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
import { Command } from 'nest-commander';
import { DataSource, Repository } from 'typeorm';
import {
ActiveOrSuspendedWorkspacesMigrationCommandRunner,
type RunOnWorkspaceArgs,
} from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { getWorkspaceSchemaName } from 'src/engine/workspace-datasource/utils/get-workspace-schema-name.util';
@Command({
name: 'upgrade:1-10:migrate-channel-partial-full-sync-stages',
description:
'Migrate message and calendar channel partial and full sync stages',
})
export class MigrateChannelPartialFullSyncStagesCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner {
constructor(
@InjectRepository(WorkspaceEntity)
protected readonly workspaceRepository: Repository<WorkspaceEntity>,
protected readonly twentyORMGlobalManager: TwentyORMGlobalManager,
@InjectDataSource()
private readonly coreDataSource: DataSource,
) {
super(workspaceRepository, twentyORMGlobalManager);
}
override async runOnWorkspace({
workspaceId,
options,
}: RunOnWorkspaceArgs): Promise<void> {
this.logger.log(
`Migrating channel sync stages for workspace ${workspaceId}`,
);
const schemaName = getWorkspaceSchemaName(workspaceId);
await this.migrateMessageChannelSyncStages(
workspaceId,
schemaName,
options,
);
await this.migrateCalendarChannelSyncStages(
workspaceId,
schemaName,
options,
);
this.logger.log(
`Successfully migrated channel sync stages for workspace ${workspaceId}`,
);
}
private async migrateMessageChannelSyncStages(
workspaceId: string,
schemaName: string,
options: RunOnWorkspaceArgs['options'],
): Promise<void> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let messageChannelUpdateResult: any;
const tableName = 'messageChannel';
if (options.dryRun) {
this.logger.log(
`Would migrate deprecated messageChannel sync stages for workspace ${workspaceId}`,
);
return;
}
try {
messageChannelUpdateResult = await this.coreDataSource.query(
`UPDATE "${schemaName}"."${tableName}"
SET "syncStage" = 'MESSAGE_LIST_FETCH_PENDING'
WHERE "syncStage" IN ('FULL_MESSAGE_LIST_FETCH_PENDING', 'PARTIAL_MESSAGE_LIST_FETCH_PENDING')`,
);
} catch {
this.logger.log(
`Error (expected) while trying to migrate messageChannel sync stages for workspace ${workspaceId}, nothing to migrate`,
);
return;
}
const messageChannelRowsUpdated = messageChannelUpdateResult[1] || 0;
this.logger.log(
`Migrated ${messageChannelRowsUpdated} messageChannel records from deprecated sync stages in workspace ${workspaceId}`,
);
}
private async migrateCalendarChannelSyncStages(
workspaceId: string,
schemaName: string,
options: RunOnWorkspaceArgs['options'],
): Promise<void> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let calendarChannelUpdateResult: any;
const tableName = 'calendarChannel';
if (options.dryRun) {
this.logger.log(
`Would migrate deprecated calendarChannel sync stages for workspace ${workspaceId}`,
);
return;
}
try {
calendarChannelUpdateResult = await this.coreDataSource.query(
`UPDATE "${schemaName}"."${tableName}"
SET "syncStage" = 'CALENDAR_EVENT_LIST_FETCH_PENDING'
WHERE "syncStage" IN ('FULL_CALENDAR_EVENT_LIST_FETCH_PENDING', 'PARTIAL_CALENDAR_EVENT_LIST_FETCH_PENDING')`,
);
} catch {
this.logger.log(
`Error (expected) while trying to migrate calendarChannel sync stages for workspace ${workspaceId}, nothing to migrate`,
);
return;
}
const calendarChannelRowsUpdated = calendarChannelUpdateResult[1] || 0;
this.logger.log(
`Migrated ${calendarChannelRowsUpdated} calendarChannel records from deprecated sync stages in workspace ${workspaceId}`,
);
}
}
@@ -5,6 +5,7 @@ import { AddWorkflowRunStopStatusesCommand } from 'src/database/commands/upgrade
import { CleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-clean-orphaned-kanban-aggregate-operation-field-metadata-id.command';
import { MigrateAttachmentAuthorToCreatedByCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-attachment-author-to-created-by.command';
import { MigrateAttachmentTypeToFileCategoryCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-attachment-type-to-file-category.command';
import { MigrateChannelPartialFullSyncStagesCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-channel-partial-full-sync-stages.command';
import { RegenerateSearchVectorsCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-regenerate-search-vectors.command';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
@@ -25,6 +26,7 @@ import { WorkspaceSchemaManagerModule } from 'src/engine/twenty-orm/workspace-sc
WorkspaceSchemaManagerModule,
],
providers: [
MigrateChannelPartialFullSyncStagesCommand,
MigrateAttachmentAuthorToCreatedByCommand,
MigrateAttachmentTypeToFileCategoryCommand,
RegenerateSearchVectorsCommand,
@@ -37,6 +39,7 @@ import { WorkspaceSchemaManagerModule } from 'src/engine/twenty-orm/workspace-sc
RegenerateSearchVectorsCommand,
AddWorkflowRunStopStatusesCommand,
CleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand,
MigrateChannelPartialFullSyncStagesCommand,
],
})
export class V1_10_UpgradeVersionCommandModule {}
@@ -13,6 +13,7 @@ import { AddWorkflowRunStopStatusesCommand } from 'src/database/commands/upgrade
import { CleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-clean-orphaned-kanban-aggregate-operation-field-metadata-id.command';
import { MigrateAttachmentAuthorToCreatedByCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-attachment-author-to-created-by.command';
import { MigrateAttachmentTypeToFileCategoryCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-attachment-type-to-file-category.command';
import { MigrateChannelPartialFullSyncStagesCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-channel-partial-full-sync-stages.command';
import { RegenerateSearchVectorsCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-regenerate-search-vectors.command';
import { FixLabelIdentifierPositionAndVisibilityCommand } from 'src/database/commands/upgrade-version-command/1-6/1-6-fix-label-identifier-position-and-visibility.command';
import { BackfillWorkflowManualTriggerAvailabilityCommand } from 'src/database/commands/upgrade-version-command/1-7/1-7-backfill-workflow-manual-trigger-availability.command';
@@ -59,6 +60,7 @@ export class UpgradeCommand extends UpgradeCommandRunner {
protected readonly regenerateSearchVectorsCommand: RegenerateSearchVectorsCommand,
protected readonly addWorkflowRunStopStatusesCommand: AddWorkflowRunStopStatusesCommand,
protected readonly cleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand: CleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand,
protected readonly migrateChannelPartialFullSyncStagesCommand: MigrateChannelPartialFullSyncStagesCommand,
) {
super(
workspaceRepository,
@@ -95,6 +97,7 @@ export class UpgradeCommand extends UpgradeCommandRunner {
this.regenerateSearchVectorsCommand,
this.addWorkflowRunStopStatusesCommand,
this.cleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand,
this.migrateChannelPartialFullSyncStagesCommand,
],
afterSyncMetadata: [
this.migrateAttachmentAuthorToCreatedByCommand,