diff --git a/.changeset/wild-buses-notice.md b/.changeset/wild-buses-notice.md new file mode 100644 index 0000000000..3620786aa8 --- /dev/null +++ b/.changeset/wild-buses-notice.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': patch +--- + +Added the option to skip database migrations by setting `skipMigrations: true` in config. This can be done globally in the database config or by plugin id. diff --git a/packages/backend-defaults/config.d.ts b/packages/backend-defaults/config.d.ts index fee8846c4b..97809da12c 100644 --- a/packages/backend-defaults/config.d.ts +++ b/packages/backend-defaults/config.d.ts @@ -453,6 +453,8 @@ export interface Config { * and asyncStackTraces booleans */ knexConfig?: object; + /** Skip running database migrations. */ + skipMigrations?: boolean; /** Plugin specific database configuration and client override */ plugin?: { [pluginId: string]: { @@ -485,6 +487,8 @@ export interface Config { knexConfig?: object; /** Configures the ownership of newly created schemas in pg databases. */ role?: string; + /** Skip running database migrations. */ + skipMigrations?: boolean; }; }; }; diff --git a/packages/backend-defaults/src/entrypoints/database/DatabaseManager.test.ts b/packages/backend-defaults/src/entrypoints/database/DatabaseManager.test.ts index 347ec742c0..0d52ff16ff 100644 --- a/packages/backend-defaults/src/entrypoints/database/DatabaseManager.test.ts +++ b/packages/backend-defaults/src/entrypoints/database/DatabaseManager.test.ts @@ -96,27 +96,83 @@ describe('DatabaseManagerImpl', () => { expect(connector2.getClient).toHaveBeenLastCalledWith('plugin2', undefined); }); - it('retains the migration skip info', async () => { + it('migration skip options take precedence over config', async () => { const connector = { getClient: jest.fn(), dropDatabase: jest.fn(), } satisfies Connector; + const impl = new DatabaseManagerImpl( + new ConfigReader({ + client: 'pg', + backend: { + database: { + skipMigrations: true, + plugin: { plugin1: { skipMigrations: true } }, + }, + }, + }), + { + pg: connector, + }, + { migrations: { skip: false } }, + ); + expect((await impl.forPlugin('plugin1')).migrations).toEqual({ + skip: false, + }); + const impl1 = new DatabaseManagerImpl(new ConfigReader({ client: 'pg' }), { pg: connector, }); - const impl2 = new DatabaseManagerImpl( - new ConfigReader({ client: 'pg' }), - { pg: connector }, - { migrations: { skip: true } }, - ); - expect((await impl1.forPlugin('plugin1')).migrations).toEqual({ skip: false, }); + }); + it('plugin can skip migrations using config', async () => { + const connector = { + getClient: jest.fn(), + dropDatabase: jest.fn(), + } satisfies Connector; + + const impl = new DatabaseManagerImpl( + new ConfigReader({ + client: 'pg', + backend: { + database: { plugin: { plugin1: { skipMigrations: true } } }, + }, + }), + { + pg: connector, + }, + ); + + expect((await impl.forPlugin('plugin1')).migrations).toEqual({ + skip: true, + }); + expect((await impl.forPlugin('plugin2')).migrations).toEqual({ + skip: false, + }); + + const impl2 = new DatabaseManagerImpl( + new ConfigReader({ + client: 'pg', + backend: { + database: { + skipMigrations: true, + plugin: { plugin1: { skipMigrations: false } }, + }, + }, + }), + { + pg: connector, + }, + ); expect((await impl2.forPlugin('plugin1')).migrations).toEqual({ + skip: false, + }); + expect((await impl2.forPlugin('plugin2')).migrations).toEqual({ skip: true, }); }); diff --git a/packages/backend-defaults/src/entrypoints/database/DatabaseManager.ts b/packages/backend-defaults/src/entrypoints/database/DatabaseManager.ts index 7e3adf17df..b3e69f0ae2 100644 --- a/packages/backend-defaults/src/entrypoints/database/DatabaseManager.ts +++ b/packages/backend-defaults/src/entrypoints/database/DatabaseManager.ts @@ -86,8 +86,16 @@ export class DatabaseManagerImpl implements LegacyRootDatabaseService { ); } const getClient = () => this.getDatabase(pluginId, connector, deps); - const migrations = { skip: false, ...this.options?.migrations }; - return { getClient, migrations }; + + const skip = + this.options?.migrations?.skip ?? + this.config.getOptionalBoolean( + `backend.database.plugin.${pluginId}.skipMigrations`, + ) ?? + this.config.getOptionalBoolean('backend.database.skipMigrations') ?? + false; + + return { getClient, migrations: { skip } }; } /**