├── .jshintrc ├── README.md ├── index.js ├── lib └── db.js ├── package.json └── tasks ├── db ├── finish.js ├── index.js ├── init.js ├── pull.js └── push.js └── grunt-task.js /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "undef": true, 4 | "unused": true, 5 | "predef": ["-Promise"], 6 | "latedef": "nofunc", 7 | "globals": { 8 | "module": false, 9 | "require": false, 10 | "define": false 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # shipit-db 2 | 3 | A set of database tasks for [Shipit](https://github.com/shipitjs/shipit). 4 | 5 | **Features:** 6 | 7 | - Works via [shipit-cli](https://github.com/shipitjs/shipit) and [grunt-shipit](https://github.com/shipitjs/grunt-shipit) 8 | - Optionally ignore specified tables 9 | 10 | **Roadmap** 11 | 12 | - DB Backup tasks 13 | 14 | ## Install 15 | 16 | ``` 17 | npm install shipit-db 18 | ``` 19 | 20 | ## Usage 21 | 22 | ### Example `shipitfile.js` 23 | 24 | ```js 25 | module.exports = function (shipit) { 26 | require('shipit-db')(shipit); 27 | 28 | shipit.initConfig({ 29 | default: { 30 | db: { 31 | ignoreTables: ['some_table'], 32 | local: { 33 | host : 'localhost', 34 | adapter : 'mysql', 35 | username : 'root', 36 | password : 'root', 37 | socket : '/Applications/MAMP/tmp/mysql/mysql.sock', 38 | database : 'mysite_local', 39 | }, 40 | } 41 | }, 42 | staging: { 43 | servers: 'user@myserver.com', 44 | db: { 45 | remote: { 46 | host : '127.0.0.1', 47 | adapter : 'mysql', 48 | username : 'myusername', 49 | password : '123password', 50 | database : 'mysite_staging', 51 | } 52 | } 53 | } 54 | }); 55 | }; 56 | ``` 57 | 58 | Dump your local database, upload and import to remote: 59 | 60 | ``` 61 | shipit staging db:push 62 | ``` 63 | 64 | Dump your remote database, download and import to local: 65 | 66 | ``` 67 | shipit staging db:pull 68 | ``` 69 | 70 | ## Options (`shipit.config.db`) 71 | 72 | ### `db.ignoreTables` 73 | 74 | Type: `Array` 75 | 76 | An array of database tables to ignore. 77 | 78 | ### `db.local` \ `db.remote` 79 | 80 | Type: `Object` 81 | 82 | An object of database credentials. 83 | 84 | ## License 85 | 86 | MIT 87 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = function (shipit) { 2 | require('./tasks/db')(shipit); 3 | }; 4 | -------------------------------------------------------------------------------- /lib/db.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var moment = require('moment'); 3 | var sprintf = require('sprintf-js').sprintf; 4 | var mkdirp = require('mkdirp'); 5 | var Promise = require('bluebird'); 6 | 7 | module.exports = function(shipit) { 8 | shipit.db = shipit.db || {}; 9 | 10 | shipit.db.createDirs = function createDirs() { 11 | return Promise.promisify(mkdirp)(shipit.db.localDumpDir).then(function() { 12 | return shipit.remote('mkdir -p ' + shipit.db.remoteDumpDir); 13 | }); 14 | }; 15 | 16 | shipit.db.dumpFile = function dumpFile(environment) { 17 | return path.join( 18 | shipit.config.db.dumpDir, 19 | sprintf('%(database)s-%(currentTime)s.sql.bz2', { 20 | database: shipit.config.db[environment].database, 21 | currentTime: moment.utc().format('YYYYMMDDHHmmss'), 22 | }) 23 | ); 24 | }; 25 | 26 | shipit.db.credentialParams = function credentialParams(dbConfig) { 27 | var params = { 28 | '-u': dbConfig.username || null, 29 | '-p': dbConfig.password || null, 30 | '-h': dbConfig.host || null, 31 | '-S': dbConfig.socket || null, 32 | '-P': dbConfig.port || null, 33 | }; 34 | 35 | var paramStr = Object.keys(params).map(function(key) { 36 | return (params[key]) ? key + '\'' + params[key] + '\'' : false; 37 | }).filter(function(elem) { 38 | return !!elem; 39 | }); 40 | 41 | return paramStr.join(' '); 42 | }; 43 | 44 | shipit.db.ignoreTablesArgs = function ignoreTablesArgs(environment) { 45 | 46 | // TODO: ignoreTables should be per-env 47 | var args = shipit.config.db.ignoreTables.map(function(table) { 48 | table = table.match(/\./) ? table : [shipit.config.db[environment].database, table].join('.'); 49 | 50 | return '--ignore-table=' + table; 51 | }); 52 | 53 | return args.join(' '); 54 | }; 55 | 56 | shipit.db.dumpCmd = function dumpCmd(environment) { 57 | return sprintf('mysqldump %(credentials)s %(database)s --lock-tables=false %(ignoreTablesArgs)s', { 58 | credentials: shipit.db.credentialParams(shipit.config.db[environment]), 59 | database: shipit.config.db[environment].database, 60 | ignoreTablesArgs: shipit.db.ignoreTablesArgs(environment) 61 | }); 62 | }; 63 | 64 | shipit.db.importCmd = function importCmd(environment, file) { 65 | return sprintf('mysql %(credentials)s -D %(database)s < %(file)s', { 66 | credentials: shipit.db.credentialParams(shipit.config.db[environment]), 67 | database: shipit.config.db[environment].database, 68 | file: path.join(path.dirname(file), path.basename(file, '.bz2')), 69 | }); 70 | }; 71 | 72 | shipit.db.createCmd = function createCmd(environment) { 73 | return sprintf('mysql %(credentials)s --execute \"CREATE DATABASE IF NOT EXISTS %(database)s;\"', { 74 | credentials: shipit.db.credentialParams(shipit.config.db[environment]), 75 | database: shipit.config.db[environment].database, 76 | }); 77 | }; 78 | 79 | shipit.db.unzipCmd = function(file) { 80 | if (shipit.config.db.shell.unzip) { 81 | return shipit.config.db.shell.unzip.call(shipit, file); 82 | } 83 | 84 | return sprintf('bunzip2 -f %(file)s', { 85 | file: file, 86 | }); 87 | }; 88 | 89 | shipit.db.zipCmd = function(file) { 90 | if (shipit.config.db.shell.zip) { 91 | return shipit.config.db.shell.zip.call(shipit, file); 92 | } 93 | 94 | return shipit.config.db.shell.zip || sprintf('bzip2 - - > %(dumpFile)s', { 95 | dumpFile: file, 96 | }); 97 | }; 98 | 99 | shipit.db.dump = function dump(environment, file) { 100 | if (shipit.config.db.shell.dump) { 101 | return shipit.config.db.shell.dump.call(shipit, environment, file); 102 | } 103 | 104 | return shipit[environment]( 105 | sprintf('%(dumpCmd)s | %(zipCmd)s', { 106 | dumpCmd: shipit.db.dumpCmd(environment), 107 | zipCmd: shipit.db.zipCmd(file), 108 | }) 109 | ); 110 | }; 111 | 112 | shipit.db.load = function load(environment, file) { 113 | if (shipit.config.db.shell.load) { 114 | return shipit.config.db.shell.load.call(shipit, environment, file); 115 | } 116 | 117 | var cmd = sprintf('%(unzipCmd)s && %(createCmd)s && %(importCmd)s', { 118 | unzipCmd: shipit.db.unzipCmd(file), 119 | importCmd: shipit.db.importCmd(environment, file), 120 | createCmd: shipit.db.createCmd(environment) 121 | }); 122 | 123 | return shipit[environment](cmd); 124 | }; 125 | 126 | shipit.db.clean = function clean(environment, path, enabled) { 127 | if (shipit.config.db.shell.clean) { 128 | return shipit.config.db.shell.clean.call(shipit, environment, path, enabled); 129 | } 130 | 131 | return enabled ? shipit[environment]('rm -f ' + path) : Promise.resolve(); 132 | }; 133 | 134 | return shipit; 135 | }; 136 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shipit-db", 3 | "version": "1.8.5", 4 | "description": "Database syncing tasks for Shipit.", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "mocha --recursive" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/timkelty/shipit-db.git" 15 | }, 16 | "keywords": [ 17 | "shipit", 18 | "database", 19 | "task" 20 | ], 21 | "author": { 22 | "name": "Tim Kelty", 23 | "email": "timkelty@gmail.com" 24 | }, 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/timkelty/shipit-db/issues" 28 | }, 29 | "homepage": "https://github.com/timkelty/shipit-db", 30 | "devDependencies": { 31 | "chai": "^1.10.0", 32 | "mocha": "^2.1.0", 33 | "rewire": "^2.1.4", 34 | "sinon": "^1.12.2", 35 | "sinon-as-promised": "^2.0.3", 36 | "sinon-chai": "^2.6.0" 37 | }, 38 | "dependencies": { 39 | "bluebird": "^2.9.1", 40 | "chalk": "^0.5.1", 41 | "lodash": "^2.4.1", 42 | "mkdirp": "^0.5.0", 43 | "moment": "^2.9.0", 44 | "path2": "^0.1.0", 45 | "shipit": "^0.1.16", 46 | "shipit-cli": "^1.1.0", 47 | "shipit-utils": "^1.0.2", 48 | "sprintf-js": "^1.0.2" 49 | }, 50 | "readmeFile": "README.md" 51 | } 52 | -------------------------------------------------------------------------------- /tasks/db/finish.js: -------------------------------------------------------------------------------- 1 | var utils = require('shipit-utils'); 2 | var db = require('../../lib/db'); 3 | 4 | /** 5 | * Finish task. 6 | * - Emit an event "dbFinish". 7 | */ 8 | 9 | module.exports = function (gruntOrShipit) { 10 | utils.registerTask(gruntOrShipit, 'db:finish', task); 11 | 12 | function task() { 13 | var shipit = db(utils.getShipit(gruntOrShipit)); 14 | shipit.emit('dbFinish'); 15 | return shipit; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /tasks/db/index.js: -------------------------------------------------------------------------------- 1 | var utils = require('shipit-utils'); 2 | 3 | /** 4 | * Database tasks. 5 | */ 6 | 7 | module.exports = function(gruntOrShipit) { 8 | require('./init')(gruntOrShipit); 9 | require('./pull')(gruntOrShipit); 10 | require('./push')(gruntOrShipit); 11 | require('./finish')(gruntOrShipit); 12 | 13 | utils.registerTask(gruntOrShipit, 'db:pull', [ 14 | 'db:init', 15 | 'db:pull:task', 16 | 'db:finish', 17 | ]); 18 | 19 | utils.registerTask(gruntOrShipit, 'db:push', [ 20 | 'db:init', 21 | 'db:push:task', 22 | 'db:finish', 23 | ]); 24 | }; 25 | -------------------------------------------------------------------------------- /tasks/db/init.js: -------------------------------------------------------------------------------- 1 | var utils = require('shipit-utils'); 2 | var path = require('path2/posix'); 3 | var _ = require('lodash'); 4 | 5 | /** 6 | * Init task. 7 | * - Emit deploy event. 8 | */ 9 | 10 | module.exports = function(gruntOrShipit) { 11 | var task = function task() { 12 | var shipit = utils.getShipit(gruntOrShipit); 13 | shipit.currentPath = path.join(shipit.config.deployTo, 'current'); 14 | shipit.sharedPath = path.join(shipit.config.deployTo, 'shared'); 15 | shipit.config.db = _.defaults(shipit.config.db || {}, { 16 | dumpDir: 'db', 17 | cleanLocal: true, 18 | cleanRemote: true, 19 | ignoreTables: [], 20 | local: {}, 21 | remote: {}, 22 | shell: {}, 23 | }); 24 | 25 | shipit.db = { 26 | localDumpDir: path.join(shipit.config.workspace, shipit.config.db.dumpDir), 27 | remoteDumpDir: path.join(shipit.sharedPath || shipit.currentPath, shipit.config.db.dumpDir), 28 | }; 29 | 30 | shipit.emit('db'); 31 | 32 | return shipit; 33 | }; 34 | 35 | utils.registerTask(gruntOrShipit, 'db:init', task); 36 | }; 37 | -------------------------------------------------------------------------------- /tasks/db/pull.js: -------------------------------------------------------------------------------- 1 | var utils = require('shipit-utils'); 2 | var path = require('path'); 3 | var db = require('../../lib/db'); 4 | 5 | module.exports = function(gruntOrShipit) { 6 | var task = function task() { 7 | var shipit = db(utils.getShipit(gruntOrShipit)); 8 | var dumpFile = shipit.db.dumpFile('remote'); 9 | var remoteDumpFilePath = path.join(shipit.sharedPath || shipit.currentPath, dumpFile); 10 | var localDumpFilePath = path.join(shipit.config.workspace, dumpFile); 11 | 12 | var download = function download() { 13 | return shipit.remoteCopy(remoteDumpFilePath, localDumpFilePath, { 14 | direction: 'remoteToLocal' 15 | }); 16 | }; 17 | 18 | return shipit.db.createDirs() 19 | .then(function() { 20 | return shipit.db.dump('remote', remoteDumpFilePath); 21 | }) 22 | .then(download) 23 | .then(function() { 24 | return shipit.db.clean('remote', remoteDumpFilePath, shipit.config.db.cleanRemote); 25 | }) 26 | .then(function() { 27 | return shipit.db.load('local', localDumpFilePath); 28 | }) 29 | .then(function() { 30 | return shipit.db.clean('local', localDumpFilePath, shipit.config.db.cleanLocal); 31 | }); 32 | }; 33 | 34 | utils.registerTask(gruntOrShipit, 'db:pull:task', task); 35 | }; 36 | -------------------------------------------------------------------------------- /tasks/db/push.js: -------------------------------------------------------------------------------- 1 | var utils = require('shipit-utils'); 2 | var path = require('path'); 3 | var db = require('../../lib/db'); 4 | 5 | module.exports = function(gruntOrShipit) { 6 | var task = function task() { 7 | var shipit = db(utils.getShipit(gruntOrShipit)); 8 | var remoteDumpFilePath = path.join(shipit.sharedPath || shipit.currentPath, shipit.db.dumpFile('local')); 9 | var localDumpFilePath = path.join(shipit.config.workspace, shipit.db.dumpFile('local')); 10 | var upload = function upload() { 11 | return shipit.remoteCopy(localDumpFilePath, remoteDumpFilePath); 12 | }; 13 | 14 | return shipit.db.createDirs() 15 | .then(function() { 16 | return shipit.db.dump('local', localDumpFilePath); 17 | }) 18 | .then(upload) 19 | .then(function() { 20 | return shipit.db.clean('local', localDumpFilePath, shipit.config.db.cleanLocal); 21 | }) 22 | .then(function() { 23 | return shipit.db.load('remote', remoteDumpFilePath); 24 | }) 25 | .then(function() { 26 | return shipit.db.clean('remote', remoteDumpFilePath, shipit.config.db.cleanRemote); 27 | }); 28 | }; 29 | 30 | utils.registerTask(gruntOrShipit, 'db:push:task', task); 31 | }; 32 | -------------------------------------------------------------------------------- /tasks/grunt-task.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | require('./db')(grunt); 3 | }; 4 | --------------------------------------------------------------------------------