diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php
index 4fabbe455..1da6c30da 100644
--- a/src/Composer/Factory.php
+++ b/src/Composer/Factory.php
@@ -16,6 +16,7 @@ use Composer\Config\JsonConfigSource;
use Composer\Json\JsonFile;
use Composer\IO\IOInterface;
use Composer\Package\Archiver;
+use Composer\Package\Version\VersionGuesser;
use Composer\Repository\RepositoryManager;
use Composer\Repository\WritableRepositoryInterface;
use Composer\Util\ProcessExecutor;
@@ -264,7 +265,8 @@ class Factory
// load package
$parser = new VersionParser;
- $loader = new Package\Loader\RootPackageLoader($rm, $config, $parser, new ProcessExecutor($io));
+ $guesser = new VersionGuesser(new ProcessExecutor($io), $parser);
+ $loader = new Package\Loader\RootPackageLoader($rm, $config, $parser, $guesser);
$package = $loader->load($localConfig);
$composer->setPackage($package);
diff --git a/src/Composer/Package/Loader/RootPackageLoader.php b/src/Composer/Package/Loader/RootPackageLoader.php
index 9c7c436bc..3043a18c5 100644
--- a/src/Composer/Package/Loader/RootPackageLoader.php
+++ b/src/Composer/Package/Loader/RootPackageLoader.php
@@ -16,13 +16,10 @@ use Composer\Package\BasePackage;
use Composer\Package\AliasPackage;
use Composer\Config;
use Composer\Factory;
+use Composer\Package\Version\VersionGuesser;
use Composer\Package\Version\VersionParser;
use Composer\Repository\RepositoryManager;
-use Composer\Repository\Vcs\HgDriver;
-use Composer\IO\NullIO;
use Composer\Util\ProcessExecutor;
-use Composer\Util\Git as GitUtil;
-use Composer\Util\Svn as SvnUtil;
/**
* ArrayLoader built for the sole purpose of loading the root package
@@ -33,16 +30,28 @@ use Composer\Util\Svn as SvnUtil;
*/
class RootPackageLoader extends ArrayLoader
{
+ /**
+ * @var RepositoryManager
+ */
private $manager;
- private $config;
- private $process;
- public function __construct(RepositoryManager $manager, Config $config, VersionParser $parser = null, ProcessExecutor $process = null)
+ /**
+ * @var Config
+ */
+ private $config;
+
+ /**
+ * @var VersionGuesser
+ */
+ private $versionGuesser;
+
+ public function __construct(RepositoryManager $manager, Config $config, VersionParser $parser = null, VersionGuesser $versionGuesser = null)
{
+ parent::__construct($parser);
+
$this->manager = $manager;
$this->config = $config;
- $this->process = $process ?: new ProcessExecutor();
- parent::__construct($parser);
+ $this->versionGuesser = $versionGuesser ?: new VersionGuesser(new ProcessExecutor(), $this->versionParser);
}
public function load(array $config, $class = 'Composer\Package\RootPackage')
@@ -56,7 +65,7 @@ class RootPackageLoader extends ArrayLoader
if (getenv('COMPOSER_ROOT_VERSION')) {
$version = getenv('COMPOSER_ROOT_VERSION');
} else {
- $version = $this->guessVersion($config);
+ $version = $this->versionGuesser->guessVersion($this->config, $config);
}
if (!$version) {
@@ -176,172 +185,4 @@ class RootPackageLoader extends ArrayLoader
return $references;
}
-
- private function guessVersion(array $config)
- {
- if (function_exists('proc_open')) {
- $version = $this->guessGitVersion($config);
- if (null !== $version) {
- return $version;
- }
-
- $version = $this->guessHgVersion($config);
- if (null !== $version) {
- return $version;
- }
-
- return $this->guessSvnVersion($config);
- }
- }
-
- private function guessGitVersion(array $config)
- {
- GitUtil::cleanEnv();
-
- // try to fetch current version from git tags
- if (0 === $this->process->execute('git describe --exact-match --tags', $output)) {
- try {
- return $this->versionParser->normalize(trim($output));
- } catch (\Exception $e) {
- }
- }
-
- // try to fetch current version from git branch
- if (0 === $this->process->execute('git branch --no-color --no-abbrev -v', $output)) {
- $branches = array();
- $isFeatureBranch = false;
- $version = null;
-
- // find current branch and collect all branch names
- foreach ($this->process->splitLines($output) as $branch) {
- if ($branch && preg_match('{^(?:\* ) *(\(no branch\)|\(detached from \S+\)|\S+) *([a-f0-9]+) .*$}', $branch, $match)) {
- if ($match[1] === '(no branch)' || substr($match[1], 0, 10) === '(detached ') {
- $version = 'dev-'.$match[2];
- $isFeatureBranch = true;
- } else {
- $version = $this->versionParser->normalizeBranch($match[1]);
- $isFeatureBranch = 0 === strpos($version, 'dev-');
- if ('9999999-dev' === $version) {
- $version = 'dev-'.$match[1];
- }
- }
- }
-
- if ($branch && !preg_match('{^ *[^/]+/HEAD }', $branch)) {
- if (preg_match('{^(?:\* )? *(\S+) *([a-f0-9]+) .*$}', $branch, $match)) {
- $branches[] = $match[1];
- }
- }
- }
-
- if (!$isFeatureBranch) {
- return $version;
- }
-
- // try to find the best (nearest) version branch to assume this feature's version
- $version = $this->guessFeatureVersion($config, $version, $branches, 'git rev-list %candidate%..%branch%');
-
- return $version;
- }
- }
-
- private function guessHgVersion(array $config)
- {
- // try to fetch current version from hg branch
- if (0 === $this->process->execute('hg branch', $output)) {
- $branch = trim($output);
- $version = $this->versionParser->normalizeBranch($branch);
- $isFeatureBranch = 0 === strpos($version, 'dev-');
-
- if ('9999999-dev' === $version) {
- $version = 'dev-'.$branch;
- }
-
- if (!$isFeatureBranch) {
- return $version;
- }
-
- // re-use the HgDriver to fetch branches (this properly includes bookmarks)
- $config = array('url' => getcwd());
- $driver = new HgDriver($config, new NullIO(), $this->config, $this->process);
- $branches = array_keys($driver->getBranches());
-
- // try to find the best (nearest) version branch to assume this feature's version
- $version = $this->guessFeatureVersion($config, $version, $branches, 'hg log -r "not ancestors(\'%candidate%\') and ancestors(\'%branch%\')" --template "{node}\\n"');
-
- return $version;
- }
- }
-
- private function guessFeatureVersion(array $config, $version, array $branches, $scmCmdline)
- {
- // ignore feature branches if they have no branch-alias or self.version is used
- // and find the branch they came from to use as a version instead
- if ((isset($config['extra']['branch-alias']) && !isset($config['extra']['branch-alias'][$version]))
- || strpos(json_encode($config), '"self.version"')
- ) {
- $branch = preg_replace('{^dev-}', '', $version);
- $length = PHP_INT_MAX;
-
- $nonFeatureBranches = '';
- if (!empty($config['non-feature-branches'])) {
- $nonFeatureBranches = implode('|', $config['non-feature-branches']);
- }
-
- foreach ($branches as $candidate) {
- // return directly, if branch is configured to be non-feature branch
- if ($candidate === $branch && preg_match('{^(' . $nonFeatureBranches . ')$}', $candidate)) {
- return $version;
- }
-
- // do not compare against other feature branches
- if ($candidate === $branch || !preg_match('{^(master|trunk|default|develop|\d+\..+)$}', $candidate, $match)) {
- continue;
- }
-
- $cmdLine = str_replace(array('%candidate%', '%branch%'), array($candidate, $branch), $scmCmdline);
- if (0 !== $this->process->execute($cmdLine, $output)) {
- continue;
- }
-
- if (strlen($output) < $length) {
- $length = strlen($output);
- $version = $this->versionParser->normalizeBranch($candidate);
- if ('9999999-dev' === $version) {
- $version = 'dev-'.$match[1];
- }
- }
- }
- }
-
- return $version;
- }
-
- private function guessSvnVersion(array $config)
- {
- SvnUtil::cleanEnv();
-
- // try to fetch current version from svn
- if (0 === $this->process->execute('svn info --xml', $output)) {
- $trunkPath = isset($config['trunk-path']) ? preg_quote($config['trunk-path'], '#') : 'trunk';
- $branchesPath = isset($config['branches-path']) ? preg_quote($config['branches-path'], '#') : 'branches';
- $tagsPath = isset($config['tags-path']) ? preg_quote($config['tags-path'], '#') : 'tags';
-
- $urlPattern = '#.*/('.$trunkPath.'|('.$branchesPath.'|'. $tagsPath .')/(.*))#';
-
- if (preg_match($urlPattern, $output, $matches)) {
- if (isset($matches[2]) && ($branchesPath === $matches[2] || $tagsPath === $matches[2])) {
- // we are in a branches path
- $version = $this->versionParser->normalizeBranch($matches[3]);
- if ('9999999-dev' === $version) {
- $version = 'dev-'.$matches[3];
- }
-
- return $version;
- }
-
- return $this->versionParser->normalize(trim($matches[1]));
- }
- }
- }
}
diff --git a/src/Composer/Package/Version/VersionGuesser.php b/src/Composer/Package/Version/VersionGuesser.php
new file mode 100644
index 000000000..98cf216c8
--- /dev/null
+++ b/src/Composer/Package/Version/VersionGuesser.php
@@ -0,0 +1,201 @@
+process = $process;
+ $this->versionParser = $versionParser;
+ }
+
+ public function guessVersion(Config $config, array $packageConfig)
+ {
+ if (function_exists('proc_open')) {
+ $version = $this->guessGitVersion($packageConfig);
+ if (null !== $version) {
+ return $version;
+ }
+
+ $version = $this->guessHgVersion($config, $packageConfig);
+ if (null !== $version) {
+ return $version;
+ }
+
+ return $this->guessSvnVersion($packageConfig);
+ }
+ }
+
+ private function guessGitVersion(array $config)
+ {
+ GitUtil::cleanEnv();
+
+ // try to fetch current version from git tags
+ if (0 === $this->process->execute('git describe --exact-match --tags', $output)) {
+ try {
+ return $this->versionParser->normalize(trim($output));
+ } catch (\Exception $e) {
+ }
+ }
+
+ // try to fetch current version from git branch
+ if (0 === $this->process->execute('git branch --no-color --no-abbrev -v', $output)) {
+ $branches = array();
+ $isFeatureBranch = false;
+ $version = null;
+
+ // find current branch and collect all branch names
+ foreach ($this->process->splitLines($output) as $branch) {
+ if ($branch && preg_match('{^(?:\* ) *(\(no branch\)|\(detached from \S+\)|\S+) *([a-f0-9]+) .*$}', $branch, $match)) {
+ if ($match[1] === '(no branch)' || substr($match[1], 0, 10) === '(detached ') {
+ $version = 'dev-'.$match[2];
+ $isFeatureBranch = true;
+ } else {
+ $version = $this->versionParser->normalizeBranch($match[1]);
+ $isFeatureBranch = 0 === strpos($version, 'dev-');
+ if ('9999999-dev' === $version) {
+ $version = 'dev-'.$match[1];
+ }
+ }
+ }
+
+ if ($branch && !preg_match('{^ *[^/]+/HEAD }', $branch)) {
+ if (preg_match('{^(?:\* )? *(\S+) *([a-f0-9]+) .*$}', $branch, $match)) {
+ $branches[] = $match[1];
+ }
+ }
+ }
+
+ if (!$isFeatureBranch) {
+ return $version;
+ }
+
+ // try to find the best (nearest) version branch to assume this feature's version
+ $version = $this->guessFeatureVersion($config, $version, $branches, 'git rev-list %candidate%..%branch%');
+
+ return $version;
+ }
+ }
+
+ private function guessHgVersion(Config $config, array $packageConfig)
+ {
+ // try to fetch current version from hg branch
+ if (0 === $this->process->execute('hg branch', $output)) {
+ $branch = trim($output);
+ $version = $this->versionParser->normalizeBranch($branch);
+ $isFeatureBranch = 0 === strpos($version, 'dev-');
+
+ if ('9999999-dev' === $version) {
+ $version = 'dev-'.$branch;
+ }
+
+ if (!$isFeatureBranch) {
+ return $version;
+ }
+
+ // re-use the HgDriver to fetch branches (this properly includes bookmarks)
+ $packageConfig = array('url' => getcwd());
+ $driver = new HgDriver($packageConfig, new NullIO(), $config, $this->process);
+ $branches = array_keys($driver->getBranches());
+
+ // try to find the best (nearest) version branch to assume this feature's version
+ $version = $this->guessFeatureVersion($config, $version, $branches, 'hg log -r "not ancestors(\'%candidate%\') and ancestors(\'%branch%\')" --template "{node}\\n"');
+
+ return $version;
+ }
+ }
+
+ private function guessFeatureVersion(array $config, $version, array $branches, $scmCmdline)
+ {
+ // ignore feature branches if they have no branch-alias or self.version is used
+ // and find the branch they came from to use as a version instead
+ if ((isset($config['extra']['branch-alias']) && !isset($config['extra']['branch-alias'][$version]))
+ || strpos(json_encode($config), '"self.version"')
+ ) {
+ $branch = preg_replace('{^dev-}', '', $version);
+ $length = PHP_INT_MAX;
+
+ $nonFeatureBranches = '';
+ if (!empty($config['non-feature-branches'])) {
+ $nonFeatureBranches = implode('|', $config['non-feature-branches']);
+ }
+
+ foreach ($branches as $candidate) {
+ // return directly, if branch is configured to be non-feature branch
+ if ($candidate === $branch && preg_match('{^(' . $nonFeatureBranches . ')$}', $candidate)) {
+ return $version;
+ }
+
+ // do not compare against other feature branches
+ if ($candidate === $branch || !preg_match('{^(master|trunk|default|develop|\d+\..+)$}', $candidate, $match)) {
+ continue;
+ }
+
+ $cmdLine = str_replace(array('%candidate%', '%branch%'), array($candidate, $branch), $scmCmdline);
+ if (0 !== $this->process->execute($cmdLine, $output)) {
+ continue;
+ }
+
+ if (strlen($output) < $length) {
+ $length = strlen($output);
+ $version = $this->versionParser->normalizeBranch($candidate);
+ if ('9999999-dev' === $version) {
+ $version = 'dev-'.$match[1];
+ }
+ }
+ }
+ }
+
+ return $version;
+ }
+
+ private function guessSvnVersion(array $config)
+ {
+ SvnUtil::cleanEnv();
+
+ // try to fetch current version from svn
+ if (0 === $this->process->execute('svn info --xml', $output)) {
+ $trunkPath = isset($config['trunk-path']) ? preg_quote($config['trunk-path'], '#') : 'trunk';
+ $branchesPath = isset($config['branches-path']) ? preg_quote($config['branches-path'], '#') : 'branches';
+ $tagsPath = isset($config['tags-path']) ? preg_quote($config['tags-path'], '#') : 'tags';
+
+ $urlPattern = '#.*/('.$trunkPath.'|('.$branchesPath.'|'. $tagsPath .')/(.*))#';
+
+ if (preg_match($urlPattern, $output, $matches)) {
+ if (isset($matches[2]) && ($branchesPath === $matches[2] || $tagsPath === $matches[2])) {
+ // we are in a branches path
+ $version = $this->versionParser->normalizeBranch($matches[3]);
+ if ('9999999-dev' === $version) {
+ $version = 'dev-'.$matches[3];
+ }
+
+ return $version;
+ }
+
+ return $this->versionParser->normalize(trim($matches[1]));
+ }
+ }
+ }
+}
diff --git a/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php b/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php
index 2a4d9ccf6..77139f928 100644
--- a/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php
+++ b/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php
@@ -15,175 +15,11 @@ namespace Composer\Test\Package\Loader;
use Composer\Config;
use Composer\Package\Loader\RootPackageLoader;
use Composer\Package\BasePackage;
+use Composer\Package\Version\VersionGuesser;
+use Composer\Package\Version\VersionParser;
class RootPackageLoaderTest extends \PHPUnit_Framework_TestCase
{
- public function testDetachedHeadBecomesDevHash()
- {
- if (!function_exists('proc_open')) {
- $this->markTestSkipped('proc_open() is not available');
- }
-
- $commitHash = '03a15d220da53c52eddd5f32ffca64a7b3801bea';
-
- $manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager')
- ->disableOriginalConstructor()
- ->getMock()
- ;
-
- $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor')
- ->setMethods(array('execute'))
- ->disableArgumentCloning()
- ->disableOriginalConstructor()
- ->getMock()
- ;
-
- $executor
- ->expects($this->at(0))
- ->method('execute')
- ->with('git describe --exact-match --tags')
- ->willReturn(1)
- ;
-
- $self = $this;
-
- $executor
- ->expects($this->at(1))
- ->method('execute')
- ->willReturnCallback(function ($command, &$output) use ($self, $commitHash) {
- $self->assertEquals('git branch --no-color --no-abbrev -v', $command);
- $output = "* (no branch) $commitHash Commit message\n";
-
- return 0;
- })
- ;
-
- $config = new Config;
- $config->merge(array('repositories' => array('packagist' => false)));
- $loader = new RootPackageLoader($manager, $config, null, $executor);
- $package = $loader->load(array());
-
- $this->assertEquals("dev-$commitHash", $package->getVersion());
- }
-
- public function testTagBecomesVersion()
- {
- if (!function_exists('proc_open')) {
- $this->markTestSkipped('proc_open() is not available');
- }
-
- $manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager')
- ->disableOriginalConstructor()
- ->getMock()
- ;
-
- $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor')
- ->setMethods(array('execute'))
- ->disableArgumentCloning()
- ->disableOriginalConstructor()
- ->getMock()
- ;
-
- $self = $this;
-
- $executor
- ->expects($this->at(0))
- ->method('execute')
- ->willReturnCallback(function ($command, &$output) use ($self) {
- $self->assertEquals('git describe --exact-match --tags', $command);
- $output = "v2.0.5-alpha2";
-
- return 0;
- })
- ;
-
- $config = new Config;
- $config->merge(array('repositories' => array('packagist' => false)));
- $loader = new RootPackageLoader($manager, $config, null, $executor);
- $package = $loader->load(array());
-
- $this->assertEquals("2.0.5.0-alpha2", $package->getVersion());
- }
-
- public function testInvalidTagBecomesVersion()
- {
- if (!function_exists('proc_open')) {
- $this->markTestSkipped('proc_open() is not available');
- }
-
- $manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager')
- ->disableOriginalConstructor()
- ->getMock()
- ;
-
- $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor')
- ->setMethods(array('execute'))
- ->disableArgumentCloning()
- ->disableOriginalConstructor()
- ->getMock()
- ;
-
- $self = $this;
-
- $executor
- ->expects($this->at(0))
- ->method('execute')
- ->willReturnCallback(function ($command, &$output) use ($self) {
- $self->assertEquals('git describe --exact-match --tags', $command);
- $output = "foo-bar";
-
- return 0;
- })
- ;
-
- $executor
- ->expects($this->at(1))
- ->method('execute')
- ->willReturnCallback(function ($command, &$output) use ($self) {
- $self->assertEquals('git branch --no-color --no-abbrev -v', $command);
- $output = "* foo 03a15d220da53c52eddd5f32ffca64a7b3801bea Commit message\n";
-
- return 0;
- })
- ;
-
- $config = new Config;
- $config->merge(array('repositories' => array('packagist' => false)));
- $loader = new RootPackageLoader($manager, $config, null, $executor);
- $package = $loader->load(array());
-
- $this->assertEquals("dev-foo", $package->getVersion());
- }
-
- public function testNoVersionIsVisibleInPrettyVersion()
- {
- $manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager')
- ->disableOriginalConstructor()
- ->getMock()
- ;
-
- $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor')
- ->setMethods(array('execute'))
- ->disableArgumentCloning()
- ->disableOriginalConstructor()
- ->getMock()
- ;
-
- $executor
- ->expects($this->any())
- ->method('execute')
- ->willReturn(null)
- ;
-
- $config = new Config;
- $config->merge(array('repositories' => array('packagist' => false)));
- $loader = new RootPackageLoader($manager, $config, null, $executor);
- $package = $loader->load(array());
-
- $this->assertEquals("1.0.0.0", $package->getVersion());
- $this->assertEquals("No version set (parsed as 1.0.0)", $package->getPrettyVersion());
- }
-
protected function loadPackage($data)
{
$manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager')
@@ -218,6 +54,37 @@ class RootPackageLoaderTest extends \PHPUnit_Framework_TestCase
), $package->getStabilityFlags());
}
+ public function testNoVersionIsVisibleInPrettyVersion()
+ {
+ $manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager')
+ ->disableOriginalConstructor()
+ ->getMock()
+ ;
+
+ $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor')
+ ->setMethods(array('execute'))
+ ->disableArgumentCloning()
+ ->disableOriginalConstructor()
+ ->getMock()
+ ;
+
+ $executor
+ ->expects($this->any())
+ ->method('execute')
+ ->willReturn(null)
+ ;
+
+ $config = new Config;
+ $config->merge(array('repositories' => array('packagist' => false)));
+ $loader = new RootPackageLoader($manager, $config, null, new VersionGuesser($executor, new VersionParser()));
+ $package = $loader->load(array());
+
+ $this->assertEquals("1.0.0.0", $package->getVersion());
+ $this->assertEquals("No version set (parsed as 1.0.0)", $package->getPrettyVersion());
+ }
+
+
+
public function testFeatureBranchPrettyVersion()
{
if (!function_exists('proc_open')) {
@@ -272,7 +139,7 @@ class RootPackageLoaderTest extends \PHPUnit_Framework_TestCase
$config = new Config;
$config->merge(array('repositories' => array('packagist' => false)));
- $loader = new RootPackageLoader($manager, $config, null, $executor);
+ $loader = new RootPackageLoader($manager, $config, null, new VersionGuesser($executor, new VersionParser()));
$package = $loader->load(array('require' => array('foo/bar' => 'self.version')));
$this->assertEquals("dev-master", $package->getPrettyVersion());
@@ -321,7 +188,7 @@ class RootPackageLoaderTest extends \PHPUnit_Framework_TestCase
$config = new Config;
$config->merge(array('repositories' => array('packagist' => false)));
- $loader = new RootPackageLoader($manager, $config, null, $executor);
+ $loader = new RootPackageLoader($manager, $config, null, new VersionGuesser($executor, new VersionParser()));
$package = $loader->load(array('require' => array('foo/bar' => 'self.version'), "non-feature-branches" => array("latest-.*")));
$this->assertEquals("dev-latest-production", $package->getPrettyVersion());
diff --git a/tests/Composer/Test/Package/Version/VersionGuesserTest.php b/tests/Composer/Test/Package/Version/VersionGuesserTest.php
new file mode 100644
index 000000000..7891d1062
--- /dev/null
+++ b/tests/Composer/Test/Package/Version/VersionGuesserTest.php
@@ -0,0 +1,158 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Test\Package\Version;
+
+use Composer\Config;
+use Composer\Package\Loader\RootPackageLoader;
+use Composer\Package\Version\VersionGuesser;
+use Composer\Package\Version\VersionParser;
+
+class VersionGuesserTest extends \PHPUnit_Framework_TestCase
+{
+ public function testDetachedHeadBecomesDevHash()
+ {
+ if (!function_exists('proc_open')) {
+ $this->markTestSkipped('proc_open() is not available');
+ }
+
+ $commitHash = '03a15d220da53c52eddd5f32ffca64a7b3801bea';
+
+ $manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager')
+ ->disableOriginalConstructor()
+ ->getMock()
+ ;
+
+ $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor')
+ ->setMethods(array('execute'))
+ ->disableArgumentCloning()
+ ->disableOriginalConstructor()
+ ->getMock()
+ ;
+
+ $executor
+ ->expects($this->at(0))
+ ->method('execute')
+ ->with('git describe --exact-match --tags')
+ ->willReturn(1)
+ ;
+
+ $self = $this;
+
+ $executor
+ ->expects($this->at(1))
+ ->method('execute')
+ ->willReturnCallback(function ($command, &$output) use ($self, $commitHash) {
+ $self->assertEquals('git branch --no-color --no-abbrev -v', $command);
+ $output = "* (no branch) $commitHash Commit message\n";
+
+ return 0;
+ })
+ ;
+
+ $config = new Config;
+ $config->merge(array('repositories' => array('packagist' => false)));
+ $guesser = new VersionGuesser($executor, new VersionParser());
+ $version = $guesser->guessVersion($config, []);
+
+ $this->assertEquals("dev-$commitHash", $version);
+ }
+
+ public function testTagBecomesVersion()
+ {
+ if (!function_exists('proc_open')) {
+ $this->markTestSkipped('proc_open() is not available');
+ }
+
+ $manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager')
+ ->disableOriginalConstructor()
+ ->getMock()
+ ;
+
+ $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor')
+ ->setMethods(array('execute'))
+ ->disableArgumentCloning()
+ ->disableOriginalConstructor()
+ ->getMock()
+ ;
+
+ $self = $this;
+
+ $executor
+ ->expects($this->at(0))
+ ->method('execute')
+ ->willReturnCallback(function ($command, &$output) use ($self) {
+ $self->assertEquals('git describe --exact-match --tags', $command);
+ $output = "v2.0.5-alpha2";
+
+ return 0;
+ })
+ ;
+
+ $config = new Config;
+ $config->merge(array('repositories' => array('packagist' => false)));
+ $guesser = new VersionGuesser($executor, new VersionParser());
+ $version = $guesser->guessVersion($config, []);
+
+ $this->assertEquals("2.0.5.0-alpha2", $version);
+ }
+
+ public function testInvalidTagBecomesVersion()
+ {
+ if (!function_exists('proc_open')) {
+ $this->markTestSkipped('proc_open() is not available');
+ }
+
+ $manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager')
+ ->disableOriginalConstructor()
+ ->getMock()
+ ;
+
+ $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor')
+ ->setMethods(array('execute'))
+ ->disableArgumentCloning()
+ ->disableOriginalConstructor()
+ ->getMock()
+ ;
+
+ $self = $this;
+
+ $executor
+ ->expects($this->at(0))
+ ->method('execute')
+ ->willReturnCallback(function ($command, &$output) use ($self) {
+ $self->assertEquals('git describe --exact-match --tags', $command);
+ $output = "foo-bar";
+
+ return 0;
+ })
+ ;
+
+ $executor
+ ->expects($this->at(1))
+ ->method('execute')
+ ->willReturnCallback(function ($command, &$output) use ($self) {
+ $self->assertEquals('git branch --no-color --no-abbrev -v', $command);
+ $output = "* foo 03a15d220da53c52eddd5f32ffca64a7b3801bea Commit message\n";
+
+ return 0;
+ })
+ ;
+
+ $config = new Config;
+ $config->merge(array('repositories' => array('packagist' => false)));
+ $guesser = new VersionGuesser($executor, new VersionParser());
+ $version = $guesser->guessVersion($config, []);
+
+ $this->assertEquals("dev-foo", $version);
+ }
+}