From 55f8b65059f014f0c6d3427406e677589b19f565 Mon Sep 17 00:00:00 2001 From: Miguel Bautista Date: Sun, 10 Sep 2017 22:30:38 -0400 Subject: [PATCH] Migrated to support latest updates --- src/index.js | 57 ++++++++++++++++---------- test/Umzug/down.test.js | 79 +++++++++++++++++++++++++------------ test/Umzug/executed.test.js | 55 ++++++++++++++++++-------- test/Umzug/pending.test.js | 55 ++++++++++++++++++-------- test/Umzug/up.test.js | 79 +++++++++++++++++++++++++------------ test/helper.js | 36 ++++++++++++++--- 6 files changed, 248 insertions(+), 113 deletions(-) diff --git a/src/index.js b/src/index.js index 5a9ff4b3..93974ae2 100644 --- a/src/index.js +++ b/src/index.js @@ -62,6 +62,7 @@ module.exports = class Umzug extends EventEmitter { params: [], path: path.resolve(process.cwd(), 'migrations'), pattern: /^\d+[\w-]+\.js$/, + traverseDirectories: false, wrap: fun => fun, ...this.options.migrations, }; @@ -436,33 +437,47 @@ module.exports = class Umzug extends EventEmitter { * @returns {Promise.} * @private */ - _findMigrations () { + _findMigrations (migrationPath) { + let isRoot = !migrationPath; + if (isRoot) { + migrationPath = this.options.migrations.path; + } return Bluebird - .promisify(fs.readdir)(this.options.migrations.path) + .promisify(fs.readdir)(migrationPath) .bind(this) - .filter(function (file) { - if (!this.options.migrations.pattern.test(file)) { - this.log('File: ' + file + ' does not match pattern: ' + this.options.migrations.pattern); - return false; - } - return true; - }) .map(function (file) { - return path.resolve(this.options.migrations.path, file); + let filePath = path.resolve(migrationPath, file); + if (this.options.migrations.traverseDirectories) { + if (fs.lstatSync(filePath).isDirectory()) { + return this._findMigrations(filePath) + .then(function (migrations) { + return migrations; + }); + } + } + if (this.options.migrations.pattern.test(file)) { + return new Migration(filePath, this.options); + } + this.log('File: ' + file + ' does not match pattern: ' + this.options.migrations.pattern); + return file; }) - .map(function (path) { - return new Migration(path, this.options); + .reduce(function (a, b) { return a.concat(b); }, []) // flatten the result to an array + .filter(function (file) { + return file instanceof Migration; // only care about Migration }) .then(function (migrations) { - return migrations.sort(function (a, b) { - if (a.file > b.file) { - return 1; - } else if (a.file < b.file) { - return -1; - } else { - return 0; - } - }); + if (isRoot) { // only sort if its root + return migrations.sort(function (a, b) { + if (a.file > b.file) { + return 1; + } else if (a.file < b.file) { + return -1; + } else { + return 0; + } + }); + } + return migrations; }); } diff --git a/test/Umzug/down.test.js b/test/Umzug/down.test.js index 3492b36d..54a03527 100644 --- a/test/Umzug/down.test.js +++ b/test/Umzug/down.test.js @@ -1,22 +1,9 @@ -import { expect } from 'chai'; +import {expect} from 'chai'; import helper from '../helper'; import Umzug from '../../src/index'; import {join} from 'path'; -describe('down', function () { - beforeEach(function () { - helper.clearTmp(); - return helper - .prepareMigrations(3) - .then((migrationNames) => { - this.migrationNames = migrationNames; - this.umzug = new Umzug({ - migrations: { path: join(__dirname, '/../tmp/') }, - storageOptions: { path: join(__dirname, '/../tmp/umzug.json') }, - }); - }); - }); - +let downTestSuite = function downTestSuite () { describe('when no migrations has been executed yet', function () { beforeEach(function () { return this.umzug.down().then((migrations) => { @@ -36,7 +23,7 @@ describe('down', function () { describe('when a migration has been executed already', function () { beforeEach(function () { return this.umzug.execute({ - migrations: [ this.migrationNames[0] ], + migrations: [this.migrationNames[0]], method: 'up', }).then(() => { return this.umzug.executed(); @@ -155,7 +142,7 @@ describe('down', function () { describe('that does not match a migration', function () { it('rejects the promise', function () { - return this.umzug.down({ to: '123-asdasd' }).then(() => { + return this.umzug.down({to: '123-asdasd'}).then(() => { return Promise.reject(new Error('We should not end up here...')); }, (err) => { expect(err.message).to.equal('Unable to find migration: 123-asdasd'); @@ -166,9 +153,9 @@ describe('down', function () { describe('that does not match an executed migration', function () { it('rejects the promise', function () { return this.umzug - .execute({ migrations: this.migrationNames, method: 'down' }) + .execute({migrations: this.migrationNames, method: 'down'}) .then(() => { - return this.umzug.down({ to: this.migrationNames[1] }); + return this.umzug.down({to: this.migrationNames[1]}); }) .then(() => { return Promise.reject(new Error('We should not end up here...')); @@ -191,7 +178,9 @@ describe('down', function () { describe('that matches an executed migration', function () { beforeEach(function () { return this.umzug.down(this.migrationNames[1]) - .then((migrations) => { this.migrations = migrations; }); + .then((migrations) => { + this.migrations = migrations; + }); }); it('returns only 1 migrations', function () { @@ -220,7 +209,7 @@ describe('down', function () { describe('that does not match an executed migration', function () { it('rejects the promise', function () { return this.umzug - .execute({ migrations: this.migrationNames, method: 'down' }) + .execute({migrations: this.migrationNames, method: 'down'}) .then(() => { return this.umzug.down(this.migrationNames[1]); }) @@ -244,7 +233,9 @@ describe('down', function () { describe('that matches an executed migration', function () { beforeEach(function () { return this.umzug.down([this.migrationNames[1]]) - .then((migrations) => { this.migrations = migrations; }); + .then((migrations) => { + this.migrations = migrations; + }); }); it('returns only 1 migrations', function () { @@ -263,7 +254,9 @@ describe('down', function () { describe('that matches multiple pending migration', function () { beforeEach(function () { return this.umzug.down(this.migrationNames.slice(1)) - .then((migrations) => { this.migrations = migrations; }); + .then((migrations) => { + this.migrations = migrations; + }); }); it('returns only 2 migrations', function () { @@ -291,7 +284,7 @@ describe('down', function () { describe('that does not match an executed migration', function () { it('rejects the promise', function () { return this.umzug - .execute({ migrations: this.migrationNames, method: 'down' }) + .execute({migrations: this.migrationNames, method: 'down'}) .then(() => { return this.umzug.down([this.migrationNames[1]]); }) @@ -306,7 +299,7 @@ describe('down', function () { describe('that does partially not match an executed migration', function () { it('rejects the promise', function () { return this.umzug - .execute({ migrations: this.migrationNames.slice(0, 2), method: 'down' }) + .execute({migrations: this.migrationNames.slice(0, 2), method: 'down'}) .then(() => { return this.umzug.down(this.migrationNames.slice(1)); }) @@ -323,7 +316,7 @@ describe('down', function () { beforeEach(function () { // a migration has been executed already... return this.umzug.execute({ - migrations: [ this.migrationNames[0] ], + migrations: [this.migrationNames[0]], method: 'up', }).then(() => { return this.umzug.executed(); @@ -350,4 +343,38 @@ describe('down', function () { }); }); }); +}; + +describe('down', function () { + beforeEach(function () { + helper.clearTmp(); + return helper + .prepareMigrations(3) + .then((migrationNames) => { + this.migrationNames = migrationNames; + this.umzug = new Umzug({ + migrations: {path: join(__dirname, '/../tmp/')}, + storageOptions: {path: join(__dirname, '/../tmp/umzug.json')}, + }); + }); + }); + + downTestSuite(); +}); + +describe('down-directories', function () { + beforeEach(function () { + helper.clearTmp(); + return helper + .prepareMigrations(3, {directories: [['1', '2'], ['1', '2'], ['1', '3', '4', '5']]}) + .then((migrationNames) => { + this.migrationNames = migrationNames; + this.umzug = new Umzug({ + migrations: {path: join(__dirname, '/../tmp/'), traverseDirectories: true}, + storageOptions: {path: join(__dirname, '/../tmp/umzug.json')}, + }); + }); + }); + + downTestSuite(); }); diff --git a/test/Umzug/executed.test.js b/test/Umzug/executed.test.js index 68fe6e61..b5f25591 100644 --- a/test/Umzug/executed.test.js +++ b/test/Umzug/executed.test.js @@ -1,22 +1,9 @@ -import { expect } from 'chai'; +import {expect} from 'chai'; import helper from '../helper'; import Umzug from '../../src/index'; import {join} from 'path'; -describe('executed', function () { - beforeEach(function () { - helper.clearTmp(); - return helper - .prepareMigrations(3) - .then((migrationNames) => { - this.migrationNames = migrationNames; - this.umzug = new Umzug({ - migrations: { path: join(__dirname, '/../tmp/') }, - storageOptions: {path: join(__dirname, '/../tmp/umzug.json')}, - }); - }); - }); - +let executedTestSuite = function executedTestSuite () { describe('when no migrations has been executed yet', function () { beforeEach(function () { return this.umzug.executed() @@ -37,7 +24,7 @@ describe('executed', function () { describe('when one migration has been executed yet', function () { beforeEach(function () { return this.umzug.execute({ - migrations: [ this.migrationNames[0] ], + migrations: [this.migrationNames[0]], method: 'up', }).then(() => { return this.umzug.executed(); @@ -84,7 +71,7 @@ describe('executed', function () { beforeEach(function () { // migration has been executed already return this.umzug.execute({ - migrations: [ this.migrationNames[0] ], + migrations: [this.migrationNames[0]], method: 'up', }).then(() => { this.umzug.storage = helper.wrapStorageAsCustomThenable(this.umzug.storage); @@ -103,4 +90,38 @@ describe('executed', function () { expect(this.migrations[0].file).to.equal(this.migrationNames[0] + '.js'); }); }); +}; + +describe('executed', function () { + beforeEach(function () { + helper.clearTmp(); + return helper + .prepareMigrations(3) + .then((migrationNames) => { + this.migrationNames = migrationNames; + this.umzug = new Umzug({ + migrations: {path: join(__dirname, '/../tmp/')}, + storageOptions: {path: join(__dirname, '/../tmp/umzug.json')}, + }); + }); + }); + + executedTestSuite(); +}); + +describe('executed-directories', function () { + beforeEach(function () { + helper.clearTmp(); + return helper + .prepareMigrations(3, {directories: [['1', '2'], ['1', '2'], ['1', '3', '4', '5']]}) + .then((migrationNames) => { + this.migrationNames = migrationNames; + this.umzug = new Umzug({ + migrations: {path: join(__dirname, '/../tmp/'), traverseDirectories: true}, + storageOptions: {path: join(__dirname, '/../tmp/umzug.json')}, + }); + }); + }); + + executedTestSuite(); }); diff --git a/test/Umzug/pending.test.js b/test/Umzug/pending.test.js index 1663293e..40606020 100644 --- a/test/Umzug/pending.test.js +++ b/test/Umzug/pending.test.js @@ -1,23 +1,10 @@ -import { expect } from 'chai'; +import {expect} from 'chai'; import helper from '../helper'; import Migration from '../../src/migration'; import Umzug from '../../src/index'; import {join} from 'path'; -describe('pending', function () { - beforeEach(function () { - helper.clearTmp(); - return helper - .prepareMigrations(3) - .then((migrationNames) => { - this.migrationNames = migrationNames; - this.umzug = new Umzug({ - migrations: {path: join(__dirname, '/../tmp/')}, - storageOptions: {path: join(__dirname, '/../tmp/umzug.json')}, - }); - }); - }); - +let pendingTestSuite = function pendingTestSuite () { describe('when no migrations has been executed yet', function () { beforeEach(function () { return this.umzug.pending().then((migrations) => { @@ -43,7 +30,7 @@ describe('pending', function () { describe('when a migration has been executed already', function () { beforeEach(function () { return this.umzug.execute({ - migrations: [ this.migrationNames[0] ], + migrations: [this.migrationNames[0]], method: 'up', }).then(() => { return this.umzug.pending(); @@ -69,7 +56,7 @@ describe('pending', function () { beforeEach(function () { // a migration has been executed already return this.umzug.execute({ - migrations: [ this.migrationNames[0] ], + migrations: [this.migrationNames[0]], method: 'up', }).then(() => { // storage returns a thenable @@ -93,4 +80,38 @@ describe('pending', function () { }); }); }); +}; + +describe('pending', function () { + beforeEach(function () { + helper.clearTmp(); + return helper + .prepareMigrations(3) + .then((migrationNames) => { + this.migrationNames = migrationNames; + this.umzug = new Umzug({ + migrations: {path: join(__dirname, '/../tmp/')}, + storageOptions: {path: join(__dirname, '/../tmp/umzug.json')}, + }); + }); + }); + + pendingTestSuite(); +}); + +describe('pending-directories', function () { + beforeEach(function () { + helper.clearTmp(); + return helper + .prepareMigrations(3, {directories: [['1', '2'], ['1', '2'], ['1', '3', '4', '5']]}) + .then((migrationNames) => { + this.migrationNames = migrationNames; + this.umzug = new Umzug({ + migrations: {path: join(__dirname, '/../tmp/'), traverseDirectories: true}, + storageOptions: {path: join(__dirname, '/../tmp/umzug.json')}, + }); + }); + }); + + pendingTestSuite(); }); diff --git a/test/Umzug/up.test.js b/test/Umzug/up.test.js index ab6c1f92..7708fbfe 100644 --- a/test/Umzug/up.test.js +++ b/test/Umzug/up.test.js @@ -1,23 +1,10 @@ -import { expect } from 'chai'; +import {expect} from 'chai'; import helper from '../helper'; import Migration from '../../src/migration'; import Umzug from '../../src'; import {join} from 'path'; -describe('up', function () { - beforeEach(function () { - helper.clearTmp(); - return helper - .prepareMigrations(3) - .then((migrationNames) => { - this.migrationNames = migrationNames; - this.umzug = new Umzug({ - migrations: {path: join(__dirname, '/../tmp/')}, - storageOptions: {path: join(__dirname, '/../tmp/umzug.json')}, - }); - }); - }); - +let upTestuite = function upTestuite () { describe('when no migrations has been executed yet', function () { beforeEach(function () { return this.umzug.up().then((migrations) => { @@ -43,7 +30,7 @@ describe('up', function () { describe('when a migration has been executed already', function () { beforeEach(function () { return this.umzug.execute({ - migrations: [ this.migrationNames[0] ], + migrations: [this.migrationNames[0]], method: 'up', }).then(() => { return this.umzug.up(); @@ -120,7 +107,7 @@ describe('up', function () { describe('that does not match a migration', function () { it('rejects the promise', function () { - return this.umzug.up({ to: '123-asdasd' }).then(() => { + return this.umzug.up({to: '123-asdasd'}).then(() => { return Promise.reject(new Error('We should not end up here...')); }, (err) => { expect(err.message).to.equal('Unable to find migration: 123-asdasd'); @@ -131,9 +118,9 @@ describe('up', function () { describe('that does not match a pending migration', function () { it('rejects the promise', function () { return this.umzug - .execute({ migrations: this.migrationNames, method: 'up' }) + .execute({migrations: this.migrationNames, method: 'up'}) .then(() => { - return this.umzug.up({ to: this.migrationNames[1] }); + return this.umzug.up({to: this.migrationNames[1]}); }) .then(() => { return Promise.reject(new Error('We should not end up here...')); @@ -148,7 +135,9 @@ describe('up', function () { describe('that matches a pending migration', function () { beforeEach(function () { return this.umzug.up(this.migrationNames[1]) - .then((migrations) => { this.migrations = migrations; }); + .then((migrations) => { + this.migrations = migrations; + }); }); it('returns only 1 migrations', function () { @@ -176,7 +165,7 @@ describe('up', function () { describe('that does not match a pending migration', function () { it('rejects the promise', function () { return this.umzug - .execute({ migrations: this.migrationNames, method: 'up' }) + .execute({migrations: this.migrationNames, method: 'up'}) .then(() => { return this.umzug.up(this.migrationNames[1]); }) @@ -193,7 +182,9 @@ describe('up', function () { describe('that matches a pending migration', function () { beforeEach(function () { return this.umzug.up([this.migrationNames[1]]) - .then((migrations) => { this.migrations = migrations; }); + .then((migrations) => { + this.migrations = migrations; + }); }); it('returns only 1 migrations', function () { @@ -211,7 +202,9 @@ describe('up', function () { describe('that matches multiple pending migration', function () { beforeEach(function () { return this.umzug.up(this.migrationNames.slice(1)) - .then((migrations) => { this.migrations = migrations; }); + .then((migrations) => { + this.migrations = migrations; + }); }); it('returns only 2 migrations', function () { @@ -240,7 +233,7 @@ describe('up', function () { describe('that does not match a pending migration', function () { it('rejects the promise', function () { return this.umzug - .execute({ migrations: this.migrationNames, method: 'up' }) + .execute({migrations: this.migrationNames, method: 'up'}) .then(() => { return this.umzug.up([this.migrationNames[1]]); }) @@ -255,7 +248,7 @@ describe('up', function () { describe('that does partially not match a pending migration', function () { it('rejects the promise', function () { return this.umzug - .execute({ migrations: this.migrationNames.slice(0, 2), method: 'up' }) + .execute({migrations: this.migrationNames.slice(0, 2), method: 'up'}) .then(() => { return this.umzug.up(this.migrationNames.slice(1)); }) @@ -272,7 +265,7 @@ describe('up', function () { beforeEach(function () { // one migration has been executed already return this.umzug.execute({ - migrations: [ this.migrationNames[0] ], + migrations: [this.migrationNames[0]], method: 'up', }).then(() => { // storage returns a thenable @@ -302,4 +295,38 @@ describe('up', function () { }); }); }); +}; + +describe('up', function () { + beforeEach(function () { + helper.clearTmp(); + return helper + .prepareMigrations(3) + .then((migrationNames) => { + this.migrationNames = migrationNames; + this.umzug = new Umzug({ + migrations: {path: join(__dirname, '/../tmp/')}, + storageOptions: {path: join(__dirname, '/../tmp/umzug.json')}, + }); + }); + }); + + upTestuite(); +}); + +describe('up-directories', function () { + beforeEach(function () { + helper.clearTmp(); + return helper + .prepareMigrations(3, {directories: [['1', '2'], ['1', '2'], ['1', '3', '4', '5']]}) + .then((migrationNames) => { + this.migrationNames = migrationNames; + this.umzug = new Umzug({ + migrations: {path: join(__dirname, '/../tmp/'), traverseDirectories: true}, + storageOptions: {path: join(__dirname, '/../tmp/umzug.json')}, + }); + }); + }); + + upTestuite(); }); diff --git a/test/helper.js b/test/helper.js index db541083..bd226b7b 100644 --- a/test/helper.js +++ b/test/helper.js @@ -3,19 +3,39 @@ import fs from 'fs'; import {join} from 'path'; const helper = module.exports = { - clearTmp () { - let files = fs.readdirSync(join(__dirname, '/tmp')); + clearTmp (path) { + let tmpPath = join(__dirname, '/tmp'); + path = path || tmpPath; + let files = fs.readdirSync(path); files.forEach((file) => { + let filePath = join(path, '/' + file); if (file.match(/\.(js|json|sqlite|coffee)$/)) { - fs.unlinkSync(join(__dirname, '/tmp/', file)); + fs.unlinkSync(filePath); + } else if (fs.lstatSync(filePath).isDirectory()) { + helper.clearTmp(filePath); } }); + if (path !== tmpPath) { + fs.rmdirSync(path); + } }, - generateDummyMigration (name) { + generateDummyMigration: function (name, subDirectories) { + let path = join(__dirname, '/tmp/'); + if (subDirectories) { + if (!_.isArray(subDirectories)) { + subDirectories = [subDirectories]; + } + subDirectories.forEach((directory) => { + path = join(path, directory + '/'); + if (!fs.existsSync(path)) { + fs.mkdirSync(path); + } + }); + } fs.writeFileSync( - join(__dirname, '/tmp/' + name + '.js'), + join(path, name + '.js'), [ '\'use strict\';', '', @@ -32,6 +52,10 @@ const helper = module.exports = { prepareMigrations (count, options) { options = { names: [], + directories: [], // can be array of strings or array of array of strings + // example 1: ['foo','bar'] ==> generates /foo and /bar + // example 2: [['foo','bar'],['foo','bar2']] ==> generates /foo/bar and /foo/bar2 + // example 3: ['foo',['foo','bar2']] ==> generates /foo and /foo/bar2 ...options || {}, }; @@ -44,7 +68,7 @@ const helper = module.exports = { _.times(count, (i) => { num++; names.push(options.names[i] || (num + '-migration')); - helper.generateDummyMigration(options.names[i]); + helper.generateDummyMigration(names[i], options.directories[i]); }); resolve(names);