public function setUp() { $this->application = new Application(); $this->context = Context::create($this->application); $this->informationCollector = $this->getMock("\\Liip\\RMT\\Information\\InformationCollector"); $this->context->setService('information-collector', $this->informationCollector); }
private function addGitFlowCommands(Context $context) { if (!$context->getVCS() instanceof VCS\Git) { return; } $this->add($this->createCommand("StartCommand")); $this->add($this->createCommand("HotfixCommand")); $this->add($this->createCommand("FinishCommand")); }
/** * Returns the current context. * * @return Context */ protected function getContext() { if ($this->context === null) { $this->context = Context::create($this->getApplication()); } return $this->context; }
public function execute() { // Handle the skip option if (Context::get('information-collector')->getValueFor(self::SKIP_OPTION)) { Context::get('output')->writeln('<error>composer security check skipped</error>'); return; } Context::get('output')->writeln('<comment>running composer security check</comment>'); // run the actual security check $checker = new SecurityChecker(); $alerts = $checker->check('composer.lock'); // exit succesfull if everything is fine if (count($alerts) == 0) { $this->confirmSuccess(); return; } // print out the advisories if available foreach ($alerts as $package => $alert) { Context::get('output')->writeln("<options=bold>{$package}</options=bold> {$alert['version']}"); foreach ($alert['advisories'] as $data) { Context::get('output')->writeln(''); Context::get('output')->writeln($data['title']); Context::get('output')->writeln($data['link']); Context::get('output')->writeln(''); } } // throw exception to have check fail throw new \Exception('composer.lock contains insecure packages (you can force a release with option --' . self::SKIP_OPTION . ')'); }
public function execute() { // Handle the skip option if (Context::get('information-collector')->getValueFor(self::SKIP_OPTION)) { Context::get('output')->writeln('<error>composer minimum-stability check skipped</error>'); return; } // file exists? if (!file_exists('composer.json')) { Context::get('output')->writeln('<error>composer.json does not exist, skipping check</error>'); return; } // if file is not readable, we can't perform our check if (!is_readable('composer.json')) { throw new \Exception('composer.json can not be read (permissions?), (you can force a release with option --' . self::SKIP_OPTION . ')'); } $contents = json_decode(file_get_contents('composer.json'), true); // fail if the composer config falls back to default, and this check has something else but default set if (!isset($contents['minimum-stability']) && $this->options['stability'] != 'stable') { throw new \Exception('minimum-stability is not set, but RMT config requires: ' . $this->options['stability'] . ' (you can force a release with option --' . self::SKIP_OPTION . ')'); } // fail if stability is set and not the one expected if (isset($contents['minimum-stability']) && $contents['minimum-stability'] != $this->options['stability']) { throw new \Exception('minimum-stability is set to: ' . $contents['minimum-stability'] . ', but RMT config requires: ' . $this->options['stability'] . ' (you can force a release with option --' . self::SKIP_OPTION . ')'); } $this->confirmSuccess(); }
/** * {@inheritdoc} * * @throws \InvalidArgumentException */ public function generateNextVersion($currentVersion) { $type = isset($this->options['type']) ? $this->options['type'] : Context::get('information-collector')->getValueFor('type'); $label = 'none'; if (isset($this->options['allow-label']) && $this->options['allow-label'] == true) { $label = isset($this->options['label']) ? $this->options['label'] : Context::get('information-collector')->getValueFor('label'); } // Type validation $validTypes = array('patch', 'minor', 'major'); if (!in_array($type, $validTypes)) { throw new \InvalidArgumentException('The option [type] must be one of: {' . implode($validTypes, ', ') . "}, \"{$type}\" given"); } if (!preg_match('#^' . $this->getValidationRegex() . '$#', $currentVersion)) { throw new \Exception('Current version format is invalid (' . $currentVersion . '). It should be major.minor.patch'); } $matches = null; preg_match('$(?:(\\d+\\.\\d+\\.\\d+)(?:(-)([a-zA-Z]+)(\\d+)?)?)$', $currentVersion, $matches); // if last version is with label if (count($matches) > 3) { list($major, $minor, $patch) = explode('.', $currentVersion); $patch = substr($patch, 0, strpos($patch, '-')); if ($label != 'none') { // increment label if (array_key_exists(3, $matches)) { $oldLabel = $matches[3]; $labelVersion = 2; // if label is new clear version if ($label !== $oldLabel) { $labelVersion = false; } elseif (array_key_exists(4, $matches)) { // if version exists increment it $labelVersion = intval($matches[4]) + 1; } } return implode(array($major, $minor, $patch), '.') . '-' . $label . $labelVersion; } return implode(array($major, $minor, $patch), '.'); } list($major, $minor, $patch) = explode('.', $currentVersion); // Increment switch ($type) { case 'major': $major += 1; $patch = $minor = 0; break; case 'minor': $minor += 1; $patch = 0; break; default: $patch += 1; break; } // new label if ($label != 'none') { return implode(array($major, $minor, $patch), '.') . '-' . $label; } return implode(array($major, $minor, $patch), '.'); }
public function execute() { try { Context::get('output')->writeEmptyLine(); Context::get('output')->writeln(Context::get('vcs')->getAllModificationsSince(Context::get('version-persister')->getCurrentVersionTag())); } catch (\Exception $e) { Context::get('output')->writeln('<error>No modification found: ' . $e->getMessage() . '</error>'); } }
public function execute() { $directory = trim(shell_exec('pwd')); $username = Context::get('information-collector')->getValueFor('ter-username'); $password = Context::get('information-collector')->getValueFor('ter-password'); $comment = Context::get('information-collector')->getValueFor('ter-comment'); $uploader = new \NamelessCoder\TYPO3RepositoryClient\Uploader(); $uploader->upload($directory, $username, $password, $comment); }
/** * Return the remote name where to publish or null if not defined * * @return string|null */ protected function getRemote() { if ($this->options['ask-remote-name']) { return Context::get('information-collector')->getValueFor('remote'); } if ($this->options['remote-name'] !== null) { return $this->options['remote-name']; } return; }
public function execute() { /** @var VCSInterface $vcs */ $vcs = Context::get('vcs'); if (count($vcs->getLocalModifications()) == 0) { Context::get('output')->writeln('<error>No modification found, aborting commit</error>'); return; } $vcs->saveWorkingCopy(str_replace('%version%', Context::getParam('new-version'), $this->options['commit-message'])); $this->confirmSuccess(); }
public function execute() { $newVersion = Context::getParam('new-version'); // newscoop/library/Newscoop/Version.php $appFile = realpath(__DIR__ . '/../src/SWP/Bundle/CoreBundle/Version/Version.php'); Context::get('output')->writeln("Updating version [<yellow>{$newVersion}</yellow>] in {$appFile}: "); $fileContent = file_get_contents($appFile); $fileContent = preg_replace('/(.*protected \\$version = .*;)/', ' protected $version = \'' . $newVersion . '\';', $fileContent); $fileContent = preg_replace('/(.*protected \\$releaseDate = .*;)/', ' protected $releaseDate = \'' . date('Y-m-d') . '\';', $fileContent); file_put_contents($appFile, $fileContent); $this->confirmSuccess(); }
/** * Execute a command and render the output through the classical indented output * @param string $cmd * @param float|null $timeout * @return Process */ public function executeCommandInProcess($cmd, $timeout = null) { Context::get('output')->write("<comment>{$cmd}</comment>\n\n"); $process = new Process($cmd); if ($timeout !== null) { $process->setTimeout($timeout); } $process->run(function ($type, $buffer) { Context::get('output')->write($buffer); }); return $process; }
public function execute() { $newVersion = Context::getParam('new-version'); $composerFile = Context::getParam('project-root') . '/composer.json'; if (!file_exists($composerFile)) { throw new \Liip\RMT\Exception("Impossible to file the composer file ({$composerFile})"); } $fileContent = file_get_contents($composerFile); $fileContent = preg_replace('/("version":[^,]*,)/', '"version": "' . $newVersion . '",', $fileContent); file_put_contents($composerFile, $fileContent); $this->confirmSuccess(); }
public function execute() { // Allow to be skipped when explicitly activated from the config if ($this->options['allow-ignore'] && Context::get('information-collector')->getValueFor($this->ignoreCheckOptionName)) { Context::get('output')->writeln('<error>requested to be ignored</error>'); return; } $modCount = count(Context::get('vcs')->getLocalModifications()); if ($modCount > 0) { throw new \Exception('Your working directory contains ' . $modCount . ' local modifications. Use the --' . $this->ignoreCheckOptionName . " option to bypass this check.\n" . 'WARNING, if your release task include a commit action, the pending changes are going to be included ' . 'in the release', self::EXCEPTION_CODE); } $this->confirmSuccess(); }
public function execute() { $versioner = new \NamelessCoder\TYPO3RepositoryClient\Versioner(); $directory = trim(shell_exec('pwd')); $version = $versioner->read('.'); $version[0] = Context::getParam('new-version'); try { $version[1] = Context::getParam('stability'); } catch (\InvalidArgumentException $e) { $version[1] = Context::get('information-collector')->getValueFor('stability'); } $versioner->write($directory, $version[0], $version[1]); }
protected function execute(InputInterface $input, OutputInterface $output) { $lastVersion = Context::get('version-persister')->getCurrentVersionTag(); $noMerges = $input->getOption('exclude-merge-commits'); if ($input->getOption('files')) { $output->writeln("Here is the list of files changed since <green>{$lastVersion}</green>:"); $output->indent(); $output->writeln(array_keys(Context::get('vcs')->getModifiedFilesSince($lastVersion))); return; } $output->writeln("Here is the list of changes since <green>{$lastVersion}</green>:"); $output->indent(); $output->writeln(Context::get('vcs')->getAllModificationsSince($lastVersion, false, $noMerges)); }
public function execute() { // Handle the skip option if (Context::get('information-collector')->getValueFor(self::SKIP_OPTION)) { Context::get('output')->writeln('<error>tests skipped</error>'); return; } // Run the tests and live output with the standard output class $timeout = isset($this->options['timeout']) ? $this->options['timeout'] : null; $process = $this->executeCommandInProcess($this->options['command'], $timeout); // Break up if the result is not good if ($process->getExitCode() !== $this->options['expected_exit_code']) { throw new \Exception('Tests fails (you can force a release with option --' . self::SKIP_OPTION . ')'); } }
public function execute() { // Handle the skip option if (Context::get('information-collector')->getValueFor(self::SKIP_OPTION)) { Context::get('output')->writeln('<error>composer.json validation skipped</error>'); return; } // Run the validation and live output with the standard output class $process = $this->executeCommandInProcess($this->options['composer'] . ' validate'); // Break up if the result is not good if ($process->getExitCode() !== 0) { throw new \Exception('composer.json invalid (you can force a release with option --' . self::SKIP_OPTION . ')'); } $this->confirmSuccess(); }
public function execute() { // Handle the commits dump if ($this->options['dump-commits'] == true) { try { $extraLines = Context::get('vcs')->getAllModificationsSince(Context::get('version-persister')->getCurrentVersionTag(), false, $this->options['exclude-merge-commits']); $this->options['extra-lines'] = $extraLines; } catch (NoReleaseFoundException $e) { Context::get('output')->writeln('<error>No commits dumped as this is the first release</error>'); } unset($this->options['dump-commits']); } $manager = new ChangelogManager($this->options['file'], $this->options['format']); $manager->update(Context::getParam('new-version'), Context::get('information-collector')->getValueFor('comment'), array_merge(array('type' => Context::get('information-collector')->getValueFor('type', null)), $this->options)); $this->confirmSuccess(); }
protected function execute(InputInterface $input, OutputInterface $output) { $this->loadContext(); $version = Context::get('version-persister')->getCurrentVersion(); if ($input->getOption('vcs-tag')) { $vcsTag = Context::get('version-persister')->getCurrentVersionTag(); } if ($input->getOption('raw') == true) { $output->writeln($input->getOption('vcs-tag') ? $vcsTag : $version); } else { $msg = "Current release is: <green>{$version}</green>"; if ($input->getOption('vcs-tag')) { $msg .= " (VCS tag: <green>{$vcsTag}</green>)"; } $output->writeln($msg); } }
/** * will update a given filename with the current version * * @param string $filename * * @throws \Liip\RMT\Exception */ protected function updateFile($filename) { $current = Context::getParam('current-version'); $next = Context::getParam('new-version'); $content = file_get_contents($filename); if (false === strpos($content, $current)) { throw new Exception('The version class ' . $filename . " does not contain the current version {$current}"); } if (isset($this->options['pattern'])) { $current = str_replace('%version%', $current, $this->options['pattern']); $next = str_replace('%version%', $next, $this->options['pattern']); } $content = str_replace($current, $next, $content); if (false === strpos($content, $next)) { throw new Exception('The version class ' . $filename . " could not be updated with version {$next}"); } file_put_contents($filename, $content); }
/** * Context factory method. * * @param \Liip\RMT\Application $application * @return \Liip\RMT\Context */ public static function create(Application $application) { $rootDir = $application->getProjectRootDir(); $helper = new Helpers\ComposerConfig(); $helper->setComposerFile($rootDir . '/composer.json'); $config = $helper->getRMTConfigSection(); $context = new Context(); $builder = new Helpers\ServiceBuilder($context); /* * The following services are config-dependent */ if ($config !== null) { if ($config->getVcs()) { $context->setService('vcs', $builder->getService($config->getVcs(), 'vcs')); } // Store the config for latter usage $context->setParameter('config', $config); /* * populate version persister */ $context->setService("version-persister", $builder->getService($config->getVersionPersister(), 'versionPersister')); $context->setService("version-detector", $builder->getService($config->getVersionDetector(), 'versionDetector')); /* * popluate lists */ foreach (array("prerequisites", self::PRERELEASE_LIST, "postReleaseActions") as $listName) { $context->createEmptyList($listName); foreach ($config->{$listName} as $service) { $context->addToList($listName, $builder->getService($service, $listName)); } } } // Provide the root dir as a context parameter $context->setParameter('project-root', $rootDir); return $context; }
public function execute() { // Output for devs $newVersion = Context::getParam('new-version'); // newscoop/library/Newscoop/Version.php $appFile = realpath(__DIR__ . '/../library/Newscoop/Version.php'); Context::get('output')->writeln("New version [<yellow>{$newVersion}</yellow>] udpated into {$appFile}: "); $fileContent = file_get_contents($appFile); $fileContent = preg_replace('/(.*const VERSION = .*;)/', " const VERSION = '{$newVersion}';", $fileContent); file_put_contents($appFile, $fileContent); // newscoop/template_engine/classes/CampVersion.php $appFile = realpath(__DIR__ . '/../template_engine/classes/CampVersion.php'); Context::get('output')->writeln("New version [<yellow>{$newVersion}</yellow>] udpated into {$appFile}: "); $fileContent = file_get_contents($appFile); $fileContent = preg_replace('/(.*private \\$m_release = .*;)/', ' private $m_release = \'' . $newVersion . '\';', $fileContent); $fileContent = preg_replace('/(.*private \\$m_releaseDate = .*;)/', ' private $m_releaseDate = \'' . date('Y-m-d') . '\';', $fileContent); $fileContent = preg_replace('/(.*private \\$m_copyrightYear = .*;)/', ' private $m_copyrightYear = ' . date('Y') . ';', $fileContent); file_put_contents($appFile, $fileContent); $this->confirmSuccess(); }
public function execute() { $command = $this->options['cmd']; Context::get('output')->write("<comment>{$command}</comment>\n\n"); // Prepare a callback for live output $callback = null; if ($this->options['live_output'] == true) { $callback = function ($type, $buffer) { $decorator = array('', ''); if ($type == Process::ERR) { $decorator = array('<error>', '</error>'); } Context::get('output')->write($decorator[0] . $buffer . $decorator[1]); }; } // Run the process $process = new Process($command); $process->run($callback); // Break up if the result is not good if ($this->options['stop_on_error'] && $process->getExitCode() !== 0) { throw new \RuntimeException("Command [{$command}] exit with code " . $process->getExitCode()); } }
/** * Determine and set the next release version. */ protected function setReleaseVersion() { try { $currentVersion = Context::get('version-persister')->getCurrentVersion(); } catch (\Exception $e) { $currentVersion = Context::get('version-generator')->getInitialVersion(); } $this->releaseVersion = Context::get('version-generator')->generateNextVersion($currentVersion); }
/** * A common method to confirm success to the user * * @param string $msg */ public function confirmSuccess($msg = 'OK') { $this->context->getOutput()->writeln('<info>' . $msg . '</info>'); }
public function loadContext() { $configHandler = new Handler($this->getApplication()->getConfig(), $this->getApplication()->getProjectRootDir()); $config = $configHandler->getBaseConfig(); // Select a branch specific config if a VCS is in use if (isset($config['vcs'])) { Context::getInstance()->setService('vcs', $config['vcs']['class'], $config['vcs']['options']); /** @var VCSInterface $vcs */ $vcs = Context::get('vcs'); try { $branch = $vcs->getCurrentBranch(); } catch (\Exception $e) { echo "[31mImpossible to read the branch name[37m"; } if (isset($branch)) { $config = $configHandler->getConfigForBranch($branch); } } // Store the config for latter usage Context::getInstance()->setParameter('config', $config); // Populate the context foreach (array('version-generator', 'version-persister') as $service) { Context::getInstance()->setService($service, $config[$service]['class'], $config[$service]['options']); } foreach (array('prerequisites', 'pre-release-actions', 'post-release-actions') as $listName) { Context::getInstance()->createEmptyList($listName); foreach ($config[$listName] as $service) { Context::getInstance()->addToList($listName, $service['class'], $service['options']); } } // Provide the root dir as a context parameter Context::getInstance()->setParameter('project-root', $this->getApplication()->getProjectRootDir()); }
/** * Constructor. * * @param \Liip\RMT\Context $context * @throws \Liip\RMT\Exception */ public function __construct(Context $context = null) { if ($context !== null) { $this->setComposerFile($context->getParam('project-root') . '/composer.json'); } }
public function testGetVersionDetector() { $application = new \Liip\RMT\Application(); $context = Context::create($application); $actual = $context->getVersionDetector(); $this->assertInstanceOf("\\Liip\\RMT\\Version\\Detector\\DetectorInterface", $actual); }
/** * Get current git tag * * @return string */ private function getCurrentVersion() { /** @var Liip\RMT\Version\Persister\PersisterInterface $versionPersister */ $versionPersister = Context::get('version-persister'); return $versionPersister->getCurrentVersion(); }