diff --git a/src/Liip/RMT/Action/BaseAction.php b/src/Liip/RMT/Action/BaseAction.php
index 502cb41c..0a365ddb 100644
--- a/src/Liip/RMT/Action/BaseAction.php
+++ b/src/Liip/RMT/Action/BaseAction.php
@@ -51,6 +51,20 @@ public function getInformationRequests()
return array();
}
+ /**
+ * This method is called after all registered information collectors have
+ * been called to validate that the action has all necessary information
+ * if anything is missing an exception should be thrown.
+ * When called, the 'current-version' and 'new-version' parameters are
+ * already known, so a check can be made on those.
+ *
+ * @throws \Exception
+ */
+ public function validateContext()
+ {
+
+ }
+
/**
* A common method to confirm success to the user
*/
diff --git a/src/Liip/RMT/Action/VcsTagAction.php b/src/Liip/RMT/Action/VcsTagAction.php
index ecff5aa5..8ab9082a 100644
--- a/src/Liip/RMT/Action/VcsTagAction.php
+++ b/src/Liip/RMT/Action/VcsTagAction.php
@@ -20,11 +20,20 @@ class VcsTagAction extends BaseAction
{
public function execute()
{
- Context::get('vcs')->createTag(
- Context::get('vcs')->getTagFromVersion(
- Context::getParam('new-version')
- )
- );
+ Context::get('vcs')->createTag($this->getVersion());
$this->confirmSuccess();
}
+
+ protected function getVersion()
+ {
+ return Context::get('vcs')->getTagFromVersion(
+ Context::getParam('new-version')
+ );
+ }
+
+ public function validateContext()
+ {
+ parent::validateContext();
+ Context::get('vcs')->validateTag($this->getVersion());
+ }
}
diff --git a/src/Liip/RMT/Command/ReleaseCommand.php b/src/Liip/RMT/Command/ReleaseCommand.php
index c799ba94..a5c5f5be 100644
--- a/src/Liip/RMT/Command/ReleaseCommand.php
+++ b/src/Liip/RMT/Command/ReleaseCommand.php
@@ -136,13 +136,20 @@ protected function execute(InputInterface $input, OutputInterface $output)
);
Context::getInstance()->setParameter('new-version', $newVersion);
+ foreach (array('prerequisites', 'pre-release-actions', 'post-release-actions') as $listName) {
+ foreach(Context::getInstance()->getList($listName) as $action) {
+ $action->validateContext();
+ }
+ }
+ Context::get('version-persister')->validateContext();
+
$this->executeActionListIfExist('pre-release-actions');
$this->getOutput()->writeSmallTitle('Release process');
$this->getOutput()->indent();
$this->getOutput()->writeln("A new version named [$newVersion] is going to be released");
- Context::get('version-persister')->save($newVersion);
+ Context::get('version-persister')->save();
$this->getOutput()->writeln('Release: Success');
$this->getOutput()->unIndent();
diff --git a/src/Liip/RMT/Exception/InvalidTagNameException.php b/src/Liip/RMT/Exception/InvalidTagNameException.php
new file mode 100644
index 00000000..30d59dbe
--- /dev/null
+++ b/src/Liip/RMT/Exception/InvalidTagNameException.php
@@ -0,0 +1,18 @@
+executeGitCommand('tag');
}
+ public function validateTag($tagName)
+ {
+ try {
+ $this->executeGitCommand("check-ref-format --allow-onelevel $tagName");
+ } catch(Exception $e) {
+ throw new InvalidTagNameException("'$tagName' is an invalid tag name for git.");
+ }
+
+ if(in_array($tagName, $this->getTags())) {
+ throw new TagAlreadyExistsException("'$tagName' already exists.");
+ }
+ }
+
public function createTag($tagName)
{
return $this->executeGitCommand("tag $tagName");
@@ -79,6 +96,11 @@ public function getCurrentBranch()
throw new \Liip\RMT\Exception('Not currently on any branch');
}
+ /**
+ * @param $cmd
+ * @throws \Liip\RMT\Exception
+ * @return string[]
+ */
protected function executeGitCommand($cmd)
{
// Avoid using some commands in dry mode
@@ -86,7 +108,7 @@ protected function executeGitCommand($cmd)
if ($cmd !== 'tag') {
$cmdWords = explode(' ', $cmd);
if (in_array($cmdWords[0], array('tag', 'push', 'add', 'commit'))) {
- return;
+ return [];
}
}
}
@@ -95,7 +117,7 @@ protected function executeGitCommand($cmd)
$cmd = 'git ' . $cmd;
exec($cmd, $result, $exitCode);
if ($exitCode !== 0) {
- throw new \Liip\RMT\Exception('Error while executing git command: ' . $cmd . "\n" . implode("\n", $result));
+ throw new Exception('Error while executing git command: ' . $cmd . "\n" . implode("\n", $result));
}
return $result;
diff --git a/src/Liip/RMT/VCS/Hg.php b/src/Liip/RMT/VCS/Hg.php
index 1fa713fc..1510a1aa 100644
--- a/src/Liip/RMT/VCS/Hg.php
+++ b/src/Liip/RMT/VCS/Hg.php
@@ -11,6 +11,9 @@
namespace Liip\RMT\VCS;
+use Liip\RMT\Exception\InvalidTagNameException;
+use Liip\RMT\Exception\TagAlreadyExistsException;
+
class Hg extends BaseVCS
{
protected $dryRun = false;
@@ -53,6 +56,17 @@ public function getTags()
return $tags;
}
+ public function validateTag($tagName)
+ {
+ if(preg_match("/[:\r\n]/", $tagName) > 0 || preg_match("/^[0-9]*$/", $tagName) > 0) {
+ throw new InvalidTagNameException("'$tagName' is an invalid tag name for mercurial.");
+ }
+
+ if(in_array($tagName, $this->getTags())) {
+ throw new TagAlreadyExistsException("'$tagName' already exists.");
+ }
+ }
+
public function createTag($tagName)
{
return $this->executeHgCommand("tag $tagName");
diff --git a/src/Liip/RMT/VCS/VCSInterface.php b/src/Liip/RMT/VCS/VCSInterface.php
index a6a858e1..da1f725b 100644
--- a/src/Liip/RMT/VCS/VCSInterface.php
+++ b/src/Liip/RMT/VCS/VCSInterface.php
@@ -11,6 +11,9 @@
namespace Liip\RMT\VCS;
+use Liip\RMT\Exception\InvalidTagNameException;
+use Liip\RMT\Exception\TagAlreadyExistsException;
+
interface VCSInterface
{
/**
@@ -25,6 +28,17 @@ public function getCurrentBranch();
*/
public function getTags();
+ /**
+ * Validate that a tag name is valid for the given VCS. If possible
+ * should also check if this tag already exists or if we can create
+ * it freely.
+ *
+ * @param $tagName
+ * @throws InvalidTagNameException in case the name is invalid
+ * @throws TagAlreadyExistsException in case the tag name already exists
+ */
+ public function validateTag($tagName);
+
/**
* Create a new tag at the current position
*
diff --git a/src/Liip/RMT/Version/Persister/ChangelogPersister.php b/src/Liip/RMT/Version/Persister/ChangelogPersister.php
index e1140128..cb63bd3a 100644
--- a/src/Liip/RMT/Version/Persister/ChangelogPersister.php
+++ b/src/Liip/RMT/Version/Persister/ChangelogPersister.php
@@ -42,11 +42,11 @@ public function getCurrentVersion()
return $this->changelogManager->getCurrentVersion();
}
- public function save($versionNumber)
+ public function save()
{
$comment = Context::get('information-collector')->getValueFor('comment');
$type = Context::get('information-collector')->getValueFor('type', null);
- $this->changelogManager->update($versionNumber, $comment, array('type' => $type));
+ $this->changelogManager->update(Context::getParam('new-version'), $comment, array('type' => $type));
}
public function getInformationRequests()
@@ -54,6 +54,11 @@ public function getInformationRequests()
return array('comment');
}
+ public function validateContext()
+ {
+
+ }
+
public function init()
{
// TODO: Implement init() method.
diff --git a/src/Liip/RMT/Version/Persister/PersisterInterface.php b/src/Liip/RMT/Version/Persister/PersisterInterface.php
index 95940c8f..598b7acb 100644
--- a/src/Liip/RMT/Version/Persister/PersisterInterface.php
+++ b/src/Liip/RMT/Version/Persister/PersisterInterface.php
@@ -26,10 +26,12 @@ public function __construct($options = array());
*/
public function getCurrentVersion();
- public function save($versionNumber);
+ public function save();
public function getInformationRequests();
+ public function validateContext();
+
// Use the very first time to init this persistence
public function init();
}
diff --git a/src/Liip/RMT/Version/Persister/VcsTagPersister.php b/src/Liip/RMT/Version/Persister/VcsTagPersister.php
index b6af61f8..82431b31 100644
--- a/src/Liip/RMT/Version/Persister/VcsTagPersister.php
+++ b/src/Liip/RMT/Version/Persister/VcsTagPersister.php
@@ -46,13 +46,23 @@ public function getCurrentVersion()
return array_pop($versions);
}
- public function save($versionNumber)
+ public function getNewVersion()
{
- $tagName = $this->getTagFromVersion($versionNumber);
+ return $this->getTagFromVersion(Context::getParam('new-version'));
+ }
+
+ public function save()
+ {
+ $tagName = $this->getNewVersion();
Context::get('output')->writeln("Creation of a new VCS tag [$tagName]");
$this->vcs->createTag($tagName);
}
+ public function validateContext()
+ {
+ Context::get('vcs')->validateTag($this->getNewVersion());
+ }
+
public function init()
{
}
diff --git a/test/Liip/RMT/Tests/Functional/HgTest.php b/test/Liip/RMT/Tests/Functional/HgTest.php
index ad6b6459..ddd68301 100644
--- a/test/Liip/RMT/Tests/Functional/HgTest.php
+++ b/test/Liip/RMT/Tests/Functional/HgTest.php
@@ -22,13 +22,21 @@ public static function cleanTags($tags)
}, $tags);
}
- public function testInitialVersion()
+ public function testNoSimpleGenerator()
{
$this->initHg();
$this->createConfig('simple', 'vcs-tag', array('vcs' => 'hg'));
+ exec('./RMT release -n --confirm-first 2> /dev/null', $result, $code);
+ $this->assertEquals($code, 1);
+ }
+
+ public function testInitialVersion()
+ {
+ $this->initHg();
+ $this->createConfig('simple', array('name' => 'vcs-tag', 'tag-prefix' => 'v'), array('vcs' => 'hg'));
exec('./RMT release -n --confirm-first');
exec('hg tags', $tags);
- $this->assertEquals(array('tip', '1'), static::cleanTags($tags));
+ $this->assertEquals(array('tip', 'v1'), static::cleanTags($tags));
}
public function testInitialVersionSemantic()
@@ -43,13 +51,13 @@ public function testInitialVersionSemantic()
public function testSimple()
{
$this->initHg();
- exec('hg tag 1');
- exec('hg tag 3');
+ exec('hg tag v1');
+ exec('hg tag v3');
exec('hg tag toto');
- $this->createConfig('simple', 'vcs-tag', array('vcs' => 'hg'));
+ $this->createConfig('simple', array('name' => 'vcs-tag', 'tag-prefix' => 'v'), array('vcs' => 'hg'));
exec('./RMT release -n');
exec('hg tags', $tags);
- $this->assertEquals(array('tip', '4', 'toto', '3', '1'), static::cleanTags($tags));
+ $this->assertEquals(array('tip', 'v4', 'toto', 'v3', 'v1'), static::cleanTags($tags));
}
public function testSemantic()
@@ -65,12 +73,12 @@ public function testSemantic()
public function testTagPrefix()
{
$this->initHg();
- exec('hg tag 2');
+ exec('hg tag v2');
exec('hg tag v_1');
$this->createConfig('simple', array('name' => 'vcs-tag', 'tag-prefix' => 'v_'), array('vcs' => 'hg'));
exec('./RMT release -n');
exec('hg tags', $tags);
- $this->assertEquals(array('tip', 'v_2', 'v_1', '2'), static::cleanTags($tags));
+ $this->assertEquals(array('tip', 'v_2', 'v_1', 'v2'), static::cleanTags($tags));
}
public function testTagPrefixWithBranchNamePlaceHolder()
diff --git a/test/Liip/RMT/Tests/Unit/VCS/GitTest.php b/test/Liip/RMT/Tests/Unit/VCS/GitTest.php
index f96a938c..56ff64e5 100644
--- a/test/Liip/RMT/Tests/Unit/VCS/GitTest.php
+++ b/test/Liip/RMT/Tests/Unit/VCS/GitTest.php
@@ -60,6 +60,53 @@ public function testGetTags()
$this->assertEquals(array('1.0.0', '1.1.0'), $vcs->getTags());
}
+ /**
+ * @dataProvider invalidTagNames
+ * @expectedException \Liip\RMT\Exception\InvalidTagNameException
+ */
+ public function testInvalidateTag($tag)
+ {
+ $vcs = new Git();
+ $vcs->validateTag($tag);
+ }
+
+ public function invalidTagNames()
+ {
+ return array(
+ array("test..test"),
+ array("test*test"),
+ array('test[test'),
+ array("test?test"),
+ array("test\ntest"),
+ array("test\rtest"),
+ array("test."),
+ array("@"),
+ array("\\"),
+ );
+ }
+
+ /**
+ * @dataProvider validTagNames
+ */
+ public function testValidateTag($tag)
+ {
+ $vcs = new Git();
+ $vcs->validateTag($tag);
+ }
+
+ public function validTagNames()
+ {
+ return array(
+ array('test/test'),
+ array('test'),
+ array(2345),
+ array('1.2'),
+ array('1.2.3'),
+ array('v1.2'),
+ array('v1.2.3'),
+ );
+ }
+
public function testCreateTag()
{
$vcs = new Git();
diff --git a/test/Liip/RMT/Tests/Unit/VCS/HgTest.php b/test/Liip/RMT/Tests/Unit/VCS/HgTest.php
index beef3c7a..0e9a4bf5 100644
--- a/test/Liip/RMT/Tests/Unit/VCS/HgTest.php
+++ b/test/Liip/RMT/Tests/Unit/VCS/HgTest.php
@@ -60,6 +60,47 @@ public function testGetTags()
$this->assertEquals(array('tip', '1.1.0', '1.0.0'), $vcs->getTags());
}
+ /**
+ * @dataProvider invalidTagNames
+ * @expectedException \Liip\RMT\Exception\InvalidTagNameException
+ */
+ public function testInvalidateTag($tag)
+ {
+ $vcs = new Hg();
+ $vcs->validateTag($tag);
+ }
+
+ public function invalidTagNames()
+ {
+ return array(
+ array(2345),
+ array('test:test'),
+ array("test\ntest"),
+ array("test\rtest"),
+ );
+ }
+
+ /**
+ * @dataProvider validTagNames
+ */
+ public function testValidateTag($tag)
+ {
+ $vcs = new Hg();
+ $vcs->validateTag($tag);
+ }
+
+ public function validTagNames()
+ {
+ return array(
+ array('test/test'),
+ array('test'),
+ array('1.2'),
+ array('1.2.3'),
+ array('v1.2'),
+ array('v1.2.3'),
+ );
+ }
+
public function testCreateTag()
{
$vcs = new Hg();