Esempio n. 1
0
 /**
  * Executes this task
  *
  * Options:
  *   command: The command to execute
  *   rollbackCommand: The command to execute as a rollback (optional)
  *
  * @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 \TYPO3\Surf\Exception\InvalidConfigurationException
  */
 public function execute(Node $node, Application $application, Deployment $deployment, array $options = array())
 {
     if (!isset($options['folders'])) {
         return;
     }
     $folders = $options['folders'];
     if (!is_array($folders)) {
         $folders = array($folders);
     }
     $replacePaths = array('{deploymentPath}' => escapeshellarg($application->getDeploymentPath()), '{sharedPath}' => escapeshellarg($application->getSharedPath()), '{releasePath}' => escapeshellarg($deployment->getApplicationReleasePath($application)), '{currentPath}' => escapeshellarg($application->getReleasesPath() . '/current'), '{previousPath}' => escapeshellarg($application->getReleasesPath() . '/previous'));
     $commands = array();
     $username = isset($options['username']) ? $options['username'] . '@' : '';
     $hostname = $node->getHostname();
     $port = $node->hasOption('port') ? '-P ' . escapeshellarg($node->getOption('port')) : '';
     foreach ($folders as $folderPair) {
         if (!is_array($folderPair) || count($folderPair) !== 2) {
             throw new InvalidConfigurationException('Each rsync folder definition must be an array of exactly two folders', 1405599056);
         }
         $sourceFolder = rtrim(str_replace(array_keys($replacePaths), $replacePaths, $folderPair[0]), '/') . '/';
         $targetFolder = rtrim(str_replace(array_keys($replacePaths), $replacePaths, $folderPair[1]), '/') . '/';
         $commands[] = "rsync -avz --delete -e ssh {$sourceFolder} {$username}{$hostname}:{$targetFolder}";
     }
     $ignoreErrors = isset($options['ignoreErrors']) && $options['ignoreErrors'] === true;
     $logOutput = !(isset($options['logOutput']) && $options['logOutput'] === false);
     $localhost = new Node('localhost');
     $localhost->setHostname('localhost');
     $this->shell->executeOrSimulate($commands, $localhost, $deployment, $ignoreErrors, $logOutput);
 }
