mirror of
https://github.com/twentyhq/twenty.git
synced 2024-11-26 04:17:15 +03:00
feat: sync all workspaces (#4353)
This commit is contained in:
parent
eabece6918
commit
c3a024b047
@ -9,6 +9,16 @@ import { kebabCase } from 'src/utils/kebab-case';
|
||||
export class CommandLogger {
|
||||
constructor(private readonly className: string) {}
|
||||
|
||||
async createSubDirectory(subDirectory: string): Promise<void> {
|
||||
const path = `./logs/${kebabCase(this.className)}/${subDirectory}`;
|
||||
|
||||
if (existsSync(path) === false) {
|
||||
await fs.mkdir(path, { recursive: true });
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
async writeLog(
|
||||
fileName: string,
|
||||
data: unknown,
|
||||
|
@ -64,4 +64,10 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> {
|
||||
|
||||
return workspace;
|
||||
}
|
||||
|
||||
async getWorkspaceIds() {
|
||||
return this.workspaceRepository
|
||||
.find()
|
||||
.then((workspaces) => workspaces.map((workspace) => workspace.id));
|
||||
}
|
||||
}
|
||||
|
@ -13,66 +13,70 @@ export class SyncWorkspaceLoggerService {
|
||||
constructor() {}
|
||||
|
||||
async saveLogs(
|
||||
workspaceId: string,
|
||||
storage: WorkspaceSyncStorage,
|
||||
workspaceMigrations: WorkspaceMigrationEntity[],
|
||||
) {
|
||||
// Create sub directory
|
||||
await this.commandLogger.createSubDirectory(workspaceId);
|
||||
|
||||
// Save workspace migrations
|
||||
await this.commandLogger.writeLog(
|
||||
'workspace-migrations',
|
||||
`${workspaceId}/workspace-migrations`,
|
||||
workspaceMigrations,
|
||||
);
|
||||
|
||||
// Save object metadata create collection
|
||||
await this.commandLogger.writeLog(
|
||||
'object-metadata-create-collection',
|
||||
`${workspaceId}/object-metadata-create-collection`,
|
||||
storage.objectMetadataCreateCollection,
|
||||
);
|
||||
|
||||
// Save object metadata update collection
|
||||
await this.commandLogger.writeLog(
|
||||
'object-metadata-update-collection',
|
||||
`${workspaceId}/object-metadata-update-collection`,
|
||||
storage.objectMetadataUpdateCollection,
|
||||
);
|
||||
|
||||
// Save object metadata delete collection
|
||||
await this.commandLogger.writeLog(
|
||||
'object-metadata-delete-collection',
|
||||
`${workspaceId}/object-metadata-delete-collection`,
|
||||
storage.objectMetadataDeleteCollection,
|
||||
);
|
||||
|
||||
// Save field metadata create collection
|
||||
await this.commandLogger.writeLog(
|
||||
'field-metadata-create-collection',
|
||||
`${workspaceId}/field-metadata-create-collection`,
|
||||
storage.fieldMetadataCreateCollection,
|
||||
);
|
||||
|
||||
// Save field metadata update collection
|
||||
await this.commandLogger.writeLog(
|
||||
'field-metadata-update-collection',
|
||||
`${workspaceId}/field-metadata-update-collection`,
|
||||
storage.fieldMetadataUpdateCollection,
|
||||
);
|
||||
|
||||
// Save field metadata delete collection
|
||||
await this.commandLogger.writeLog(
|
||||
'field-metadata-delete-collection',
|
||||
`${workspaceId}/field-metadata-delete-collection`,
|
||||
storage.fieldMetadataDeleteCollection,
|
||||
);
|
||||
|
||||
// Save relation metadata create collection
|
||||
await this.commandLogger.writeLog(
|
||||
'relation-metadata-create-collection',
|
||||
`${workspaceId}/relation-metadata-create-collection`,
|
||||
storage.relationMetadataCreateCollection,
|
||||
);
|
||||
|
||||
// Save relation metadata update collection
|
||||
await this.commandLogger.writeLog(
|
||||
'relation-metadata-update-collection',
|
||||
`${workspaceId}/relation-metadata-update-collection`,
|
||||
storage.relationMetadataUpdateCollection,
|
||||
);
|
||||
|
||||
// Save relation metadata delete collection
|
||||
await this.commandLogger.writeLog(
|
||||
'relation-metadata-delete-collection',
|
||||
`${workspaceId}/relation-metadata-delete-collection`,
|
||||
storage.relationMetadataDeleteCollection,
|
||||
);
|
||||
}
|
||||
|
@ -5,12 +5,13 @@ import { Command, CommandRunner, Option } from 'nest-commander';
|
||||
import { DataSourceService } from 'src/metadata/data-source/data-source.service';
|
||||
import { WorkspaceSyncMetadataService } from 'src/workspace/workspace-sync-metadata/workspace-sync-metadata.service';
|
||||
import { WorkspaceHealthService } from 'src/workspace/workspace-health/workspace-health.service';
|
||||
import { WorkspaceService } from 'src/core/workspace/services/workspace.service';
|
||||
|
||||
import { SyncWorkspaceLoggerService } from './services/sync-workspace-logger.service';
|
||||
|
||||
// TODO: implement dry-run
|
||||
interface RunWorkspaceMigrationsOptions {
|
||||
workspaceId: string;
|
||||
workspaceId?: string;
|
||||
dryRun?: boolean;
|
||||
force?: boolean;
|
||||
}
|
||||
@ -27,6 +28,7 @@ export class SyncWorkspaceMetadataCommand extends CommandRunner {
|
||||
private readonly workspaceHealthService: WorkspaceHealthService,
|
||||
private readonly dataSourceService: DataSourceService,
|
||||
private readonly syncWorkspaceLoggerService: SyncWorkspaceLoggerService,
|
||||
private readonly workspaceService: WorkspaceService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@ -35,56 +37,63 @@ export class SyncWorkspaceMetadataCommand extends CommandRunner {
|
||||
_passedParam: string[],
|
||||
options: RunWorkspaceMigrationsOptions,
|
||||
): Promise<void> {
|
||||
const issues = await this.workspaceHealthService.healthCheck(
|
||||
options.workspaceId,
|
||||
);
|
||||
const workspaceIds = options.workspaceId
|
||||
? [options.workspaceId]
|
||||
: await this.workspaceService.getWorkspaceIds();
|
||||
|
||||
// Security: abort if there are issues.
|
||||
if (issues.length > 0) {
|
||||
if (!options.force) {
|
||||
this.logger.error(
|
||||
`Workspace contains ${issues.length} issues, aborting.`,
|
||||
for (const workspaceId of workspaceIds) {
|
||||
const issues = await this.workspaceHealthService.healthCheck(workspaceId);
|
||||
|
||||
// Security: abort if there are issues.
|
||||
if (issues.length > 0) {
|
||||
if (!options.force) {
|
||||
this.logger.error(
|
||||
`Workspace contains ${issues.length} issues, aborting.`,
|
||||
);
|
||||
|
||||
this.logger.log(
|
||||
'If you want to force the migration, use --force flag',
|
||||
);
|
||||
this.logger.log(
|
||||
'Please use `workspace:health` command to check issues and fix them before running this command.',
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.warn(
|
||||
`Workspace contains ${issues.length} issues, sync has been forced.`,
|
||||
);
|
||||
|
||||
this.logger.log('If you want to force the migration, use --force flag');
|
||||
this.logger.log(
|
||||
'Please use `workspace:health` command to check issues and fix them before running this command.',
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.warn(
|
||||
`Workspace contains ${issues.length} issues, sync has been forced.`,
|
||||
);
|
||||
}
|
||||
const dataSourceMetadata =
|
||||
await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail(
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
const dataSourceMetadata =
|
||||
await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail(
|
||||
options.workspaceId,
|
||||
);
|
||||
const { storage, workspaceMigrations } =
|
||||
await this.workspaceSyncMetadataService.syncStandardObjectsAndFieldsMetadata(
|
||||
{
|
||||
workspaceId,
|
||||
dataSourceId: dataSourceMetadata.id,
|
||||
},
|
||||
{ applyChanges: !options.dryRun },
|
||||
);
|
||||
|
||||
const { storage, workspaceMigrations } =
|
||||
await this.workspaceSyncMetadataService.syncStandardObjectsAndFieldsMetadata(
|
||||
{
|
||||
workspaceId: options.workspaceId,
|
||||
dataSourceId: dataSourceMetadata.id,
|
||||
},
|
||||
{ applyChanges: !options.dryRun },
|
||||
);
|
||||
|
||||
if (options.dryRun) {
|
||||
await this.syncWorkspaceLoggerService.saveLogs(
|
||||
storage,
|
||||
workspaceMigrations,
|
||||
);
|
||||
if (options.dryRun) {
|
||||
await this.syncWorkspaceLoggerService.saveLogs(
|
||||
workspaceId,
|
||||
storage,
|
||||
workspaceMigrations,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Option({
|
||||
flags: '-w, --workspace-id [workspace_id]',
|
||||
description: 'workspace id',
|
||||
required: true,
|
||||
required: false,
|
||||
})
|
||||
parseWorkspaceId(value: string): string {
|
||||
return value;
|
||||
|
@ -3,6 +3,7 @@ import { Module } from '@nestjs/common';
|
||||
import { DataSourceModule } from 'src/metadata/data-source/data-source.module';
|
||||
import { WorkspaceSyncMetadataModule } from 'src/workspace/workspace-sync-metadata/workspace-sync-metadata.module';
|
||||
import { WorkspaceHealthModule } from 'src/workspace/workspace-health/workspace-health.module';
|
||||
import { WorkspaceModule } from 'src/core/workspace/workspace.module';
|
||||
|
||||
import { SyncWorkspaceMetadataCommand } from './sync-workspace-metadata.command';
|
||||
|
||||
@ -12,6 +13,7 @@ import { SyncWorkspaceLoggerService } from './services/sync-workspace-logger.ser
|
||||
imports: [
|
||||
WorkspaceSyncMetadataModule,
|
||||
WorkspaceHealthModule,
|
||||
WorkspaceModule,
|
||||
DataSourceModule,
|
||||
],
|
||||
providers: [SyncWorkspaceMetadataCommand, SyncWorkspaceLoggerService],
|
||||
|
Loading…
Reference in New Issue
Block a user