mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
🐛 re-run migration for sqlite/pg (#7323)
closes #7192 - add 008 migration - added script to re-run 006/01 - re-run 006/01 migration for postgres in any timezone (transform formats only) - re-run 006/01 migration for sqlite (transform formats only) - rely on format checks for sqlite, do not check server TZ
This commit is contained in:
parent
b598656ff1
commit
774a662fb2
4 changed files with 288 additions and 19 deletions
|
@ -39,18 +39,16 @@ module.exports = function transformDatesIntoUTC(options, logger) {
|
|||
return sequence([
|
||||
function databaseCheck() {
|
||||
// we have to change the sqlite format, because it stores dates as integer
|
||||
if (ServerTimezoneOffset === 0 && config.database.client !== 'sqlite3') {
|
||||
if (ServerTimezoneOffset === 0 && config.database.client === 'mysql') {
|
||||
return Promise.reject(new Error('skip'));
|
||||
}
|
||||
|
||||
if (config.database.isPostgreSQL()) {
|
||||
return Promise.reject(new Error('skip'));
|
||||
}
|
||||
|
||||
if (config.database.client === 'sqlite3') {
|
||||
_private.noOffset = true;
|
||||
} else {
|
||||
} else if (config.database.client === 'mysql') {
|
||||
_private.noOffset = false;
|
||||
} else if (config.database.client === 'sqlite3') {
|
||||
_private.noOffset = true;
|
||||
}
|
||||
|
||||
logger.info(messagePrefix + '(could take a while)...');
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
var config = require('../../../../config'),
|
||||
_ = require('lodash'),
|
||||
models = require(config.paths.corePath + '/server/models'),
|
||||
transfomDatesIntoUTC = require(config.paths.corePath + '/server/data/migration/fixtures/006/01-transform-dates-into-utc'),
|
||||
Promise = require('bluebird'),
|
||||
messagePrefix = 'Fix sqlite/pg format: ',
|
||||
_private = {};
|
||||
|
||||
_private.rerunDateMigration = function rerunDateMigration(options, logger) {
|
||||
var settingsMigrations, settingsKey = '006/01';
|
||||
|
||||
return models.Settings.findOne({key: 'migrations'}, options)
|
||||
.then(function removeMigrationSettings(result) {
|
||||
try {
|
||||
settingsMigrations = JSON.parse(result.attributes.value) || {};
|
||||
} catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
|
||||
// CASE: migration ran already
|
||||
if (settingsMigrations.hasOwnProperty(settingsKey)) {
|
||||
delete settingsMigrations[settingsKey];
|
||||
|
||||
return models.Settings.edit({
|
||||
key: 'migrations',
|
||||
value: JSON.stringify(settingsMigrations)
|
||||
}, options);
|
||||
}
|
||||
})
|
||||
.then(function () {
|
||||
return transfomDatesIntoUTC(options, logger);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* this migration script is a very special one for people who run their server in UTC and use sqlite3 or run their server in any TZ and use postgres
|
||||
* 006/01-transform-dates-into-utc had a bug for this case, see what happen because of this bug https://github.com/TryGhost/Ghost/issues/7192
|
||||
*/
|
||||
module.exports = function fixSqliteFormat(options, logger) {
|
||||
// CASE: skip this script when using mysql
|
||||
if (config.database.client === 'mysql') {
|
||||
logger.warn(messagePrefix + 'This script only runs, when using sqlite/postgres as database.');
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// CASE: database is postgres, server is in ANY TZ, run 006/001 again
|
||||
// we can't check the format for PG somehow, so we just run the migration again
|
||||
if (config.database.isPostgreSQL()) {
|
||||
return _private.rerunDateMigration(options, logger);
|
||||
}
|
||||
|
||||
// CASE: sqlite3 and server is UTC, we check if the date migration was already running
|
||||
return options.transacting.raw('select created_at from users')
|
||||
.then(function (users) {
|
||||
// safety measure
|
||||
if (!users || !users.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// CASE: if type is string and sqlite, then it already has the correct date format
|
||||
if (!_.isNumber(users[0].created_at)) {
|
||||
logger.warn(messagePrefix + 'Your dates are in correct format.');
|
||||
return;
|
||||
}
|
||||
|
||||
return _private.rerunDateMigration(options, logger);
|
||||
});
|
||||
};
|
3
core/server/data/migration/fixtures/008/index.js
Normal file
3
core/server/data/migration/fixtures/008/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
module.exports = [
|
||||
require('./01-fix-sqlite-pg-format')
|
||||
];
|
|
@ -19,6 +19,7 @@ var should = require('should'),
|
|||
fixtures005 = require('../../server/data/migration/fixtures/005'),
|
||||
fixtures006 = require('../../server/data/migration/fixtures/006'),
|
||||
fixtures007 = require('../../server/data/migration/fixtures/007'),
|
||||
fixtures008 = require('../../server/data/migration/fixtures/008'),
|
||||
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
|
@ -953,6 +954,8 @@ describe('Fixtures', function () {
|
|||
});
|
||||
|
||||
describe('Tasks:', function () {
|
||||
var isPostgres = false;
|
||||
|
||||
it('should have tasks for 006', function () {
|
||||
should.exist(fixtures006);
|
||||
fixtures006.should.be.an.Array().with.lengthOf(1);
|
||||
|
@ -965,7 +968,7 @@ describe('Fixtures', function () {
|
|||
|
||||
beforeEach(function () {
|
||||
configUtils.config.database.isPostgreSQL = function () {
|
||||
return false;
|
||||
return isPostgres;
|
||||
};
|
||||
|
||||
sandbox.stub(Date.prototype, 'getTimezoneOffset', function () {
|
||||
|
@ -973,6 +976,10 @@ describe('Fixtures', function () {
|
|||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
isPostgres = false;
|
||||
});
|
||||
|
||||
describe('error cases', function () {
|
||||
before(function () {
|
||||
serverTimezoneOffset = 0;
|
||||
|
@ -996,18 +1003,6 @@ describe('Fixtures', function () {
|
|||
.catch(done);
|
||||
});
|
||||
|
||||
it('server offset is 0 and postgresql', function (done) {
|
||||
migrationsSettingsValue = '{}';
|
||||
configUtils.config.database.client = 'pg';
|
||||
|
||||
updateClient({}, loggerStub)
|
||||
.then(function () {
|
||||
loggerStub.warn.called.should.be.true();
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
it('migration already ran', function (done) {
|
||||
migrationsSettingsValue = '{ "006/01": "timestamp" }';
|
||||
|
||||
|
@ -1069,6 +1064,45 @@ describe('Fixtures', function () {
|
|||
sandbox.stub(api.settings, 'updateSettingsCache').returns(Promise.resolve({}));
|
||||
});
|
||||
|
||||
it('pg: server TZ is UTC, only format is changing', function (done) {
|
||||
createdAt = moment(1464798678537).toDate();
|
||||
configUtils.config.database.client = 'pg';
|
||||
isPostgres = true;
|
||||
serverTimezoneOffset = 0;
|
||||
|
||||
moment(createdAt).format('YYYY-MM-DD HH:mm:ss').should.eql('2016-06-01 16:31:18');
|
||||
|
||||
updateClient({}, loggerStub)
|
||||
.then(function () {
|
||||
_.each(newModels, function (model) {
|
||||
moment(model.get('created_at')).format('YYYY-MM-DD HH:mm:ss').should.eql('2016-06-01 16:31:18');
|
||||
});
|
||||
|
||||
migrationsSettingsWasUpdated.should.eql(true);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
it('pg: server TZ is non UTC, only format is changing', function (done) {
|
||||
createdAt = moment(1464798678537).toDate();
|
||||
configUtils.config.database.client = 'pg';
|
||||
isPostgres = true;
|
||||
|
||||
moment(createdAt).format('YYYY-MM-DD HH:mm:ss').should.eql('2016-06-01 16:31:18');
|
||||
|
||||
updateClient({}, loggerStub)
|
||||
.then(function () {
|
||||
_.each(newModels, function (model) {
|
||||
moment(model.get('created_at')).format('YYYY-MM-DD HH:mm:ss').should.eql('2016-06-01 16:31:18');
|
||||
});
|
||||
|
||||
migrationsSettingsWasUpdated.should.eql(true);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
it('server offset is 0 and sqlite', function (done) {
|
||||
serverTimezoneOffset = 0;
|
||||
createdAt = moment(1464798678537).toDate();
|
||||
|
@ -1204,6 +1238,172 @@ describe('Fixtures', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Update to 008', function () {
|
||||
it('should call all the 008 fixture upgrades', function (done) {
|
||||
// Setup
|
||||
// Create a new stub, this will replace sequence, so that db calls don't actually get run
|
||||
var sequenceStub = sandbox.stub(),
|
||||
sequenceReset = update.__set__('sequence', sequenceStub),
|
||||
tasks = versioning.getUpdateFixturesTasks('008', loggerStub);
|
||||
|
||||
sequenceStub.returns(Promise.resolve([]));
|
||||
|
||||
update(tasks, loggerStub, {transacting: transactionStub}).then(function (result) {
|
||||
should.exist(result);
|
||||
|
||||
loggerStub.info.calledOnce.should.be.true();
|
||||
loggerStub.warn.called.should.be.false();
|
||||
|
||||
sequenceStub.calledOnce.should.be.true();
|
||||
|
||||
sequenceStub.firstCall.calledWith(sinon.match.array, sinon.match.object, loggerStub).should.be.true();
|
||||
sequenceStub.firstCall.args[0].should.be.an.Array().with.lengthOf(1);
|
||||
sequenceStub.firstCall.args[0][0].should.be.a.Function().with.property('name', 'fixSqliteFormat');
|
||||
|
||||
// Reset
|
||||
sequenceReset();
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
describe('Tasks:', function () {
|
||||
it('should have tasks for 008', function () {
|
||||
should.exist(fixtures008);
|
||||
fixtures008.should.be.an.Array().with.lengthOf(1);
|
||||
});
|
||||
|
||||
describe('01-fix-sqlite-pg-format', function () {
|
||||
var updateClient = rewire('../../server/data/migration/fixtures/008/01-fix-sqlite-pg-format'),
|
||||
serverTimezoneOffset = 60,
|
||||
transfomDatesIntoUTCStub, rawStub, isPostgres = false, isPostgreSQLWasCalled = false;
|
||||
|
||||
beforeEach(function () {
|
||||
configUtils.config.database.isPostgreSQL = function () {
|
||||
isPostgreSQLWasCalled = true;
|
||||
return isPostgres;
|
||||
};
|
||||
|
||||
sandbox.stub(Date.prototype, 'getTimezoneOffset', function () {
|
||||
return serverTimezoneOffset;
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
serverTimezoneOffset = 60;
|
||||
isPostgres = false;
|
||||
isPostgreSQLWasCalled = false;
|
||||
});
|
||||
|
||||
describe('success', function () {
|
||||
beforeEach(function () {
|
||||
sandbox.stub(models.Settings, 'findOne', function (options) {
|
||||
if (options.key === 'migrations') {
|
||||
return Promise.resolve({attributes: {value: '{"006/01":"2016-09-05T12:39:11Z", "005/02": "2015-09-05T12:39:11Z"}'}});
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
sandbox.stub(models.Settings, 'edit', function (data) {
|
||||
data.key.should.eql('migrations');
|
||||
data.value.should.eql('{"005/02":"2015-09-05T12:39:11Z"}');
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
transfomDatesIntoUTCStub = sandbox.stub().returns(Promise.resolve());
|
||||
updateClient.__set__('transfomDatesIntoUTC', transfomDatesIntoUTCStub);
|
||||
});
|
||||
|
||||
it('sqlite and server TZ is UTC: date format is integer', function (done) {
|
||||
serverTimezoneOffset = 0;
|
||||
configUtils.config.database.client = 'sqlite3';
|
||||
|
||||
rawStub = sandbox.stub().returns(Promise.resolve([{created_at: Date.now()}]));
|
||||
|
||||
updateClient({transacting: {raw: rawStub}}, loggerStub)
|
||||
.then(function () {
|
||||
models.Settings.edit.callCount.should.eql(1);
|
||||
models.Settings.findOne.callCount.should.eql(1);
|
||||
transfomDatesIntoUTCStub.callCount.should.eql(1);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
it('postgres and server TZ is UTC', function (done) {
|
||||
serverTimezoneOffset = 0;
|
||||
configUtils.config.database.client = 'pg';
|
||||
isPostgres = true;
|
||||
|
||||
updateClient({}, loggerStub)
|
||||
.then(function () {
|
||||
isPostgreSQLWasCalled.should.eql(true);
|
||||
models.Settings.edit.callCount.should.eql(1);
|
||||
models.Settings.findOne.callCount.should.eql(1);
|
||||
transfomDatesIntoUTCStub.callCount.should.eql(1);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
it('postgres and server TZ is not UTC', function (done) {
|
||||
configUtils.config.database.client = 'pg';
|
||||
isPostgres = true;
|
||||
|
||||
updateClient({}, loggerStub)
|
||||
.then(function () {
|
||||
isPostgreSQLWasCalled.should.eql(true);
|
||||
models.Settings.edit.callCount.should.eql(1);
|
||||
models.Settings.findOne.callCount.should.eql(1);
|
||||
transfomDatesIntoUTCStub.callCount.should.eql(1);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('error', function () {
|
||||
it('skip mysql', function (done) {
|
||||
configUtils.config.database.client = 'mysql';
|
||||
|
||||
updateClient({}, loggerStub)
|
||||
.then(function () {
|
||||
loggerStub.warn.called.should.be.true();
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
it('skip sqlite and non UTC server timezone', function (done) {
|
||||
configUtils.config.database.client = 'sqlite3';
|
||||
rawStub = sandbox.stub().returns(Promise.resolve([{created_at: moment().format('YYYY-MM-DD HH:mm:ss')}]));
|
||||
|
||||
updateClient({transacting: {raw:rawStub}}, loggerStub)
|
||||
.then(function () {
|
||||
loggerStub.warn.called.should.be.true();
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
it('skip sqlite with UTC server timezone, but correct format', function (done) {
|
||||
configUtils.config.database.client = 'sqlite3';
|
||||
serverTimezoneOffset = 0;
|
||||
|
||||
rawStub = sandbox.stub().returns(Promise.resolve([{created_at: moment().format('YYYY-MM-DD HH:mm:ss')}]));
|
||||
|
||||
updateClient({transacting: {raw: rawStub}}, loggerStub)
|
||||
.then(function () {
|
||||
loggerStub.warn.called.should.be.true();
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Populate fixtures', function () {
|
||||
|
|
Loading…
Add table
Reference in a new issue