Esempio n. 2
0
 /**
  * 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');
     }
 }
Esempio n. 3
0
 /**
  * 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);
 }
Esempio n. 4
0
 /**
  * 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);
 }
Esempio n. 5
0
 /**
  * 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);
 }
Esempio n. 6
0
 /**
  * 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())
 {
     if (!isset($options['rollbackCommand'])) {
         return;
     }
     $replacePaths = array('{deploymentPath}' => $application->getDeploymentPath(), '{sharedPath}' => $application->getSharedPath(), '{releasePath}' => $deployment->getApplicationReleasePath($application), '{currentPath}' => $application->getReleasesPath() . '/current', '{previousPath}' => $application->getReleasesPath() . '/previous');
     $command = $options['rollbackCommand'];
     $command = str_replace(array_keys($replacePaths), $replacePaths, $command);
     $this->shell->execute($command, $node, $deployment, true);
 }
Esempio n. 7
0
 /**
  * Execute 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 \TYPO3\Surf\Exception\InvalidConfigurationException
  * @throws \TYPO3\Surf\Exception\TaskExecutionException
  */
 public function execute(Node $node, Application $application, Deployment $deployment, array $options = array())
 {
     if (!isset($options['repositoryUrl'])) {
         throw new \TYPO3\Surf\Exception\InvalidConfigurationException(sprintf('Missing "repositoryUrl" option for application "%s"', $application->getName()), 1374074052);
     }
     $localCheckoutPath = $deployment->getWorkspacePath($application);
     $node = $deployment->getNode('localhost');
     $sha1 = $this->executeOrSimulateGitCloneOrUpdate($localCheckoutPath, $node, $deployment, $options);
     $this->executeOrSimulatePostGitCheckoutCommands($localCheckoutPath, $sha1, $node, $deployment, $options);
 }
 /**
  * Execute 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 = [])
 {
     if (!isset($options['directories']) || !is_array($options['directories']) || $options['directories'] === []) {
         return;
     }
     $commands = ['cd ' . $application->getSharedPath()];
     foreach ($options['directories'] as $path) {
         $commands[] = 'mkdir -p ' . $path;
     }
     $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 \TYPO3\Surf\Exception\TaskExecutionException
  */
 public function execute(Node $node, Application $application, Deployment $deployment, array $options = array())
 {
     $this->hosting = $application->getOption('hosting');
     $this->username = $options['username'];
     $this->hostname = $node->getHostname();
     $this->deployment = $deployment;
     $this->resourcePath = $this->packageManager->getPackage('Famelo.Surf.SharedHosting')->getResourcesPath() . 'Private/' . $this->hosting;
     $this->temporaryPath = FLOW_PATH_ROOT . '/Data/Temporary/Deployment/' . $this->hosting;
     if (!is_dir($this->temporaryPath)) {
         \TYPO3\Flow\Utility\Files::createDirectoryRecursively($this->temporaryPath);
     }
 }
 /**
  * @param \TYPO3\Surf\Domain\Model\Node $node
  * @param \TYPO3\Surf\Domain\Model\Application $application
  * @param \TYPO3\Surf\Domain\Model\Deployment $deployment
  * @param array $options
  * @throws \TYPO3\Surf\Exception\TaskExecutionException
  * @return void
  */
 public function execute(Node $node, Application $application, Deployment $deployment, array $options = array())
 {
     if ($application->getOption('transferMethod') == 'rsync') {
         $path = $deployment->getWorkspacePath($application);
         $node = $deployment->getNode('localhost');
         $command = 'beard patch';
     } else {
         $patch = $deployment->getApplicationReleasePath($application);
         $command = $application->getOption('phpPath') . ' beard.phar patch';
     }
     $command = sprintf('cd %s && %s', escapeshellarg($path), $command);
     $this->shell->executeOrSimulate($command, $node, $deployment);
 }
Esempio n. 11
0
 /**
  * @param Application $application
  * @return string
  */
 public function getWorkspacePath(Application $application)
 {
     $workspacePath = FLOW_PATH_DATA . 'Surf/';
     if ($application->hasOption('repositoryUrl')) {
         $urlParts = GeneralUtility::getUrlPartsFromRepositoryUrl($application->getOption('repositoryUrl'));
         $workspacePath .= preg_replace('/[^a-zA-Z0-9]/', '-', $urlParts['path']);
         $workspacePath .= '_' . substr(sha1($application->getOption('repositoryUrl')), 0, 5);
     } else {
         // Default
         $workspacePath .= $this->getName() . '/' . $application->getName();
     }
     return $workspacePath;
 }
