graphile-migrate
Version:
Opinionated SQL-powered migration tool for PostgreSQL
100 lines • 4.72 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const pgMinify = require("pg-minify");
const fs_1 = require("fs");
const current_1 = require("../current");
const hash_1 = require("../hash");
const instrumentation_1 = require("../instrumentation");
const migration_1 = require("../migration");
const settings_1 = require("../settings");
const sluggify_1 = require("../sluggify");
const _common_1 = require("./_common");
const migrate_1 = require("./migrate");
const reset_1 = require("./reset");
function omit(obj, keys) {
const newObject = Object.assign({}, obj);
for (const key of keys) {
delete newObject[key];
}
return newObject;
}
async function _commit(parsedSettings, messageOverride = undefined) {
const { migrationsFolder } = parsedSettings;
const currentLocation = await current_1.getCurrentMigrationLocation(parsedSettings);
const contents = await current_1.readCurrentMigration(parsedSettings, currentLocation);
const committedMigrationsFolder = `${migrationsFolder}/committed`;
const allMigrations = await migration_1.getAllMigrations(parsedSettings);
const lastMigration = allMigrations[allMigrations.length - 1];
const newMigrationNumber = lastMigration
? parseInt(lastMigration.filename, 10) + 1
: 1;
if (Number.isNaN(newMigrationNumber)) {
throw new Error("Could not determine next migration number");
}
const { headers, body } = migration_1.parseMigrationText(currentLocation.path, contents, false);
const messageFromComment = headers.Message;
const message = messageOverride !== undefined ? messageOverride : messageFromComment;
if (message && /[\r\n\0\b\v\f\cA-\cZ]/u.test(message)) {
throw new Error("Invalid commit message: contains disallowed characters");
}
if (message && message.length > 512) {
throw new Error("Invalid commit message: message is too long (max: 512 chars)");
}
const sluggifiedMessage = message ? sluggify_1.sluggify(message) : null;
const newMigrationFilename = String(newMigrationNumber).padStart(6, "0") +
(sluggifiedMessage ? `-${sluggifiedMessage}` : "") +
".sql";
if (!migration_1.isMigrationFilename(newMigrationFilename)) {
throw Error("Could not construct migration filename");
}
const minifiedBody = pgMinify(body);
if (minifiedBody === "") {
throw new Error("Current migration is blank.");
}
const hash = hash_1.calculateHash(body, lastMigration && lastMigration.hash);
const finalBody = migration_1.serializeMigration(body, Object.assign({ Previous: lastMigration ? lastMigration.hash : "-", Hash: hash, Message: message ? message : undefined }, omit(headers, ["Previous", "Hash", "Message"])));
await reset_1._reset(parsedSettings, true);
const newMigrationFilepath = `${committedMigrationsFolder}/${newMigrationFilename}`;
await fs_1.promises.writeFile(newMigrationFilepath, finalBody);
await fs_1.promises.chmod(newMigrationFilepath, "440");
parsedSettings.logger.info(`graphile-migrate: New migration '${newMigrationFilename}' created`);
try {
await migrate_1._migrate(parsedSettings, true);
await migrate_1._migrate(parsedSettings);
await current_1.writeCurrentMigration(parsedSettings, currentLocation, parsedSettings.blankMigrationContent.trim() + "\n");
}
catch (e) {
instrumentation_1.logDbError(parsedSettings, e);
parsedSettings.logger.error("ABORTING...");
await current_1.writeCurrentMigration(parsedSettings, currentLocation, body);
await fs_1.promises.unlink(newMigrationFilepath);
parsedSettings.logger.error("ABORTED AND ROLLED BACK");
throw e;
}
}
exports._commit = _commit;
async function commit(settings, message) {
const parsedSettings = await settings_1.parseSettings(settings, true);
return _commit(parsedSettings, message);
}
exports.commit = commit;
exports.commitCommand = {
command: "commit",
aliases: [],
describe: "Commits the current migration into the `committed/` folder, resetting the current migration. Resets the shadow database.",
builder: {
message: {
type: "string",
alias: ["m"],
description: "Optional commit message to label migration, must not contain newlines.",
nargs: 1,
},
},
handler: async (argv) => {
if (argv.message !== undefined && !argv.message) {
throw new Error("Missing or empty commit message after --message flag");
}
await commit(await _common_1.getSettings({ configFile: argv.config }), argv.message);
},
};
//# sourceMappingURL=commit.js.map