Skip to content

Instantly share code, notes, and snippets.

@rachaelshaw
Created December 15, 2017 20:19
Show Gist options
  • Save rachaelshaw/03a1853fdbb60a611822c5203474c6c5 to your computer and use it in GitHub Desktop.
Save rachaelshaw/03a1853fdbb60a611822c5203474c6c5 to your computer and use it in GitHub Desktop.
Example App - Migrations

Example devops instructions

Deployment

To deploy to staging:

sails run deploy

Wiping / messing with the staging database

To connect to the staging database from your local dev environment:

sails_models__migrate=safe sails_datastores__default__ssl=true sails_datastores__default__adapter=sails-postgresql sails_datastores__default__url=postgres://…:…@…:…/… sails console

To completely wipe it of all data (while maintaining the schema), just run the same thing, but with sails_models__migrate=drop:

sails_models__migrate=drop sails_datastores__default__ssl=true sails_datastores__default__adapter=sails-postgresql sails_datastores__default__url=postgres://…:…@…:…/… sails console

Troubleshooting tip: If you see schema migration errors on a deploy to staging, it probably just means that something was changed, but the bootstrap version was not incremented. To fix that, the easiest solution is to (A) first increment the bootstrap version (config/bootstrap.js), then (B) redeploy.

Do keep in mind though, that in "production production", manual schema migrations need to be run. The bootstrap script will ALWAYS refuse to drop the database when sails.config.environment==='production'-- in fact, just to be safe, it'll also refuse to drop the database if NODE_ENV=production, unless sails.config.environment is "staging".

Initializing / migrating the database in staging / production

Notes:

  • Before migrating a database in production, be sure to put the site into maintenance mode and back up the existing database!
  • To migrate a remote database, specify the database URL in the DB_URL environment var, e.g. postgres://mypguser:mypgpass@mypgserver.com:5432/dbname.
  • To initialize a new database, make sure that an empty PostgreSQL database with the desired name exists at the URL you want to deploy to.
  • Run npm run knex migrate:latest to execute any previously-unrun migration scripts. For empty databases, this will first import the base SQL file.
  • Run npm run knex migrate:rollback to rollback all of the migrations that were executed the last time npm run knex migrate:latest was run.
  • Run npm run knex-migrate up or npm run knex-migrate down to execute/rollback a single migration. Helpful for testing migration scripts.
  • Run npm run knex migrate:make <kebab-cased-description-of-migration> to make a new migration script. See the Knex.js docs for more info on creating migration scripts.
  • Run npm run knex or npm run knex-migrate for more help with those commands.

The commit hook

If you've installed the pre-commit hook bundled in this project (sails run install-pre-commit-hook), then any time you try to commit a change to a model without also including an up/down migration script, you'll see something like this:

∑ git commit -m "Make companyName of an Organization a required attribute."
____________________________________________________________________________________________________

Sorry to interrupt, but it looks like you're trying to commit a new/modified/deleted model file,
without an accompanying schema migration script.  Manual up/down migration scripts are a way of
making sure the records in your production database are properly adjusted when models change, so
it's important to include one any time that happens-- especially if those models represent data
that is stored in a SQL database.

To make a new migration script, run:
    npm run knex migrate:make <kebab-cased-description-of-migration>

(See the Knex.js docs on http://knexjs.com for further reference info.)

 [?] If you're unsure or need advice, head over to https://sailsjs.com/support
____________________________________________________________________________________________________

To skip the commit hook (e.g. because you only changed some comments), use --no-verify.

module.exports = {
friendlyName: 'Create pre-commit hook',
description: 'Create a customized pre-commit hook for this development environment.',
inputs: {},
fn: async function(inputs, exits){
var fs = require('fs');
var path = require('path');
var cmdOutputReport = await sails.stdlib('process').executeCommand({ command: 'which node' });
var filePath = path.resolve(__dirname, '..', '.git', 'hooks', 'pre-commit');
fs.writeFileSync(filePath, '#!' + cmdOutputReport.stdout + '\n' + GENERIC_PRECOMMIT_HOOK_SCRIPT_BODY);
fs.chmodSync(filePath, '777');
return exits.success();
}
};
var GENERIC_PRECOMMIT_HOOK_SCRIPT_BODY = `
/**
* Pre-commit hook to prevent commits that change models unless they
* also include a migration file.
*
* To skip, use the "--no-verify" option when committing.
* (useful if you just added a comment to a model)
*/
var exec = require('child_process').exec;
var _ = require('@sailshq/lodash');
// Get the current Git status (in shorthand mode)
exec('git status -s', function(err, stdout) {
if (err) { process.exit(0); }
// Split into individual lines.
var lines = stdout.split('\\n');
// Flag indicating that a model file has been modified.
var modifiedModel = false;
// Flag indicating that a migration file has been added.
var addedMigration = false;
// Loop through each line in the output, checking for entries about model files or migrations.
_.each(lines, function(line) {
if (line.match(/^[MAD]\\s+api\\/models\\//)) { modifiedModel = true; }
if (line.match(/^A\\s+db\\/migrations\\//)) { addedMigration = true; }
});
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// FUTURE: Maybe use the \`commit.msg\` hook thingy to be able to help make a better inference when
// automatically suggesting an appropriate kebab-cased name for the new up/down migration
// (i.e. could also base it on your attempted commit message)
//
// see https://stackoverflow.com/a/44423052/486547
//
// > Note that we could also potentially look at which model files were added/removed/modified
// > base the suggested naming on that. For example, if you updated the "User.js" model file,
// > removed the "Admin.js" model file, and added the "Organization.js" model file, with a
// > commit message of something like "implemented unified login", then we might suggest:
// >
// > npm run knex migrate:make updated-user-removed-admin-added-organization
// >
// > Or maybe only:
// >
// > npm run knex migrate:make implemented-unified-login
// >
// > Or even:
// >
// > npm run knex migrate:make updated-user-removed-admin-added-organization--because--implemented-unified-login
// >
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// If a model was modified, but no migration was added, bail.
if (modifiedModel && !addedMigration) {
console.error('____________________________________________________________________________________________________');
console.error();
console.error('Sorry to interrupt, but it looks like you\\\'re trying to commit a new/modified/deleted model file,');
console.error('without an accompanying schema migration script. Manual up/down migration scripts are a way of');
console.error('making sure the records in your production database are properly adjusted when models change, so');
console.error('it\\\'s important to include one any time that happens-- especially if those models represent data');
console.error('that is stored in a SQL database.');
console.error();
console.error('To make an empty new migration script, run:');
console.error(' npm run knex migrate:make <kebab-cased-description-of-migration>');
console.error();
console.error('(See the Knex.js docs on http://knexjs.com for further reference info.)');
console.error();
console.error('If this is just a trivial change that doesn\\\'t require a new migration script, you can also skip');
console.error('this pre-commit check using the \`--no-verify\` command-line option. For example:');
console.error(' git commit -am "Update comments (no migration necessary)" --no-verify');
console.error();
console.error(' [?] If you\\\'re unsure or need advice, head over to https://sailsjs.com/support');
console.error('____________________________________________________________________________________________________');
process.exit(1);
}
process.exit(0);
});
`;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment