Skip to content

Instantly share code, notes, and snippets.

@ntd
Last active September 14, 2021 06:14
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 ntd/3f3af953802eeb55bd3aee7213044dd5 to your computer and use it in GitHub Desktop.
Save ntd/3f3af953802eeb55bd3aee7213044dd5 to your computer and use it in GitHub Desktop.
Deployer strategy for SilverStripe 4 (with public enabled)
<?php
/**
* This is the shared deployer code I use in my projects. I put it
* somewhere in the filesystem and then, in each SilverStripe project,
* I add `deploy.php`:
* ```
* <?php
* require '/path/to/my/deployer-silverstripe4.php';
* Deployer\set('application', 'my_application_name');
* ```
* and `hosts.yml`:
* ```
* mytestingdeployment:
* hostname: myserver
* stage: staging
* deploy_path: "/var/staging/{{application}}"
* myfinaldeployment:
* hostname: myserver
* stage: production
* deploy_path: "/var/www/{{application}}"
* ```
*/
namespace Deployer;
require 'recipe/silverstripe.php';
// Fallback settings, overridable in `hosts.yml`
set('default_stage', 'production');
set('shared_dirs', [ 'public/assets' ]);
set('writable_dirs', [ 'public/assets' ]);
set('writable_chmod_mode', 'g+rwX');
set('http_group', 'www-data');
set('env_candidates', [ './.env.{{hostname}}', './.env.{{stage}}', './.env' ]);
inventory('hosts.yml');
// This will require the proper `cachetool` binary installed in path:
// https://github.com/gordalina/cachetool
desc('Clear opcache cache');
task('cachetool:clear:opcache', function () {
run('cachetool opcache:reset -n --fcgi');
});
desc('Clear APCU cache');
task('cachetool:clear:apcu', function () {
run('cachetool apcu:cache:clear -n --fcgi');
});
// Override the writable task to change the group *and* the mode, so
// the group will be able to write. AFAIK the default writable task
// performs one (and only one!) of those actions.
desc('Make writable dirs');
task('deploy:writable', function () {
$dirs = join(' ', get('writable_dirs'));
if (empty($dirs)) {
return;
}
$group = get('http_group');
$mode = get('writable_chmod_mode');
$recurse = get('writable_recursive') ? '-R' : '';
cd('{{release_path}}');
run("mkdir -p $dirs");
// Ignore errors (likely due to bogus permission denied)
run("chgrp --quiet $recurse -H $group $dirs || :");
run("chmod --quiet $recurse $mode $dirs || :");
});
// Use `rsync` for updating code on the remote host
desc('Update code');
task('deploy:update_code', function () {
// `rsync` options
$options = [
'-R',
// The `-FF` argument allows to override the rules below
// with local `.rsync-filter` files: see `man rsync`
'-FF',
// Default filter rules
'--filter="+ /app/***"',
'--filter="+ /composer.*"',
'--filter="+ /main/***"',
'--filter="+ /themes/***"',
'--filter="- /public/assets/"',
'--filter="- /public/resources/"',
'--filter="+ /public/***"',
'--filter="- *"',
];
upload('./', '{{release_path}}', [ 'options' => $options ]);
});
// Custom task that uploads the proper `.env` file
desc('Upload the environment file');
task('silverstripe:environment', function () {
foreach (get('env_candidates') as $candidate) {
$env = parse($candidate);
if (file_exists($env)) {
upload($env, '{{release_path}}/.env');
return;
}
}
throw new Exception('No valid .env file found.');
});
desc('Deploy your project');
task('deploy', [
'deploy:info',
'deploy:prepare',
'deploy:lock',
'deploy:release',
'deploy:update_code',
'silverstripe:environment',
'deploy:shared',
'deploy:writable',
'deploy:vendors',
'deploy:clear_paths',
'deploy:symlink',
'cachetool:clear:opcache',
'cachetool:clear:apcu',
'silverstripe:buildflush',
'deploy:unlock',
'cleanup',
'success',
]);
// Automatically unlock the deployment on failures
after('deploy:failed', 'deploy:unlock');
task('backup:info', function () {
writeln("✈︎ Starting backup of <fg=cyan>{{hostname}}</fg=cyan>");
})
->setPrivate()
->shallow();
// Create a local dump of the remote database
desc('Update the local database dump with remote content');
task('backup:database', function () {
// Source .env to get database access settings
$dump = run(
'source {{ release_path }}/.env && mysqldump --compact' .
' -h$SS_DATABASE_SERVER -u$SS_DATABASE_USERNAME' .
' -p$SS_DATABASE_PASSWORD $SS_DATABASE_NAME'
);
// Store the database dump in the root folder of the project
$db = get('application', 'dump');
file_put_contents("./$db.sql", $dump);
});
// Fetch assets from the remote
desc('Download assets');
task('backup:assets', function () {
// By default, consider the first shared_dirs as the assets dir
$dir = current(get('shared_dirs', []));
if (empty($dir)) {
return;
}
// Download all the crap
$from = get('deploy_path') . '/shared/' . $dir . '/';
$to = './' . $dir . '/';
download($from, $to, [ 'options' => [
'--delete',
'-a',
]]);
});
task('backup:success', function () {
writeln('<info>Backup terminated successfully!</info>');
})
->local()
->shallow()
->setPrivate();
desc('Backup your project');
task('backup', [
'backup:info',
'backup:database',
'backup:assets',
'backup:success',
])
->onStage('production');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment