diff --git a/src/Liip/RMT/Action/BaseAction.php b/src/Liip/RMT/Action/BaseAction.php index 502cb41c..f110e103 100644 --- a/src/Liip/RMT/Action/BaseAction.php +++ b/src/Liip/RMT/Action/BaseAction.php @@ -27,6 +27,14 @@ public function __construct($options = array()) */ abstract public function execute(); + /** + * Rollback the effect of this action + */ + public function rollback() + { + // assume there is nothing to do by default + } + /** * Return the name of the action as it will be display to the user * diff --git a/src/Liip/RMT/Action/VcsCommitAction.php b/src/Liip/RMT/Action/VcsCommitAction.php index a74bb414..07288e9c 100644 --- a/src/Liip/RMT/Action/VcsCommitAction.php +++ b/src/Liip/RMT/Action/VcsCommitAction.php @@ -38,9 +38,19 @@ public function execute() return; } - $vcs->saveWorkingCopy( - str_replace('%version%', Context::getParam('new-version'), $this->options['commit-message']) - ); + $vcs->saveWorkingCopy($this->getCommitMessage(Context::getParam('new-version'))); + $this->confirmSuccess(); + } + + public function rollback() + { + $version = Context::get('version-persister')->getCurrentVersion(); + Context::get('vcs')->revertLastCommit($this->getCommitMessage($version)); $this->confirmSuccess(); } + + protected function getCommitMessage($version) + { + return str_replace('%version%', $version, $this->options['commit-message']); + } } diff --git a/src/Liip/RMT/Action/VcsTagAction.php b/src/Liip/RMT/Action/VcsTagAction.php index ecff5aa5..2f07977c 100644 --- a/src/Liip/RMT/Action/VcsTagAction.php +++ b/src/Liip/RMT/Action/VcsTagAction.php @@ -27,4 +27,12 @@ public function execute() ); $this->confirmSuccess(); } + + public function rollback() + { + $tag = Context::get('version-persister')->getCurrentVersionTag(); + Context::get('vcs')->deleteTag($tag); + $this->confirmSuccess(); + } + } diff --git a/src/Liip/RMT/Application.php b/src/Liip/RMT/Application.php index 9491d17f..272a94a7 100644 --- a/src/Liip/RMT/Application.php +++ b/src/Liip/RMT/Application.php @@ -18,6 +18,7 @@ use Liip\RMT\Command\CurrentCommand; use Liip\RMT\Command\ConfigCommand; use Liip\RMT\Command\InitCommand; +use Liip\RMT\Command\RollbackCommand; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Application as BaseApplication; @@ -50,6 +51,7 @@ public function __construct() // Add command that require the config file if (file_exists($this->getConfigFilePath())) { $this->add(new ReleaseCommand()); + $this->add(new RollbackCommand()); $this->add(new CurrentCommand()); $this->add(new ChangesCommand()); $this->add(new ConfigCommand()); diff --git a/src/Liip/RMT/Command/RollbackCommand.php b/src/Liip/RMT/Command/RollbackCommand.php new file mode 100644 index 00000000..7fd562ab --- /dev/null +++ b/src/Liip/RMT/Command/RollbackCommand.php @@ -0,0 +1,60 @@ +setName('rollback'); + $this->setDescription('Rollback the last release if there was no change since.'); + $this->setHelp('The rollback should be used to cancel a previously done release.'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + if (count(Context::get('vcs')->getLocalModifications()) > 0) { + Context::get('output')->writeln('Local modifications found. Aborting.'); + return; + } + + $tag = Context::get('version-persister')->getCurrentVersionTag(); + $modifications = Context::get('vcs')->getAllModificationsSince($tag, false, false); + if (count($modifications) > 0) { + Context::get('output')->writeln('There were commits since the last release. Aborting.'); + return; + } + + $this->rollbackActionListIfExist('post-release-actions'); + $this->rollbackActionListIfExist('pre-release-actions'); + } + + protected function rollbackActionListIfExist($name) + { + $actions = Context::getInstance()->getList($name); + $actions = array_reverse($actions); + foreach ($actions as $num => $action) { + $this->getOutput()->write(++$num.') '.$action->getTitle().' : '); + $action->rollback(); + } + } +} diff --git a/src/Liip/RMT/VCS/Git.php b/src/Liip/RMT/VCS/Git.php index 4c35efb0..5111b318 100644 --- a/src/Liip/RMT/VCS/Git.php +++ b/src/Liip/RMT/VCS/Git.php @@ -50,6 +50,11 @@ public function createTag($tagName) return $this->executeGitCommand("tag $tagName"); } + public function deleteTag($tagName) + { + return $this->executeGitCommand("tag -d $tagName"); + } + public function publishTag($tagName, $remote = null) { $remote = $remote == null ? 'origin' : $remote; @@ -68,6 +73,18 @@ public function saveWorkingCopy($commitMsg = '') $this->executeGitCommand("commit -m \"$commitMsg\""); } + public function revertLastCommit($commitMsg = null) + { + if (! is_null($commitMsg)) { + $msg = $this->executeGitCommand('log -1 --pretty=%B'); + if (count($msg) != 1 || $msg[0] !== $commitMsg) { + return; + } + } + + $this->executeGitCommand('reset --hard HEAD~1'); + } + public function getCurrentBranch() { $branches = $this->executeGitCommand('branch'); diff --git a/src/Liip/RMT/VCS/Hg.php b/src/Liip/RMT/VCS/Hg.php index 1fa713fc..f0277f38 100644 --- a/src/Liip/RMT/VCS/Hg.php +++ b/src/Liip/RMT/VCS/Hg.php @@ -58,6 +58,11 @@ public function createTag($tagName) return $this->executeHgCommand("tag $tagName"); } + public function deleteTag($tagName) + { + return $this->executeHgCommand("tag --remove $tagName"); + } + public function publishTag($tagName, $remote = null) { // nothing to do, tags are published with other changes @@ -75,6 +80,17 @@ public function saveWorkingCopy($commitMsg = '') $this->executeHgCommand("commit -m \"$commitMsg\""); } + public function revertLastCommit($commitMsg = null) + { + if (! is_null($commitMsg)) { + $msg = $this->executeHgCommand('log -l 1 -T "{desc}"'); + if (count($msg) != 1 || $msg[0] !== $commitMsg) { + return; + } + } + + $this->executeHgCommand('reset --hard HEAD~1'); } + public function getCurrentBranch() { $data = $this->executeHgCommand('branch'); diff --git a/src/Liip/RMT/VCS/VCSInterface.php b/src/Liip/RMT/VCS/VCSInterface.php index a6a858e1..d1bdb93c 100644 --- a/src/Liip/RMT/VCS/VCSInterface.php +++ b/src/Liip/RMT/VCS/VCSInterface.php @@ -32,6 +32,13 @@ public function getTags(); */ public function createTag($tagName); + /** + * Delete a tag + * + * @param string $tagName + */ + public function deleteTag($tagName); + /** * Publish a new created tag * @@ -78,6 +85,14 @@ public function getLocalModifications(); */ public function saveWorkingCopy($commitMsg = ''); + /** + * Revert the last commit. If a message is given, only revert + * if the commit message matches. + * + * @param string|null $commitMsg + */ + public function revertLastCommit($commitMsg = null); + /** * Publish local modification *