mirror of
https://github.com/e107inc/e107.git
synced 2025-07-25 17:01:43 +02:00
Deployers, a concept unique to this repository, are now more separated from Codeception modules. This commit adds NoopDeployer, LocalDeployer, and SFTPDeployer to address the three deployment target types in use by testers today. The changes are backwards-incompatible because the structure of config.sample.yml has changed, and all testers need to change their config.yml or config.local.yml to continue testing. The reason for this change is that the section "manual" no longer makes sense now that Deployers are on a spectrum of automation levels. The subsections under "manual" have been broken out into the root level. The "db_dump" section has been merged into the new "db" root section. There is a new "fs" root section used by the SFTP Deployer. Other changes, enhancements, and bugfixes: * cPanelDeployer no longer downgrades to "manual" mode when credentials are missing or an unsupported component is requested. It now throws an exception. * Deployer::unlinkAppFile() was implemented for acceptance tests out of necessity because the app requires a configuration file to be deleted before re-running the app's installer. * If a Deployer subclass does not implement the unlinkAppFile() method, tests that depend on the method will be skipped gracefully. * DeployerFactory now has a better autoload mechanism. * A logical error in lib/config.php prevented missing nested array items from using their default values. * The Base Helper no longer pointlessly caches the DelayedDb module * _bootstrap.php serializes the config.yml params into a global constant so that the DeployerFactory can freely access the information.
107 lines
2.8 KiB
PHP
107 lines
2.8 KiB
PHP
<?php
|
||
|
||
class SFTPDeployer extends Deployer
|
||
{
|
||
public function start()
|
||
{
|
||
self::println();
|
||
self::println("=== SFTP Deployer – Bring Up ===");
|
||
if (in_array('fs', $this->components))
|
||
{
|
||
$this->start_fs();
|
||
}
|
||
}
|
||
|
||
private function getFsParams()
|
||
{
|
||
return $this->params['fs'];
|
||
}
|
||
|
||
private function generateSshpassPrefix()
|
||
{
|
||
if (empty($this->getFsParam('privkey_path')) &&
|
||
!empty($this->getFsParam('password')))
|
||
{
|
||
return 'sshpass -p '.escapeshellarg($this->getFsParam('password')).' ';
|
||
}
|
||
return '';
|
||
}
|
||
|
||
private function getFsParam($key)
|
||
{
|
||
return $this->getFsParams()[$key];
|
||
}
|
||
|
||
private function generateRsyncRemoteShell()
|
||
{
|
||
$prefix = 'ssh -p '.escapeshellarg($this->getFsParam('port'));
|
||
if (!empty($this->getFsParam('privkey_path')))
|
||
return $prefix.' -i ' . escapeshellarg($this->getFsParam('privkey_path'));
|
||
else
|
||
return $prefix;
|
||
}
|
||
|
||
private static function runCommand($command, &$stdout = null, &$stderr = null)
|
||
{
|
||
$descriptorSpec = [
|
||
1 => ['pipe', 'w'],
|
||
2 => ['pipe', 'w'],
|
||
];
|
||
$pipes = [];
|
||
self::println("Running this command…:");
|
||
self::println($command);
|
||
$resource = proc_open($command, $descriptorSpec, $pipes, APP_PATH);
|
||
$stdout = stream_get_contents($pipes[1]);
|
||
$stderr = stream_get_contents($pipes[2]);
|
||
self::println("---------- stdout ----------");
|
||
self::println(trim($stdout));
|
||
self::println("---------- stderr ----------");
|
||
self::println(trim($stderr));
|
||
self::println("----------------------------");
|
||
foreach ($pipes as $pipe)
|
||
{
|
||
fclose($pipe);
|
||
}
|
||
return proc_close($resource);
|
||
}
|
||
|
||
public function stop()
|
||
{
|
||
self::println("=== SFTP Deployer – Tear Down ===");
|
||
}
|
||
|
||
public function unlinkAppFile($relative_path)
|
||
{
|
||
self::println("Deleting file \"$relative_path\" from deployed test location…");
|
||
$fs_params = $this->getFsParams();
|
||
$command = $this->generateSshpassPrefix().
|
||
$this->generateRsyncRemoteShell().
|
||
" ".escapeshellarg("{$fs_params['user']}@{$fs_params['host']}").
|
||
" ".escapeshellarg("rm -v " . escapeshellarg(rtrim($fs_params['path'], '/')."/$relative_path"));
|
||
$retcode = self::runCommand($command);
|
||
if ($retcode === 0)
|
||
{
|
||
self::println("Deleted file \"$relative_path\" from deployed test location");
|
||
}
|
||
else
|
||
{
|
||
self::println("No such file to delete: \"$relative_path\"");
|
||
}
|
||
}
|
||
|
||
private function start_fs()
|
||
{
|
||
$fs_params = $this->getFsParams();
|
||
$fs_params['path'] = rtrim($fs_params['path'], '/') . '/';
|
||
$command = $this->generateSshpassPrefix() .
|
||
'rsync -e ' .
|
||
escapeshellarg($this->generateRsyncRemoteShell()) .
|
||
' --delete -avzHXShs ' .
|
||
escapeshellarg(rtrim(APP_PATH, '/') . '/') . ' ' .
|
||
escapeshellarg("{$fs_params['user']}@{$fs_params['host']}:{$fs_params['path']}");
|
||
$retcode = self::runCommand($command);
|
||
if ($retcode !== 0) {
|
||
throw new Exception("SFTP deployment failed. Run with --debug to see stdout and stderr.");
|
||
}
|
||
}
|
||
}
|