/** * Cleanup old releases by listing all releases and keeping a configurable * number of old releases (application option "keepReleases"). The current * and previous release (if one exists) are protected from removal. * * Example configuration: * * $application->setOption('keepReleases', 2); * * Note: There is no rollback for this cleanup, so we have to be sure not to delete any * live or referenced releases. * * @param \TYPO3\Surf\Domain\Model\Node $node * @param \TYPO3\Surf\Domain\Model\Application $application * @param \TYPO3\Surf\Domain\Model\Deployment $deployment * @param array $options * @return void */ public function execute(Node $node, Application $application, Deployment $deployment, array $options = array()) { if (!isset($options['keepReleases'])) { $deployment->getLogger()->debug(($deployment->isDryRun() ? 'Would keep' : 'Keeping') . ' all releases for "' . $application->getName() . '"'); return; } $keepReleases = $options['keepReleases']; $releasesPath = $application->getReleasesPath(); $currentReleaseIdentifier = $deployment->getReleaseIdentifier(); $previousReleasePath = $application->getReleasesPath() . '/previous'; $previousReleaseIdentifier = trim($this->shell->execute("if [ -h {$previousReleasePath} ]; then basename `readlink {$previousReleasePath}` ; fi", $node, $deployment)); $allReleasesList = $this->shell->execute("if [ -d {$releasesPath}/. ]; then find {$releasesPath}/. -maxdepth 1 -type d -exec basename {} \\; ; fi", $node, $deployment); $allReleases = preg_split('/\\s+/', $allReleasesList, -1, PREG_SPLIT_NO_EMPTY); $removableReleases = array(); foreach ($allReleases as $release) { if ($release !== '.' && $release !== $currentReleaseIdentifier && $release !== $previousReleaseIdentifier && $release !== 'current' && $release !== 'previous') { $removableReleases[] = trim($release); } } sort($removableReleases); $removeReleases = array_slice($removableReleases, 0, count($removableReleases) - $keepReleases); $removeCommand = ''; foreach ($removeReleases as $removeRelease) { $removeCommand .= "rm -rf {$releasesPath}/{$removeRelease};rm -f {$releasesPath}/{$removeRelease}REVISION;"; } if (count($removeReleases) > 0) { $deployment->getLogger()->info(($deployment->isDryRun() ? 'Would remove' : 'Removing') . ' releases ' . implode(', ', $removeReleases)); $this->shell->executeOrSimulate($removeCommand, $node, $deployment); } else { $deployment->getLogger()->info('No releases to remove'); } }
/** * Rollback this task * * @param \TYPO3\Surf\Domain\Model\Node $node * @param \TYPO3\Surf\Domain\Model\Application $application * @param \TYPO3\Surf\Domain\Model\Deployment $deployment * @param array $options * @return void * @todo Make the removal of a failed release configurable, sometimes it's necessary to inspect a failed release */ public function rollback(Node $node, Application $application, Deployment $deployment, array $options = array()) { $releasesPath = $application->getReleasesPath(); $releasePath = $deployment->getApplicationReleasePath($application); $commands = array('rm ' . $releasesPath . '/next', 'rm -rf ' . $releasePath); $this->shell->execute($commands, $node, $deployment, true); }
/** * Executes this task * * @param \TYPO3\Surf\Domain\Model\Node $node * @param \TYPO3\Surf\Domain\Model\Application $application * @param \TYPO3\Surf\Domain\Model\Deployment $deployment * @param array $options * @return void */ public function execute(Node $node, Application $application, Deployment $deployment, array $options = array()) { $releaseIdentifier = $deployment->getReleaseIdentifier(); $releasesPath = $application->getReleasesPath(); $commands = array("mkdir -p {$releasesPath}/{$releaseIdentifier}/Data", "cd {$releasesPath}/{$releaseIdentifier}", 'ln -sf ../../../shared/Data/Logs ./Data/Logs', 'ln -sf ../../../shared/Data/Persistent ./Data/Persistent'); $this->shell->executeOrSimulate($commands, $node, $deployment); }
/** * Executes this task * * @param \TYPO3\Surf\Domain\Model\Node $node * @param \TYPO3\Surf\Domain\Model\Application $application * @param \TYPO3\Surf\Domain\Model\Deployment $deployment * @param array $options * @return void * @throws TaskExecutionException */ public function execute(Node $node, Application $application, Deployment $deployment, array $options = array()) { $commands = array('cd ' . escapeshellarg(rtrim($application->getReleasesPath(), '/') . '/' . $this->getTargetPath($options)), 'rm -f ' . escapeshellarg($this->getFileName($options))); $this->shell->executeOrSimulate($commands, $node, $deployment); $commands[0] = 'cd ' . escapeshellarg(rtrim($deployment->getWorkspacePath($application), '/') . '/' . $this->getTargetPath($options)); $this->shell->executeOrSimulate($commands, $deployment->getNode('localhost'), $deployment); }
/** * Executes this task * * @param \TYPO3\Surf\Domain\Model\Node $node * @param \TYPO3\Surf\Domain\Model\Application $application * @param \TYPO3\Surf\Domain\Model\Deployment $deployment * @param array $options * @return void * @throws TaskExecutionException */ public function execute(Node $node, Application $application, Deployment $deployment, array $options = array()) { $targetPath = isset($options['deploymentLogTargetPath']) ? $options['deploymentLogTargetPath'] : '.'; $fileName = !empty($options['deploymentLogFileName']) ? $options['deploymentLogFileName'] : 'deployment.log'; $optionsToLog = !empty($options['deploymentLogOptions']) ? $options['deploymentLogOptions'] : array('tag', 'branch', 'sha1'); $logContent = array(date('Y-m-d H:i:s (D)'), 'Application: ' . $application->getName(), 'Deployment: ' . $deployment->getName(), 'Status: ' . $deployment->getStatus()); foreach ($optionsToLog as $key) { if (!empty($options[$key])) { $logContent[] = $key . ' = ' . $options[$key]; } } $commands = array('cd ' . escapeshellarg($application->getReleasesPath()), 'echo ' . escapeshellarg(implode(' | ', $logContent)) . ' >> ' . rtrim($targetPath, '/') . '/' . $fileName); $this->shell->executeOrSimulate($commands, $node, $deployment); }
/** * * @param \TYPO3\Surf\Domain\Model\Application $application * @return string */ public function getApplicationReleasePath(Application $application) { return $application->getReleasesPath() . '/' . $this->getReleaseIdentifier(); }
/** * @param Node $node * @param Application $application * @param string $path * @param string $file * @return string */ protected function getArgument(Node $node, Application $application, $path, $file) { $argument = ''; if ($node->hasOption('username')) { $username = $node->getOption('username'); if (!empty($username)) { $argument .= $username . '@'; } } $argument .= $node->getHostname() . ':'; $argument .= rtrim($application->getReleasesPath(), '/') . '/'; $argument = rtrim($argument . $path, '/') . '/'; $argument .= $file; return $argument; }
/** * Rollback this task * * @param \TYPO3\Surf\Domain\Model\Node $node * @param \TYPO3\Surf\Domain\Model\Application $application * @param \TYPO3\Surf\Domain\Model\Deployment $deployment * @param array $options * @return void */ public function rollback(Node $node, Application $application, Deployment $deployment, array $options = array()) { $releasesPath = $application->getReleasesPath(); $this->shell->execute('cd ' . $releasesPath . ' && rm -f ./current && mv ./previous ./current', $node, $deployment, true); }
/** * @param \TYPO3\Surf\Domain\Model\Application $application * @return string */ public function getApplicationReleasePath(Application $application) { return $application->getReleasesPath(); }