Ver código fonte

Support aliases for numeric branches. Fixes #3461

Damian Mooyman 10 anos atrás
pai
commit
7bb85ff21e

+ 8 - 4
doc/articles/aliases.md

@@ -38,10 +38,14 @@ specifying a `branch-alias` field under `extra` in `composer.json`:
 }
 ```
 
-The branch version must begin with `dev-` (non-comparable version), the alias
-must be a comparable dev version (i.e. start with numbers, and end with
-`.x-dev`). The `branch-alias` must be present on the branch that it references.
-For `dev-master`, you need to commit it on the `master` branch.
+If you alias a non-comparible version (such as dev-develop) `dev-` must prefix the
+branch name. You may also alias a comparible version (i.e. start with numbers,
+and end with `.x-dev`), but only as a more specific version.
+For example, 1.x-dev could be aliased as 1.2.x-dev.
+
+The alias must be a comparable dev version, and the `branch-alias` must be present on
+the branch that it references. For `dev-master`, you need to commit it on the
+`master` branch.
 
 As a result, anyone can now require `1.0.*` and it will happily install
 `dev-master`.

+ 9 - 1
src/Composer/Package/Loader/ArrayLoader.php

@@ -224,7 +224,7 @@ class ArrayLoader implements LoaderInterface
      */
     public function getBranchAlias(array $config)
     {
-        if ('dev-' !== substr($config['version'], 0, 4)
+        if (('dev-' !== substr($config['version'], 0, 4) && '-dev' !== substr($config['version'], -4))
             || !isset($config['extra']['branch-alias'])
             || !is_array($config['extra']['branch-alias'])
         ) {
@@ -248,6 +248,14 @@ class ArrayLoader implements LoaderInterface
                 continue;
             }
 
+            // If using numeric aliases ensure the alias is a valid subversion
+            if(($sourcePrefix = $this->versionParser->parseNumericAliasPrefix($sourceBranch))
+                && ($targetPrefix = $this->versionParser->parseNumericAliasPrefix($targetBranch))
+                && (stripos($targetPrefix, $sourcePrefix) !== 0)
+            ) {
+                continue;
+            }
+
             return $validatedTargetBranch;
         }
     }

+ 11 - 0
src/Composer/Package/Loader/ValidatingArrayLoader.php

@@ -251,6 +251,17 @@ class ValidatingArrayLoader implements LoaderInterface
                     if ('-dev' !== substr($validatedTargetBranch, -4)) {
                         $this->warnings[] = 'extra.branch-alias.'.$sourceBranch.' : the target branch ('.$targetBranch.') must be a parseable number like 2.0-dev';
                         unset($this->config['extra']['branch-alias'][$sourceBranch]);
+
+                        continue;
+                    }
+
+                    // If using numeric aliases ensure the alias is a valid subversion
+                    if(($sourcePrefix = $this->versionParser->parseNumericAliasPrefix($sourceBranch))
+                        && ($targetPrefix = $this->versionParser->parseNumericAliasPrefix($targetBranch))
+                        && (stripos($targetPrefix, $sourcePrefix) !== 0)
+                    ) {
+                        $this->warnings[] = 'extra.branch-alias.'.$sourceBranch.' : the target branch ('.$targetBranch.') is not a valid numeric alias for this version';
+                        unset($this->config['extra']['branch-alias'][$sourceBranch]);
                     }
                 }
             }

+ 15 - 0
src/Composer/Package/Version/VersionParser.php

@@ -169,6 +169,21 @@ class VersionParser
         throw new \UnexpectedValueException('Invalid version string "'.$version.'"'.$extraMessage);
     }
 
+    /**
+     * Extract numeric prefix from alias, if it is in numeric format, suitable for
+     * version comparison
+     *
+     * @param string $branch Branch name (e.g. 2.1.x-dev)
+     * @return string|false Numeric prefix if present (e.g. 2.1.) or false
+     */
+    public function parseNumericAliasPrefix($branch) {
+        if(preg_match('/^(?<version>(\d+\\.)*\d+).x-dev$/i', $branch, $matches)) {
+            return $matches['version'].".";
+        } else {
+            return false;
+        }
+    }
+
     /**
      * Normalizes a branch name to be able to perform comparisons on it
      *

+ 22 - 0
tests/Composer/Test/Package/Loader/ArrayLoaderTest.php

@@ -138,6 +138,28 @@ class ArrayLoaderTest extends \PHPUnit_Framework_TestCase
 
         $this->assertInstanceOf('Composer\Package\AliasPackage', $package);
         $this->assertEquals('1.0.x-dev', $package->getPrettyVersion());
+
+        $config = array(
+            'name' => 'B',
+            'version' => '4.x-dev',
+            'extra' => array('branch-alias' => array('4.x-dev' => '4.0.x-dev')),
+        );
+
+        $package = $this->loader->load($config);
+
+        $this->assertInstanceOf('Composer\Package\AliasPackage', $package);
+        $this->assertEquals('4.0.x-dev', $package->getPrettyVersion());
+
+        $config = array(
+            'name' => 'C',
+            'version' => '4.x-dev',
+            'extra' => array('branch-alias' => array('4.x-dev' => '3.4.x-dev')),
+        );
+
+        $package = $this->loader->load($config);
+
+        $this->assertInstanceOf('Composer\Package\CompletePackage', $package);
+        $this->assertEquals('4.x-dev', $package->getPrettyVersion());
     }
 
     public function testAbandoned()

+ 15 - 0
tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php

@@ -140,6 +140,7 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase
                         'branch-alias' => array(
                             'dev-master' => '2.0-dev',
                             'dev-old' => '1.0.x-dev',
+                            '3.x-dev' => '3.1.x-dev'
                         ),
                     ),
                     'bin' => array(
@@ -324,6 +325,20 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase
                 ),
                 false
             ),
+            array(
+                array(
+                    'name' => 'foo/bar',
+                    'extra' => array(
+                        'branch-alias' => array(
+                            '5.x-dev' => '3.1.x-dev'
+                        ),
+                    )
+                ),
+                array(
+                    'extra.branch-alias.5.x-dev : the target branch (3.1.x-dev) is not a valid numeric alias for this version'
+                ),
+                false
+            ),
         );
     }
 }

+ 20 - 0
tests/Composer/Test/Package/Version/VersionParserTest.php

@@ -76,6 +76,26 @@ class VersionParserTest extends \PHPUnit_Framework_TestCase
         $this->assertSame($expected, $parser->normalize($input));
     }
 
+    public function numericAliasVersions() {
+        return array(
+            array('0.x-dev',        '0.'),
+            array('1.0.x-dev',      '1.0.'),
+            array('1.x-dev',        '1.'),
+            array('1.2.x-dev',      '1.2.'),
+            array('dev-develop',    false),
+            array('dev-master',     false),
+        );
+    }
+
+    /**
+     * @dataProvider numericAliasVersions
+     */
+    public function testParseNumericAliasPrefix($input, $expected)
+    {
+        $parser = new VersionParser;
+        $this->assertSame($expected, $parser->parseNumericAliasPrefix($input));
+    }
+
     public function successfulNormalizedVersions()
     {
         return array(

+ 2 - 0
tests/Composer/Test/Package/Version/VersionSelectorTest.php

@@ -115,6 +115,8 @@ class VersionSelectorTest extends \PHPUnit_Framework_TestCase
             array('dev-master', true, 'dev', '~2.1@dev', '2.1.x-dev'),
             array('dev-master', true, 'dev', '~2.1@dev', '2.1.3.x-dev'),
             array('dev-master', true, 'dev', '~2.0@dev', '2.x-dev'),
+            // numeric alias
+            array('3.x-dev', true, 'dev', '~3.0@dev', '3.0.x-dev'),
         );
     }