Skip to content

Instantly share code, notes, and snippets.

@desaiuditd
Last active December 3, 2020 16:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save desaiuditd/c4509339bb9bb9eae6a1 to your computer and use it in GitHub Desktop.
Save desaiuditd/c4509339bb9bb9eae6a1 to your computer and use it in GitHub Desktop.
Gulp rsync Deploy

WordPress Theme Deploy Script

To setup the deploy in your repo.

  • git submodule add -f git@gist.github.com:/c4509339bb9bb9eae6a1.git wp-deploy

While cloning the main repo,

  • git clone --recursive <repo-url>

OR

  • git clone <repo-url>
  • cd <repo-dir>
  • git submodule init

Pre-requisite

  • npm install

How to setup deploy.json

You will need to set following parameters in the deploy.json

{
  "staging": {
    "themeName": "example",                  // THEME FOLDER NAME UNDER wp-content/themes/ DIRECTORY
    "destination": "/var/www/staging.example.com/htdocs/wp-content/themes/",
    "root": "wp-content/themes/example",
    "releasesDirectory": "/var/www/staging.example.com/releases/",   // THIS IS WHERE ALL THE RELEASES WILL BE STORED. IF NOT PASSED, THIS WILL BE SET TO destination/../releases
    "hostname": "staging.example.com",
    "username": "www-data",
    "port": 22
  },
  "production": {
    "themeName": "example",                  // THEME FOLDER NAME UNDER wp-content/themes/ DIRECTORY
    "destination": "/var/www/example.com/htdocs/wp-content/themes/",
    "root": "wp-content/themes/example",
    "releasesDirectory": "/var/www/example.com/releases/",   // THIS IS WHERE ALL THE RELEASES WILL BE STORED. IF NOT PASSED, THIS WILL BE SET TO destination/../releases
    "hostname": "example.com",
    "username": "www-data",
    "port": 22
  }
}

How to Deploy

There is a gulp task written for deployment.

There are two modes for deployment.

Staging

  • gulp deploy --staging

Production

  • gulp deploy --production

NOTE: To be able to deploy changes, you will need to have access of server with www-data user.

How to View Available Releases

Staging

  • gulp releases --staging

Production

  • gulp releases --production

How to Rollback to previous version

You can find out the timestamp from gulp releases command. It will show you all the available releases.

Staging

  • gulp rollback --staging --revision=<timestamp>

