1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-01-02 12:47:41 +02:00

Server: Do not allow the server to start if a migration needs to be applied

This commit is contained in:
Laurent Cozic 2023-08-05 17:42:29 +01:00
parent 2f6e146841
commit 1acbb5dc9a
4 changed files with 26 additions and 10 deletions

View File

@ -5,7 +5,7 @@ import * as Koa from 'koa';
import * as fs from 'fs-extra';
import Logger, { LoggerWrapper, TargetType } from '@joplin/utils/Logger';
import config, { fullVersionString, initConfig, runningInDocker } from './config';
import { migrateLatest, waitForConnection, sqliteDefaultDir, latestMigration } from './db';
import { migrateLatest, waitForConnection, sqliteDefaultDir, latestMigration, needsMigration, migrateList } from './db';
import { AppContext, Env, KoaNext } from './utils/types';
import FsDriverNode from '@joplin/lib/fs-driver-node';
import { getDeviceTimeDrift } from '@joplin/lib/ntp';
@ -293,6 +293,10 @@ async function main() {
await migrateLatest(connectionCheck.connection);
appLogger().info('Latest migration:', await latestMigration(connectionCheck.connection));
} else {
if (!config().DB_ALLOW_INCOMPLETE_MIGRATIONS && (await needsMigration(connectionCheck.connection))) {
const list = await migrateList(connectionCheck.connection, true);
throw new Error(`One or more migrations need to be applied:\n\n${list}`);
}
appLogger().info('Skipped database auto-migration.');
}

View File

@ -1,6 +1,6 @@
import { afterAllTests, beforeAllDb, beforeEachDb, db } from './utils/testing/testUtils';
import sqlts from '@rmp135/sql-ts';
import { DbConnection, migrateDown, migrateUp, nextMigration } from './db';
import { DbConnection, migrateDown, migrateLatest, migrateUp, needsMigration, nextMigration } from './db';
async function dbSchemaSnapshot(db: DbConnection): Promise<any> {
return sqlts.toTypeScript({}, db as any);
@ -8,18 +8,15 @@ async function dbSchemaSnapshot(db: DbConnection): Promise<any> {
describe('db', () => {
beforeAll(async () => {
await beforeAllDb('db', { autoMigrate: false });
});
afterAll(async () => {
await afterAllTests();
});
beforeEach(async () => {
await beforeAllDb('db', { autoMigrate: false });
await beforeEachDb();
});
afterEach(async () => {
await afterAllTests();
});
it('should allow upgrading and downgrading schema', async () => {
// Migrations before that didn't have a down() step.
const ignoreAllBefore = '20210819165350_user_flags';
@ -70,4 +67,12 @@ describe('db', () => {
}
});
it('should tell if a migration is required', async () => {
expect(await needsMigration(db())).toBe(true);
await migrateLatest(db());
expect(await needsMigration(db())).toBe(false);
});
});

View File

@ -337,6 +337,11 @@ export async function migrateList(db: DbConnection, asString = true) {
return output.map(l => `${l.done ? '✓' : '✗'} ${l.name}`).join('\n');
}
export const needsMigration = async (db: DbConnection) => {
const list = await migrateList(db, false) as Migration[];
return !!list.find(m => !m.done);
};
export async function nextMigration(db: DbConnection): Promise<string> {
const list = await migrateList(db, false) as Migration[];

View File

@ -56,6 +56,7 @@ const defaultEnvValues: EnvVariables = {
DB_SLOW_QUERY_LOG_ENABLED: false,
DB_SLOW_QUERY_LOG_MIN_DURATION: 1000,
DB_AUTO_MIGRATION: true,
DB_ALLOW_INCOMPLETE_MIGRATIONS: false,
POSTGRES_PASSWORD: 'joplin',
POSTGRES_DATABASE: 'joplin',
@ -129,6 +130,7 @@ export interface EnvVariables {
DB_SLOW_QUERY_LOG_ENABLED: boolean;
DB_SLOW_QUERY_LOG_MIN_DURATION: number;
DB_AUTO_MIGRATION: boolean;
DB_ALLOW_INCOMPLETE_MIGRATIONS: boolean;
POSTGRES_PASSWORD: string;
POSTGRES_DATABASE: string;