Workspace seeders with version (#10895)
# Introduction close https://github.com/twentyhq/core-team-issues/issues/487 Updated the seeders to infer the workspace's version from the `APP_VERSION` env var To test in local run: `npx nx database:reset twenty-server` with either a defined or not defined `APP_VERSION` in your `.env` ( note that invalid semver values will throw an error and stop the process ) ( valid version ex: `APP_VERSION=1.0.0`)
This commit is contained in:
@ -3,14 +3,13 @@ import { InjectRepository } from '@nestjs/typeorm';
|
|||||||
|
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
|
|
||||||
import {
|
import { seedCoreSchema } from 'src/database/typeorm-seeds/core';
|
||||||
deleteCoreSchema,
|
import { deleteCoreSchema } from 'src/database/typeorm-seeds/core/demo';
|
||||||
seedCoreSchema,
|
|
||||||
} from 'src/database/typeorm-seeds/core/demo';
|
|
||||||
import { rawDataSource } from 'src/database/typeorm/raw/raw.datasource';
|
import { rawDataSource } from 'src/database/typeorm/raw/raw.datasource';
|
||||||
import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator';
|
import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator';
|
||||||
import { CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service';
|
import { CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service';
|
||||||
import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum';
|
import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum';
|
||||||
|
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||||
import { WorkspaceManagerService } from 'src/engine/workspace-manager/workspace-manager.service';
|
import { WorkspaceManagerService } from 'src/engine/workspace-manager/workspace-manager.service';
|
||||||
|
|
||||||
@ -22,6 +21,7 @@ export class DataSeedDemoWorkspaceService {
|
|||||||
protected readonly workspaceRepository: Repository<Workspace>,
|
protected readonly workspaceRepository: Repository<Workspace>,
|
||||||
@InjectCacheStorage(CacheStorageNamespace.EngineWorkspace)
|
@InjectCacheStorage(CacheStorageNamespace.EngineWorkspace)
|
||||||
private readonly workspaceSchemaCache: CacheStorageService,
|
private readonly workspaceSchemaCache: CacheStorageService,
|
||||||
|
private readonly environmentService: EnvironmentService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async seedDemo(): Promise<void> {
|
async seedDemo(): Promise<void> {
|
||||||
@ -43,7 +43,15 @@ export class DataSeedDemoWorkspaceService {
|
|||||||
await deleteCoreSchema(rawDataSource, workspaceId);
|
await deleteCoreSchema(rawDataSource, workspaceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
await seedCoreSchema(rawDataSource, workspaceId);
|
const appVersion = this.environmentService.get('APP_VERSION');
|
||||||
|
|
||||||
|
await seedCoreSchema({
|
||||||
|
workspaceDataSource: rawDataSource,
|
||||||
|
workspaceId,
|
||||||
|
appVersion,
|
||||||
|
seedBilling: false,
|
||||||
|
seedFeatureFlags: false,
|
||||||
|
});
|
||||||
await this.workspaceManagerService.initDemo(workspaceId);
|
await this.workspaceManagerService.initDemo(workspaceId);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -95,8 +95,14 @@ export class DataSeedWorkspaceCommand extends CommandRunner {
|
|||||||
await rawDataSource.initialize();
|
await rawDataSource.initialize();
|
||||||
|
|
||||||
const isBillingEnabled = this.environmentService.get('IS_BILLING_ENABLED');
|
const isBillingEnabled = this.environmentService.get('IS_BILLING_ENABLED');
|
||||||
|
const appVersion = this.environmentService.get('APP_VERSION');
|
||||||
|
|
||||||
await seedCoreSchema(rawDataSource, workspaceId, isBillingEnabled);
|
await seedCoreSchema({
|
||||||
|
workspaceDataSource: rawDataSource,
|
||||||
|
workspaceId,
|
||||||
|
seedBilling: isBillingEnabled,
|
||||||
|
appVersion,
|
||||||
|
});
|
||||||
|
|
||||||
await rawDataSource.destroy();
|
await rawDataSource.destroy();
|
||||||
|
|
||||||
|
|||||||
@ -1,29 +1,9 @@
|
|||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
|
||||||
import {
|
|
||||||
seedUsers,
|
|
||||||
deleteUsersByWorkspace,
|
|
||||||
} from 'src/database/typeorm-seeds/core/demo/users';
|
|
||||||
import {
|
|
||||||
seedWorkspaces,
|
|
||||||
deleteWorkspaces,
|
|
||||||
} from 'src/database/typeorm-seeds/core/demo/workspaces';
|
|
||||||
import { deleteFeatureFlags } from 'src/database/typeorm-seeds/core/demo/feature-flags';
|
import { deleteFeatureFlags } from 'src/database/typeorm-seeds/core/demo/feature-flags';
|
||||||
import {
|
import { deleteUserWorkspaces } from 'src/database/typeorm-seeds/core/demo/user-workspaces';
|
||||||
deleteUserWorkspaces,
|
import { deleteUsersByWorkspace } from 'src/database/typeorm-seeds/core/demo/users';
|
||||||
seedUserWorkspaces,
|
import { deleteWorkspaces } from 'src/database/typeorm-seeds/core/demo/workspaces';
|
||||||
} from 'src/database/typeorm-seeds/core/demo/user-workspaces';
|
|
||||||
|
|
||||||
export const seedCoreSchema = async (
|
|
||||||
workspaceDataSource: DataSource,
|
|
||||||
workspaceId: string,
|
|
||||||
) => {
|
|
||||||
const schemaName = 'core';
|
|
||||||
|
|
||||||
await seedWorkspaces(workspaceDataSource, schemaName, workspaceId);
|
|
||||||
await seedUsers(workspaceDataSource, schemaName);
|
|
||||||
await seedUserWorkspaces(workspaceDataSource, schemaName, workspaceId);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deleteCoreSchema = async (
|
export const deleteCoreSchema = async (
|
||||||
workspaceDataSource: DataSource,
|
workspaceDataSource: DataSource,
|
||||||
|
|||||||
@ -6,19 +6,37 @@ import { seedUserWorkspaces } from 'src/database/typeorm-seeds/core/user-workspa
|
|||||||
import { seedUsers } from 'src/database/typeorm-seeds/core/users';
|
import { seedUsers } from 'src/database/typeorm-seeds/core/users';
|
||||||
import { seedWorkspaces } from 'src/database/typeorm-seeds/core/workspaces';
|
import { seedWorkspaces } from 'src/database/typeorm-seeds/core/workspaces';
|
||||||
|
|
||||||
export const seedCoreSchema = async (
|
type SeedCoreSchemaArgs = {
|
||||||
workspaceDataSource: DataSource,
|
workspaceDataSource: DataSource;
|
||||||
workspaceId: string,
|
workspaceId: string;
|
||||||
isBillingEnabled: boolean,
|
appVersion: string | undefined;
|
||||||
) => {
|
seedBilling?: boolean;
|
||||||
|
seedFeatureFlags?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const seedCoreSchema = async ({
|
||||||
|
appVersion,
|
||||||
|
workspaceDataSource,
|
||||||
|
workspaceId,
|
||||||
|
seedBilling = true,
|
||||||
|
seedFeatureFlags: shouldSeedFeatureFlags = true,
|
||||||
|
}: SeedCoreSchemaArgs) => {
|
||||||
const schemaName = 'core';
|
const schemaName = 'core';
|
||||||
|
|
||||||
await seedWorkspaces(workspaceDataSource, schemaName, workspaceId);
|
await seedWorkspaces({
|
||||||
|
workspaceDataSource,
|
||||||
|
schemaName,
|
||||||
|
workspaceId,
|
||||||
|
appVersion,
|
||||||
|
});
|
||||||
await seedUsers(workspaceDataSource, schemaName);
|
await seedUsers(workspaceDataSource, schemaName);
|
||||||
await seedUserWorkspaces(workspaceDataSource, schemaName, workspaceId);
|
await seedUserWorkspaces(workspaceDataSource, schemaName, workspaceId);
|
||||||
await seedFeatureFlags(workspaceDataSource, schemaName, workspaceId);
|
|
||||||
|
|
||||||
if (isBillingEnabled) {
|
if (shouldSeedFeatureFlags) {
|
||||||
|
await seedFeatureFlags(workspaceDataSource, schemaName, workspaceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seedBilling) {
|
||||||
await seedBillingSubscriptions(
|
await seedBillingSubscriptions(
|
||||||
workspaceDataSource,
|
workspaceDataSource,
|
||||||
schemaName,
|
schemaName,
|
||||||
|
|||||||
@ -2,57 +2,68 @@ import { WorkspaceActivationStatus } from 'twenty-shared';
|
|||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||||
|
import { extractVersionMajorMinorPatch } from 'src/utils/version/extract-version-major-minor-patch';
|
||||||
|
|
||||||
const tableName = 'workspace';
|
const tableName = 'workspace';
|
||||||
|
|
||||||
export const SEED_APPLE_WORKSPACE_ID = '20202020-1c25-4d02-bf25-6aeccf7ea419';
|
export const SEED_APPLE_WORKSPACE_ID = '20202020-1c25-4d02-bf25-6aeccf7ea419';
|
||||||
export const SEED_ACME_WORKSPACE_ID = '3b8e6458-5fc1-4e63-8563-008ccddaa6db';
|
export const SEED_ACME_WORKSPACE_ID = '3b8e6458-5fc1-4e63-8563-008ccddaa6db';
|
||||||
|
|
||||||
export const seedWorkspaces = async (
|
export type SeedWorkspaceArgs = {
|
||||||
workspaceDataSource: DataSource,
|
workspaceDataSource: DataSource;
|
||||||
schemaName: string,
|
schemaName: string;
|
||||||
workspaceId: string,
|
workspaceId: string;
|
||||||
) => {
|
appVersion: string | undefined;
|
||||||
const workspaces: {
|
};
|
||||||
[key: string]: Pick<
|
|
||||||
Workspace,
|
const workspaceSeederFields = [
|
||||||
| 'id'
|
'id',
|
||||||
| 'displayName'
|
'displayName',
|
||||||
| 'inviteHash'
|
'subdomain',
|
||||||
| 'logo'
|
'inviteHash',
|
||||||
| 'subdomain'
|
'logo',
|
||||||
| 'activationStatus'
|
'activationStatus',
|
||||||
>;
|
'version',
|
||||||
} = {
|
] as const satisfies (keyof Workspace)[];
|
||||||
|
|
||||||
|
type WorkspaceSeederFields = Pick<
|
||||||
|
Workspace,
|
||||||
|
(typeof workspaceSeederFields)[number]
|
||||||
|
>;
|
||||||
|
|
||||||
|
export const seedWorkspaces = async ({
|
||||||
|
schemaName,
|
||||||
|
workspaceDataSource,
|
||||||
|
workspaceId,
|
||||||
|
appVersion,
|
||||||
|
}: SeedWorkspaceArgs) => {
|
||||||
|
const version = extractVersionMajorMinorPatch(appVersion);
|
||||||
|
|
||||||
|
const workspaces: Record<string, WorkspaceSeederFields> = {
|
||||||
[SEED_APPLE_WORKSPACE_ID]: {
|
[SEED_APPLE_WORKSPACE_ID]: {
|
||||||
id: workspaceId,
|
id: SEED_APPLE_WORKSPACE_ID,
|
||||||
displayName: 'Apple',
|
displayName: 'Apple',
|
||||||
subdomain: 'apple',
|
subdomain: 'apple',
|
||||||
inviteHash: 'apple.dev-invite-hash',
|
inviteHash: 'apple.dev-invite-hash',
|
||||||
logo: 'https://twentyhq.github.io/placeholder-images/workspaces/apple-logo.png',
|
logo: 'https://twentyhq.github.io/placeholder-images/workspaces/apple-logo.png',
|
||||||
activationStatus: WorkspaceActivationStatus.ACTIVE,
|
activationStatus: WorkspaceActivationStatus.ACTIVE,
|
||||||
|
version: version,
|
||||||
},
|
},
|
||||||
[SEED_ACME_WORKSPACE_ID]: {
|
[SEED_ACME_WORKSPACE_ID]: {
|
||||||
id: workspaceId,
|
id: SEED_ACME_WORKSPACE_ID,
|
||||||
displayName: 'Acme',
|
displayName: 'Acme',
|
||||||
subdomain: 'acme',
|
subdomain: 'acme',
|
||||||
inviteHash: 'acme.dev-invite-hash',
|
inviteHash: 'acme.dev-invite-hash',
|
||||||
logo: 'https://logos-world.net/wp-content/uploads/2022/05/Acme-Logo-700x394.png',
|
logo: 'https://logos-world.net/wp-content/uploads/2022/05/Acme-Logo-700x394.png',
|
||||||
activationStatus: WorkspaceActivationStatus.ACTIVE,
|
activationStatus: WorkspaceActivationStatus.ACTIVE,
|
||||||
|
version: version,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
await workspaceDataSource
|
await workspaceDataSource
|
||||||
.createQueryBuilder()
|
.createQueryBuilder()
|
||||||
.insert()
|
.insert()
|
||||||
.into(`${schemaName}.${tableName}`, [
|
.into(`${schemaName}.${tableName}`, workspaceSeederFields)
|
||||||
'id',
|
|
||||||
'displayName',
|
|
||||||
'subdomain',
|
|
||||||
'inviteHash',
|
|
||||||
'logo',
|
|
||||||
'activationStatus',
|
|
||||||
])
|
|
||||||
.orIgnore()
|
.orIgnore()
|
||||||
.values(workspaces[workspaceId])
|
.values(workspaces[workspaceId])
|
||||||
.execute();
|
.execute();
|
||||||
|
|||||||
Reference in New Issue
Block a user