mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
106 lines
3.6 KiB
TypeScript
106 lines
3.6 KiB
TypeScript
import path from "node:path";
|
|
|
|
import dotenv from "dotenv";
|
|
import { Knex } from "knex";
|
|
import { Logger } from "pino";
|
|
|
|
import { PgSqlLock } from "./keystore/keystore";
|
|
|
|
dotenv.config();
|
|
|
|
type TArgs = {
|
|
auditLogDb?: Knex;
|
|
applicationDb: Knex;
|
|
logger: Logger;
|
|
};
|
|
|
|
const isProduction = process.env.NODE_ENV === "production";
|
|
const migrationConfig = {
|
|
directory: path.join(__dirname, "./db/migrations"),
|
|
loadExtensions: [".mjs", ".ts"],
|
|
tableName: "infisical_migrations"
|
|
};
|
|
|
|
const migrationStatusCheckErrorHandler = (err: Error) => {
|
|
// happens for first time in which the migration table itself is not created yet
|
|
// error: select * from "infisical_migrations" - relation "infisical_migrations" does not exist
|
|
if (err?.message?.includes("does not exist")) {
|
|
return true;
|
|
}
|
|
throw err;
|
|
};
|
|
|
|
export const runMigrations = async ({ applicationDb, auditLogDb, logger }: TArgs) => {
|
|
try {
|
|
// akhilmhdh(Feb 10 2025): 2 years from now remove this
|
|
if (isProduction) {
|
|
const migrationTable = migrationConfig.tableName;
|
|
const hasMigrationTable = await applicationDb.schema.hasTable(migrationTable);
|
|
if (hasMigrationTable) {
|
|
const firstFile = (await applicationDb(migrationTable).where({}).first()) as { name: string };
|
|
if (firstFile?.name?.includes(".ts")) {
|
|
await applicationDb(migrationTable).update({
|
|
name: applicationDb.raw("REPLACE(name, '.ts', '.mjs')")
|
|
});
|
|
}
|
|
}
|
|
if (auditLogDb) {
|
|
const hasMigrationTableInAuditLog = await auditLogDb.schema.hasTable(migrationTable);
|
|
if (hasMigrationTableInAuditLog) {
|
|
const firstFile = (await auditLogDb(migrationTable).where({}).first()) as { name: string };
|
|
if (firstFile?.name?.includes(".ts")) {
|
|
await auditLogDb(migrationTable).update({
|
|
name: auditLogDb.raw("REPLACE(name, '.ts', '.mjs')")
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const shouldRunMigration = Boolean(
|
|
await applicationDb.migrate.status(migrationConfig).catch(migrationStatusCheckErrorHandler)
|
|
); // db.length - code.length
|
|
if (!shouldRunMigration) {
|
|
logger.info("No migrations pending: Skipping migration process.");
|
|
return;
|
|
}
|
|
|
|
if (auditLogDb) {
|
|
await auditLogDb.transaction(async (tx) => {
|
|
await tx.raw("SELECT pg_advisory_xact_lock(?)", [PgSqlLock.BootUpMigration]);
|
|
logger.info("Running audit log migrations.");
|
|
|
|
const didPreviousInstanceRunMigration = !(await auditLogDb.migrate
|
|
.status(migrationConfig)
|
|
.catch(migrationStatusCheckErrorHandler));
|
|
if (didPreviousInstanceRunMigration) {
|
|
logger.info("No audit log migrations pending: Applied by previous instance. Skipping migration process.");
|
|
return;
|
|
}
|
|
|
|
await auditLogDb.migrate.latest(migrationConfig);
|
|
logger.info("Finished audit log migrations.");
|
|
});
|
|
}
|
|
|
|
await applicationDb.transaction(async (tx) => {
|
|
await tx.raw("SELECT pg_advisory_xact_lock(?)", [PgSqlLock.BootUpMigration]);
|
|
logger.info("Running application migrations.");
|
|
|
|
const didPreviousInstanceRunMigration = !(await applicationDb.migrate
|
|
.status(migrationConfig)
|
|
.catch(migrationStatusCheckErrorHandler));
|
|
if (didPreviousInstanceRunMigration) {
|
|
logger.info("No application migrations pending: Applied by previous instance. Skipping migration process.");
|
|
return;
|
|
}
|
|
|
|
await applicationDb.migrate.latest(migrationConfig);
|
|
logger.info("Finished application migrations.");
|
|
});
|
|
} catch (err) {
|
|
logger.error(err, "Boot up migration failed");
|
|
process.exit(1);
|
|
}
|
|
};
|