Workspace command decorators (#19397)

# Introduction
Migrating the workspace commands to the decorator version + timestamp
listing as for the instance commands

We've now been able to remove the upgrade command abstraction where we
needed to import all modules and order them
Now they're dynamically retrieved at upgrade runtime, sorted by
timestamp

## Instance and workspace commands name
The name is computed from the command metadata `version` `className` and
`timestamp` we have a duplicate validation at module init from the
unified registry
This commit is contained in:
Paul Rastoin
2026-04-07 18:33:48 +02:00
committed by GitHub
parent 24a5273a79
commit c0eacedfec
52 changed files with 1147 additions and 2868 deletions
@@ -2,16 +2,14 @@
exports[`InstanceCommandGenerationService should encode version correctly in file and class names 1`] = `
{
"className": "V1_19_Test_1775000000000",
"fileName": "1-19-instance-command-fast-1775000000000-test.ts",
"className": "TestCommand",
"fileName": "1-20-instance-command-fast-1775000000000-test.ts",
"fileTemplate": "import { MigrationInterface, QueryRunner } from 'typeorm';
import { RegisteredInstanceMigration } from 'src/database/typeorm/core/decorators/registered-instance-migration.decorator';
@RegisteredInstanceMigration('1.19.0', 1775000000000)
export class V1_19_Test_1775000000000 implements MigrationInterface {
name = 'V1_19_Test_1775000000000';
import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator';
@RegisteredInstanceCommand('1.20.0', 1775000000000)
export class TestCommand implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('SELECT 1');
}
@@ -26,16 +24,14 @@ export class V1_19_Test_1775000000000 implements MigrationInterface {
exports[`InstanceCommandGenerationService should escape backslashes in SQL queries 1`] = `
{
"className": "V1_21_UpdatePath_1775000000000",
"className": "UpdatePathCommand",
"fileName": "1-21-instance-command-fast-1775000000000-update-path.ts",
"fileTemplate": "import { MigrationInterface, QueryRunner } from 'typeorm';
import { RegisteredInstanceMigration } from 'src/database/typeorm/core/decorators/registered-instance-migration.decorator';
@RegisteredInstanceMigration('1.21.0', 1775000000000)
export class V1_21_UpdatePath_1775000000000 implements MigrationInterface {
name = 'V1_21_UpdatePath_1775000000000';
import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator';
@RegisteredInstanceCommand('1.21.0', 1775000000000)
export class UpdatePathCommand implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('UPDATE "core"."config" SET "value" = E\\'path\\\\\\\\to\\\\\\\\file\\'');
}
@@ -50,16 +46,14 @@ export class V1_21_UpdatePath_1775000000000 implements MigrationInterface {
exports[`InstanceCommandGenerationService should escape single quotes in SQL queries 1`] = `
{
"className": "V1_21_UpdateConfig_1775000000000",
"className": "UpdateConfigCommand",
"fileName": "1-21-instance-command-fast-1775000000000-update-config.ts",
"fileTemplate": "import { MigrationInterface, QueryRunner } from 'typeorm';
import { RegisteredInstanceMigration } from 'src/database/typeorm/core/decorators/registered-instance-migration.decorator';
@RegisteredInstanceMigration('1.21.0', 1775000000000)
export class V1_21_UpdateConfig_1775000000000 implements MigrationInterface {
name = 'V1_21_UpdateConfig_1775000000000';
import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator';
@RegisteredInstanceCommand('1.21.0', 1775000000000)
export class UpdateConfigCommand implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('UPDATE "core"."config" SET "value" = \\'it\\'\\'s done\\'');
}
@@ -74,16 +68,14 @@ export class V1_21_UpdateConfig_1775000000000 implements MigrationInterface {
exports[`InstanceCommandGenerationService should generate a migration with a single up/down query 1`] = `
{
"className": "V1_21_AddFooColumn_1775000000000",
"className": "AddFooColumnCommand",
"fileName": "1-21-instance-command-fast-1775000000000-add-foo-column.ts",
"fileTemplate": "import { MigrationInterface, QueryRunner } from 'typeorm';
import { RegisteredInstanceMigration } from 'src/database/typeorm/core/decorators/registered-instance-migration.decorator';
@RegisteredInstanceMigration('1.21.0', 1775000000000)
export class V1_21_AddFooColumn_1775000000000 implements MigrationInterface {
name = 'V1_21_AddFooColumn_1775000000000';
import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator';
@RegisteredInstanceCommand('1.21.0', 1775000000000)
export class AddFooColumnCommand implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('ALTER TABLE "core"."user" ADD "foo" varchar');
}
@@ -98,16 +90,14 @@ export class V1_21_AddFooColumn_1775000000000 implements MigrationInterface {
exports[`InstanceCommandGenerationService should generate a migration with multiple queries 1`] = `
{
"className": "V1_21_CreateTaskTable_1775000000000",
"className": "CreateTaskTableCommand",
"fileName": "1-21-instance-command-fast-1775000000000-create-task-table.ts",
"fileTemplate": "import { MigrationInterface, QueryRunner } from 'typeorm';
import { RegisteredInstanceMigration } from 'src/database/typeorm/core/decorators/registered-instance-migration.decorator';
@RegisteredInstanceMigration('1.21.0', 1775000000000)
export class V1_21_CreateTaskTable_1775000000000 implements MigrationInterface {
name = 'V1_21_CreateTaskTable_1775000000000';
import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator';
@RegisteredInstanceCommand('1.21.0', 1775000000000)
export class CreateTaskTableCommand implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('CREATE TABLE "core"."task" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "name" varchar NOT NULL)');
await queryRunner.query('ALTER TABLE "core"."task" ADD CONSTRAINT "PK_task" PRIMARY KEY ("id")');
@@ -124,16 +114,14 @@ export class V1_21_CreateTaskTable_1775000000000 implements MigrationInterface {
exports[`InstanceCommandGenerationService should generate a migration with query parameters 1`] = `
{
"className": "V1_21_SeedSetting_1775000000000",
"className": "SeedSettingCommand",
"fileName": "1-21-instance-command-fast-1775000000000-seed-setting.ts",
"fileTemplate": "import { MigrationInterface, QueryRunner } from 'typeorm';
import { RegisteredInstanceMigration } from 'src/database/typeorm/core/decorators/registered-instance-migration.decorator';
@RegisteredInstanceMigration('1.21.0', 1775000000000)
export class V1_21_SeedSetting_1775000000000 implements MigrationInterface {
name = 'V1_21_SeedSetting_1775000000000';
import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator';
@RegisteredInstanceCommand('1.21.0', 1775000000000)
export class SeedSettingCommand implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('INSERT INTO "core"."setting" ("key", "value") VALUES ($1, $2)', ["theme","dark"]);
}
@@ -148,16 +136,14 @@ export class V1_21_SeedSetting_1775000000000 implements MigrationInterface {
exports[`InstanceCommandGenerationService should use default migration name in class and file names 1`] = `
{
"className": "V1_21_AutoGenerated_1775000000000",
"className": "AutoGeneratedCommand",
"fileName": "1-21-instance-command-fast-1775000000000-auto-generated.ts",
"fileTemplate": "import { MigrationInterface, QueryRunner } from 'typeorm';
import { RegisteredInstanceMigration } from 'src/database/typeorm/core/decorators/registered-instance-migration.decorator';
@RegisteredInstanceMigration('1.21.0', 1775000000000)
export class V1_21_AutoGenerated_1775000000000 implements MigrationInterface {
name = 'V1_21_AutoGenerated_1775000000000';
import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator';
@RegisteredInstanceCommand('1.21.0', 1775000000000)
export class AutoGeneratedCommand implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('ALTER TABLE "core"."user" ADD "bar" integer');
}
@@ -171,7 +171,7 @@ describe('InstanceCommandGenerationService', () => {
const result = await service.generate({
migrationName: 'test',
version: '1.19.0',
version: '1.20.0',
timestamp: FIXED_TIMESTAMP,
});