Esempio n. 12
0
 /**
  * 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);
 }
Esempio n. 13
0
    /**
     * Execute 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 \TYPO3\Surf\Exception\InvalidConfigurationException
     * @throws \TYPO3\Surf\Exception\TaskExecutionException
     */
    public function execute(Node $node, Application $application, Deployment $deployment, array $options = array())
    {
        if (!isset($options['repositoryUrl'])) {
            throw new \TYPO3\Surf\Exception\InvalidConfigurationException(sprintf('Missing "repositoryUrl" option for application "%s"', $application->getName()), 1335974764);
        }
        $releasePath = $deployment->getApplicationReleasePath($application);
        $checkoutPath = $application->getDeploymentPath() . '/cache/transfer';
        if (!isset($options['hardClean'])) {
            $options['hardClean'] = true;
        }
        $sha1 = $this->executeOrSimulateGitCloneOrUpdate($checkoutPath, $node, $deployment, $options);
        $command = strtr("\n\t\t\tcp -RPp {$checkoutPath}/. {$releasePath}\n\t\t\t\t&& (echo {$sha1} > {$releasePath}" . 'REVISION)
			', "\t\n", '  ');
        $this->shell->executeOrSimulate($command, $node, $deployment);
        $this->executeOrSimulatePostGitCheckoutCommands($releasePath, $sha1, $node, $deployment, $options);
    }
Esempio n. 14
0
 /**
  * @test
  */
 public function applicationOptionsOverrideDeploymentOptions()
 {
     $globalOptions = array('MyVendor\\MyPackage\\Task\\TaskGroup\\MyTask[taskOption]' => 'Deployment');
     $this->deployment->setOptions($globalOptions);
     $applicationOptions = array('MyVendor\\MyPackage\\Task\\TaskGroup\\MyTask[taskOption]' => 'Application');
     $this->application->setOptions($applicationOptions);
     $this->task->expects($this->atLeastOnce())->method('execute')->willReturnCallback(function ($_, $__, $___, $options) {
         if ($options['taskOption'] !== 'Application') {
             throw new \RuntimeException('Node options do not override deployment options!');
         }
     });
     $localOptions = array();
     $this->taskManager->execute('MyVendor\\MyPackage\\Task\\TaskGroup\\MyTask', $this->node, $this->application, $this->deployment, 'test', $localOptions);
 }
Esempio n. 15
0
 /**
  * @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;
 }
Esempio n. 16
0
 /**
  * Get a local workspace directory for the application
  */
 public function getWorkspacePath(Application $application)
 {
     return $this->workspacesBasePath . '/' . $this->getName() . '/' . $application->getName();
 }
Esempio n. 17
0
 /**
  * Prints stages and contained tasks for given application
  *
  * @param Application $application
  * @param array $stages
  * @param array $tasks
  */
 protected function printStages(Application $application, array $stages, array $tasks)
 {
     foreach ($stages as $stage) {
         $this->output->writeln('      <comment>' . $stage . ':</comment>');
         foreach (['before', 'tasks', 'after'] as $stageStep) {
             $output = '';
             foreach (['_', $application->getName()] as $applicationName) {
                 $label = $applicationName === '_' ? 'for all applications' : 'for application ' . $applicationName;
                 if (isset($tasks['stage'][$applicationName][$stage][$stageStep])) {
                     foreach ($tasks['stage'][$applicationName][$stage][$stageStep] as $task) {
                         $output .= '          <success>' . $task . '</success> <info>(' . $label . ')</info>' . PHP_EOL;
                     }
                 }
             }
             if (strlen($output) > 0) {
                 $this->output->writeln('        <info>' . $stageStep . ':</info>');
             }
             $this->output->write($output);
         }
     }
 }
Esempio n. 18
0
 /**
  * Execute 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())
 {
     $options = array('directories' => array('shared/Data/Logs', 'shared/Data/Persistent', 'shared/Configuration'), 'baseDirectory' => $application->getDeploymentPath());
     parent::execute($node, $application, $deployment, $options);
 }
Esempio n. 19
0
 /**
  * Execute a task and consider configured before / after "hooks"
  *
  * Will also execute tasks that are registered to run before or after this task.
  *
  * @param string $task
  * @param \TYPO3\Surf\Domain\Model\Node $node
  * @param \TYPO3\Surf\Domain\Model\Application $application
  * @param \TYPO3\Surf\Domain\Model\Deployment $deployment
  * @param string $stage
  * @param array $callstack
  * @return void
  * @throws \TYPO3\Surf\Exception\TaskExecutionException
  */
 protected function executeTask($task, Node $node, Application $application, Deployment $deployment, $stage, array &$callstack = array())
 {
     foreach (array('_', $application->getName()) as $applicationName) {
         if (isset($this->tasks['before'][$applicationName][$task])) {
             foreach ($this->tasks['before'][$applicationName][$task] as $beforeTask) {
                 $deployment->getLogger()->debug('Task "' . $beforeTask . '" before "' . $task);
                 $this->executeTask($beforeTask, $node, $application, $deployment, $stage, $callstack);
             }
         }
     }
     if (isset($callstack[$task])) {
         throw new \TYPO3\Surf\Exception\TaskExecutionException('Cycle for task "' . $task . '" detected, aborting.', 1335976544);
     }
     if (isset($this->tasks['defined'][$task])) {
         $this->taskManager->execute($this->tasks['defined'][$task]['task'], $node, $application, $deployment, $stage, $this->tasks['defined'][$task]['options'], $task);
     } else {
         $this->taskManager->execute($task, $node, $application, $deployment, $stage);
     }
     $callstack[$task] = true;
     foreach (array('_', $application->getName()) as $applicationName) {
         $label = $applicationName === '_' ? 'for all' : 'for application ' . $applicationName;
         if (isset($this->tasks['after'][$applicationName][$task])) {
             foreach ($this->tasks['after'][$applicationName][$task] as $beforeTask) {
                 $deployment->getLogger()->debug('Task "' . $beforeTask . '" after "' . $task . '" ' . $label);
                 $this->executeTask($beforeTask, $node, $application, $deployment, $stage, $callstack);
             }
         }
     }
 }
 /**
  * @param \TYPO3\Surf\Domain\Model\Application $application
  *
  * @return void
  *
  * @throws TaskExecutionException
  */
 protected function setRemoteNode(Application $application)
 {
     $this->requireApplication(__METHOD__);
     $nodes = $application->getNodes();
     if (count($nodes) < 1) {
         throw new TaskExecutionException("There is no node is set for application '{$application->getName()}'. Please check your TYPO3/Surf configuration.");
     }
     $this->remoteNode = array_shift($nodes);
 }
Esempio n. 21
0
 /**
  * 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);
 }
Esempio n. 22
0
 /**
  * @test
  * @dataProvider stageStepExamples
  */
 public function beforeAndAfterStageStepsAreIndependentOfApplications($callback, $expectedTasks)
 {
     $executedTasks = array();
     $deployment = $this->buildDeployment($executedTasks);
     $workflow = $deployment->getWorkflow();
     $flowApplication = new Application('TYPO3 Flow Application');
     $flowApplication->addNode(new Node('flow-1.example.com'));
     $deployment->addApplication($flowApplication);
     $deployment->initialize();
     $callback($workflow, $flowApplication);
     $workflow->run($deployment);
     $this->assertEquals($expectedTasks, $executedTasks);
 }
Esempio n. 23
0
 /**
  * Override options for a task
  *
  * The order of the options is:
  *
  *   Deployment, Node, Application, Task
  *
  * A task option will always override more global options from the
  * Deployment, Node or Application.
  *
  * Global options for a task should be prefixed with the task name to prevent naming
  * issues between different tasks. For example passing a special option to the
  * GitCheckoutTask could be expressed like 'TYPO3\\Surf\\Task\\GitCheckoutTask[sha1]' => '1234...'.
  *
  * @param string $taskName
  * @param \TYPO3\Surf\Domain\Model\Deployment $deployment
  * @param \TYPO3\Surf\Domain\Model\Node $node
  * @param \TYPO3\Surf\Domain\Model\Application $application
  * @param array $taskOptions
  * @return array
  */
 protected function overrideOptions($taskName, Deployment $deployment, Node $node, Application $application, array $taskOptions)
 {
     $globalOptions = array_merge($deployment->getOptions(), $node->getOptions(), $application->getOptions());
     $globalTaskOptions = array();
     foreach ($globalOptions as $optionKey => $optionValue) {
         if (strlen($optionKey) > strlen($taskName) && strpos($optionKey, $taskName) === 0 && $optionKey[strlen($taskName)] === '[') {
             $globalTaskOptions[substr($optionKey, strlen($taskName) + 1, -1)] = $optionValue;
         }
     }
     return array_merge($globalOptions, $globalTaskOptions, $taskOptions);
 }