UNPKG

3.25 kBPlain TextView Raw
1import * as assert from 'assert';
2import * as path from 'path';
3import { spinner, Command, Project, unwrap } from 'denali-cli';
4import * as tryRequire from 'try-require';
5import * as cmdExists from 'command-exists';
6import * as Bluebird from 'bluebird';
7import { exec } from 'child_process';
8
9const run = Bluebird.promisify<string, string>(exec);
10const commandExists = Bluebird.promisify<boolean, string>(cmdExists);
11
12/**
13 * Run migrations to update your database schema
14 *
15 * @package commands
16 */
17export default class MigrateCommand extends Command {
18
19 /* tslint:disable:completed-docs typedef */
20 static commandName = 'migrate';
21 static description = 'Run migrations to update your database schema';
22 static longDescription = unwrap`
23 Runs (or rolls back) schema migrations for your database. Typically only
24 applies when use SQL-based databases.`;
25
26 static flags = {
27 environment: {
28 description: 'The target environment to build for.',
29 default: process.env.NODE_ENV || 'development',
30 type: <any>'string'
31 },
32 rollback: {
33 description: 'Rollback the latest migration, or latest --step migrations. Defaults to 1 step.',
34 default: false,
35 type: <any>'boolean'
36 },
37 redo: {
38 description: 'Shortcut for rolling back then migrating up again. If used with --step, it will replay that many migrations. If used with --version, it will roll back to that version then replay. If neither, defaults to --step 1',
39 default: false,
40 type: <any>'boolean'
41 }
42 };
43
44 static runsInApp = true;
45
46 async run(argv: any) {
47 let knex = tryRequire('knex');
48 if (!knex) {
49 await spinner.start('Installing knex (required for migrations)');
50 let yarnExists = await commandExists('yarn');
51 if (yarnExists) {
52 await run('yarn add knex --mutex network');
53 } else {
54 await run('npm install --save knex');
55 }
56 knex = require('knex');
57 await spinner.succeed('Knex installed');
58 }
59 let project = new Project({
60 environment: argv.environment,
61 buildDummy: true
62 });
63 let application = await project.createApplication();
64 assert(application.config.migrations && application.config.migrations.db, 'DB connection info is missing. You must supply the knex connection info in config.migrations.db.');
65 let db = knex(application.config.migrations.db);
66 let migrationsDir = path.join(application.dir, 'config', 'migrations');
67 try {
68 if (argv.rollback) {
69 await spinner.start('Rolling back last migration');
70 await db.migrate.rollback({ directory: migrationsDir });
71 } else if (argv.redo) {
72 await spinner.start('Rolling back and replaying last migration');
73 await db.migrate.rollback({ directory: migrationsDir });
74 await db.migrate.latest({ directory: migrationsDir });
75 } else {
76 await spinner.start('Running migrations to latest');
77 await db.migrate.latest({ directory: migrationsDir });
78 }
79 let newVersion = await db.migrate.currentVersion();
80 await spinner.succeed(`Migrated to ${ newVersion }`);
81 } catch (error) {
82 await spinner.fail(`Migrations failed:\n${ error.stack }`);
83 } finally {
84 await db.destroy();
85 }
86 }
87
88}