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

CLI: adds support for asynchronous knexfile loading #3748

Merged
merged 3 commits into from Mar 24, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
39 changes: 23 additions & 16 deletions bin/cli.js
Expand Up @@ -28,9 +28,14 @@ const fsPromised = {
writeFile: promisify(fs.writeFile),
};

function openKnexfile(configPath) {
const config = require(configPath);

async function openKnexfile(configPath) {
let config = require(configPath);
if (typeof config === 'function') {
config = config();
}
if (config instanceof Promise) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is redundant, you can simply await config() and if it's not a promise, it will just return the value.

config = await config;
}
// FYI: By default, the extension for the migration files is inferred
// from the knexfile's extension. So, the following lines are in
// place for backwards compatibility purposes.
Expand All @@ -39,7 +44,7 @@ function openKnexfile(configPath) {
return config;
}

function initKnex(env, opts) {
async function initKnex(env, opts) {
checkLocalModule(env);
if (process.cwd() !== env.cwd) {
process.chdir(env.cwd);
Expand All @@ -55,7 +60,7 @@ function initKnex(env, opts) {
}

env.configuration = env.configPath
? openKnexfile(env.configPath)
? await openKnexfile(env.configPath)
: mkConfigObj(opts);

const resolvedConfig = resolveEnvironmentConfig(opts, env.configuration);
Expand Down Expand Up @@ -145,10 +150,10 @@ function invoke(env) {
`--stub [<relative/path/from/knexfile>|<name>]`,
'Specify the migration stub to use. If using <name> the file must be located in config.migrations.directory'
)
.action((name) => {
.action(async (name) => {
const opts = commander.opts();
opts.client = opts.client || 'sqlite3'; // We don't really care about client when creating migrations
const instance = initKnex(env, opts);
const instance = await initKnex(env, opts);
const ext = getMigrationExtension(env, opts);
const configOverrides = { extension: ext };

Expand All @@ -171,7 +176,7 @@ function invoke(env) {
.option('--verbose', 'verbose')
.action(() => {
pending = initKnex(env, commander.opts())
.migrate.latest()
.then((instance) => instance.migrate.latest())
.then(([batchNo, log]) => {
if (log.length === 0) {
success(color.cyan('Already up to date'));
Expand All @@ -191,7 +196,7 @@ function invoke(env) {
)
.action((name) => {
pending = initKnex(env, commander.opts())
.migrate.up({ name })
.then((instance) => instance.migrate.up({ name }))
.then(([batchNo, log]) => {
if (log.length === 0) {
success(color.cyan('Already up to date'));
Expand All @@ -217,7 +222,7 @@ function invoke(env) {
const { all } = cmd;

pending = initKnex(env, commander.opts())
.migrate.rollback(null, all)
.then((instance) => instance.migrate.rollback(null, all))
.then(([batchNo, log]) => {
if (log.length === 0) {
success(color.cyan('Already at the base migration'));
Expand All @@ -238,7 +243,7 @@ function invoke(env) {
)
.action((name) => {
pending = initKnex(env, commander.opts())
.migrate.down({ name })
.then((instance) => instance.migrate.down({ name }))
.then(([batchNo, log]) => {
if (log.length === 0) {
success(color.cyan('Already at the base migration'));
Expand All @@ -260,7 +265,7 @@ function invoke(env) {
.description(' View the current version for the migration.')
.action(() => {
pending = initKnex(env, commander.opts())
.migrate.currentVersion()
.then((instance) => instance.migrate.currentVersion())
.then((version) => {
success(color.green('Current Version: ') + color.blue(version));
})
Expand All @@ -273,7 +278,9 @@ function invoke(env) {
.description(' List all migrations files with status.')
.action(() => {
pending = initKnex(env, commander.opts())
.migrate.list()
.then((instance) => {
return instance.migrate.list();
})
.then(([completed, newMigrations]) => {
listMigrations(completed, newMigrations);
})
Expand All @@ -291,10 +298,10 @@ function invoke(env) {
`--stub [<relative/path/from/knexfile>|<name>]`,
'Specify the seed stub to use. If using <name> the file must be located in config.seeds.directory'
)
.action((name) => {
.action(async (name) => {
const opts = commander.opts();
opts.client = opts.client || 'sqlite3'; // We don't really care about client when creating seeds
const instance = initKnex(env, opts);
const instance = await initKnex(env, opts);
const ext = getSeedExtension(env, opts);
const configOverrides = { extension: ext };
const stub = getStubPath('seeds', env, opts);
Expand All @@ -317,7 +324,7 @@ function invoke(env) {
.option('--specific', 'run specific seed file')
.action(() => {
pending = initKnex(env, commander.opts())
.seed.run({ specific: argv.specific })
.then((instance) => instance.seed.run({ specific: argv.specific }))
.then(([log]) => {
if (log.length === 0) {
success(color.cyan('No seed files exist'));
Expand Down
27 changes: 27 additions & 0 deletions test/cli/knexfile-test.spec.js
Expand Up @@ -65,6 +65,33 @@ module.exports = {
);
});

it('Run migrations with knexfile returning function passed', () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also add same tests for seeder execution? Ideally the two should work symmetrically.

return execCommand(
`node ${KNEX} migrate:latest --knexfile=test/jake-util/knexfile/knexfile_func.js --knexpath=../knex.js`,
{
expectedOutput: 'Batch 1 run: 1 migrations',
}
);
});

it('Run migrations with knexfile with async passed', () => {
return execCommand(
`node ${KNEX} migrate:latest --knexfile=test/jake-util/knexfile/knexfile_async.js --knexpath=../knex.js`,
{
expectedOutput: 'Batch 1 run: 1 migrations',
}
);
});

it('Run migrations with knexfile with promise passed', () => {
return execCommand(
`node ${KNEX} migrate:latest --knexfile=test/jake-util/knexfile/knexfile_promise.js --knexpath=../knex.js`,
{
expectedOutput: 'Batch 1 run: 1 migrations',
}
);
});

it("changes the process's cwd to the directory that contains the knexfile", () => {
const knexfile = 'test/jake-util/knexfile-relative/knexfile.js';
const expectedCWD = tildify(path.resolve(path.dirname(knexfile)));
Expand Down
12 changes: 12 additions & 0 deletions test/jake-util/knexfile/knexfile_async.js
@@ -0,0 +1,12 @@
module.exports = async () => ({
client: 'sqlite3',
connection: {
filename: __dirname + '/../test.sqlite3',
},
migrations: {
directory: __dirname + '/../knexfile_migrations',
},
seeds: {
directory: __dirname + '/../knexfile_seeds',
},
});
12 changes: 12 additions & 0 deletions test/jake-util/knexfile/knexfile_func.js
@@ -0,0 +1,12 @@
module.exports = () => ({
client: 'sqlite3',
connection: {
filename: __dirname + '/../test.sqlite3',
},
migrations: {
directory: __dirname + '/../knexfile_migrations',
},
seeds: {
directory: __dirname + '/../knexfile_seeds',
},
});
12 changes: 12 additions & 0 deletions test/jake-util/knexfile/knexfile_promise.js
@@ -0,0 +1,12 @@
module.exports = Promise.resolve({
client: 'sqlite3',
connection: {
filename: __dirname + '/../test.sqlite3',
},
migrations: {
directory: __dirname + '/../knexfile_migrations',
},
seeds: {
directory: __dirname + '/../knexfile_seeds',
},
});