Production

  • gulp rollback --production --revision=<timestamp>
{
"staging": {
"themeName": "example",
"destination": "/var/www/staging.example.com/htdocs/wp-content/themes/",
"root": "wp-content/themes/example",
"releasesDirectory": "/var/www/staging.example.com/releases/",
"hostname": "staging.example.com",
"username": "www-data",
"port": 22
},
"production": {
"themeName": "example",
"destination": "/var/www/example.com/htdocs/wp-content/themes/",
"root": "wp-content/themes/example",
"releasesDirectory": "/var/www/example.com/releases/",
"hostname": "example.com",
"username": "www-data",
"port": 22
}
}
/**
* Created by udit on 19/3/15.
*/
var argv = require( 'yargs' ).argv;
var gulp = require( 'gulp' );
var fs = require( 'fs.extra' );
var rsync = require( 'gulp-rsync' );
var gulpSSH = require( 'gulp-ssh' );
var chalk = require( 'chalk' );
var deployJSON = require( './deploy.json' );
var deployConfig;
var sshConnect;
var releasesDirecoryBase;
var timestamp;
var releasesDirecory;
gulp.task( 'setupSSH', function() {
if ( argv.staging ) {
// Staging
deployConfig = deployJSON.staging;
} else if( argv.production ) {
//Production
deployConfig = deployJSON.production;
} else {
// Custom Environment
console.log( chalk.bold.red( '"staging" or "production" environment is not passed. USE : gulp <command> --<environment> If your custom environment is configured then you need to provide its support. Comming Soon !' ) );
process.exit();
}
var homePath = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE
var privateKey = homePath + '/.ssh/id_rsa';
// Setup SSH object for remote commands
sshConnect = gulpSSH( {
ignoreErrors: false,
sshConfig: {
host: deployConfig.hostname,
port: deployConfig.port,
username: deployConfig.username,
privateKey: fs.readFileSync( privateKey )
}
} );
// decide releaseDirectoryBase for rsync
releasesDirecoryBase = ( deployConfig.releasesDirectory ) ? deployConfig.releasesDirectory : deployConfig.destination + '../releases/';
var releaseDirCheckCommand = 'mkdir -p ' + releasesDirecoryBase;
return sshConnect.shell( [ releaseDirCheckCommand ] )
.pipe( gulp.dest('./') )
.on( 'end', function() { console.log( chalk.green( "SSH setup Complete !" ) ); console.log( chalk.green( "Output:" ) ); console.log( fs.readFileSync('./gulp-ssh.shell.log' ).toString() ); } );
} );
gulp.task( 'upload', [ 'setupSSH' ], function() {
var now = new Date();
var month = "" + (now.getMonth() + 1);
var day = "" + now.getDate();
var hours = "" + now.getHours();
var minutes = "" + now.getMinutes();
var seconds = "" + now.getSeconds();
// Calculate Timestamp
timestamp = now.getFullYear()
+ ( month.length < 2 ? "0" + month : month )
+ ( day.length < 2 ? "0" + day : day )
+ ( hours.length < 2 ? "0" + hours : hours )
+ ( minutes.length < 2 ? "0" + minutes : minutes )
+ ( seconds.length < 2 ? "0" + seconds : seconds );
// generate releaseDirectory
releasesDirecory = releasesDirecoryBase + timestamp + "/";
// Setup local rsync config
var rsyncLocalConfig = {};
rsyncLocalConfig['destination'] = releasesDirecory;
rsyncLocalConfig['root'] = deployConfig.root;
rsyncLocalConfig['hostname'] = deployConfig.hostname;
rsyncLocalConfig['username'] = deployConfig.username;
rsyncLocalConfig['incremental'] = true;
rsyncLocalConfig['progress'] = true;
rsyncLocalConfig['relative'] = true;
rsyncLocalConfig['emptyDirectory'] = true;
rsyncLocalConfig['recursive'] = true;
rsyncLocalConfig['recursiveclean'] = false;
rsyncLocalConfig['exclude'] = [ 'node_modules/**', '.sass-cache/**', '/vendor/**' ];
return gulp.src( [ deployConfig.root+'/**', '!' + deployConfig.root + '/node_modules/**', '!' + deployConfig.root + '/.sass-cache/**', '!' + deployConfig.root + '/vendor/**' ] )
// Copy files to releases folder on the server.
.pipe( rsync( rsyncLocalConfig ) )
.on( 'end', function() { console.log( chalk.green( 'Upload Complete !' ) ); } );
} );
gulp.task( 'setcurrent', [ 'upload' ], function() {
// setup resetCurrentVersionCommand on the server
var resetCurrentVersionCommand = 'cd ' + releasesDirecoryBase + ' && rm -rf current && rm -rf .currentTimeStamp && ln -s ' + releasesDirecory + ' current && echo "' + timestamp + '" >> .currentTimeStamp';
return sshConnect.shell( [ resetCurrentVersionCommand ] )
.pipe( gulp.dest( './' ) )
.on( 'end', function() { console.log( chalk.green( "Current version setup Complete !" ) ); console.log( chalk.green( "Output:" ) ); console.log( fs.readFileSync('./gulp-ssh.shell.log' ).toString() ); } );
} );
gulp.task( 'symlink', [ 'setcurrent' ], function() {
var symlinkCommand = 'mkdir -p ' + deployConfig.destination + ' && rm -rf ' + deployConfig.destination + deployConfig.themeName +' && cd ' + deployConfig.destination + ' && ln -s ' + releasesDirecoryBase + 'current ' + deployConfig.themeName;
return sshConnect.shell( [ symlinkCommand ] )
.pipe( gulp.dest( './' ) )
.on( 'end', function() { console.log( chalk.green( "Symlink Complete !" ) ); console.log( chalk.green( "Output:" ) ); console.log( fs.readFileSync('./gulp-ssh.shell.log' ).toString() ); } );
} );
gulp.task( 'deploy', [ 'setcurrent', 'symlink', 'upload', 'setupSSH' ] );
gulp.task( 'releases', [ 'setupSSH' ], function() {
var showReleasesCommand = 'echo "\nList of Releases:\n" && ls -lsa ' + releasesDirecoryBase + ' && echo "\nCurrent Revision:\n" && cat ' + releasesDirecoryBase + '.currentTimeStamp && echo "\nTheme Directory Status:\n" && ls -lsa ' + deployConfig.destination + deployConfig.themeName;
return sshConnect.shell( [ showReleasesCommand ] )
.pipe( gulp.dest( './' ) )
.on( 'end', function() { console.log( chalk.green( "Output:" ) ); console.log( fs.readFileSync('./gulp-ssh.shell.log' ).toString() ); } );
} );
gulp.task( 'rollback', [ 'setupSSH' ], function() {
if ( ! argv.revision ) {
console.log( chalk.bold.red( 'You need to pass valid revision to be able to rollback ! USE : gulp rollback --<environment> --revision=<timestamp> !' ) );
process.exit();
}
releasesDirecory = releasesDirecoryBase + argv.revision + "/";
var rollbackCommand = '[ -d "' + releasesDirecory + '" ] && ( cd ' + releasesDirecoryBase + ' && rm -rf current && rm -rf .currentTimeStamp && ln -s ' + releasesDirecory + ' current && echo "' + argv.revision + '" >> .currentTimeStamp && mkdir -p ' + deployConfig.destination + ' && rm -rf ' + deployConfig.destination + deployConfig.themeName +' && cd ' + deployConfig.destination + ' && ln -s ' + releasesDirecoryBase + 'current ' + deployConfig.themeName + ' && echo "Success : Rollback done successfully !" ) || echo "Error: Revision "' + argv.revision + '" does not exists. Please use gulp releases to view available releases."'
return sshConnect.shell( [ rollbackCommand ] )
.pipe( gulp.dest( './' ) )
.on( 'end', function() { console.log( chalk.green( "Output:" ) ); console.log( fs.readFileSync('./gulp-ssh.shell.log' ).toString() ); } );
} );
{
"devDependencies": {
"gulp": "^3.8.10",
"gulp-ssh": ">=0.3.3",
"gulp-rsync": ">=0.0.5",
"yargs": ">=3.5.4",
"fs.extra": ">=1.3.2",
"chalk": ">=1.0.0"
},
"engines": {
"node": ">=0.10.0"
},
"private": true,
"scripts": {
"test": "gulp && git status | grep 'working directory clean' >/dev/null || (echo 'Please commit all changes generated by building'; exit 1)"
},
"dependencies": {
"gulp-install": "^0.2.0"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment