2014-07-12 14:23:22 +04:00
< ? php
/* ( c ) Anton Medvedev < anton @ elfet . ru >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
2015-02-15 15:28:44 +03:00
/**
* Common parameters .
*/
2015-01-03 00:04:00 +03:00
set ( 'keep_releases' , 3 );
2015-02-15 15:28:44 +03:00
set ( 'shared_dirs' , []);
set ( 'shared_files' , []);
2015-02-15 23:24:08 +03:00
set ( 'writable_dirs' , []);
2015-02-20 15:26:31 +03:00
set ( 'writable_use_sudo' , true ); // Using sudo in writable commands?
2015-02-25 12:49:25 +03:00
/**
* Environment vars
*/
2015-02-25 13:04:18 +03:00
env ( 'branch' , '' ); // Branch to deploy.
2015-02-25 12:49:25 +03:00
env ( 'env_vars' , '' ); // For Composer installation. Like SYMFONY_ENV=prod
2015-06-04 20:00:14 +07:00
env ( 'composer_options' , 'install --no-dev --verbose --prefer-dist --optimize-autoloader --no-progress --no-interaction' );
2015-06-16 13:15:36 +02:00
env ( 'git_cache' , function (){ //whether to use git cache - faster cloning by borrowing objects from existing clones.
2015-06-16 11:31:49 +02:00
$gitVersion = run ( 'git version' );
$regs = [];
if ( preg_match ( '/((\d+\.?)+)/' , $gitVersion , $regs )) {
$version = $regs [ 1 ];
} else {
$version = " 1.0.0 " ;
}
2015-06-16 13:15:36 +02:00
return version_compare ( $version , '2.3' , '>=' );
2015-06-16 11:31:49 +02:00
});
2015-02-24 17:13:10 +03:00
/**
2015-02-24 18:47:48 +03:00
* Default arguments and options .
2015-02-24 17:13:10 +03:00
*/
argument ( 'stage' , \Symfony\Component\Console\Input\InputArgument :: OPTIONAL , 'Run tasks only on this server or group of servers.' );
2015-02-24 18:47:48 +03:00
option ( 'tag' , null , \Symfony\Component\Console\Input\InputOption :: VALUE_OPTIONAL , 'Tag to deploy.' );
2015-01-03 00:04:00 +03:00
2014-07-12 14:23:22 +04:00
/**
* Rollback to previous release .
*/
task ( 'rollback' , function () {
2015-01-03 14:48:38 +03:00
$releases = env ( 'releases_list' );
2014-07-12 14:23:22 +04:00
if ( isset ( $releases [ 1 ])) {
2015-03-23 09:19:12 +07:00
$releaseDir = " { { deploy_path}}/releases/ { $releases [ 1 ] } " ;
2015-01-03 14:48:38 +03:00
2014-07-12 14:23:22 +04:00
// Symlink to old release.
2015-03-23 09:19:12 +07:00
run ( " cd { { deploy_path}} && ln -nfs $releaseDir current " );
2014-07-12 14:23:22 +04:00
// Remove release
2015-03-23 09:19:12 +07:00
run ( " rm -rf { { deploy_path}}/releases/ { $releases [ 0 ] } " );
2015-01-03 14:48:38 +03:00
if ( isVerbose ()) {
writeln ( " Rollback to ` { $releases [ 1 ] } ` release was successful. " );
}
2014-07-12 14:23:22 +04:00
} else {
writeln ( " <comment>No more releases you can revert to.</comment> " );
}
}) -> desc ( 'Rollback to previous release' );
/**
* Preparing server for deployment .
*/
task ( 'deploy:prepare' , function () {
2015-05-13 16:26:26 +07:00
\Deployer\Task\Context :: get () -> getServer () -> connect ();
2015-05-13 19:00:12 +07:00
// Check if shell is POSIX-compliant
2015-05-12 00:11:24 +07:00
try {
2015-05-19 14:58:32 +07:00
cd ( '' ); // To run command as raw.
2015-05-13 19:00:12 +07:00
run ( 'echo $0' );
2015-05-12 00:11:24 +07:00
} catch ( \RuntimeException $e ) {
2015-05-13 16:52:34 +07:00
$formatter = \Deployer\Deployer :: get () -> getHelper ( 'formatter' );
$errorMessage = [
" Shell on your server is not POSIX-compliant. Please change to sh, bash or similar. " ,
" Usually, you can change your shell to bash by running: chsh -s /bin/bash " ,
];
write ( $formatter -> formatBlock ( $errorMessage , 'error' , true ));
2015-05-13 13:26:48 +07:00
throw $e ;
2015-05-12 00:11:24 +07:00
}
2015-05-13 19:00:12 +07:00
run ( 'if [ ! -d {{deploy_path}} ]; then echo ""; fi' );
2015-05-11 14:04:14 +01:00
2014-07-12 14:23:22 +04:00
// Create releases dir.
2015-03-23 09:19:12 +07:00
run ( " cd { { deploy_path}} && if [ ! -d releases ]; then mkdir releases; fi " );
2014-07-12 14:23:22 +04:00
// Create shared dir.
2015-03-23 09:19:12 +07:00
run ( " cd { { deploy_path}} && if [ ! -d shared ]; then mkdir shared; fi " );
2014-07-12 14:23:22 +04:00
}) -> desc ( 'Preparing server for deploy' );
2015-01-03 00:04:00 +03:00
/**
* Return release path .
*/
env ( 'release_path' , function () {
2015-03-23 09:19:12 +07:00
return str_replace ( " \n " , '' , run ( " readlink { { deploy_path}}/release " ));
2015-01-03 00:04:00 +03:00
});
2014-07-12 14:23:22 +04:00
/**
2015-01-03 00:04:00 +03:00
* Release
2014-07-12 14:23:22 +04:00
*/
2015-01-03 00:04:00 +03:00
task ( 'deploy:release' , function () {
2015-06-12 12:05:35 +02:00
$release = run ( 'date +%Y%m%d%H%M%S' );
2014-07-12 14:23:22 +04:00
2015-03-23 09:19:12 +07:00
$releasePath = " { { deploy_path}}/releases/ $release " ;
2014-07-12 14:23:22 +04:00
2015-02-15 23:24:08 +03:00
$i = 0 ;
while ( is_dir ( env () -> parse ( $releasePath )) && $i < 42 ) {
$releasePath .= '.' . ++ $i ;
}
2015-01-03 00:04:00 +03:00
run ( " mkdir $releasePath " );
2014-07-12 14:23:22 +04:00
2015-05-08 13:03:22 +03:00
run ( " cd { { deploy_path}} && if [ -h release ]; then rm release; fi " );
2015-01-03 00:04:00 +03:00
2015-03-23 09:19:12 +07:00
run ( " ln -s $releasePath { { deploy_path}}/release " );
2015-01-03 00:04:00 +03:00
}) -> desc ( 'Prepare release' );
2014-07-12 14:23:22 +04:00
/**
2015-01-03 00:04:00 +03:00
* Update project code
2014-07-12 14:23:22 +04:00
*/
2015-01-03 00:04:00 +03:00
task ( 'deploy:update_code' , function () {
2015-01-03 15:01:48 +03:00
$repository = get ( 'repository' );
2015-02-25 12:49:25 +03:00
$branch = env ( 'branch' );
2015-06-16 11:31:49 +02:00
$gitCache = env ( 'git_cache' );
2015-06-16 13:15:36 +02:00
$depth = $gitCache ? '' : '--depth 1' ;
2015-02-24 18:47:48 +03:00
if ( input () -> hasOption ( 'tag' )) {
$tag = input () -> getOption ( 'tag' );
2015-02-25 12:20:04 +03:00
}
$at = '' ;
if ( ! empty ( $tag )) {
$at = " -b $tag " ;
} else if ( ! empty ( $branch )) {
$at = " -b $branch " ;
}
2015-02-25 12:36:25 -05:00
2015-06-16 11:31:49 +02:00
$releases = env ( 'releases_list' );
if ( $gitCache && isset ( $releases [ 1 ])){
try {
run ( " git clone $at --recursive -q --reference { { deploy_path}}/releases/ { $releases [ 1 ] } --dissociate $repository { { release_path}} 2>&1 " );
} catch ( RuntimeException $exc ) {
// If {{deploy_path}}/releases/{$releases[1]} has a failed git clone, is empty, shallow etc, git would throw error and give up. So we're forcing it to act without reference in this situation
run ( " git clone $at --recursive -q $repository { { release_path}} 2>&1 " );
}
} else {
2015-06-16 13:15:36 +02:00
// if we're using git cache this would be identical to above code in catch - full clone. If not, it would create shallow clone.
run ( " git clone $at $depth --recursive -q $repository { { release_path}} 2>&1 " );
2015-06-16 11:31:49 +02:00
}
2015-02-25 12:36:25 -05:00
2015-01-03 00:04:00 +03:00
}) -> desc ( 'Updating code' );
2014-07-12 14:23:22 +04:00
/**
2015-01-03 00:04:00 +03:00
* Create symlinks for shared directories and files .
2014-07-12 14:23:22 +04:00
*/
task ( 'deploy:shared' , function () {
2015-03-23 09:19:12 +07:00
$sharedPath = " { { deploy_path}}/shared " ;
2014-07-12 14:23:22 +04:00
2015-02-15 15:28:44 +03:00
foreach ( get ( 'shared_dirs' ) as $dir ) {
2015-01-03 00:04:00 +03:00
// Remove from source
2015-03-23 09:19:12 +07:00
run ( " if [ -d $ (echo { { release_path}}/ $dir ) ]; then rm -rf { { release_path}}/ $dir ; fi " );
2014-07-12 14:23:22 +04:00
2015-02-25 12:36:25 -05:00
// Create shared dir if it does not exist
2015-02-15 15:28:44 +03:00
run ( " mkdir -p $sharedPath / $dir " );
2014-07-12 14:23:22 +04:00
2015-02-25 12:36:25 -05:00
// Create path to shared dir in release dir if it does not exist
// (symlink will not create the path and will fail otherwise)
2015-03-23 09:19:12 +07:00
run ( " mkdir -p `dirname { { release_path}}/ $dir ` " );
2015-02-25 12:36:25 -05:00
2014-07-12 14:23:22 +04:00
// Symlink shared dir to release dir
2015-03-23 09:19:12 +07:00
run ( " ln -nfs $sharedPath / $dir { { release_path}}/ $dir " );
2014-07-12 14:23:22 +04:00
}
2015-01-03 00:04:00 +03:00
foreach ( get ( 'shared_files' ) as $file ) {
// Remove from source
2015-06-04 14:22:37 +03:00
run ( " if [ -f $ (echo { { release_path}}/ $file ) ]; then rm -rf { { release_path}}/ $file ; fi " );
2014-07-12 14:23:22 +04:00
// Create dir of shared file
run ( " mkdir -p $sharedPath / " . dirname ( $file ));
2015-01-03 00:04:00 +03:00
// Touch shared
2014-07-12 14:23:22 +04:00
run ( " touch $sharedPath / $file " );
2015-01-03 00:04:00 +03:00
// Symlink shared dir to release dir
2015-03-23 09:19:12 +07:00
run ( " ln -nfs $sharedPath / $file { { release_path}}/ $file " );
2014-07-12 14:23:22 +04:00
}
}) -> desc ( 'Creating symlinks for shared files' );
/**
2015-02-15 23:24:08 +03:00
* Make writable dirs .
2014-07-12 14:23:22 +04:00
*/
2015-02-15 23:24:08 +03:00
task ( 'deploy:writable' , function () {
$dirs = join ( ' ' , get ( 'writable_dirs' ));
2015-02-20 15:26:31 +03:00
$sudo = get ( 'writable_use_sudo' ) ? 'sudo' : '' ;
2015-02-15 23:24:08 +03:00
2015-05-05 00:36:28 +07:00
if ( ! empty ( $dirs )) {
2015-02-15 23:24:08 +03:00
2015-05-13 16:52:34 +07:00
try {
$httpUser = run ( " ps aux | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d \ -f1 " ) -> toString ();
2015-02-15 23:24:08 +03:00
2015-05-13 16:52:34 +07:00
cd ( '{{release_path}}' );
2015-02-15 23:41:52 +03:00
2015-05-13 16:52:34 +07:00
if ( strpos ( run ( " chmod 2>&1; true " ), '+a' ) !== false ) {
2015-02-15 23:24:08 +03:00
2015-05-13 16:52:34 +07:00
if ( ! empty ( $httpUser )) {
run ( " $sudo chmod +a \" $httpUser allow delete,write,append,file_inherit,directory_inherit \" $dirs " );
}
2015-02-25 12:36:25 -05:00
2015-05-13 16:52:34 +07:00
run ( " $sudo chmod +a \" `whoami` allow delete,write,append,file_inherit,directory_inherit \" $dirs " );
} elseif ( commandExist ( 'setfacl' )) {
if ( ! empty ( $httpUser )) {
run ( " $sudo setfacl -R -m u: \" $httpUser\ " : rwX - m u : `whoami` : rwX $dirs " );
run ( " $sudo setfacl -dR -m u: \" $httpUser\ " : rwX - m u : `whoami` : rwX $dirs " );
} else {
run ( " $sudo chmod 777 $dirs " );
}
2015-02-15 23:24:08 +03:00
2015-02-20 15:26:31 +03:00
} else {
2015-02-25 12:36:25 -05:00
run ( " $sudo chmod 777 $dirs " );
2015-02-20 15:26:31 +03:00
}
2015-02-15 23:24:08 +03:00
2015-05-13 16:52:34 +07:00
} catch ( \RuntimeException $e ) {
$formatter = \Deployer\Deployer :: get () -> getHelper ( 'formatter' );
$errorMessage = [
" Unable to setup correct permissions for writable dirs. " ,
" You need co configure sudo's sudoers files to don't prompt for password, " ,
" or setup correct permissions manually. " ,
];
write ( $formatter -> formatBlock ( $errorMessage , 'error' , true ));
2015-02-15 23:24:08 +03:00
2015-05-13 16:52:34 +07:00
throw $e ;
2015-02-15 23:24:08 +03:00
}
2014-07-12 14:23:22 +04:00
}
2015-02-15 23:24:08 +03:00
2015-02-20 15:26:31 +03:00
}) -> desc ( 'Make writable dirs' );
2014-07-12 14:23:22 +04:00
/**
2015-01-03 00:04:00 +03:00
* Installing vendors tasks .
2014-07-12 14:23:22 +04:00
*/
task ( 'deploy:vendors' , function () {
2015-02-15 23:24:08 +03:00
if ( commandExist ( 'composer' )) {
$composer = 'composer' ;
} else {
2015-05-05 00:09:48 +07:00
run ( " cd { { release_path}} && curl -sS https://getcomposer.org/installer | php " );
2015-02-15 15:28:44 +03:00
$composer = 'php composer.phar' ;
2014-07-12 14:23:22 +04:00
}
2015-06-04 20:00:14 +07:00
run ( " cd { { release_path}} && { { env_vars}} $composer { { composer_options}} " );
2014-07-12 14:23:22 +04:00
}) -> desc ( 'Installing vendors' );
/**
2015-01-03 00:04:00 +03:00
* Create symlink to last release .
2014-07-12 14:23:22 +04:00
*/
task ( 'deploy:symlink' , function () {
2015-05-12 13:15:51 +07:00
run ( " cd { { deploy_path}} && ln -sfn { { release_path}} current " ); // Atomic override symlink.
run ( " cd { { deploy_path}} && rm release " ); // Remove release link.
2014-07-12 14:23:22 +04:00
}) -> desc ( 'Creating symlink to release' );
/**
2015-01-03 00:04:00 +03:00
* Return list of releases on server .
*/
env ( 'releases_list' , function () {
2015-03-23 09:19:12 +07:00
$list = run ( 'ls {{deploy_path}}/releases' ) -> toArray ();
2015-01-03 00:04:00 +03:00
rsort ( $list );
return $list ;
});
/**
* Return current release path .
*/
env ( 'current' , function () {
2015-03-23 09:19:12 +07:00
return run ( " readlink { { deploy_path}}/current " ) -> toString ();
2015-01-03 00:04:00 +03:00
});
/**
* Show current release number .
*/
task ( 'current' , function () {
writeln ( 'Current release: ' . basename ( env ( 'current' )));
}) -> desc ( 'Show current release.' );
/**
* Cleanup old releases .
2014-07-12 14:23:22 +04:00
*/
task ( 'cleanup' , function () {
2015-01-03 00:04:00 +03:00
$releases = env ( 'releases_list' );
2014-07-12 14:23:22 +04:00
2015-01-03 00:04:00 +03:00
$keep = get ( 'keep_releases' );
2014-07-12 14:23:22 +04:00
while ( $keep > 0 ) {
array_shift ( $releases );
-- $keep ;
}
foreach ( $releases as $release ) {
2015-03-23 09:19:12 +07:00
run ( " rm -rf { { deploy_path}}/releases/ $release " );
2014-07-12 14:23:22 +04:00
}
2015-03-23 09:19:12 +07:00
run ( " cd { { deploy_path}} && if [ -e release ]; then rm release; fi " );
run ( " cd { { deploy_path}} && if [ -h release ]; then rm release; fi " );
2015-01-03 14:48:38 +03:00
2014-07-12 14:23:22 +04:00
}) -> desc ( 'Cleaning up old releases' );
2015-02-25 12:55:56 +03:00
/**
* Success message
*/
task ( 'success' , function () {
writeln ( " <info>Successfully deployed!</info> " );
})
-> once ()
-> setPrivate ();