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:
Paul Rastoin
2025-03-17 15:32:49 +01:00
committed by GitHub
parent 3e3e8de400
commit 8b5d5b35ad
5 changed files with 86 additions and 63 deletions

View File

@ -3,14 +3,13 @@ import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import {
deleteCoreSchema,
seedCoreSchema,
} from 'src/database/typeorm-seeds/core/demo';
import { seedCoreSchema } from 'src/database/typeorm-seeds/core';
import { deleteCoreSchema } from 'src/database/typeorm-seeds/core/demo';
import { rawDataSource } from 'src/database/typeorm/raw/raw.datasource';
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 { 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 { WorkspaceManagerService } from 'src/engine/workspace-manager/workspace-manager.service';
@ -22,6 +21,7 @@ export class DataSeedDemoWorkspaceService {
protected readonly workspaceRepository: Repository<Workspace>,
@InjectCacheStorage(CacheStorageNamespace.EngineWorkspace)
private readonly workspaceSchemaCache: CacheStorageService,
private readonly environmentService: EnvironmentService,
) {}
async seedDemo(): Promise<void> {
@ -43,7 +43,15 @@ export class DataSeedDemoWorkspaceService {
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);
}
} catch (error) {

View File

@ -95,8 +95,14 @@ export class DataSeedWorkspaceCommand extends CommandRunner {
await rawDataSource.initialize();
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();

View File

@ -1,29 +1,9 @@
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 {
deleteUserWorkspaces,
seedUserWorkspaces,
} 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);
};
import { deleteUserWorkspaces } from 'src/database/typeorm-seeds/core/demo/user-workspaces';
import { deleteUsersByWorkspace } from 'src/database/typeorm-seeds/core/demo/users';
import { deleteWorkspaces } from 'src/database/typeorm-seeds/core/demo/workspaces';
export const deleteCoreSchema = async (
workspaceDataSource: DataSource,

View File

@ -6,19 +6,37 @@ import { seedUserWorkspaces } from 'src/database/typeorm-seeds/core/user-workspa
import { seedUsers } from 'src/database/typeorm-seeds/core/users';
import { seedWorkspaces } from 'src/database/typeorm-seeds/core/workspaces';
export const seedCoreSchema = async (
workspaceDataSource: DataSource,
workspaceId: string,
isBillingEnabled: boolean,
) => {
type SeedCoreSchemaArgs = {
workspaceDataSource: DataSource;
workspaceId: string;
appVersion: string | undefined;
seedBilling?: boolean;
seedFeatureFlags?: boolean;
};
export const seedCoreSchema = async ({
appVersion,
workspaceDataSource,
workspaceId,
seedBilling = true,
seedFeatureFlags: shouldSeedFeatureFlags = true,
}: SeedCoreSchemaArgs) => {
const schemaName = 'core';
await seedWorkspaces(workspaceDataSource, schemaName, workspaceId);
await seedWorkspaces({
workspaceDataSource,
schemaName,
workspaceId,
appVersion,
});
await seedUsers(workspaceDataSource, schemaName);
await seedUserWorkspaces(workspaceDataSource, schemaName, workspaceId);
await seedFeatureFlags(workspaceDataSource, schemaName, workspaceId);
if (isBillingEnabled) {
if (shouldSeedFeatureFlags) {
await seedFeatureFlags(workspaceDataSource, schemaName, workspaceId);
}
if (seedBilling) {
await seedBillingSubscriptions(
workspaceDataSource,
schemaName,

View File

@ -2,57 +2,68 @@ import { WorkspaceActivationStatus } from 'twenty-shared';
import { DataSource } from 'typeorm';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { extractVersionMajorMinorPatch } from 'src/utils/version/extract-version-major-minor-patch';
const tableName = 'workspace';
export const SEED_APPLE_WORKSPACE_ID = '20202020-1c25-4d02-bf25-6aeccf7ea419';
export const SEED_ACME_WORKSPACE_ID = '3b8e6458-5fc1-4e63-8563-008ccddaa6db';
export const seedWorkspaces = async (
workspaceDataSource: DataSource,
schemaName: string,
workspaceId: string,
) => {
const workspaces: {
[key: string]: Pick<
Workspace,
| 'id'
| 'displayName'
| 'inviteHash'
| 'logo'
| 'subdomain'
| 'activationStatus'
>;
} = {
export type SeedWorkspaceArgs = {
workspaceDataSource: DataSource;
schemaName: string;
workspaceId: string;
appVersion: string | undefined;
};
const workspaceSeederFields = [
'id',
'displayName',
'subdomain',
'inviteHash',
'logo',
'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]: {
id: workspaceId,
id: SEED_APPLE_WORKSPACE_ID,
displayName: 'Apple',
subdomain: 'apple',
inviteHash: 'apple.dev-invite-hash',
logo: 'https://twentyhq.github.io/placeholder-images/workspaces/apple-logo.png',
activationStatus: WorkspaceActivationStatus.ACTIVE,
version: version,
},
[SEED_ACME_WORKSPACE_ID]: {
id: workspaceId,
id: SEED_ACME_WORKSPACE_ID,
displayName: 'Acme',
subdomain: 'acme',
inviteHash: 'acme.dev-invite-hash',
logo: 'https://logos-world.net/wp-content/uploads/2022/05/Acme-Logo-700x394.png',
activationStatus: WorkspaceActivationStatus.ACTIVE,
version: version,
},
};
await workspaceDataSource
.createQueryBuilder()
.insert()
.into(`${schemaName}.${tableName}`, [
'id',
'displayName',
'subdomain',
'inviteHash',
'logo',
'activationStatus',
])
.into(`${schemaName}.${tableName}`, workspaceSeederFields)
.orIgnore()
.values(workspaces[workspaceId])
.execute();