Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adds cli debug option #6

Merged
merged 1 commit into from
Dec 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Either use environment variables
UPMIG_PATH=./migrations
UPMIG_TABLE=pg_upmig
UPMIG_REJECT=false
UPMIG_DEBUG=false
```
or use `.upmigrc.js` to set global options:
```javascript
Expand All @@ -48,7 +49,8 @@ try {
module.exports = {
migrations: "./migrations", // Where to store migrations files
table: "pg_upmig", // Table name where migrations history is stored
reject: false
reject: false,
debug: false
};
```
## Migrations folder tree view
Expand Down Expand Up @@ -89,6 +91,7 @@ Options:
-m, --migrations <path> specify migrations path (default: "./migrations")
-p, --pgtable <table> specify migration table name (default: "pg_upmig")
-r, --reject dont ignore unauthorized ssl rejection
-d, --debug print debug informations

Commands:
up [options] perform all pending migrations
Expand Down Expand Up @@ -312,4 +315,4 @@ Returns an array of objects representing migration file:
|name|string|Migration name excluding timestamp.|
## Todo
- [ ] Custom logger implementation
- [ ] Remove dispensable dependencies
- [x] Remove dispensable dependencies
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "pg-upmig",
"version": "0.0.27",
"version": "0.0.28",
"description": "Postgresql migration tool",
"keywords": [
"database",
Expand Down
29 changes: 21 additions & 8 deletions src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ const path = require("path");
let migrationsPath = process.env.UPMIG_PATH||"./migrations";
let pgTable = process.env.UPMIG_TABLE||"pg_upmig";
let reject = Boolean(process.env.UPMIG_REJECT)||false;
let debug = Boolean(process.env.UPMIG_DEBUG)||false;

try {
const dotConfig = require(path.join(process.cwd(), ".upmigrc.js"));
migrationsPath = dotConfig.migrations?dotConfig.migrations:migrationsPath;
pgTable = dotConfig.table?dotConfig.table:pgTable;
reject = dotConfig.reject?dotConfig.reject:reject;
debug = dotConfig.debug?dotConfig.debug:debug;
} catch (error) {}

function steps (s) {
Expand Down Expand Up @@ -47,6 +49,9 @@ function setOpt (namespace) {
break;
case "reject":
reject = option;
break;
case "debug":
debug = option;
}
}
}
Expand All @@ -56,20 +61,24 @@ exports.setOpt = setOpt;
exports._env = () => {
return {
migrationsPath,
pgTable
pgTable,
reject,
debug
};
}

program.on("option:migrations", setOpt("migrations"));
program.on("option:pgtable", setOpt("pgtable"));
program.on("option:reject", setOpt("reject"));
program.on("option:debug", setOpt("debug"));

program.version(pkg.version)
.arguments("<cmd> [opt]")
.usage("<command> [options]")
.option("-m, --migrations <path>", "specify migrations path", "./migrations")
.option("-p, --pgtable <table>", "specify migration table name", "pg-upmig", migTable)
.option("-r, --reject", "dont ignore unauthorized ssl rejection");
.option("-r, --reject", "dont ignore unauthorized ssl rejection")
.option("-d, --debug", "print debug informations");

async function up (cmd) {
const mig = new migration({
Expand All @@ -83,7 +92,8 @@ async function up (cmd) {
table: pgTable,
migrations: migrationsPath,
to: cmd.to,
steps: cmd.steps
steps: cmd.steps,
debug
});
const done = await mig.up();
mig.release();
Expand All @@ -102,7 +112,7 @@ program

const len = done.reduce((accu, file) => Math.max(accu, file.name.length), 21);
for (let file of done) {
process.stdout.write(`\n\x1b[32m⇈")}\t\x1b[33m${file.name}\x1b[0m${" ".repeat(Math.ceil(len-file.name.length))}\t\x1b[35;1m${file.ts}\x1b[0m`);
process.stdout.write(`\n\x1b[32m⇈\t\x1b[33m${file.name}\x1b[0m${" ".repeat(Math.ceil(len-file.name.length))}\t\x1b[35;1m${file.ts}\x1b[0m`);
}
process.stdout.write(`\n\x1b[32m✓\x1b[0m\tMigrations completed:${" ".repeat(Math.ceil(len-21))}\t\x1b[35;1m${done.length}\x1b[0m`);
process.stdout.write("\n\n");
Expand All @@ -116,7 +126,7 @@ async function create (cmd, name){
}
}
});
await mig.init({migrations: migrationsPath, table: pgTable});
await mig.init({migrations: migrationsPath, table: pgTable, debug});
const file = await mig.create(name?name.join("-"):"", cmd.nosql);
mig.release();
return file;
Expand All @@ -143,7 +153,7 @@ async function pending (cmd) {
}
}
});
await mig.init({migrations: migrationsPath, table: pgTable, history: cmd.history});
await mig.init({migrations: migrationsPath, table: pgTable, history: cmd.history, debug});
const list = await mig.pending();
mig.release();
return list;
Expand All @@ -157,9 +167,12 @@ program
.option("-H, --history", "show history about migrations")
.action(async (cmd) => {
const list = await pending(cmd);
const len = list.pending.reduce((accu, file) => Math.max(accu, file.name.length), 19);
const len = list.pending.reduce((accu, file) => Math.max(accu, file.name.length, (list.last||{}).name||0), 19);
if (list.last && cmd.history) {
process.stdout.write(`\n\x1b[32m✓ Last\t\t\x1b[32m${list.last.name}\x1b[0m${" ".repeat(Math.ceil(len-list.last.name.length))}\t\x1b[35m${list.last.ts}\x1b[0m\n`);
}
for (let file of list.pending) {
process.stdout.write(`\n\x1b[34m⇉\t\x1b[33;1m${file.name}\x1b[0m${" ".repeat(Math.ceil(len-file.name.length))}\t\x1b[35;1m${file.ts}\x1b[0m`);
process.stdout.write(`\n\x1b[34m⇉ Pending\t\x1b[33;1m${file.name}\x1b[0m${" ".repeat(Math.ceil(len-file.name.length))}\t\x1b[35;1m${file.ts}\x1b[0m`);
}
process.stdout.write(`\n\x1b[36mⓘ\x1b[0m\tPending migrations:${" ".repeat(Math.ceil(len-19))}\t\x1b[35;1m${list.pending.length}\x1b[0m${cmd.history?`/\x1b[35;1m${list.history+list.pending.length}\x1b[0m \x1b[32;1m(${list.history}\x1b[0m done)`:""}`);
process.stdout.write("\n\n");
Expand Down
20 changes: 14 additions & 6 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ class migration {
const dotConfig = require(path.join(process.cwd(),".upmigrc.js"));
this.options.migrations = dotConfig.migrations?dotConfig.migrations:this.options.migrations;
this.options.table = dotConfig.table?dotConfig.table:this.options.table;
} catch (error) { }
} catch (error) {
this._debug(error, 3);
}

if ((params||{}).options) {
Object.assign(this.options, params.options);
Expand All @@ -73,9 +75,9 @@ class migration {
if (!this.client) {
if ((params||{}).connection) {
if (!params.connection.hasOwnProperty("ssl")) {
params.connection.ssl= { rejectUnauthorized: process.env.UPMIG_REJECT||false };
params.connection.ssl= { rejectUnauthorized: Boolean(process.env.UPMIG_REJECT||0) };
} else if (!params.connection.ssl.hasOwnProperty("rejectUnauthorized")) {
params.connection.ssl["rejectUnauthorized"] = process.env.UPMIG_REJECT||false;
params.connection.ssl["rejectUnauthorized"] = Boolean(process.env.UPMIG_REJECT||0);
}
// Uses connection params
this.client = new Client(params.connection);
Expand All @@ -84,7 +86,7 @@ class migration {
// At this point, if nothing is provided we let PG client rise errors
this.client = new Client({
ssl: {
rejectUnauthorized: process.env.UPMIG_REJECT||false
rejectUnauthorized: Boolean(process.env.UPMIG_REJECT||0)
}
});
}
Expand Down Expand Up @@ -276,7 +278,7 @@ module.exports = async (client, method) => {
await this.init();

const files = await this._files();
const latest = this._pluck(await this._query(`SELECT ts FROM ${this.options.table} ORDER BY ts DESC;`));
const latest = this._pluck(await this._query(`SELECT ts, name FROM ${this.options.table} ORDER BY ts DESC;`));
let idx = 0;

// Find the first file with a timestamp greater than the last successful migration
Expand All @@ -286,7 +288,13 @@ module.exports = async (client, method) => {

const pending = idx >= 0 ? files.slice(idx, files.length) : [];

return {pending, history: latest.length};
let last = null;
// Find the last migration
if (latest.length) {
last = latest[0];
}

return {pending, history: latest.length, last};
}

/**
Expand Down
7 changes: 5 additions & 2 deletions tests/cli.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ describe("Core logic", () => {
};
expect(pending).toEqual({
history: 0,
last: null,
pending: [file]
});
});
Expand Down Expand Up @@ -304,13 +305,15 @@ describe("List pending migrations", () => {
}
const containing = [];

containing.push(expect.stringMatching(new RegExp(`Last\\s+${fixtures.migrationFile}\\s+\[0\-9\]+`)))

for (let i = 0; i < details.length; i++) {
containing.push(expect.stringMatching(new RegExp(`${details[i][2]}\\s+${details[i][1]}$`, "i")));
containing.push(expect.stringMatching(new RegExp(`Pending\\s+${details[i][2]}\\s+${details[i][1]}$`, "i")));
}
containing.push(expect.stringMatching(new RegExp(`Pending migrations:\\s+${details.length}/\[0\-9\]\+\\s\\(\[0\-9\]\+\\sdone\\)$`, "i")));

const response = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, fixtures.cli._cmds.list, "-H"], [], {env});
expect(response.trim().replace(/\x1b[[0-9;]+m/g, "").split(EOL)).toEqual(containing);
expect(response.trim().replace(/\x1b[[0-9;]+m/g, "").split(EOL).filter(item => item)).toEqual(containing);
});
});

Expand Down
32 changes: 16 additions & 16 deletions tests/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ describe("Migration using environment variables", () => {

test("Should list empty pending migrations", async () => {
const files = await mig.pending();
expect(files).toEqual({pending: [], history: 0});
expect(files).toEqual({pending: [], last: null, history: 0});
});

test("Should create migration files", async () => {
Expand All @@ -105,7 +105,7 @@ describe("Migration using environment variables", () => {

test("Should list pending migrations", async () => {
const files = await mig.pending();
expect(files).toEqual({pending: [{filename: jestmig, name: jestmig.replace(/^([0-9]+)_/, ""), ts: parseInt(jestmig.match(/^([0-9]+)_/)[1], 10)}], history: 0});
expect(files).toEqual({last: null, pending: [{filename: jestmig, name: jestmig.replace(/^([0-9]+)_/, ""), ts: parseInt(jestmig.match(/^([0-9]+)_/)[1], 10)}], history: 0});
});

test("Should perform pending migrations", async () => {
Expand All @@ -117,7 +117,7 @@ describe("Migration using environment variables", () => {

test("Should list empty pending migrations with history", async () => {
const files = await mig.pending();
expect(files).toEqual({pending: [], history: 1});
expect(files).toEqual({pending: [], history: 1, last: {name: jestmig.replace(/^([0-9]+)_/, ""), ts: parseInt(jestmig.match(/^([0-9]+)_/)[1], 10)}});
});

test("Should create 4 migration files with SQL", async () => {
Expand Down Expand Up @@ -147,7 +147,7 @@ describe("Migration using environment variables", () => {
ts: parseInt(item.match(/^([0-9]+)_/)[1], 10)
};
});
expect(files).toEqual({pending, history: 1});
expect(files).toEqual({pending, history: 1, last: {name: jestmig.replace(/^([0-9]+)_/, ""), ts: parseInt(jestmig.match(/^([0-9]+)_/)[1], 10)}});
});

test("Should perform 2 pending migrations over 3 steps", async () => {
Expand Down Expand Up @@ -213,7 +213,7 @@ describe("Migration using custom PG database client", () => {

test("Should list empty pending migrations", async () => {
const files = await mig.pending();
expect(files).toEqual({pending: [], history: 0});
expect(files).toEqual({pending: [], history: 0, last: null});
});

test("Should create migration files", async () => {
Expand All @@ -224,7 +224,7 @@ describe("Migration using custom PG database client", () => {

test("Should list pending migrations", async () => {
const files = await mig.pending();
expect(files).toEqual({pending: [{filename: jestmig, name: jestmig.replace(/^([0-9]+)_/, ""), ts: parseInt(jestmig.match(/^([0-9]+)_/)[1], 10)}], history: 0});
expect(files).toEqual({last: null, pending: [{filename: jestmig, name: jestmig.replace(/^([0-9]+)_/, ""), ts: parseInt(jestmig.match(/^([0-9]+)_/)[1], 10)}], history: 0});
});

test("Should perform pending migrations", async () => {
Expand All @@ -236,7 +236,7 @@ describe("Migration using custom PG database client", () => {

test("Should list empty pending migrations with history", async () => {
const files = await mig.pending();
expect(files).toEqual({pending: [], history: 1});
expect(files).toEqual({pending: [], history: 1, last: {name: jestmig.replace(/^([0-9]+)_/, ""), ts: parseInt(jestmig.match(/^([0-9]+)_/)[1], 10)}});
});

test("Should create 4 migration files with SQL", async () => {
Expand Down Expand Up @@ -266,7 +266,7 @@ describe("Migration using custom PG database client", () => {
ts: parseInt(item.match(/^([0-9]+)_/)[1], 10)
};
});
expect(files).toEqual({pending, history: 1});
expect(files).toEqual({pending, history: 1, last: {name: jestmig.replace(/^([0-9]+)_/, ""), ts: parseInt(jestmig.match(/^([0-9]+)_/)[1], 10)}});
});

test("Should perform 2 pending migrations over 3 steps", async () => {
Expand Down Expand Up @@ -334,7 +334,7 @@ describe("Migration using custom Knex database client", () => {

test("Should list empty pending migrations", async () => {
const files = await mig.pending();
expect(files).toEqual({pending: [], history: 0});
expect(files).toEqual({pending: [], history: 0, last: null});
});

test("Should create migration files", async () => {
Expand All @@ -345,7 +345,7 @@ describe("Migration using custom Knex database client", () => {

test("Should list pending migrations", async () => {
const files = await mig.pending();
expect(files).toEqual({pending: [{filename: jestmig, name: jestmig.replace(/^([0-9]+)_/, ""), ts: parseInt(jestmig.match(/^([0-9]+)_/)[1], 10)}], history: 0});
expect(files).toEqual({last: null, pending: [{filename: jestmig, name: jestmig.replace(/^([0-9]+)_/, ""), ts: parseInt(jestmig.match(/^([0-9]+)_/)[1], 10)}], history: 0});
});

test("Should perform pending migrations", async () => {
Expand All @@ -357,7 +357,7 @@ describe("Migration using custom Knex database client", () => {

test("Should list empty pending migrations with history", async () => {
const files = await mig.pending();
expect(files).toEqual({pending: [], history: 1});
expect(files).toEqual({pending: [], history: 1, last: {name: jestmig.replace(/^([0-9]+)_/, ""), ts: parseInt(jestmig.match(/^([0-9]+)_/)[1], 10)}});
});

test("Should create 4 migration files with SQL", async () => {
Expand Down Expand Up @@ -387,7 +387,7 @@ describe("Migration using custom Knex database client", () => {
ts: parseInt(item.match(/^([0-9]+)_/)[1], 10)
};
});
expect(files).toEqual({pending, history: 1});
expect(files).toEqual({pending, history: 1, last: {name: jestmig.replace(/^([0-9]+)_/, ""), ts: parseInt(jestmig.match(/^([0-9]+)_/)[1], 10)}});
});

test("Should perform 2 pending migrations over 3 steps", async () => {
Expand Down Expand Up @@ -448,7 +448,7 @@ describe("Migration using default database client with connection parameters", (

test("Should list empty pending migrations", async () => {
const files = await mig.pending();
expect(files).toEqual({pending: [], history: 0});
expect(files).toEqual({pending: [], history: 0, last: null});
});

test("Should create migration files", async () => {
Expand All @@ -459,7 +459,7 @@ describe("Migration using default database client with connection parameters", (

test("Should list pending migrations", async () => {
const files = await mig.pending();
expect(files).toEqual({pending: [{filename: jestmig, name: jestmig.replace(/^([0-9]+)_/, ""), ts: parseInt(jestmig.match(/^([0-9]+)_/)[1], 10)}], history: 0});
expect(files).toEqual({last: null, pending: [{filename: jestmig, name: jestmig.replace(/^([0-9]+)_/, ""), ts: parseInt(jestmig.match(/^([0-9]+)_/)[1], 10)}], history: 0});
});

test("Should perform pending migrations", async () => {
Expand All @@ -471,7 +471,7 @@ describe("Migration using default database client with connection parameters", (

test("Should list empty pending migrations with history", async () => {
const files = await mig.pending();
expect(files).toEqual({pending: [], history: 1});
expect(files).toEqual({pending: [], history: 1, last: {name: jestmig.replace(/^([0-9]+)_/, ""), ts: parseInt(jestmig.match(/^([0-9]+)_/)[1], 10)}});
});

test("Should create 4 migration files with SQL", async () => {
Expand Down Expand Up @@ -501,7 +501,7 @@ describe("Migration using default database client with connection parameters", (
ts: parseInt(item.match(/^([0-9]+)_/)[1], 10)
};
});
expect(files).toEqual({pending, history: 1});
expect(files).toEqual({pending, history: 1, last: {name: jestmig.replace(/^([0-9]+)_/, ""), ts: parseInt(jestmig.match(/^([0-9]+)_/)[1], 10)}});
});

test("Should perform 2 pending migrations over 3 steps", async () => {
Expand Down