From eeff1c79bad67d3055afa5ee3180763095f15671 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 25 Jul 2024 16:46:57 +0200 Subject: [PATCH] Fix addressability of branches containing # characters (#12042) Fixes #12029 --- src/Composer/DependencyResolver/Problem.php | 12 ++++++ src/Composer/Repository/VcsRepository.php | 3 +- .../solver-problem-with-hash-in-branch.test | 40 +++++++++++++++++++ .../Test/Repository/VcsRepositoryTest.php | 4 ++ 4 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 tests/Composer/Test/Fixtures/installer/solver-problem-with-hash-in-branch.test diff --git a/src/Composer/DependencyResolver/Problem.php b/src/Composer/DependencyResolver/Problem.php index cf2cb381e..a49bf5436 100644 --- a/src/Composer/DependencyResolver/Problem.php +++ b/src/Composer/DependencyResolver/Problem.php @@ -25,6 +25,7 @@ use Composer\Semver\Constraint\Constraint; use Composer\Semver\Constraint\ConstraintInterface; use Composer\Package\Version\VersionParser; use Composer\Repository\PlatformRepository; +use Composer\Semver\Constraint\MultiConstraint; /** * Represents a problem detected while solving dependencies @@ -262,6 +263,17 @@ class Problem } } + if ($constraint instanceof Constraint && $constraint->getOperator() === Constraint::STR_OP_EQ && Preg::isMatch('{^dev-.*#.*}', $constraint->getPrettyString())) { + $newConstraint = Preg::replace('{ +as +([^,\s|]+)$}', '', $constraint->getPrettyString()); + $packages = $repositorySet->findPackages($packageName, new MultiConstraint([ + new Constraint(Constraint::STR_OP_EQ, $newConstraint), + new Constraint(Constraint::STR_OP_EQ, str_replace('#', '+', $newConstraint)) + ], false)); + if (\count($packages) > 0) { + return ["- Root composer.json requires $packageName".self::constraintToText($constraint) . ', ', 'found '.self::getPackageList($packages, $isVerbose, $pool, $constraint).'. The # character in branch names is replaced by a + character. Make sure to require it as "'.str_replace('#', '+', $constraint->getPrettyString()).'".']; + } + } + // first check if the actual requested package is found in normal conditions // if so it must mean it is rejected by another constraint than the one given here if ($packages = $repositorySet->findPackages($packageName, $constraint)) { diff --git a/src/Composer/Repository/VcsRepository.php b/src/Composer/Repository/VcsRepository.php index d10ad87a0..575352954 100644 --- a/src/Composer/Repository/VcsRepository.php +++ b/src/Composer/Repository/VcsRepository.php @@ -341,7 +341,8 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt // make sure branch packages have a dev flag if (strpos($parsedBranch, 'dev-') === 0 || VersionParser::DEFAULT_BRANCH_ALIAS === $parsedBranch) { - $version = 'dev-' . $branch; + $version = 'dev-' . str_replace('#', '+', $branch); + $parsedBranch = str_replace('#', '+', $parsedBranch); } else { $prefix = strpos($branch, 'v') === 0 ? 'v' : ''; $version = $prefix . Preg::replace('{(\.9{7})+}', '.x', $parsedBranch); diff --git a/tests/Composer/Test/Fixtures/installer/solver-problem-with-hash-in-branch.test b/tests/Composer/Test/Fixtures/installer/solver-problem-with-hash-in-branch.test new file mode 100644 index 000000000..e45a57720 --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/solver-problem-with-hash-in-branch.test @@ -0,0 +1,40 @@ +--TEST-- +Test the problem output suggests fixes for branch names where the # was replaced by + +--COMPOSER-- +{ + "repositories": [ + { + "type": "package", + "package": [ + { "name": "package/found", "version": "dev-foo+bar" }, + { "name": "package/found2", "version": "dev-foo+abcd09832478" }, + { "name": "package/works", "version": "dev-foo+abcd09832478" }, + { "name": "package/works2", "version": "dev-+123" } + ] + } + ], + "require": { + "package/found": "dev-foo#bar", + "package/found2": "dev-foo#abcd09832478", + "package/works": "dev-foo+abcd09832478", + "package/works2": "dev-+123" + } +} + +--RUN-- +update + +--EXPECT-EXIT-CODE-- +2 + +--EXPECT-OUTPUT-- +Loading composer repositories with package information +Updating dependencies +Your requirements could not be resolved to an installable set of packages. + + Problem 1 + - Root composer.json requires package/found dev-foo#bar, found package/found[dev-foo+bar]. The # character in branch names is replaced by a + character. Make sure to require it as "dev-foo+bar". + Problem 2 + - Root composer.json requires package/found2 dev-foo#abcd09832478, found package/found2[dev-foo+abcd09832478]. The # character in branch names is replaced by a + character. Make sure to require it as "dev-foo+abcd09832478". + +--EXPECT-- diff --git a/tests/Composer/Test/Repository/VcsRepositoryTest.php b/tests/Composer/Test/Repository/VcsRepositoryTest.php index 692e716b8..429b12b30 100644 --- a/tests/Composer/Test/Repository/VcsRepositoryTest.php +++ b/tests/Composer/Test/Repository/VcsRepositoryTest.php @@ -94,6 +94,9 @@ class VcsRepositoryTest extends TestCase $exec('git add foo'); $exec('git commit -m change-a'); + // add foo#bar branch which should result in dev-foo+bar + $exec('git branch foo#bar'); + // add version to composer.json $exec('git checkout master'); $composer['version'] = '1.0.0'; @@ -154,6 +157,7 @@ class VcsRepositoryTest extends TestCase '1.1.x-dev' => true, 'dev-feature-b' => true, 'dev-feature/a-1.0-B' => true, + 'dev-foo+bar' => true, 'dev-master' => true, '9999999-dev' => true, // alias of dev-master ];