diff --git a/.gitignore b/.gitignore index 2f9917b9..9291863c 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,7 @@ node_modules .lock-wscript test/tmp +test/tmp2 + +# User's IDE data +.vscode diff --git a/index.js b/index.js index de5bea4e..09b3d96d 100644 --- a/index.js +++ b/index.js @@ -55,13 +55,24 @@ var Umzug = module.exports = redefine.Class(/** @lends Umzug.prototype */ { throw new Error('The logging-option should be either a function or false'); } + let defaultPattern = /^\d+[\w-]+\.js$/ + this.options.migrations = _.assign({ params: [], path: path.resolve(process.cwd(), 'migrations'), - pattern: /^\d+[\w-]+\.js$/, + pattern: defaultPattern, wrap: function (fun) { return fun; } }, this.options.migrations); + // this ensures that the default pattern is used when pattern is undefined, but multiple paths are defined + let patternArr = _.flatten([this.options.migrations.pattern]) + let pathArr = _.flatten([this.options.migrations.path]) + if(patternArr.length < pathArr.length) { + this.options.migrations.pattern = patternArr.concat( + _().range(pathArr.length-patternArr.length).fill(defaultPattern).value() + ) + } + this.storage = this._initStorage(); EventEmitter.call(this); @@ -412,14 +423,24 @@ var Umzug = module.exports = redefine.Class(/** @lends Umzug.prototype */ { * @private */ _findMigrations: function () { - return Bluebird - .promisify(fs.readdir)(this.options.migrations.path) + let readDirP = Bluebird.promisify(fs.readdir); + let paths = _.flatten([this.options.migrations.path]) + let patterns = _.flatten([this.options.migrations.pattern]) + return Bluebird.resolve( + paths // ensures always an [] + ).reduce((fileAccumulator, currentPath) => { + return readDirP(currentPath).then((files) => { + let pathFiles = files.map(file => [currentPath, file]) + return fileAccumulator.concat(pathFiles) + }) + }, []) .bind(this) - .filter(function (file) { - return this.options.migrations.pattern.test(file); + .filter(function (pathFile) { + return patterns[paths.indexOf(pathFile[0])] // choose the pattern that relates to the source of this file + .test(pathFile[1]); // regex test }) - .map(function (file) { - return path.resolve(this.options.migrations.path, file); + .map(function (pathFile) { + return path.resolve(pathFile[0], pathFile[1]); }) .map(function (path) { return new Migration(path, this.options); diff --git a/package.json b/package.json index d4d7ddf0..09ae8a0d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "umzug", - "version": "1.11.0", + "version": "1.11.2", "description": "Framework agnostic migration tool for Node.JS", "main": "index.js", "dependencies": { diff --git a/test/helper.js b/test/helper.js index a06e0a5d..97bb3b19 100644 --- a/test/helper.js +++ b/test/helper.js @@ -5,12 +5,13 @@ var Bluebird = require('bluebird'); var fs = require('fs'); var helper = module.exports = { - clearTmp: function () { - var files = fs.readdirSync(__dirname + '/tmp'); - + clearTmp: function (tmpNum) { + tmpNum = tmpNum || '' + var files = fs.readdirSync(__dirname + `/tmp${tmpNum}`); + files.forEach(function (file) { - if (file.match(/\.(js|json|sqlite)$/)) { - fs.unlinkSync(__dirname + '/tmp/' + file); + if (file.match(/\.(js|json|sqlite|coffee)$/)) { + fs.unlinkSync(__dirname + `/tmp${tmpNum}/` + file); } }); }, @@ -41,6 +42,7 @@ var helper = module.exports = { var num = 0; helper.clearTmp(); + helper.clearTmp(2); _.times(count, function (i) { num++; diff --git a/test/index/constructor.test.js b/test/index/constructor.test.js index c7d9c2b8..2506e93e 100644 --- a/test/index/constructor.test.js +++ b/test/index/constructor.test.js @@ -3,6 +3,7 @@ var expect = require('expect.js'); var Umzug = require('../../index'); var sinon = require('sinon'); +var helper = require('../helper'); describe('constructor', function () { it('exposes some methods', function () { @@ -39,4 +40,69 @@ describe('constructor', function () { umzug.log(); expect(spy.called).to.be(true); }); + + it('can accept multiple directories for migrations', function() { + let umzug; + return helper.prepareMigrations(2, { names: ['1111-migration', '../tmp2/234-migration'] }) + .then(() => { + umzug = new Umzug({ + migrations: { path: [__dirname + '/../tmp/', __dirname + '/../tmp2/'] }, + storageOptions: { path: __dirname + '/../tmp/umzug.json' }, + logging: this.logSpy + }); + return umzug._findMigrations() + }).then((migrationsFound) => { + expect(migrationsFound.length).to.be(2) + }) + }) + + it('can accept multiple directories and patterns for migrations', function() { + let umzug; + return helper.prepareMigrations(5, { names: [ + '1111-foo-migration', + '1111-bar-migration', + '../tmp2/234-foo-migration', + '../tmp2/2345-bar-migration', + '../tmp2/23456-zar-migration' + ] }) + .then(() => { + umzug = new Umzug({ + migrations: { + path: [__dirname + '/../tmp/', __dirname + '/../tmp2/'], + pattern: [/^.*\.js$/, /-foo-|-zar-/] + }, + storageOptions: { path: __dirname + '/../tmp/umzug.json' }, + logging: this.logSpy + }); + return umzug._findMigrations() + }).then((migrationsFound) => { + expect(migrationsFound.length).to.be(4) + }) + }) + + it('can use defaults for multiple directories and patterns for migrations', function() { + let umzug; + return helper.prepareMigrations(6, { names: [ + '1111-foo-migration', + '1211-bar-migration', + '1311-to-foo-migration', + '../tmp2/234-foo-migration', + '../tmp2/2345-bar-migration', + '../tmp2/23456-zar-migration' + ] }) + .then(() => { + umzug = new Umzug({ + migrations: { + path: [__dirname + '/../tmp/', __dirname + '/../tmp2/'], + pattern: [/-foo-/] + }, + storageOptions: { path: __dirname + '/../tmp/umzug.json' }, + logging: this.logSpy + }); + return umzug._findMigrations() + }).then((migrationsFound) => { + expect(migrationsFound.length).to.be(5) + }) + }) + }); diff --git a/test/tmp2/.gitkeep b/test/tmp2/.gitkeep new file mode 100644 index 00000000..e69de29b