diff --git a/core/server/data/schema/bootup.js b/core/server/data/schema/bootup.js new file mode 100644 index 0000000000..a1154da853 --- /dev/null +++ b/core/server/data/schema/bootup.js @@ -0,0 +1,27 @@ +var Promise = require('bluebird'), + versioning = require('./versioning'), + migrations = require('../migration'), + errors = require('./../../errors'); + +module.exports = function bootUp() { + return versioning + .getDatabaseVersion() + .then(function successHandler(result) { + if (!/^alpha/.test(result)) { + // This database was not created with Ghost alpha, and is not compatible + throw new errors.DatabaseVersion( + 'Your database version is not compatible with Ghost 1.0.0 Alpha (master branch)', + 'Want to keep your DB? Use Ghost < 1.0.0 or the "stable" branch. Otherwise please delete your DB and restart Ghost', + 'More information on the Ghost 1.0.0 Alpha at https://support.ghost.org/v1-0-alpha' + ); + } + }, + // We don't use .catch here, as it would catch the error from the successHandler + function errorHandler(err) { + if (err instanceof errors.DatabaseNotPopulated) { + return migrations.populate(); + } + + return Promise.reject(err); + }); +}; diff --git a/core/server/data/schema/default-settings.json b/core/server/data/schema/default-settings.json index bc953347b2..736576e4bd 100644 --- a/core/server/data/schema/default-settings.json +++ b/core/server/data/schema/default-settings.json @@ -1,7 +1,7 @@ { "core": { "databaseVersion": { - "defaultValue": "008" + "defaultValue": "alpha.1" }, "dbHash": { "defaultValue": null diff --git a/core/server/data/schema/index.js b/core/server/data/schema/index.js index f641d958f3..ade35a3f81 100644 --- a/core/server/data/schema/index.js +++ b/core/server/data/schema/index.js @@ -1,11 +1,6 @@ -var schema = require('./schema'), - checks = require('./checks'), - commands = require('./commands'), - versioning = require('./versioning'), - defaultSettings = require('./default-settings'); - -module.exports.tables = schema; -module.exports.checks = checks; -module.exports.commands = commands; -module.exports.versioning = versioning; -module.exports.defaultSettings = defaultSettings; +module.exports.tables = require('./schema'); +module.exports.checks = require('./checks'); +module.exports.commands = require('./commands'); +module.exports.versioning = require('./versioning'); +module.exports.defaultSettings = require('./default-settings'); +module.exports.bootUp = require('./bootup'); diff --git a/core/server/data/schema/versioning.js b/core/server/data/schema/versioning.js index 71f5605661..57b2a194a0 100644 --- a/core/server/data/schema/versioning.js +++ b/core/server/data/schema/versioning.js @@ -31,10 +31,6 @@ function getDatabaseVersion() { .where('key', 'databaseVersion') .first('value') .then(function (version) { - if (!version || isNaN(version.value)) { - return Promise.reject(new errors.DatabaseVersion(i18n.t('errors.data.versioning.index.dbVersionNotRecognized'))); - } - return version.value; }); } diff --git a/core/server/errors/index.js b/core/server/errors/index.js index c9bed00a39..0b5c16b528 100644 --- a/core/server/errors/index.js +++ b/core/server/errors/index.js @@ -125,7 +125,14 @@ errors = { var self = this, origArgs = _.toArray(arguments).slice(1), stack, - msgs; + msgs, + hideStack = false; + + // DatabaseVersion errors are usually fatal, we output a nice message + // And the stack is not at all useful in this case + if (err instanceof DatabaseVersion) { + hideStack = true; + } if (_.isArray(err)) { _.each(err, function (e) { @@ -172,7 +179,7 @@ errors = { // add a new line msgs.push('\n'); - if (stack) { + if (stack && !hideStack) { msgs.push(stack, '\n'); } diff --git a/core/server/ghost-server.js b/core/server/ghost-server.js index 23f5520012..8d7eb6a427 100644 --- a/core/server/ghost-server.js +++ b/core/server/ghost-server.js @@ -181,11 +181,15 @@ GhostServer.prototype.logStartMessages = function () { // Startup & Shutdown messages if (process.env.NODE_ENV === 'production') { console.log( - chalk.green(i18n.t('notices.httpServer.ghostIsRunningIn', {env: process.env.NODE_ENV})), - i18n.t('notices.httpServer.yourBlogIsAvailableOn', {url: config.get('url')}), + chalk.red('Currently running Ghost 1.0.0 Alpha, this is NOT suitable for production! \n'), + chalk.white('Please switch to the stable branch. \n'), + chalk.white('More information on the Ghost 1.0.0 Alpha at: ') + chalk.cyan('https://support.ghost.org/v1-0-alpha') + '\n', chalk.gray(i18n.t('notices.httpServer.ctrlCToShutDown')) ); } else { + console.log( + chalk.blue('Welcome to the Ghost 1.0.0 Alpha - this version of Ghost is for development only.') + ); console.log( chalk.green(i18n.t('notices.httpServer.ghostIsRunningIn', {env: process.env.NODE_ENV})), i18n.t('notices.httpServer.listeningOn'), diff --git a/core/server/index.js b/core/server/index.js index 38015c6b1f..aab3e9bbbe 100644 --- a/core/server/index.js +++ b/core/server/index.js @@ -21,8 +21,7 @@ var express = require('express'), config = require('./config'), errors = require('./errors'), middleware = require('./middleware'), - migrations = require('./data/migration'), - versioning = require('./data/schema/versioning'), + db = require('./data/schema'), models = require('./models'), permissions = require('./permissions'), apps = require('./apps'), @@ -77,43 +76,8 @@ function init(options) { return api.themes.loadThemes(); }).then(function () { models.init(); - }).then(function () { - return versioning.getDatabaseVersion() - .then(function (currentVersion) { - var response = migrations.update.isDatabaseOutOfDate({ - fromVersion: currentVersion, - toVersion: versioning.getNewestDatabaseVersion(), - forceMigration: process.env.FORCE_MIGRATION - }), maintenanceState; - - if (response.migrate === true) { - maintenanceState = config.get('maintenance').enabled || false; - config.set('maintenance:enabled', true); - - migrations.update.execute({ - fromVersion: currentVersion, - toVersion: versioning.getNewestDatabaseVersion(), - forceMigration: process.env.FORCE_MIGRATION - }).then(function () { - config.set('maintenance:enabled', maintenanceState); - }).catch(function (err) { - if (!err) { - return; - } - - errors.logErrorAndExit(err, err.context, err.help); - }); - } else if (response.error) { - return Promise.reject(response.error); - } - }) - .catch(function (err) { - if (err instanceof errors.DatabaseNotPopulated) { - return migrations.populate(); - } - - return Promise.reject(err); - }); + // @TODO: this is temporary, replace migrations with a warning if a DB exists + return db.bootUp(); }).then(function () { // Populate any missing default settings return models.Settings.populateDefaults(); diff --git a/core/test/unit/migration_spec.js b/core/test/unit/migration_spec.js index 1230173c62..927e855ff7 100644 --- a/core/test/unit/migration_spec.js +++ b/core/test/unit/migration_spec.js @@ -32,7 +32,7 @@ var should = require('should'), // both of which are required for migrations to work properly. describe('DB version integrity', function () { // Only these variables should need updating - var currentDbVersion = '008', + var currentDbVersion = 'alpha.1', currentSchemaHash = 'b3bdae210526b2d4393359c3e45d7f83', currentFixturesHash = '30b0a956b04e634e7f2cddcae8d2fd20'; diff --git a/core/test/unit/server_spec.js b/core/test/unit/server_spec.js index 14ad37ea92..967bc6371e 100644 --- a/core/test/unit/server_spec.js +++ b/core/test/unit/server_spec.js @@ -18,7 +18,8 @@ var should = require('should'), sandbox = sinon.sandbox.create(); describe('server bootstrap', function () { - var middlewareStub, resetMiddlewareStub, initDbHashAndFirstRunStub, resetInitDbHashAndFirstRunStub; + var middlewareStub, resetMiddlewareStub, initDbHashAndFirstRunStub, resetInitDbHashAndFirstRunStub, + populateStub; before(function () { models.init(); @@ -28,7 +29,7 @@ describe('server bootstrap', function () { middlewareStub = sandbox.stub(); initDbHashAndFirstRunStub = sandbox.stub(); - sandbox.stub(migration, 'populate').returns(Promise.resolve()); + populateStub = sandbox.stub(migration, 'populate').returns(Promise.resolve()); sandbox.stub(models.Settings, 'populateDefaults').returns(Promise.resolve()); sandbox.stub(permissions, 'init').returns(Promise.resolve()); sandbox.stub(api, 'init').returns(Promise.resolve()); @@ -69,7 +70,11 @@ describe('server bootstrap', function () { }); }); - it('database does exist: expect no update', function (done) { + // @TODO fix these two tests once we've decided on a new migration + // versioning scheme + // the tests do not work right now because if the version isn't an + // alpha version, we error. I've added two temporary tests to show this. + it.skip('database does exist: expect no update', function (done) { sandbox.stub(migration.update, 'isDatabaseOutOfDate').returns({migrate:false}); sandbox.spy(migration.update, 'execute'); @@ -91,7 +96,7 @@ describe('server bootstrap', function () { }); }); - it('database does exist: expect update', function (done) { + it.skip('database does exist: expect update', function (done) { sandbox.stub(migration.update, 'isDatabaseOutOfDate').returns({migrate:true}); sandbox.stub(migration.update, 'execute').returns(Promise.resolve()); @@ -120,5 +125,44 @@ describe('server bootstrap', function () { done(err); }); }); + + // @TODO remove these temporary tests ;) + it('TEMP: database does exist: expect alpha error', function (done) { + sandbox.stub(migration.update, 'isDatabaseOutOfDate').returns({migrate:false}); + sandbox.spy(migration.update, 'execute'); + + sandbox.stub(versioning, 'getDatabaseVersion', function () { + return Promise.resolve('006'); + }); + + bootstrap() + .then(function () { + done('This should not be called'); + }) + .catch(function (err) { + err.errorType.should.eql('DatabaseVersion'); + err.message.should.eql('Your database version is not compatible with Ghost 1.0.0 Alpha (master branch)'); + done(); + }); + }); + + it('TEMP: database does exist: expect alpha error', function (done) { + sandbox.stub(migration.update, 'isDatabaseOutOfDate').returns({migrate:true}); + sandbox.stub(migration.update, 'execute').returns(Promise.resolve()); + + sandbox.stub(versioning, 'getDatabaseVersion', function () { + return Promise.resolve('006'); + }); + + bootstrap() + .then(function () { + done('This should not be called'); + }) + .catch(function (err) { + err.errorType.should.eql('DatabaseVersion'); + err.message.should.eql('Your database version is not compatible with Ghost 1.0.0 Alpha (master branch)'); + done(); + }); + }); }); }); diff --git a/core/test/unit/versioning_spec.js b/core/test/unit/versioning_spec.js index a8714809d0..ef3993128b 100644 --- a/core/test/unit/versioning_spec.js +++ b/core/test/unit/versioning_spec.js @@ -106,7 +106,11 @@ describe('Versioning', function () { }).catch(done); }); - it('should throw error if version does not exist', function (done) { + // @TODO change this so we handle a non-existent version? + // There is an open bug in Ghost around this: + // https://github.com/TryGhost/Ghost/issues/7345 + // I think it is a timing error + it.skip('should throw error if version does not exist', function (done) { // Setup knexMock.schema.hasTable.returns(new Promise.resolve(true)); queryMock.first.returns(new Promise.resolve()); @@ -128,7 +132,9 @@ describe('Versioning', function () { }).catch(done); }); - it('should throw error if version is not a number', function (done) { + // @TODO decide on a new scheme for database versioning and update + // how we validate those versions + it.skip('should throw error if version is not a number', function (done) { // Setup knexMock.schema.hasTable.returns(new Promise.resolve(true)); queryMock.first.returns(new Promise.resolve('Eyjafjallajökull')); diff --git a/package.json b/package.json index 42a09805da..34cd875e81 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghost", - "version": "0.11.0", + "version": "1.0.0-alpha.0", "description": "Just a blogging platform.", "author": "Ghost Foundation", "homepage": "http://ghost.org",