0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-03-11 02:12:21 -05:00

Migration adds fixtures on first run only

closes #731, closes #732

- fixtures are imported using the models, rather than knex
- migration treats fresh installs differently
- migration throws errors for un-initialisable databases
- small amount of extra code to deal with old DBs still using currentVersion & give them a nice error message
This commit is contained in:
Hannah Wolfe 2013-09-14 23:14:39 +01:00
parent b902f8109c
commit 02436645fe
4 changed files with 164 additions and 109 deletions

View file

@ -1,11 +0,0 @@
var uuid = require('node-uuid');
module.exports = {
posts: [],
roles: [],
permissions: [],
permissions_roles: []
};

View file

@ -1,13 +0,0 @@
var uuid = require('node-uuid');
module.exports = {
posts: [],
settings: [],
roles: [],
permissions: [],
permissions_roles: []
};

View file

@ -1,6 +1,11 @@
var uuid = require('node-uuid');
var sequence = require('when/sequence'),
_ = require('underscore'),
Post = require('../../models/post').Post,
Role = require('../../models/role').Role,
Permission = require('../../models/permission').Permission,
uuid = require('node-uuid');
module.exports = {
var fixtures = {
posts: [
{
"uuid": uuid.v4(),
@ -14,71 +19,71 @@ module.exports = {
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1373578890610,
"created_by": 1,
"updated_at": 1373578997173,
"updated_by": 1,
"published_at": 1373578895817,
"published_by": 1
"meta_description": null
}
],
roles: [
{
"id": 1,
"name": "Administrator",
"description": "Administrators"
"uuid": uuid.v4(),
"name": "Administrator",
"description": "Administrators"
},
{
"id": 2,
"name": "Editor",
"description": "Editors"
"uuid": uuid.v4(),
"name": "Editor",
"description": "Editors"
},
{
"id": 3,
"name": "Author",
"description": "Authors"
"uuid": uuid.v4(),
"name": "Author",
"description": "Authors"
}
],
permissions: [
{
"id": 1,
"name": "Edit posts",
"action_type": "edit",
"object_type": "post"
"uuid": uuid.v4(),
"name": "Edit posts",
"action_type": "edit",
"object_type": "post"
},
{
"id": 2,
"name": "Remove posts",
"action_type": "remove",
"object_type": "post"
"uuid": uuid.v4(),
"name": "Remove posts",
"action_type": "remove",
"object_type": "post"
},
{
"id": 3,
"name": "Create posts",
"action_type": "create",
"object_type": "post"
}
],
permissions_roles: [
{
"id": 1,
"permission_id": 1,
"role_id": 1
},
{
"id": 2,
"permission_id": 2,
"role_id": 1
},
{
"id": 3,
"permission_id": 3,
"role_id": 1
"uuid": uuid.v4(),
"name": "Create posts",
"action_type": "create",
"object_type": "post"
}
]
};
module.exports = {
populateFixtures: function () {
var ops = [];
_.each(fixtures.posts, function (post) {
ops.push(function () {return Post.add(post); });
});
_.each(fixtures.roles, function (role) {
ops.push(function () {return Role.add(role); });
});
_.each(fixtures.permissions, function (permission) {
ops.push(function () {return Permission.add(permission); });
});
// finally, grant admins all permissions
ops.push(function () {
Role.forge({id: 1}).fetch({withRelated: ['permissions']}).then(function (role) {
role.permissions().attach([1, 2, 3]);
});
});
return sequence(ops);
}
};

View file

@ -4,49 +4,105 @@ var _ = require('underscore'),
series = require('when/sequence'),
errors = require('../../errorHandling'),
knex = require('../../models/base').Knex,
initialVersion = '000',
// This databaseVersion string should always be the current version of Ghost,
// we could probably load it from the config file.
// - Will be possible after default-settings.json restructure
databaseVersion = '000';
defaultSettings = require('../default-settings'),
Settings = require('../../models/settings').Settings,
fixtures = require('../fixtures'),
initialVersion = '000',
defaultDatabaseVersion;
// Default Database Version
// The migration version number according to the hardcoded default settings
// This is the version the database should be at or migrated to
function getDefaultDatabaseVersion() {
if (!defaultDatabaseVersion) {
// This be the current version according to the software
defaultDatabaseVersion = _.find(defaultSettings.core, function (setting) {
return setting.key === 'databaseVersion';
}).defaultValue;
}
return defaultDatabaseVersion;
}
// Database Current Version
// The migration version number according to the database
// This is what the database is currently at and may need to be updated
function getDatabaseVersion() {
return knex.Schema.hasTable('settings').then(function () {
// Check for the databaseVersion from the settings table
return knex('settings')
.where('key', 'databaseVersion')
.select('value')
.then(function (databaseVersionSetting) {
if (databaseVersionSetting && databaseVersionSetting.length > 0) {
databaseVersionSetting = databaseVersionSetting[0].value;
} else {
// we didn't get a response we understood, assume initialVersion
databaseVersionSetting = initialVersion;
}
return databaseVersionSetting;
});
return knex.Schema.hasTable('settings').then(function (exists) {
// Check for the current version from the settings table
if (exists) {
// Temporary code to deal with old databases with currentVersion settings
// TODO: remove before release
return knex('settings')
.where('key', 'databaseVersion')
.orWhere('key', 'currentVersion')
.select('value')
.then(function (versions) {
var databaseVersion = _.reduce(versions, function (memo, version) {
return parseInt(version.value, 10) > parseInt(memo, 10) ? version.value : memo;
}, initialVersion);
if (!databaseVersion || databaseVersion.length === 0) {
// we didn't get a response we understood, assume initialVersion
databaseVersion = initialVersion;
}
return when.resolve(databaseVersion);
});
}
return when.reject('Settings table does not exist');
});
}
function setDatabaseVersion() {
return knex('settings')
.where('key', 'databaseVersion')
.update({ 'value': defaultDatabaseVersion });
}
module.exports = {
databaseVersion: databaseVersion,
// Check for whether data is needed to be bootstrapped or not
init: function () {
var self = this;
return getDatabaseVersion().then(function (databaseVersionSetting) {
// We are assuming here that the databaseVersionSetting will
// always be less than the databaseVersion value.
if (databaseVersionSetting === databaseVersion) {
// There are 4 possibilities:
// 1. The database exists and is up-to-date
// 2. The database exists but is out of date
// 3. The database exists but the currentVersion setting does not or cannot be understood
// 4. The database has not yet been created
return getDatabaseVersion().then(function (databaseVersion) {
var defaultVersion = getDefaultDatabaseVersion();
if (databaseVersion === defaultVersion) {
// 1. The database exists and is up-to-date
return when.resolve();
}
// Bring the data up to the latest version
return self.migrateUpFromVersion(databaseVersion);
}, function () {
// If the settings table doesn't exist, bring everything up from initial version.
return self.migrateUpFromVersion(initialVersion);
if (databaseVersion < defaultVersion) {
// 2. The database exists but is out of date
return self.migrateUpFromVersion(databaseVersion);
}
if (databaseVersion > defaultVersion) {
// 3. The database exists but the currentVersion setting does not or cannot be understood
// In this case we don't understand the version because it is too high
errors.logError('Database is not compatible with software version.');
process.exit(-3);
}
}, function (err) {
if (err === 'Settings table does not exist') {
// 4. The database has not yet been created
// Bring everything up from initial version.
return self.migrateUpFreshDb();
}
// 3. The database exists but the currentVersion setting does not or cannot be understood
// In this case the setting was missing or there was some other problem
errors.logError('Database is not recognisable.' + err);
process.exit(-2);
});
},
@ -55,19 +111,33 @@ module.exports = {
reset: function () {
var self = this;
return getDatabaseVersion().then(function (databaseVersionSetting) {
// bring everything down from the databaseVersion
return self.migrateDownFromVersion(databaseVersionSetting);
return getDatabaseVersion().then(function (databaseVersion) {
// bring everything down from the current version
return self.migrateDownFromVersion(databaseVersion);
}, function () {
// If the settings table doesn't exist, bring everything down from initial version.
return self.migrateDownFromVersion(initialVersion);
});
},
// Only do this if we have no database at all
migrateUpFreshDb: function () {
var migration = require('./' + initialVersion);
return migration.up().then(function () {
// Load the fixtures
return fixtures.populateFixtures();
}).then(function () {
// Initialise the default settings
return Settings.populateDefaults();
});
},
// Migrate from a specific version to the latest
migrateUpFromVersion: function (version, max) {
var versions = [],
maxVersion = max || this.getVersionAfter(databaseVersion),
maxVersion = max || this.getVersionAfter(getDefaultDatabaseVersion()),
currVersion = version,
tasks = [];
@ -91,11 +161,15 @@ module.exports = {
});
// Run each migration in series
return series(tasks);
return series(tasks).then(function () {
// Finally update the databases current version
return setDatabaseVersion();
});
},
migrateDownFromVersion: function (version) {
var versions = [],
var self = this,
versions = [],
minVersion = this.getVersionBefore(initialVersion),
currVersion = version,
tasks = [];
@ -114,7 +188,7 @@ module.exports = {
return migration.down();
} catch (e) {
errors.logError(e);
return when.reject(e);
return self.migrateDownFromVersion(initialVersion);
}
};
});